<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Rudrank Riyam on Medium]]></title>
        <description><![CDATA[Stories by Rudrank Riyam on Medium]]></description>
        <link>https://medium.com/@rudrankriyam?source=rss-f79b60908c24------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*E7LJQH6LC4sv3BEgwpS-0Q.jpeg</url>
            <title>Stories by Rudrank Riyam on Medium</title>
            <link>https://medium.com/@rudrankriyam?source=rss-f79b60908c24------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 15 May 2026 09:04:37 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@rudrankriyam/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Exploring Indie Life: Checklist for iOS 18 App Release]]></title>
            <link>https://rudrankriyam.medium.com/exploring-indie-life-checklist-for-ios-18-app-release-d2eab3b9da64?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/d2eab3b9da64</guid>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Tue, 13 Aug 2024 09:58:54 GMT</pubDate>
            <atom:updated>2024-08-14T20:10:43.355Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Originally published at </em><a href="https://www.rudrank.com/exploring-indie-life-checklist-for-ios-18-app-release/"><em>https://www.rudrank.com</em></a><em> on August 13, 2024.</em></p><p>The new iPhone will probably be out in a month, and iOS 18 will be out a week later after that. A lot of us are gearing up for a successful Day 1 release, and I created a checklist for myself to ensure everything goes according to plan.</p><p>As an indie developer, I know how important it is to be ready when a new iOS version drops. As Jordan Morgan said, <em>“You only launch once.”</em></p><p>The opportunity to seize and shine on the App Store is right in front of you. So, let’s dive into the checklist that I have created for a smooth iOS 18 app release of Meshing.</p><p>This post focuses on the app itself, and the subsequent ones will be about App Store Connect and press.</p><h3>Polish Your Feature Set</h3><p>The main thing. Creating a delightful app for users to enjoy. The one that works flawlessly before release. We all can dream, right?</p><p>As my app is iOS 18+, I am rigorously testing on the iPhone 14 Pro Max and XR to work with different screen sizes. I know a buggy app can quickly lose users, no matter how innovative the features are, so the core features should work well, and that is why I decided to have a TestFlight early on:</p><h3>Valuable Onboarding</h3><p>As soon as the user opens the app and sees the onboarding screen, they should <em>feel </em>that <strong>this is the app that will solve all of the life problems! </strong>Oh, I wish there was an app that worked that way.</p><p>The app should solve the problem they are looking to solve, and the onboarding gives a glipmse of it. It has enough guidance to get users started, but not so much that it becomes overwhelming. I hate those personalised never ending onboarding screens.</p><p>I plan to have a single screen onboarding, highlighting the core features. For my app, it is simple: you create a mesh gradient, you export it, or copy it to clipboard. And the cherry on top is Meshing AI for prompt based gradients. Quick, and to the point.</p><h3>Implement iOS 18 Features</h3><p>Apple loves to feature apps that showcase their latest iOS capabilities. I look for good ways to add the shiny new iOS 18 features into my app. We have the Control Widgets, and the custom translation in the Translate framework.</p><p>I want to make sure it feel natural, not forced.</p><h3>Set Up Analytics</h3><p>Not as brutal as big companies, but enough to know what the user are generally using. Keeping privacy as atmost priority. I have been using TelemetryDeck for a few years and happy with it tracking the key metrics.</p><p>In the early stages, I <em>need</em> this data to support the priority list for future updates and features.</p><h3>Feedback-Friendly Settings Page</h3><p>While I have not even created a settings page yet, I want to include an option for users to provide feedback. I am not a fan of buried contact forms, either so this will be a simple “Bug!” or “Feature Request” button within the settings that opens up mail.</p><p>I used something similar for Gradient Game and it is casual, friendly, and somewhat screams “I want to hear from you!” And it worked. User feedback is gold for us indie devs.</p><h3>An Effective Paywall</h3><p>Ah, time to print.</p><p>And pay bills.</p><p>Nope, not a paywall that opens every launch to bombard me with “BUY NOW!” sheets with insane weekly pricing. My paywall is going to be clear, upfront, and offer value. I am thinking of “Meshing Pro” version that unlocks export feature and Meshing AI. It is difficult to balance what should be under the free version, and what all is worth upgrading for. Meshing AI is for sure worth it, and I have to pay OpenAI, too.</p><p>The templates are an investment too because I manually create them, and it provides immediate value to the user who wants quick gradients.</p><p>Should export be under a paywall? Maybe a few free exports and then show the paywall? I want users to upgrade because they love the app, not because I have annoyed them into submission.</p><p>As I am writing this post during <a href="https://revenuecat-ship-a-ton.devpost.com/?ref=rudrank.com">RevenueCat’s Ship-a-ton</a>, I will use their new Paywall editor to come up with a subscription model. My plan is:</p><ul><li>3 dollars a month</li><li>20 dollars a year</li><li>30 dollars for lifetime access</li></ul><p>I have to think harder on the pricing. I do want tonot to undersell my work, while providing enough value to the user, too.</p><h3>Performance and Leaks</h3><p>When I saw the animated mesh gradients takes a whopping 10–12% and 100 MB on my phone, I was shocked. Creating a simple mesh gradient tool is harder on performance, and who knew pretty colors could be such resource hogs?</p><p>Here is my plan:</p><ol><li>Use Xcode Instruments to find the bottlenecks, especially when animating</li><li>Keep an eye on memory usage.</li><li>Move some computations to background threads.</li><li>Compress images without losing quality.</li></ol><p>A smooth app is a happy app leading to happy users!</p><h3>Errors??</h3><p>Working with APIs like OpenAI, or my backend means that everything and anything can go wrong. Error handling to gracefully manage issues is one of the least enjoyable work for me.</p><p>But we live in the LLMs era! I can handoff this work to Claude, and also use the ContentUnavailableView for consistency. Apart from user-friendly error messages and I want to at least add suggestions for resolving the issue.</p><h3>Accessibility Check</h3><p>I have to run through my app using VoiceOver and VoiceControl. And ensure the UI works well for extra large font sizes.</p><p>By running through all of this, I want to make sure Meshing is an app that everyone can enjoy, regardless of how they interact with their device. It is a bit of extra work, sure, but worth to know that anyone who wants to create beautiful mesh gradients can do so with ease.</p><h3>Localization</h3><p>While English is widely used, I have already localized the app for Simplified Chinese because I got some great feedback from a designer and I wanted to appreciate their efforts. My plan is to localise for the following languages:</p><p>I am using Localizable.xcstrings and Claude to translate the initial versions giving it the content of the app, so it can localise better. Then, I have friends who can look over the final translation to let me know if I am on the correct path!</p><h3>Moving Forward</h3><p>A lot of work is left. And I need to stay focused and adaptable. Here is my plan moving forward:</p><ul><li>Focus on core features and iOS 18 integrations first while testing thoroughly.</li><li>Take in the feedback and suggestions from the X community and implement them.</li><li>Work harder on the paywall structure and pricing tiers.</li><li>The app should be accessible to everyone.</li><li>Finalize translations and verify their accuracy.</li><li>Start planning App Store presence and press outreach.</li><li>And finally, take good care of myself.</li></ul><p>Happy shipping!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d2eab3b9da64" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Freelancing: The Idea of Freelancing]]></title>
            <link>https://rudrankriyam.medium.com/exploring-freelancing-the-idea-of-freelancing-309460edf2bb?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/309460edf2bb</guid>
            <category><![CDATA[freelance]]></category>
            <category><![CDATA[freelancers]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[freelancing]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Fri, 27 Oct 2023 14:49:27 GMT</pubDate>
            <atom:updated>2023-10-27T14:51:06.031Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jPkphe5N_oySsh1NdQA_Pg.png" /></figure><blockquote>This is a chapter from my book on Exploring Freelancing: <a href="https://rudrank.gumroad.com/l/freelance-journey">https://rudrank.gumroad.com/l/freelance-journey</a></blockquote><p>I still chuckle when I think about it. I have talked about this in numerous podcasts about how I started with iOS development in the first place.</p><p>2018, sophomore year of college. I was enjoying my sleek MacBook Air, feeling like the coolest kid on the block. That was until some classmates decided to have fun at my expense. <em>“Hey, bet that fancy MacBook cannot even run a single game our Windows machines can!”</em> they teased. Well, maybe they had a point. But my ego got hurt anyway, and I considered that a challenge.</p><p>Instead of sulking, I thought, <em>“What could this MacBook do that their Windows machine cannot?”</em> That is when I stumbled upon iOS development and an Udemy course by Angela Yu. The more I got into it, the more I felt like I had found my thing. An escape from reality instead of boring college courses. Writing in the Swift language felt flawless. Late nights were spent exploring the courses and tinkering with baby apps for the thrill.</p><p>I bumped into this senior who was doing something called as freelancing — someone whose Google Chrome had numerous tabs with the names of sites like <strong>Fiverr</strong> and <strong>Upwork</strong>. He was hustling, making some good dollars on the side by offering his Alexa skills. For me, he was living proof that fun hobbies could also bring in the money to help me get my next materialistic need: a MacBook Pro.</p><p>That was an eye-opener. My MacBook might not have played games as theirs did, but it sure played a different kind — a game that could potentially set the stage for my future!</p><h3><strong>The Learning Curve</strong></h3><p>When I first dipped my toes into iOS development, I was lost. The course I started with was comparatively easy initially, so I stopped going to college and binged the videos, locking myself around the four walls. A lot of code and mistakes, and nights where I would find myself staring blankly at my MacBook screen or a single error mocking me for hours. Syntax ones, logical ones, you name it, and I probably made that mistake. So much banging my head on the network calls and APIs, UI constraints, and everything in between.</p><p>However, every time I felt like giving up, I remembered the jests of my classmates. Call it spite-driven development. Each hurdle taught me something new; with every mistake, I wanted to improve at making apps.</p><p>Did I feel like giving up? Absolutely. More times than I would like to admit. But you know that the thing about hitting rock bottom is that you can only go up from there. Each setback became a stepping stone, each frustration more of a lesson.</p><p>If I wanted to freelance like my senior, I had to persist, and I realised creating apps for Apple devices was fun if I was paid handsomely for it.</p><h3><strong>Tapping the Resources</strong></h3><p>Angela Yu’s Udemy course was my starting point, but I slowly moved to more books and courses to explore. I picked up “The Swift Programming Language” by Apple Inc. It is the bible for Swift language used to develop Apple Platforms. Easy to understand and direct. I can spend hours crafting a better solution or search on my best friend: Stack Overflow. Someone there solved it, so sometimes it is not worth reinventing the wheel.</p><h3><strong>The Reality Check</strong></h3><p>After setting myself on many different freelancing accounts, I found myself mostly glued to the screen instead of college assignments, mindlessly refreshing the screen in anticipation of that first gig offer after applying to endless contracts. It felt like standing in a virtual auditorium, resume in hand, waiting for someone to call me onto the stage. <br> <br> Except no one did. The days turned into weeks, and there was not a single offer or even a message.</p><p>The reality sunk in: the freelancing world is less welcoming than I had imagined. I had zero experience. The dreams of echoing my senior’s success seemed to drift farther away from me every day as I started giving up hope. Now that I look back, it is obvious that it was a loop of no experience and no offer and no experience because of no offer and no offer because of no experience. Still, I was foolish enough to let doubts and impatience cloud my thoughts, and finally, I decided — freelancing was off the table. <br> <br> It was a hard pill to swallow, especially after witnessing firsthand someone who had turned it into a profitable lifestyle.</p><h3><strong>The Internship Insight</strong></h3><p>It was around this time when internships caught my eye. Unlike freelancing, where the vast sea of competition can be disheartening, internships provided a more structured environment for honing my skills. Plus, there was the appeal of steady income and mentorship, which felt like a safer bet for a still-green developer like myself.</p><p>I applied to a few places, leveraging the projects I had built while following Angela Yu’s course and other tutorials. One of the college seniors reached out to me as I was the only iOS developer around, and soon, I found myself interning at a small start-up working on some cool iOS projects. As it was a small one, I was their iOS intern and the iOS lead, starting two iOS apps from scratch.</p><p>It was not freelancing; I did not control my time or the project, but it was something. The income was mediocre but enough for my materialistic endeavours. I remember the joy of unboxing the new headphones I had longed for — bought from my internship earnings.</p><p>Though my jump start into iOS development took a different turn with internships, the idea of freelancing did not entirely leave me. The internship experience was a good step toward becoming a more experienced developer. Working with a backend developer, an Android developer, and a designer as a team gave me a more rounded skill set. Despite the initial hurdles and missteps, it confirmed that iOS development was the right track for me.</p><p>While my MacBook may not have been a gaming powerhouse, Xcode (Apple’s IDE to develop apps) became a tool for my ambition and dreams and a game I was more than willing to play.</p><blockquote>If you liked reading this chapter, checkout my book on Exploring Freelancing: <a href="https://rudrank.gumroad.com/l/freelance-journey">https://rudrank.gumroad.com/l/freelance-journey</a></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=309460edf2bb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring WishKit: Creating Your First Wish! ✨]]></title>
            <link>https://rudrankriyam.medium.com/exploring-wishkit-creating-your-first-wish-923559d325cf?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/923559d325cf</guid>
            <category><![CDATA[ios-apps]]></category>
            <category><![CDATA[ios-development]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Sat, 21 Oct 2023 07:02:33 GMT</pubDate>
            <atom:updated>2023-10-21T09:05:49.090Z</atom:updated>
            <content:encoded><![CDATA[<h4>Capture and analyse product feedback and feature requests in one place.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*621mXEPnxbJJjOTq" /><figcaption>Photo by <a href="https://unsplash.com/@casparrubin?utm_source=medium&amp;utm_medium=referral">Caspar Camille Rubin</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>When I was working on the <a href="https://apps.apple.com/in/app/gradient-game/id1479784361">Gradient Game</a>, I used to get a lot of feedback and product requests via mail. I usually got overwhelmed and never got to work on them, and unfortunately not capitalise on it either. I want to change that with my newest app, <a href="https://apps.apple.com/us/app/music-discovery-with-fusion/id6458877273">Fusion</a>.</p><p>Fortunately, I stumbled upon Martin’s <a href="https://www.wishkit.io">WishKit</a>! It helps to capture and analyse product feedback and feature requests in one place. And that’s what I want!</p><p>I have already implemented more than a few in the app and have a lot of happy TestFlight users! I am improving and customising the UI of the WishKit screen, so I wanted to pen down my experience using it in my app! In this article, I walk you through getting started with WishKit and configuring it to fit your app’s needs.</p><h3>Introduction</h3><p>WishKit lets you easily add feature request functionality to your app, allowing users to suggest and vote on new features. This is what my current screen looks like for using the framework in my app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IQltUfHA8wUObTr0UcRsAQ.png" /></figure><h3><strong>Adding WishKit as a Dependency</strong></h3><p>The first step in getting started with WishKit is to add it as a dependency in Xcode. When managing via Swift Package Manager, add WishKit as a dependency by adding it to the dependencies value of your Package.swift:</p><pre>dependencies: [<br> .package(url: “https://github.com/wishkit/wishkit-ios.git&quot;, .upToNextMajor(from: “4.0.0”))<br>]</pre><h3><strong>Configuring WishKit with your API Key</strong></h3><p>Once you have added WishKit as a dependency, you must configure it with your API Key. You can find your API Key in your admin dashboard on <a href="http://wishkit.io">wishkit.io</a>. In the first view of your app, add the following code to configure WishKit with your API Key:</p><pre>@main<br>struct FusionApp: App {<br><br>  init() {<br>    WishKit.configure(with: &quot;&lt;#App-API-Key#&gt;&quot;)<br>  }<br><br>  var body: some Scene {<br>    WindowGroup {<br>      // Your app&#39;s content here<br>    }<br>  }<br>}</pre><h3><strong>Using WishKit in Your Views</strong></h3><p>Now that you have configured WishKit, you can use it in any of your views. Simply import the WishKit framework and use WishKit.view. This is how I am using it in my app:</p><pre>struct SettingsView: View {<br>    var body: some View {<br>      NavigationStack {<br>        List {<br>          Section(&quot;Make a Wish! ✨&quot;) {<br>            NavigationLink(destination: WishKit.view, label: {<br>              Label(&quot;Request feature&quot;, systemImage: &quot;wand.and.stars&quot;)<br>            })<br>          }<br>        }<br>      }<br>    }<br>}</pre><p>Note: If one of the parent views does not have a NavigationView/NavigationStack, you must call withNavigation() on WishKit.view.</p><h3>Configuring WishKit UI Elements</h3><p>WishKit provides several configuration options to customise its UI elements. You can configure options such as the status badge, description display, segmented control, drop shadow, comment section, and more. Here is an example of how I am using some of these options:</p><pre>// Show the status badge of a feature request (e.g. pending, approved, etc.).<br>WishKit.config.statusBadge = .show<br><br>// Shows full description of a feature request in the list.<br>WishKit.config.expandDescriptionInList = true<br><br>// Remove drop shadow.<br>WishKit.config.dropShadow = .hide<br><br>// Change the corner radius.<br>WishKit.config.cornerRadius = 12</pre><p>Feel free to experiment with other configuration options WishKit provides to further customise the UI elements according to your app’s needs. Explore the static property config to know more about them.</p><h3>Theming WishKit</h3><p>You can also theme WishKit to match your app’s colour scheme. Another example of how I am theming the view for my app:</p><pre>// Set the primary color for WishKit theme<br>WishKit.theme.primaryColor = .primary<br><br>// Set the text color for the Add button<br>WishKit.config.buttons.addButton.textColor = .set(light: .white, dark: .black)<br><br>// Set the text color for the Save button<br>WishKit.config.buttons.saveButton.textColor = .set(light: .white, dark: .black)</pre><p>By setting the primary colour for the WishKit theme, I customise the overall colour scheme of WishKit to match my app’s primary colour.</p><p>Additionally, by setting the text colour for the <strong>Add</strong> and <strong>Save</strong> buttons, I ensure that the text is visible and readable against the background colour of the buttons. Similarly, you can also update the colour of the upvote button.</p><p>Feel free to adjust these colours according to your app’s design and colour scheme.</p><h3>Conclusion</h3><p>With WishKit, I can easily add feature request functionality to my app and engage with the users.</p><p>I hope this small introduction will encourage you to use it in your app, too! Make sure you actually work on the feedback gathered from your users and iterate on your app’s features. Share your experience with WishKit and tag <a href="https://twitter.com/MartinLasek">Martin</a> on X (formerly Twitter). Happy coding!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=923559d325cf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Technical Writing: The Taste of Online Money]]></title>
            <link>https://rudrankriyam.medium.com/exploring-technical-writing-the-taste-of-online-money-328539e2df0a?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/328539e2df0a</guid>
            <category><![CDATA[writing]]></category>
            <category><![CDATA[money]]></category>
            <category><![CDATA[online-money]]></category>
            <category><![CDATA[technical-writing]]></category>
            <category><![CDATA[online-money-making-tips]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Fri, 13 Oct 2023 05:04:47 GMT</pubDate>
            <atom:updated>2023-10-13T05:04:47.641Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CUneTi4usTPTMyoRDOHFjA.png" /></figure><blockquote>This post is an excerpt from my upcoming book “Exploring Technical Writing”.</blockquote><blockquote>You can pre-order the book at <strong>50% discount — </strong><a href="https://rudrank.gumroad.com/l/technical-writing/pre-order">https://rudrank.gumroad.com/l/technical-writing/pre-order</a></blockquote><p><em>“When I was young I thought that money was the most important thing in life; now that I am old I know that it is.” — Oscar Wilde</em></p><p>After publishing the first article on Medium in 2019, I learned that Medium has a program that pays you for the views from the paid members. This was a new opportunity that changed my perspective on writing. Get paid to write about what you love! I yearned to earn my first dollar online via writing.</p><p>During my college end-semester exams, I wanted to do everything except study. I decided to channel this energy into writing. I started writing a few more articles. At that time, I did not know what to write, and I was exploring many open-source projects and libraries for my app. So, I created a few curation articles instead of focusing on a particular topic or a tutorial. Like “5 SwiftUI Open-Source Projects to Use in Your Next App”.</p><p><strong>Joining the Medium Partner Program</strong></p><p>The program, called as the Medium Partner Program, probably commenced in November of 2019. I joined on November 20th just to try out my luck and hope to earn some bucks for my coffee addiction at college. Little did I know that this decision would lead to my first taste of online money. Under the Medium Partner Program, I wrote my first article, “Playing with Combine: Grid Layout in SwiftUI.” This article became eligible to earn money and was included in the metered paywall, allowing readers to pay for access or view it as part of their monthly subscription. And subsequently, I made my other articles eligible under the metered paywall.</p><p>These posts were a hit. I still do not know why, but I can guess that developers do not want to do the hard research and are happy to have a post that curates the popular tested projects. This way, they save time on the research and cherry-pick the project they like. The impressions on these articles, plus the Google SEO effect, were huge, with tens of thousands of views.</p><p><strong>The Disappointment</strong></p><p>However, my excitement was short-lived when I received an email on December 13th stating they could not pay me for my earnings. The reason was that Stripe, the payment processing platform, was still under preview for India. I did not have anything to lose despite the disappointment.</p><p><strong>The Unexpected Twist</strong></p><p>Surprisingly, Medium made a one-time payment through PayPal for the money I had earned. However, it was a temporary solution before shutting down the Medium Partner Program in India. I made <strong>$92.73</strong> from Medium in the first month of writing!</p><p>That was a lot of money for me as a college student in India. That was a month of food and coffee expenses for me. I know people from NYC cannot comprehend this, but this taste of online money from writing was delicious.</p><p>This experience opened my eyes to the possibilities of earning income through my passion. While it has been four years since the Medium Partner Program shut down, I am grateful for it for providing a platform for writers like me to showcase our work and earn recognition. It turned out to be a stepping stone towards realising the potential of online writing and its opportunities.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=328539e2df0a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Technical Writing: The First Post on Medium]]></title>
            <link>https://rudrankriyam.medium.com/exploring-technical-writing-the-first-post-on-medium-a3aedd72dcf8?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/a3aedd72dcf8</guid>
            <category><![CDATA[technical-writing]]></category>
            <category><![CDATA[ｗｒｉｔｉｎｇ]]></category>
            <category><![CDATA[medium]]></category>
            <category><![CDATA[writing]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Wed, 11 Oct 2023 09:22:47 GMT</pubDate>
            <atom:updated>2023-10-11T09:22:47.437Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CUneTi4usTPTMyoRDOHFjA.png" /></figure><blockquote>This post is an excerpt from my upcoming book “Exploring Technical Writing”.</blockquote><blockquote>You can pre-order the book at <strong>50% discount — </strong><a href="https://rudrank.gumroad.com/l/technical-writing/pre-order">https://rudrank.gumroad.com/l/technical-writing/pre-order</a></blockquote><p><em>“I write to discover what I know.” — Flannery O’Connor</em></p><p>Have you ever had an idea late at night that would not let you sleep, and you just did not know where to share it? Back in 2019, I came across a new framework introduced by Apple called Combine. It intrigued me, and I decided to learn more by picking up a book. Little did I know that this decision would lead me to an idea for my first post on Medium.</p><h3><strong>Discovering the Gap in SwiftUI</strong></h3><p>Around the same time in 2019, Apple also introduced another framework called SwiftUI, which allowed for declarative development for Apple platforms. However, as it was in the initial stages, something was missing from the framework. It lacked a native view for creating grid layouts with multiple rows and columns. This sparked an idea while reading about the Combine framework late at night.</p><h3><strong>Innovative Solution Using Combine</strong></h3><p>I thought of using two loops to create the desired layout while emitting values through the stream. To simplify, imagine you have a photo album with spaces for pairs of photos. You have six pictures of landscapes: mountains, beaches, forests, deserts, lakes, and valleys. You want to arrange them in the album so that every page shows two landscapes side by side:</p><p>Mountains | Beaches</p><p>Forests | Deserts</p><p>Lakes | Valleys</p><p>That is what I aimed to do, using the Combine framework. It seemed like a breakthrough, and I wanted to share it with others. However, when I searched the internet for similar approaches, I could not find any content related to it. I was amazed because no one else seemed to have this idea?</p><p>This led me to the dilemma of where to post my idea and the solution. I did not have a blog or want to invest in a domain. After using WordPress before, it was not the option I was looking for either. That is when I discovered Medium.com.</p><h3><strong>From Idea to Validation</strong></h3><p>I saw popular developers posting on Medium and gaining recognition, which motivated me to choose it as the platform for my first post. I wanted to share my idea and hopefully receive some claps as validation (haha!) and engagement from the community.</p><p>So, I went about writing my first post on Medium! I started with “Playing With Combine: Grid Layout in SwiftUI”, creating a playful but not click-bait title. At that time, the developers working with SwiftUI knew about the absence of a grid layout; for them, it was an instant click.</p><p>In the introduction, I briefly explained the context of my idea and how it came about. I mentioned Combine and SwiftUI and the lack of a native grid view in the framework.</p><p>Next, I explained my idea of using two loops to create the grid layout. I provided step-by-step instructions and code snippets to demonstrate implementing this solution in SwiftUI.</p><p>After explaining the solution, I shared the results, including the screenshots or images to visually showcase the grid layout created with multiple rows and columns.</p><p>Writing the first post on Medium over a night was nerve-wracking. I was too excited to share my idea and implementation as if I achieved the fusion of some nuclear elements. And people loved it! I went back to check the statistics, and the <a href="https://medium.com/better-programming/playing-with-combine-grid-layout-in-swiftui-42e652d6462e">post</a> has almost <strong>twenty thousand views</strong> and 830 claps over four years! Half of the views are from Google, meaning Medium’s strong domain authority did its magic.</p><p>This experience taught me that sometimes the best ideas come when you least expect them. Sharing my opinion on Medium and seeing it resonate with many people boosted my confidence. The initial writing success motivated me to explore, learn, and share more in the future!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3aedd72dcf8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Technical Writing: Writing as a Kid]]></title>
            <link>https://rudrankriyam.medium.com/exploring-technical-writing-writing-as-a-kid-372d0f223135?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/372d0f223135</guid>
            <category><![CDATA[writing]]></category>
            <category><![CDATA[blogging]]></category>
            <category><![CDATA[technical-writing]]></category>
            <category><![CDATA[ｗｒｉｔｉｎｇ]]></category>
            <category><![CDATA[blog]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Tue, 10 Oct 2023 10:14:33 GMT</pubDate>
            <atom:updated>2023-10-10T10:14:33.966Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CUneTi4usTPTMyoRDOHFjA.png" /><figcaption>Exploring Technical Writing</figcaption></figure><blockquote>This post is an excerpt from my upcoming book “Exploring Technical Writing”.</blockquote><blockquote>You can pre-order the book at <strong>50% discount — </strong><a href="https://rudrank.gumroad.com/l/technical-writing/pre-order">https://rudrank.gumroad.com/l/technical-writing/pre-order</a></blockquote><p><em>“Writing is the painting of the voice.” — Voltaire</em></p><p>Reflecting on my writing journey, I cannot help but giggle at the memories of my early days as a kid blogger. I was just 14 or maybe 15, so I prefer to embrace the innocence of the term “kid” instead of a teenager, finding joy in the little things.</p><h3><strong>Embarking on a Journey</strong></h3><p>It all started a decade ago when I had a “Freeze the Seconds” photography blog on WordPress dot com. I used to go on trips and take lots of pictures. I felt each picture had a story, and I would write creative captions for them. It was my little corner of the internet to express my creativity and share my experiences with others. I was a young shutterbug, and this blog was a way to express my love of capturing moments.</p><p>I loved taking pictures, capturing moments, and sharing them with the world. People liked what I was doing. I remember one comment that made me beam with joy. Someone said, “Great pictures! You surely seem to be having a thing for imagination. :)” It was one of my favourite moments!</p><p>But, for some reason, I cannot remember, I deleted that blog. It was either at the end of 2012 or the beginning of 2013. It was an impulsive decision, and I said goodbye to “Freeze the Seconds.”</p><p>Starting that blog was the initial part of my journey as a writer. It helped me express myself and connect with others, even though it was a few lines of captions.</p><h3><strong>Finding My Voice</strong></h3><p>In 2014, a new chapter of my writing journey began. There was a classmate of mine who was super good at writing complex English sentences. Everyone thought he was the superstar of the class! I felt envious and wanted to be cool like him.</p><p>But for me, writing was more about sharing my thoughts and feelings, a means of self-expression and cherishing being in my little world of reality. A virtual escape from the reality of high school, where I could vent out my thoughts and feelings. At that time, my life mostly revolved around solving homework and the constant dread of attending school.</p><p>So, I started a blog called “Husk of Abandoned Dreams”. I still do not know why I chose that name, but it sounded heavy. This blog became my getaway where I could be myself without any judgment.</p><p>My first blog post was a raw introduction to who I was. I wanted to be real, to be me. It was unfiltered and perhaps too honest. I introduced myself as a “<em>screwed 17-year-old teenager, science student [LOL].</em>” I shared my love for music how I enjoyed playing the guitar and piano, and writing songs. I was candid about my views and scepticism towards friendship and love and how gaming and music were my lifelines. I ended my post with a quote by Justina Chen,</p><p><em>“You raze the old to raise the new.”</em></p><p>Those words were powerful. It reflected my mindset: to break free from my past and build a new future!</p><p>I was an introvert, and sharing my thoughts with the world was not something I was comfortable with. I was putting myself out there, all my thoughts and feelings, for the world to see. It was scary. At that time, I did not even consider myself a blogger. I mentioned in my post that blogging was not my game. But I was so tired of feeling unheard, so I poured my heart out on my blog, even if nobody seemed to care. I wrote about everything disturbing my mind, from personal experiences to social issues to my mistakes.</p><p>I did not have a specific topic or theme for my blog, though. It was a way to process my thoughts and emotions and connect with others who might relate to what I was going through.</p><h3><strong>The Power of Words</strong></h3><p>As time passed, I received feedback and comments from readers who resonated with my posts. It was a small but supportive community that encouraged me to continue blogging. I realised that my words had the power to impact others and create a sense of connection.</p><p>Looking back, I realise how much I have grown since then. My thoughts have evolved, my writing has improved, and my understanding of the world has broadened. But one thing has remained constant — my love for writing. It was my first step into the writing world and paved the way for my journey as a technical writer.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=372d0f223135" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring TipKit: Creating Your First Tip]]></title>
            <link>https://medium.com/better-programming/exploring-tipkit-creating-your-first-tip-9013ede179b8?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/9013ede179b8</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[tipkit]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[ios-development]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Tue, 29 Aug 2023 21:15:30 GMT</pubDate>
            <atom:updated>2023-08-30T13:28:41.402Z</atom:updated>
            <content:encoded><![CDATA[<h4>Learn how to craft and display your first user-friendly tip in your SwiftUI app using Apple’s new TipKit framework.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Em9_HmCbtE1B3etc" /><figcaption>Photo by <a href="https://unsplash.com/@robman?utm_source=medium&amp;utm_medium=referral">Rob Hampson</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p><a href="https://developer.apple.com/documentation/tipkit">TipKit</a> is a framework to help you easily present helpful tips and educational cues to users, guiding them through the features of an app at the right moment. Designed for SwiftUI, UIKit, and AppKit, this article will specifically focus on SwiftUI.</p><p>In this post, I will refer to creating a tip for my app, Fussion<strong>, </strong>where you get Spotify’s Blend-like features for Apple Music. I want to create numerous tips to guide users to either add feature request, or learn how to use the app’s features.</p><h3>Tip Protocol</h3><p>Let’s delve into the protocol Tip, which conforms to both Identifiable and Sendable. This protocol acts as the foundation for creating, defining, and shaping tips.</p><pre>@available(macOS 14.0, iOS 17.0, tvOS 17.0, watchOS 10.0, xrOS 1.0, *)<br>protocol Tip: Identifiable, Sendable { }</pre><p>The Tip protocol has several instance properties that allow for different tip customisation. We start with the context of MyFirstTip, a simple tip, to explore how to set up the content of a tip.</p><pre>struct MyFirstTip: Tip {<br>  var title: Text {<br>    Text(&quot;Testing a tip!&quot;)<br>  }<br>  <br>  var message: Text? {<br>    Text(&quot;It is working!&quot;)<br>  }<br><br>  var image: Image? {<br>    Image(systemName: &quot;star&quot;)<br>  }<br>}</pre><h3>Understanding the Properties</h3><p>The foremost property is the title, a non-optional attribute and the main requirement for a tip that conveys the benefit of your tip. In the example of MyFirstTip, the title is &quot;Testing a tip!&quot;. Well, it is the first tip; we start with some testing, hah. This sets the stage and is often the first thing the user will read.</p><pre>var title: Text { get }</pre><p>Although optional, the next attribute, the message, works with the title to deepen user understanding. In MyFirstTip, this is presented as &quot;It is working!&quot; adding a layer of confirmation to the title that we are testing!</p><pre>var message: Text? { get }</pre><p>Then, we have the image, another optional property that provides visual context to the tip. It makes the tip more engaging while offering a quick, intuitive cue for users to grasp the essence of the tip. For MyFirstTip, this image of a star complements the title and message, making me happy about the testing process.</p><pre>var image: Image? { get }</pre><p>Each property — title, message, and image— serves its role in forming a valuable tip. The title catches your eye and grabs attention, the message makes things clear, and the picture adds a fun touch — these work together to create a helpful and easy-to-understand tip for the user.</p><h3>Creating a Tip</h3><p>A tip should be more than just informational — it should encapsulate the essence of the feature it’s guiding the user toward. I have created a WishKitTip tip to guide users on adding a &quot;wish&quot; or feature request within my app.</p><pre>@available(macOS 14.0, iOS 17.0, tvOS 17.0, watchOS 10.0, *)<br>struct WishKitTip: Tip {<br>  var title: Text {<br>    Text(&quot;Add a Wish!&quot;)<br>      .font(.tipTitle)<br>  }<br>  <br>  var message: Text? {<br>    Text(&quot;Upvote or create your feature request for me to work on.&quot;)<br>      .font(.tipMessage)<br>  }<br>  <br>  var image: Image? {<br>    Image(systemName: &quot;wand.and.rays.inverse&quot;)<br>  }<br>}</pre><p>Notice how I use SwiftUI’s built-in .font() modifier directly within the tip&#39;s title and message properties. This demonstrates the advantage of TipKit&#39;s full integration with SwiftUI—you can employ any SwiftUI modifiers for Text to make your tips customisable.</p><ul><li>title: Text: The title here is &quot;Add a Wish!&quot; with a font style set to .tipTitle. This aligns with the feature it discusses—adding a wish or feature request.</li><li>message: Text?: The message serves as a secondary guide. It specifies what actions the user can perform—either upvote an existing wish or create a new one.</li><li>image: Image?: The image uses the system symbol wand.and.rays.inverse, visually supporting the &quot;wish&quot; concept. An image can speak a thousand words, and here, it quietly but effectively tells the user that my coding magic to implement their favourite feature is just a click away. 🤪</li></ul><h3>Configuring TipKit</h3><p>Before we show our first tip to users, we need to get TipKit ready. To do that, we use the Tips.configure() method. It configures an app’s tips.</p><pre>@available(macOS 14.0, iOS 17.0, tvOS 17.0, watchOS 10.0, *)<br>@frozen public enum Tips {<br>  public static func configure(_ configuration: [Tips.ConfigurationOption] = []) throws<br>}</pre><p>Usually, you do this setup right when your app starts. For UIKit, this would be in the AppDelegate. For SwiftUI, you can do it directly in the @main App struct.</p><p>Here’s how I do it for my app, Fussion:</p><pre>@main struct FussionApp: App {<br>  init() {<br>    do {<br>      try await Tips.configure()<br>    } catch {<br>      print(&quot;Failed to configure TipKit: \(error)&quot;)<br>    }<br>  }<br>  <br>  var body: some Scene {<br>    WindowGroup {<br>      ContentView()<br>    }<br>  }<br>}</pre><p>With the initial setup done, we are ready to help us display useful tips to our users using SwiftUI.</p><h3>Displaying the Tip</h3><p>The TipKit team created TipView, making placing the views easier. We can add this TipView to any part of our app. I have a new tip in place — this time, I let the users know they can long-press to play a station.</p><pre>@available(macOS 14.0, iOS 17.0, tvOS 17.0, watchOS 10.0, *)<br>struct PlayStationDirectlyTip: Tip {<br>  var title: Text {<br>    Text(&quot;Play the station!&quot;)<br>      .font(.tipTitle)<br>  }<br><br>  var message: Text? {<br>    Text(&quot;Long-press the cover art of the station to play it directly.&quot;)<br>      .font(.tipMessage)<br>  }<br><br>  var image: Image? {<br>    Image(systemName: &quot;radio.fill&quot;)<br>  }<br>}</pre><p>Smart move, and it makes the navigation even simpler in <strong>Fussion:</strong></p><pre>ScrollView {<br>  LazyVGrid(columns: columns) {<br>    NavigationLink(destination: ///)<br>    })<br>    .buttonStyle(.plain)<br>  }<br>  .padding(.horizontal)<br><br>  if #available(macOS 14.0, iOS 17.0, tvOS 17.0, watchOS 10.0, *) {<br>    TipView(PlayStationDirectlyTip(), arrowEdge: .top)<br>      .padding(.horizontal)<br>  }<br>}</pre><p>And there you have it! This way, the users are guided and enriched with features they might have missed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QlmS4bk0iYHwjXU7m892Ig.png" /></figure><h3>Conclusion</h3><p>TipKit provides a straightforward yet powerful way to offer timely, context-sensitive tips in your apps. It supports all of Apple’s platforms and integrates cleanly with SwiftUI, UIKit, and AppKit. Properly setting the framework significantly improves your app&#39;s user onboarding and feature discovery.</p><p>So, implement TipKit in your app and help users understand new features seamlessly. Happy coding!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9013ede179b8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/exploring-tipkit-creating-your-first-tip-9013ede179b8">Exploring TipKit: Creating Your First Tip</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[1. Continuous Improvement in 2022]]></title>
            <link>https://medium.com/random-ramblingsrambling-on-about-my-experiences/1-continuous-improvement-in-2022-230188d6fe75?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/230188d6fe75</guid>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Sun, 13 Aug 2023 19:08:21 GMT</pubDate>
            <atom:updated>2023-08-13T19:08:21.732Z</atom:updated>
            <content:encoded><![CDATA[<p><em>This is an archived newsletter issue published on December 19, 2021.</em></p><p>It’s 18th December already. I can’t believe that 2021 is almost over. It was like March a few days ago, and now it’ll be Christmas in a few days.</p><p>This year has been different for many of you, including me — a wild ride.</p><p>I went from getting offers to work as a full-time iOS engineer to rejecting them and risking working as a freelancer and a technical writer. And the biggest challenge — battling for life with COVID. The year ended on a good note when I decided to switch paths a little and land a role as a Developer Relations Engineer.</p><h3>Rudrank on Twitter: &quot;Some professional news: I joined @codemagicio as the Developer Relations Engineer! 🥳 / Twitter&quot;</h3><p>Some professional news: I joined @codemagicio as the Developer Relations Engineer! 🥳</p><p>I didn’t tick a single goal I planned for myself in the 2021 roadmap, and I’m glad it went that way. I slowly realise that life isn’t a to-do list to tick your goals and be happy about it. I did that in 2020, got my “dream” internship at Apple, and then it felt aimless.</p><h3>Daniel Vassallo on Twitter: &quot;2021 Year In ReviewAlmost nothing that I&#39;m doing now I could have predicted to be doing this time last year. / Twitter&quot;</h3><p>2021 Year In ReviewAlmost nothing that I&#39;m doing now I could have predicted to be doing this time last year.</p><p>I’ve learned about myself how I love to take ambitious challenges. Let’s refactor the whole codebase! Let’s push this big feature that’ll double the revenue in a week! Let’s write this blog post in a day!</p><p>I never succeeded in any of them and failed miserably instead.</p><p>I messed up the refactor.</p><p>The big feature broke in production because I wrote the code quickly.</p><p>And I intended to complete that post in a day? Well, that took me a month.</p><h3>Continuous Improvement in 2022</h3><p>Advocating for a CI/CD platform made me realise how I need a continuous integration process in my life too. Instead of refactoring the whole codebase, let’s take one non-crucial screen to refactor, send a pull request, make sure it works, and then move on to the next small thing. Instead of writing a post in a day, let’s focus on writing one section in a day. Achievable? Without any doubt.</p><p>It isn’t easy to maintain <strong>consistency, </strong>and it should be. This habit of trying to achieve everything at once has taken months to develop, and it’ll take months to break too.</p><h3>Ed Latimore on Twitter: &quot;Be consistent for 1 year and you&#39;ll surpass even your wildest ambition. / Twitter&quot;</h3><p>Be consistent for 1 year and you&#39;ll surpass even your wildest ambition.</p><h3>Journaling</h3><p>I used to write (like using a pen and paper) a lot a few years ago to curate my thoughts and emotions into bits and pieces of paper. It definitely helped me to understand what my mind hopes and what the reality is.</p><h3>MIDE✦OLADELE on Twitter: &quot;How to stop lying to yourself:Start journaling.Our minds avoid difficult conversations to remain comfortable.Write on your:* Thoughts* Emotions * Current situation You&#39;ll be able to review your thoughts and bring yourself to reality / Twitter&quot;</h3><p>How to stop lying to yourself:Start journaling.Our minds avoid difficult conversations to remain comfortable.Write on your:* Thoughts* Emotions * Current situation You&#39;ll be able to review your thoughts and bring yourself to reality</p><h3>Early Conclusion</h3><p>I’m still evaluating what value this newsletter provides and how to proceed further in 2020.</p><p>Do people like ramblings instead of newsletters filled with tech? I don’t know.</p><p>All I know is I want to be consistent with it, and if you loved what I wrote above, share it with your friends!</p><p>If you didn’t, do let me know your feedback, and if you want, you can unsubscribe.</p><p>Happy weekend!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=230188d6fe75" width="1" height="1" alt=""><hr><p><a href="https://medium.com/random-ramblingsrambling-on-about-my-experiences/1-continuous-improvement-in-2022-230188d6fe75">1. Continuous Improvement in 2022</a> was originally published in <a href="https://medium.com/random-ramblingsrambling-on-about-my-experiences">Random Ramblings</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring MusicKit: User’s Personal Apple Music Station]]></title>
            <link>https://rudrankriyam.medium.com/exploring-musickit-users-personal-apple-music-station-699aee48276a?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/699aee48276a</guid>
            <category><![CDATA[apple-music]]></category>
            <category><![CDATA[swift-language]]></category>
            <category><![CDATA[ios-programming]]></category>
            <category><![CDATA[musickit]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Thu, 20 Jul 2023 07:14:41 GMT</pubDate>
            <atom:updated>2023-07-20T07:15:55.660Z</atom:updated>
            <content:encoded><![CDATA[<p>I am working on a new app <strong>FusionMix, </strong>that revolves around creating the same “Blend for Spotify” experience for Apple Music users. I am inclining towards the user’s personal Apple Music station to achieve it.</p><p>Working with the station is straightforward. Apple Music API has a dedicated endpoint, and we can use MusicKit to parse the station data.</p><h3>User’s Personal Apple Music Station Endpoint</h3><p>To fetch the current user’s personal Apple Music station, we use the following endpoint:</p><pre>https://api.music.apple.com/v1/catalog/{storefront}/stations?filter[identity]=personal</pre><p>The following endpoint returns an array of stations, and we can get the station data we want.</p><p>For example, this is what my station response looks like:</p><pre>{<br>    &quot;data&quot;: [<br>        {<br>            &quot;id&quot;: &quot;ra.u-04bcab05bb818ecf1abb70ff757&quot;,<br>            &quot;type&quot;: &quot;stations&quot;,<br>            &quot;href&quot;: &quot;/v1/catalog/in/stations/ra.u-04bcab05bb818ecf1abb70ff757&quot;,<br>            &quot;attributes&quot;: {<br>                &quot;isLive&quot;: false,<br>                &quot;name&quot;: &quot;Rudrank Riyam’s Station&quot;,<br>                &quot;mediaKind&quot;: &quot;audio&quot;,<br>                &quot;artwork&quot;: {<br>                    &quot;width&quot;: 2400,<br>                    &quot;height&quot;: 2400,<br>                    &quot;url&quot;: &quot;https://is1-ssl.mzstatic.com/image/thumb/Features124/v4/7b/1d/f0/7b1df048-0017-8ac0-98c9-735f14849606/mza_7507996640781423701.png/{w}x{h}bb.jpg&quot;<br>                },<br>                &quot;url&quot;: &quot;https://music.apple.com/in/station/rudrank-riyams-station/ra.u-04bcab05bb818ecf1abb70ff757&quot;,<br>                &quot;playParams&quot;: {<br>                    &quot;id&quot;: &quot;ra.u-04bcab05bb818ecf1abb70ff757&quot;,<br>                    &quot;kind&quot;: &quot;radioStation&quot;,<br>                    &quot;format&quot;: &quot;tracks&quot;,<br>                    &quot;stationHash&quot;: &quot;CgoIByIGCIDRuo8f&quot;,<br>                    &quot;hasDrm&quot;: false,<br>                    &quot;mediaType&quot;: 0<br>                }<br>            }<br>        }<br>    ],<br>    &quot;meta&quot;: {<br>        &quot;filters&quot;: {<br>            &quot;identity&quot;: {<br>                &quot;personal&quot;: [<br>                    {<br>                        &quot;id&quot;: &quot;ra.u-04bcab05bb818ecf1abb70ff757&quot;,<br>                        &quot;type&quot;: &quot;stations&quot;,<br>                        &quot;href&quot;: &quot;/v1/catalog/in/stations/ra.u-04bcab05bb818ecf1abb70ff757&quot;<br>                    }<br>                ]<br>            }<br>        }<br>    }<br>}</pre><p>We can see that the data contains an array of Station objects. To use this in your Swift project with MusicKit, we use MusicDataRequest to decode it to MusicItemCollection&lt;Station&gt; structure.</p><h3>Get User’s Personal Apple Music Station with MusicKit</h3><p>We define an enum for potential errors, we might encounter:</p><pre>enum PersonalStationError: Error {<br>  case invalidURL<br>  case notFound<br>}</pre><p>This enum includes two cases: invalidURL and notFound, which represent possible issues we might run into while fetching the personal music station.</p><p>Next, we fetch the current country code which we use as a storefront:</p><pre>let storefront = try await MusicDataRequest.currentCountryCode</pre><p>After we have the storefront, we build the URL request using URLComponents and append the storefront to the path and include a query item to filter the personal station:</p><pre>var urlComponents = URLComponents()<br>urlComponents.scheme = &quot;https&quot;<br>urlComponents.host = &quot;api.music.apple.com&quot;<br>urlComponents.path = &quot;/v1/catalog/\(storefront)/stations/personal&quot;<br>urlComponents.queryItems = [URLQueryItem(name: &quot;filter[identity]&quot;, value: &quot;personal&quot;)]</pre><p>Then, we use the MusicDataRequest that handles both the authorisation and music user token for us:</p><pre>guard let url = urlComponents.url else {<br>  throw PersonalStationError.invalidURL<br>}<br><br>let request = MusicDataRequest(urlRequest: URLRequest(url: url))<br>let response = try await request.response()</pre><p>After getting the response, we decode the data into a collection of MusicKit’s Station:</p><pre>let stations = try JSONDecoder().decode(MusicItemCollection&lt;Station&gt;.self, from: response.data)</pre><p>Lastly, we get the first station from our stations list:</p><pre>guard let personalStation = stations.first else {<br>  throw PersonalStationError.notFound<br>}<br><br>debugPrint(personalStation)</pre><p>That’s it! This fetches your personal Apple Music station using MusicKit.</p><p>Printing the station to the console, I get the following for my station:</p><pre>Station(<br>  id: &quot;ra.u-04bcab05bb818ecf1abb70ff757&quot;,<br>  name: &quot;Rudrank Riyam’s Station&quot;,<br>  isLive: false,<br>  url: &quot;https://music.apple.com/in/station/rudrank-riyams-station/ra.u-04bcab05bb818ecf1abb70ff757&quot;</pre><h3>Play User’s Personal Apple Music Station with MusicKit</h3><p>To play this station, you need to set the queue of the player and play it:</p><pre>do {<br>  guard let station = station else { return }<br>  ApplicationMusicPlayer.shared.queue = [station]<br>  try await ApplicationMusicPlayer.shared.play()<br>} catch {<br>  debugPrint(error)<br>}</pre><h3>Conclusion</h3><p>Using MusicKit for fetching a user’s personal Apple Music station is simple. However, remember to handle potential errors appropriately and give clear feedback to your users.</p><p>Happy coding, and keep the station playing!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=699aee48276a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using the New iOS 15 DynamicTypeSize in SwiftUI]]></title>
            <link>https://medium.com/better-programming/using-the-new-ios-15-dynamictypesize-in-swiftui-8e8e860aebde?source=rss-f79b60908c24------2</link>
            <guid isPermaLink="false">https://medium.com/p/8e8e860aebde</guid>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios-apps]]></category>
            <category><![CDATA[dynamic-type]]></category>
            <dc:creator><![CDATA[Rudrank Riyam]]></dc:creator>
            <pubDate>Wed, 02 Mar 2022 08:45:20 GMT</pubDate>
            <atom:updated>2022-03-05T01:03:02.997Z</atom:updated>
            <content:encoded><![CDATA[<h4>Make your text and views accessible for different font sizes</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pb4g9AaeoXytXTLU" /><figcaption>Photo by <a href="https://unsplash.com/@cardmapr?utm_source=medium&amp;utm_medium=referral">CardMapr</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>I introduced myself to the world of dynamic text sizes back in August 2019. My country’s popular food delivery apps didn’t change the text size when changing the system font size. (they still don’t) I wondered what APIs are required to increase the text sizes and alter the view accordingly.</p><p>In SwiftUI, using the system font text style automatically changes:</p><pre>Text(&quot;Something cool goes in here.&quot;)<br>  .font(.body)</pre><p>It also adjusts the view and the constraints accordingly when the size increases or decreases. But, as you increase the text size to the accessibility sizes (huge text), the view may truncate and look unreadable. You may have to create another different view structure to solve this.</p><h3>Old Way — ContentSizeCategory</h3><p>SwiftUI provides us with an environment ContentSizeCategory. Here’s an example from my app where I change the layout from a grid to a list when the size increases:</p><pre>struct HomeGameTypeView: View {<br>  <a href="http://twitter.com/EnvironmentObject">@EnvironmentObject</a> var preferences: Preferences<br>  <br>  <a href="http://twitter.com/Environment">@Environment</a>(\.sizeCategory) private var category<br>  <br>  var body: some View {<br>    if category &gt;= .extraExtraLarge {<br>      ScrollView {<br>        LazyVStack {<br>          list<br>        }<br>      }<br>    } else {<br>      LazyVGrid(columns: [.init(), .init()]) {<br>        list<br>      }<br>    }<br>  }<br>  <br>  var list: some View {<br>    ForEach(GameTypeOption.allCases) { type in<br>      HomeGameTypeRow(selection: $preferences.gameTypeSelection, type: type)<br>    }<br>  }<br>}</pre><h3>New Way — DynamicTypeSize</h3><p>In iOS 15, the ContentSizeCategory is deprecated and replaced by DynamicTypeSize. Rewriting the above example:</p><pre>struct HomeGameTypeView: View {<br>  <a href="http://twitter.com/EnvironmentObject">@EnvironmentObject</a> var preferences: Preferences<br>  <br>  <a href="http://twitter.com/Environment">@Environment</a>(\.dynamicTypeSize) var size // &lt;- NEW<br>  <br>  var body: some View {<br>    if size &gt;= .xxLarge { // &lt;- NEW<br>      ScrollView {<br>        LazyVStack {<br>          list<br>        }<br>      }<br>    } else {<br>      LazyVGrid(columns: [.init(), .init()]) {<br>        list<br>      }<br>    }<br>  }<br>}</pre><p>This can also limit the text sizes to a particular size (not recommended, in my opinion) or a range of sizes.</p><pre>var content: some View {<br>  Text(item.name.uppercased())<br>    .font(.title)<br>    .dynamicTypeSize(..&lt;DynamicTypeSize.accessibility1) // &lt;- RANGE<br>    .foregroundColor(.primary)<br>}</pre><p>I know that the title text style is large enough, and I don’t want it to go beyond the accessibility medium size.</p><h3>DynamicTypeSize in Previews</h3><p>To test different sizes in previews, you can add a constant size as an environment to the preview:</p><pre>struct IntroductionView_Previews: PreviewProvider {<br>  static var previews: some View {<br>    IntroductionView()<br>      .environment(\.dynamicTypeSize, .accessibility1) // &lt;- CONSTANT<br>  }<br>}</pre><h3>Large Content Viewer</h3><p>If you’re constraining the text size, you can add the method accessibilityShowsLargeContentViewer(). When the user is on an accessibility text size, a long tap on the view shows an enlarged text size:</p><pre>var body: some View {<br>  Button(action: action) {<br>    content<br>  }<br>  .buttonStyle(HomeButtonStyle(isSelected: false))<br>  .padding([.bottom, .horizontal], 8)<br>  .accessibilityShowsLargeContentViewer()<br>}</pre><p>Although, note these words from the documentation:</p><p>Rely on the large content viewer only when items must remain small due to unavoidable design constraints. For example, buttons in a tab bar remain small to leave more room for the main app content.</p><p>Don’t use the large content viewer to replace proper Dynamic Type support. For example, Dynamic Type allows items in a list to grow or shrink vertically to accommodate the user’s preferred font size. Rely on the large content viewer only when items must remain small due to unavoidable design constraints.</p><h3>Conclusion</h3><p>Dynamic Type helps your users use your app for any text size, providing them with an exceptional experience. Using SwiftUI makes it easier to add Dynamic Type and structure the views accordingly.</p><p>I know it gets tougher as the views get more complex, but you can still try your best to make your apps accessible for at least xxxlarge sizes.</p><pre><strong>Want to Connect?</strong></pre><pre>If you have a better approach, let me know <a href="https://twitter.com/rudrankriyam">on Twitter</a>!</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8e8e860aebde" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/using-the-new-ios-15-dynamictypesize-in-swiftui-8e8e860aebde">Using the New iOS 15 DynamicTypeSize in SwiftUI</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>