<?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 Chinmay Kabi on Medium]]></title>
        <description><![CDATA[Stories by Chinmay Kabi on Medium]]></description>
        <link>https://medium.com/@chinmaykabi?source=rss-45255f4277bc------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*RQ9mYAawZI6IaYOgaz6WSw.jpeg</url>
            <title>Stories by Chinmay Kabi on Medium</title>
            <link>https://medium.com/@chinmaykabi?source=rss-45255f4277bc------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 22 Jun 2026 05:46:01 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@chinmaykabi/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[Case in point : How Flutter optimizes widget rebuilds and why it used phone number as otp]]></title>
            <link>https://chinmaykabi.medium.com/case-in-point-how-flutter-optimizes-widget-rebuilds-and-why-it-used-phone-number-as-otp-58a5283f7053?source=rss-45255f4277bc------2</link>
            <guid isPermaLink="false">https://medium.com/p/58a5283f7053</guid>
            <category><![CDATA[flutter-widget]]></category>
            <category><![CDATA[flutter-app-development]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Chinmay Kabi]]></dc:creator>
            <pubDate>Sun, 31 Oct 2021 13:27:19 GMT</pubDate>
            <atom:updated>2021-10-31T13:27:19.188Z</atom:updated>
            <content:encoded><![CDATA[<h3>Case in point : How Flutter optimizes widget rebuilds and why it used phone number as otp</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/499/1*M60WL5gfrJsEXMJh8beMHg.jpeg" /><figcaption>How my widgets interacted in this case</figcaption></figure><blockquote>I’m a man of few means, and a developer of even fewer lines of code — Yours truly</blockquote><p>This is my login screen with avant garde security.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8fbfbea5a81d38cb48be3e779e7b4311/href">https://medium.com/media/8fbfbea5a81d38cb48be3e779e7b4311/href</a></iframe><p>Looks about fine, right? Go through this gem of a code, and you will have a rough idea of how it will work. You can take it out for a spin on this <a href="https://dartpad.dartlang.org/?id=93af39f39ed30b55021e2db22b5e4a7f&amp;null_safety=true">dartpad.dev snippet</a>.</p><p><strong>Something isn’t right</strong></p><p>If you failed to notice, go back and try these steps again. Enter a phone number, press on send otp, and while the textfield changes, the phone number is prefilled in that field. You can see the `otp` hint text once you clear the prefilled number. But why is this behaviour happening?</p><p><strong><em>Enter Flutter’s Sublinear widget tree building</em></strong></p><h3><strong>Sublinear widget building</strong></h3><p>A general adage for Flutter is “It’s all widgets”. For eg, Padding is not a property of a widget but a widget itself. As a result Flutter has to handle a deeply nested widget tree. Traversing this whole tree the usual way will result in bad performance, so Flutter has some tricks up its sleeve to achieve it in sublinear time.</p><p>One of these tricks is not visiting the tree if the child has not marked itself as dirty(change of state). This tree <strong><em>also</em></strong> holds the state of the widget. Now to find which of the widgets is dirty, a tree diff algorithm would be easier, but not necessarily efficient, so Flutter uses its own algotithm of O(N) complexity. Keep in mind that most layout alsorithms you will find are O(n²) or worse, and a sublinear algorithm is key to achieve a 60fps render in Flutter</p><p>The child list reconciliation algorithm optimizes for the following cases:</p><ul><li>The old child list is empty.</li><li>The two lists are identical.</li><li>There is an insertion or removal of one or more widgets in exactly one place in the list.</li><li>If each list contains a widget with the same key, the two widgets are matched.</li><li>Along with keys, the runtime type is also checked at the same level.</li></ul><p>In my case, the runtime type was the same, and because there were no keys assigned to the widgets, they were considered to have the same state. So while the widget is switched because of a simple boolean flag, the state of that widget is not. And thus the state of the old widget is imposed on the new one, because the poor thing could not distinguish one from the other :(</p><p>The easy fix is to pass each of the textfields a unique key!</p><p>Why this felt like a bug to me at first was because we are accustomed to differentiating different objects of same runtime types depending on their instances, and at times by the data they hold. Things get clearer though once we understand why Flutter does the things it does, doesn’t it?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*SDfcSqR6bfbqnIaJ4GL5AA.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=58a5283f7053" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How !to make a calling app in Flutter for Android devices]]></title>
            <link>https://chinmaykabi.medium.com/how-to-make-a-calling-app-in-flutter-for-android-devices-506c92e01a31?source=rss-45255f4277bc------2</link>
            <guid isPermaLink="false">https://medium.com/p/506c92e01a31</guid>
            <category><![CDATA[agora]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[voip]]></category>
            <category><![CDATA[plugins]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Chinmay Kabi]]></dc:creator>
            <pubDate>Mon, 14 Jun 2021 16:29:17 GMT</pubDate>
            <atom:updated>2021-06-14T18:12:23.903Z</atom:updated>
            <content:encoded><![CDATA[<h3>How !to make a calling app in Flutter for Android devices</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/537/1*oBQOEMqodM2U3ClssavBLw.jpeg" /><figcaption>Use the right tools for the job!</figcaption></figure><p><em>Disclaimer- That </em><em>! in the title is not a typo, read it as </em><em>not. This article is not a tutorial about how to make a WhatsApp or skype type calling app, rather it is an article about how I fell short of making such an app using flutter.</em></p><p>I have been trying to make a voice calling app using Flutter. You will find many articles and videos about how easy-peasy it is to integrate Twilio or Agora into a flutter app, but I could not find one resource which dived deep into making a true calling app in Flutter. What do I mean by <strong><em>true calling app</em></strong> ?</p><h3>What a true calling app should have</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*mvz4pUgt0XYH9f59.png" /><figcaption>On receiving data notification for call</figcaption></figure><p>On receiving data notification for call</p><ul><li>The app should work even when it is in background, or terminated even.</li><li>The app should work over a keyguard(i.e- the lockscreen)</li><li>If the user is using the phone, a <a href="https://developer.android.com/training/notify-user/time-sensitive">time sensitive notification</a> should pop up.</li><li>When accepted, this should launch into its own UI, where you see the call details like caller id, duration etc.</li><li>This notification should be a full screen notification so that we can see the call interface when the device is locked and not in use.</li><li>During a call, when the user presses the back button, there should be a notification of a foreground service, which shows the info about ongoing call, and has options for disconnecting.</li><li>We can use either the inbuilt calling app, or we can implement our own screen for incoming/outgoing calls and for call in progress.</li><li>I wanted to build it without writing any platform specific code, or just the least amount of code.</li></ul><h3>Building the app</h3><p>I am using the <a href="https://pub.dev/packages/agora_rtc_engine">agora_rtc_engine</a> plugin for making voice calls. You can find a tutorial on their <a href="https://docs.agora.io/en/Voice/start_call_audio_flutter?platform=Flutter">official docs here</a>. If we implement just what the tutorial says, we will be joining a voice channel as soon as we launch the app, and anyone having the same app can speak into and listen to this voice call.</p><p>So the voice call part is taken care of pretty easily. Now for how to get the behaviour of getting an actual phone call(getting a Caller ID screen, an accept/reject screen).</p><h3>Take #1</h3><p>I set up a FCM in flutter to receive data messages. You can read about difference between notification messages and data messages in my <a href="https://stackoverflow.com/a/67968481/14371894">stackoverflow answer here</a>. I went with data messages because I wanted to be in control of the notification I generate.</p><p>My next plan was to use <a href="https://pub.dev/packages/flutter_local_notifications#custom-notification-icons-and-sounds">flutter_local_notifications</a> plugin and generate a notification. This plugin also has a full screen intent option, which when set to true can show your app when when phone is locked. But there are certain properties the notification should have.So I would listen to a data message, in both foreground and background/terminated state. Upon receiving one, I will generate a notification with full screen intent as true.</p><h4>Properties of the notification</h4><ul><li>They should be non dismissable by swipe action. Only way it is dismissed if the ring is over or the user rejects the call.</li><li>The notification should have accept and reject buttons. Depending on the response, we should open either the ongoing call UI or reject the call.</li><li>There should be a non dismissable notification during the call, which will show some options like mute, disconnect, etc, along with caller id, duration etc.</li></ul><h4>The fault in our notifications</h4><ul><li>flutter_local_notifications does not have any solution for time sensitive notifications.</li><li>It also does not have any solution for having action buttons in the notification</li><li>awesome_notifications has a solution for action button, but no solution for time sensitive notification.</li><li>It also does not support full screen notifications.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/608/0*iGgMsolo6G2KBssA.jpg" /><figcaption>Always has been eh?</figcaption></figure><p>Navigating to a particular screen upon tapping the notification is rather easy, as there are callbacks available for times when the app has been opened due to a notification. For this though you need to use a notificaication message, in which the notification will be handled directly by the plugin. If you want to implement it in data messages, you will have to write some platform dependent code as well.</p><h3>Take #2</h3><p>I tried handling the incoming calls like a gentleman! Upon further digging I found out that apps like Whatsapp, Skype, Insta, Zoom etc handle incoming calls and outgoing calls using something called <a href="https://developer.apple.com/documentation/callkit">callkit in iOS</a> and <a href="https://developer.android.com/reference/android/telecom/ConnectionService">ConnectionService in Android</a>. Plugins already exist for this in flutter, namely <a href="https://pub.dev/packages/callkeep">callkeep</a> and <a href="https://pub.dev/packages/callkeep">flutter_callkeep</a>.</p><p>These plugins, when asked to show a call, mimic the exact behavior as a normal telecom call would, using the same notifications, showing the same UI. Each interaction, like accepting a call, rejecting a call, toggling loudspeaker, holding a call etc all have their callbacks. Seems pretty straightforward, right?</p><h4>Callkeep couldn’t keep up</h4><p>There is a bug in both the packages.</p><ul><li>When you start a call, and reject a call then everything works fine.</li><li>When you accept the call though, the Call UI hangs all of a sudden. From the logs it seems like it is starting a lot of calls internally, and they all clash with each other.</li></ul><p>The plugins are still a bit usable in Android Pie, but completely unusable in Android 10.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*0daX-M2fExutajam.jpg" /><figcaption>Why are we here, just to suffer?</figcaption></figure><h3>Take #3</h3><p>A hacky solution (platform side code included).</p><p>Our pain problem with notification is that we can’t have action buttons + time sensitive + full screen notifications together. We can all compensate for this by generating our own notification using <a href="https://flutter.dev/docs/development/platform-integration/platform-channels">platform channel</a>.</p><h4>The plan</h4><ul><li>Write a function that can generate a notification of our requirements, a good example is <a href="https://developer.android.com/training/notify-user/time-sensitive">time sensitive notification</a> example here.</li><li>You can assign a pending intent to this intent for full screen notification. Flutter apps have only one activity. To get the reference to this activity, you can follow this snippet.</li><li>Open MainActivity as soon as the user either taps on the notification or accepts the call.</li><li>Check whether the app was called because of a notification tap by invoking some MethodChannel right as the app starts. Depending on the result, you can either navigate to the app as usual or to the Call UI screen.</li><li>If you find it difficult to determine if the app was started from a notification or not, using something like Shared Preferences. Store a key-value pair signifying that app was started in notification inside the BroadcastListener. Once the app has launched and a MethodChannel is involed asking whether app was launched from notification, reset it. P.S- This is a hacky solution, better solutions exist.</li><li>As soon as the app is launched, spawn another service, this time a <a href="https://developer.android.com/guide/components/foreground-services">foreground service</a>. Every foreground service <strong>MUST</strong> have a notification associated with it. We can use this notification to signify an ongoing call, regardless of whether is in the app or outside it. This service runs until the user has disconnected the call.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/0*wlqZ5AtI18GL8fc2.jpg" /><figcaption>Same energy as our solution</figcaption></figure><h3>Take #4</h3><p>What I feel is the legit solution!</p><p>Previously in the article I mentioned something about <a href="https://developer.android.com/reference/android/telecom/ConnectionService">ConnectionService</a>. This is the recommended way for any app that either</p><ul><li>Can make phone calls (VoIP or otherwise) and want those calls to be integrated into the built-in phone app. Referred to as a <em>system managed</em> ConnectionService.</li><li>Are a standalone calling app and don’t want their calls to be integrated into the built-in phone app. Referred to as a <em>self managed</em> ConnectionService.</li></ul><p>What both callkeep and flutter_callkeep plugins offered is system managed ConnectionService. What we need is self managed. The main issue here is resources, or lack thereof. The only resource I could find is <a href="https://developer.android.com/guide/topics/connectivity/telecom/selfManaged#no-active">this guide</a>. There are not any tutorials/blogs about how to implement this. We can learn how to implement this by looking at some existing projects though, a good point is <a href="https://github.com/AgoraIO-Usecase/Video-Calling">AgoraIO-Usercase/Video-Calling</a> repository.</p><p>Getting this functionality all wrapped in a flutter plugin is the best solution we can manage with flutter in my opinion. What I believe personally though is that implementing it in native is the easiest way out. That way we do not have to worry about handling communication between native android and flutter.</p><blockquote>Flutter is a cross-platform UI **toolkit<em>* that is designed to allow code &gt; reuse across operating systems such as iOS and Android, while also <br> allowing applications to interface directly with underlying platform<br> services*. — </em><a href="https://flutter.dev/docs/resources/architectural-overview"><em>Flutter architectural overview</em></a></blockquote><p>Google considers Flutter as a UI toolkit, and personally so do I. Sometimes we may have to implement some framework level functionalities(like handling telephony in this case) just so that we can show a call accept/reject screen in flutter. This can be pretty straightforward in native android. So the question lies with the developer, <em>is it worth the effort?</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/666/0*tZWtXzHg7jriv5QS.jpg" /></figure><blockquote>P.S — This article is everything I could find and make sense of while researching about this for 3 days straight. I decided to write this article because there are a lot of people on StackOverflow and Github Issues who do not have an answer to this question. While I have not been able to provide an answer, yet, I hope to make the question clearer.</blockquote><blockquote>I am not a pro developer, so if you find any discrepancies, feel free to comment, the whole point of this article to bring whatever little exists about this on the internet at a single place! Also, I’ll be working on the plugin myself, I’ll be updating the article with a link to the repo in some days.</blockquote><p><em>Originally published at </em><a href="https://dev.to/chinmaykb/how-to-make-a-calling-app-in-flutter-for-android-devices-3hpg"><em>https://dev.to</em></a><em> on June 14, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=506c92e01a31" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Working with Firebase Cloud Firestore made easier with “withConverter()” in Flutter]]></title>
            <link>https://chinmaykabi.medium.com/working-with-firebase-cloud-firestore-made-easier-with-withconverter-in-flutter-1d736f396650?source=rss-45255f4277bc------2</link>
            <guid isPermaLink="false">https://medium.com/p/1d736f396650</guid>
            <category><![CDATA[firestore]]></category>
            <category><![CDATA[json]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[flutter-app-development]]></category>
            <dc:creator><![CDATA[Chinmay Kabi]]></dc:creator>
            <pubDate>Fri, 09 Oct 2020 12:05:46 GMT</pubDate>
            <atom:updated>2021-06-28T18:17:47.470Z</atom:updated>
            <content:encoded><![CDATA[<h3>Working with Firebase Cloud Firestore made easier with “.withConverter()”</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*f25CgCWwoEmG-WfQW197Jg.jpeg" /><figcaption>Everybody has the stick, only a few know to yield it properly!</figcaption></figure><blockquote><em>Disclaimer — This article is not about how to set up firebase. </em><a href="https://firebase.flutter.dev/"><em>firebase.flutter.dev</em></a><em> is a good place to learn about that. This article is about an issue I face personally while using Firebase Cloud Firestore, and what I do to make life a little easier!</em></blockquote><h3>The Problem</h3><p>Assuming you are a Flutter developer, you love dart for being strongly typed. But when we are dealing with Firebase Cloud Firestore, it returns a Map&lt;String, dynamic&gt; object. There are quite a few downsides to it.</p><ol><li>We lose type safety- We may push data of an unintended data type</li><li>No code completion- You need to type all the keys of the map. Life’s hell if the map is too nested :/</li></ol><h3>The Solution</h3><p>We add some order to the chaos! We map this response to an object, simple! Like how we treat an api response, similarly.</p><h3>The Demonstration</h3><p>I have set up a firebase cloud firestore with a single document, with fairly nested data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*wpliG5YwFoCLwkmu.png" /><figcaption>Data used for demonstration purposes only. I’m envious if your production app has only this much data in its database!</figcaption></figure><p>From this document we want to fetch the data field of the first achievement of the first friend, and also the name of the first friend.</p><h3>Handle data the usual way</h3><pre>Future&lt;Map&lt;String, dynamic&gt;?&gt; getDataTheUsualWay(String document) async {<br>final _data =<br>    (await firestoreInstance.collection(&#39;users&#39;).doc(document).get())<br>        .data();<br>return _data;<br>}</pre><p>Inside FutureBuilder, this is handled in the following manner.</p><pre>...<br>FutureBuilder(<br>    future: getDataTheUsualWay(&#39;ENYMl6A76UTENuQ9fnOi&#39;),<br>    builder:(BuildContext context,<br>        AsyncSnapshot&lt;Map&lt;String, dynamic&gt;?&gt; snapshot){<br>            return snapshot.connectionState != ConnectionState.done<br>        ? Center(child: CircularProgressIndicator())<br>        : Center(<br>            child: Column(<br>                mainAxisAlignment: MainAxisAlignment.center,<br>                crossAxisAlignment: CrossAxisAlignment.center,<br>                mainAxisSize: MainAxisSize.max,<br>                children: [<br>                Text(<br>                    &#39;Data handled as how all other tutorials say &#39;),<br>                Text(<br>                    &#39;Name is ${snapshot.data![&#39;people&#39;][&#39;friends&#39;][0][&#39;name&#39;]}&#39;),<br>                Text(snapshot.data![&#39;people&#39;][&#39;friends&#39;][0]<br>                    [&#39;achievements&#39;][0][&#39;data&#39;]),<br>                Text(snapshot.data![&#39;people&#39;][&#39;friends&#39;][0]<br>                    [&#39;achievements&#39;][0][&#39;type&#39;]),<br>                ],<br>            ),<br>            );<br>        }<br>)</pre><p>You will be getting no help from the IDE whatsoever while typing snapshot.data![&#39;people&#39;[&#39;friends&#39;][0][&#39;achievements&#39;][0][&#39;data&#39;]. Any typos, or a wrong data type will result in an error. Because of which you will have to keep referring back to the database, hence slowing you down considerably.</p><h3>Handle data the better way.</h3><p>Firebase has a method called .withConverter(). What this does is that instead of dealing in Map&lt;String, dynamic&gt;, this method will deal in terms of an object of a serializable class. Didn&#39;t get it? Just follow along!</p><p>First, we need a json of the document. We can get that by doing this</p><pre>var firestoreInstance = FirebaseFirestore.instance;<br>final _data = await firestoreInstance<br>    .collection(&#39;users&#39;)<br>    .doc(&#39;*replae with document id*&#39;) <br>    .get();<br>print(json.encode(_data.data()));</pre><p>For my example the output was this json.</p><pre>{<br>   &quot;achievements&quot;:[<br>      {<br>         &quot;data&quot;:&quot;Strong meme game&quot;,<br>         &quot;type&quot;:&quot;non-academic&quot;<br>      },<br>      {<br>         &quot;data&quot;:&quot;Cleared multiple subjects without submitting assignments&quot;,<br>         &quot;type&quot;:&quot;academic&quot;<br>      }<br>   ],<br>   &quot;alive&quot;:true,<br>   &quot;name&quot;:&quot;Chinmay Kabi&quot;,<br>   &quot;people&quot;:{<br>      &quot;friends&quot;:[<br>         {<br>            &quot;achievements&quot;:[<br>               {<br>                  &quot;data&quot;:&quot;Funny name&quot;,<br>                  &quot;type&quot;:&quot;non-academic&quot;<br>               }<br>            ],<br>            &quot;name&quot;:&quot;Mr Thingumbob&quot;<br>         }<br>      ]<br>   },<br>   &quot;age&quot;:69<br>}</pre><p>Now open <a href="https://app.quicktype.io/">Quicktype</a>. This website helps you generate serializable classes from json, such that you pass the json to a method and it returns an object such that the keys of the map are the properties of this object! This is how it will look</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/0*vwkXisWNjmc-a0Wj.png" /><figcaption>“My secret is your secret, and everybody will see”- Frankie Presto</figcaption></figure><p>Select dart from the options and it will generate the required code. Copy this code into a class, user.dart in my case.</p><p>After doing this, we can simply do this</p><pre>Future&lt;User?&gt;? getDataTheBetterWay(String document) async {<br>    final _data = await firestoreInstance<br>        .collection(&#39;users&#39;)<br>        .doc(document)<br>        .withConverter&lt;User&gt;(<br>            fromFirestore: (snapshot, _) =&gt;<br>                userFromJson(json.encode(snapshot.data())),<br>            toFirestore: (model, _) =&gt; json.decode(userToJson(model)))<br>        .get();<br>    return _data.data();<br>}</pre><p>This returns a User object. Getting the name of this user is as simple as user.name, which the IDE will give you code suggestions for the moment you have typed user.n. We can display the same data we had shown before in this way.</p><pre>FutureBuilder(<br>    future: getDataTheBetterWay(&#39;ENYMl6A76UTENuQ9fnOi&#39;),<br>    builder: (BuildContext context, AsyncSnapshot&lt;User?&gt; snapshot) {<br>    return snapshot.connectionState != ConnectionState.done<br>        ? Center(child: CircularProgressIndicator())<br>        : Center(<br>            child: Column(<br>                mainAxisAlignment: MainAxisAlignment.center,<br>                crossAxisAlignment: CrossAxisAlignment.center,<br>                mainAxisSize: MainAxisSize.max,<br>                children: [<br>                Text(&#39;Data handled using my method&#39;),<br>                Text(<br>                    &#39;Name is ${snapshot.data!.people.friends[0].name}&#39;),<br>                Text(snapshot<br>                    .data!.people.friends[0].achievements[0].data),<br>                Text(snapshot<br>                    .data!.people.friends[0].achievements[0].type),<br>                ],<br>            ),<br>            );<br>    },<br>),</pre><p>Typing snapshot.data!.people.friends[0].achievements[0].data will be effortless for you because code suggestions! Also this ensures type safety, so a string cannot magically turn into a number(sorry JS people!). Such an arrangement is helpful when you have to refer a lot of fields of a document. But it only gets better!</p><h3>Updating data the usual way</h3><p>Updating the values of a top level field is easy, but what about a nested field? We will be updating the type field of the first achievements of the first friends.</p><pre>Future&lt;void&gt; updateDataTheUsualWay(String document, String data) async {<br>    final userRef = firestoreInstance.collection(&#39;users&#39;).doc(document);<br>    final userData = (await userRef.get()).data();<br>    var friendsList = userData![&#39;people&#39;][&#39;friends&#39;];<br>    friendsList[0][&#39;achievements&#39;][0][&#39;type&#39;] = data;<br>    await userRef.update({<br>      &quot;people&quot;: {&quot;friends&quot;: friendsList}<br>    });<br>    print(data);<br>  }</pre><p>There is no way to update a particular index of an array and push the update, we need to use the whole array, and pick out the fields we want to update. Then we push an update for the whole array. If that array is nested inside another field, or a map, or (god forbid) another list, we need to pass the reference for those nested fields, so that Firebase knows what to update. This is done my typing the map with the properties manually, maintaining the structure until we hit the array we have mutated, then we pass the mutated array. In this case, we have mutated friends array. We have a copy of the mutated array. But we cannot pass it directly. Because it is nested inside people, we need to pass this map to the update().</p><pre>{<br>    &quot;people&quot;:{<br>        &quot;friends&quot;:friendsList<br>    }<br>}</pre><p>This is just for a single level nesting. Imaging having multi level nesting, and updating multiple fields in multiple levels. Thankfully, you don’t have to!</p><h3>Updating data the better way</h3><p>We will be updating the same fields.</p><pre>Future&lt;void&gt; updateDataTheBetterWay(String document, User user) async {<br>    final userRef = firestoreInstance<br>        .collection(&#39;users&#39;)<br>        .doc(document)<br>        .withConverter&lt;User&gt;(<br>            fromFirestore: (snapshot, _) =&gt;<br>                userFromJson(json.encode(snapshot.data())),<br>            toFirestore: (model, _) =&gt; model.toJson());<br>    await userRef.set(user);<br>  }</pre><p>While calling this function, we can mutate the values of the properties as we feel like. So mutating the properties is something like this.</p><pre>user!.people.friends[0].achievements[0].type = data;<br>updateDataTheBetterWay(&#39;ENYMl6A76UTENuQ9fnOi&#39;, user);</pre><p>Clean right?<br> Feel free to mutate as many parameters you want. Everything can be done easily in a type safe way, and code suggestions will help you make coding this a breeze!</p><p>Sad thing is that I have not come across .withConverter() in any of the tutorials for firebase database. I hope this article acts as a primer for this, and makes working with Firebase cloud firestore a bit easier. This is by no means an in-depth article about .withConverter(), so feel free to comment about anything you want me to cover more about this in another article!</p><p>You can find the sample project I have made with this code <a href="https://github.com/Chinmay-KB/better_firebase_flutter">here</a>.</p><p><em>Originally published at </em><a href="https://dev.to/chinmaykb/working-with-firebase-database-made-easier-with-withconverter-473n"><em>https://dev.to</em></a><em> on June 28, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1d736f396650" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[project-spampr: The hero that tried saving Hacktoberfest ‘20]]></title>
            <link>https://medium.com/dsc-nit-rourkela/project-spampr-the-hero-that-tried-saving-hacktoberfest-20-bd415d07e6d9?source=rss-45255f4277bc------2</link>
            <guid isPermaLink="false">https://medium.com/p/bd415d07e6d9</guid>
            <category><![CDATA[probot]]></category>
            <category><![CDATA[pull-request]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[hacktoberfest]]></category>
            <dc:creator><![CDATA[Chinmay Kabi]]></dc:creator>
            <pubDate>Fri, 09 Oct 2020 11:56:07 GMT</pubDate>
            <atom:updated>2020-10-09T12:20:09.707Z</atom:updated>
            <content:encoded><![CDATA[<h3>project-spampr: The Hero that tried saving Hacktoberfest ’20</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AqieQWBWIjdotduOs2sqBg.png" /><figcaption>Low effort poster B-)</figcaption></figure><p><em>Eh ! It’s the thoughts that matter, right?</em></p><p>For those who are still using Internet Explorer, Hacktoberfest is Digital Ocean’s annual month long celebration of Open Source community and contributions. Digital Ocean ships a T- shirt and stickers to the first 70,000 people who successfully open 4 pull requests to any public repository. At least that’s what it was for the past seven years until October 2nd 2020.</p><p>This year, things went tits up when a barrage of noobs bombarded public repositories with spammy pull requests. Some of the jewels being…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YM4S7gTLEmx740g-" /><figcaption>I remember being punished for not writing the full word :/</figcaption></figure><p>It was a maintainer’s worst nightmare come true, like a Github version of Denial of Service attack!. They had to reject those PRs, close them, label them invalid manually to prevent overcrowding. Within a day of Hacktoberfest, it had drawn massive flak for the mess it had caused. I have taken part in Hacktoberfest for the last 2 years, and the T shirts are very dear to me. If they were to be doled out for trash pull requests, then it would reduce the value of the T shirts the legitimate contributors had earned. So in the morning of 2nd October, I set out to restore the balance of the open source universe, all by myself…</p><h3>The gameplan</h3><ol><li>Make a GitHub bot.</li><li>Find out a way to screen spammy PRs</li><li>Deploy it ASAP !!!</li></ol><h3>The problems</h3><ol><li>I didn’t know the difference between a GitHub action and a GitHub bot, let alone how they work.</li><li>I believe JS should not exist on the face of this Earth, and now I had to code in JS.</li><li>I hardly know JS</li><li>Webhooks?? What?</li></ol><h3>Good Luck and Godspeed…</h3><p>I don’t know if it was my ignorance or lack of familiarity with JS, but I could hardly find any good documentation for a beginner testing waters in GitHub app. Many of the tutorials I looked into were about GitHub actions(which I still don’t understand). It took me an hour or so before I found something called <a href="https://probot.github.io/">Probot</a> .</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/943/0*CI-CCyBzOLe4AHAi" /></figure><p>It is a nice little Node JS module that actually did a lot of heavy lifting. We can create a probot app scaffold using npm. It generates all the required files, along with a hello world program which you can start tweaking to understand how things work. To get it working, you need to have installed Node.js. Then you can create the basic scaffold using this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/0*BMUqdJbNN7kajYbs" /><figcaption>Works with npm too</figcaption></figure><p>We see a bunch of files being generated, one of them being index.js</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_X62OyEJ-1RcC79J" /><figcaption>That’s the business logic people!</figcaption></figure><p>The only thing to understand here is how webhooks and context works. Webhooks are continuously listening for any events on the other end. In the above code, it is listening to <em>“issues.opened”</em> event.</p><p>Next comes what context is and how it works. Context is just an awesome abstraction of all the data payload you receive from any event and a gateway to make API requests without having to write any code for API requests. Context has a lot of things that you can access through it. You can find a lost of it <a href="https://probot.github.io/api/latest/classes/context.html">here</a> . What I used in this case are the following.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*EZr4HLYWOQIJrzIT" /></figure><p>If the webhook receives a trigger due to a pull request, it will receive data only for a pull request in the context, we don’t have to worry about it. Similarly for issues opening closing and other such events. So context.payload contains all the data we may need. Next if we want to post a comment, or publish a label to a PR or an issue, we can use context.github. One thing to note here is Pull Requests are to be treated as Issues when doing stuff common to both, for eg- commenting, labelling, assigning etc. I realized it the hard way after struggling for an hour or two. So I now had to comment on the PR opened, so I treated it like an issue and it worked!!</p><p>Next comes labels. It is the same as labels to be added to issues! Easy right?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Z5AypCylfzutma94" /></figure><p>One major thing to note here is you won’t find Probot documentation explaining in a lot of detail. You can see the parallel between this context and <a href="https://octokit.github.io/rest.js/v18">Octokit</a> though. Do have a look at it though. Had I known that Probot uses Octokit under the hood, and commenting on PR has to be done the same way as issues, things would be over in an hour.</p><blockquote>I wasted time so that you don’t have to….</blockquote><h3>Who’s been naughty in PRs?</h3><blockquote>Assumptions were made…</blockquote><p>In a fairly active repository, the workflow usually is</p><ul><li>An issue is opened by maintainers. Interested person interacts with maintainers and gets himself/herself assigned to the issue.</li><li>If there exists no issue related to the thing someone wants to contribute, they can open one. The flow is then similar to previous point.</li></ul><p>The assumptions made were that</p><ol><li>If someone has not been assigned an issue before, it means they are not entrusted with contributing to the repository by the maintainers.</li><li>If someone is assigned to any of the open issues, then the maintainers believe that the contributor is genuine and would make genuine contributions, regardless of which issue they end up sending a PR about.</li></ol><p>Have a look at this video, you’ll understand better!</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F0dgPtYPgGP0%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D0dgPtYPgGP0&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F0dgPtYPgGP0%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/a0e597d21a5cccfe2976720de824d3ed/href">https://medium.com/media/a0e597d21a5cccfe2976720de824d3ed/href</a></iframe><p>This was easy to achieve.</p><ol><li>Get a list of all issues on a repository using a public API. For eg <a href="https://api.github.com/repos/Chinmay-KB/project-spampr/issues?state=open">https://api.github.com/repos/Chinmay-KB/project-spampr/issues?state=open</a></li><li>Get a list of all the assignees to all open issues.</li><li>See if the username who opened the PR has any of the issues assigned to them.</li><li>If they are assigned, label the PR as approved, if not send a “personalized” comment out to them.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/840/0*xyVAyiLwhZiawBlR" /><figcaption>You get a new insult every time. You’re welcome</figcaption></figure><p>After that run npm start and the app is running on localhost already!</p><p>And here you are, ready to fight spammy PR, one repo at a time…. For a few hours at least.</p><p>Digital Ocean declared that as of October 3, Hacktoberfest is an opt-in program for repositories. Now not just any PR would be counted as a legit contribution. Either the repository needs to have the Hacktoberfest topic or the pull requests should have Hacktoberfest-approved labels assigned to them to be counted as a legitimate PR. Sway of the mighty hand you see!</p><p>It was good learning for me though, from knowing nothing about GitHub bots to having deployed one on Heroku, all within 12 hours is quite a learning ! The bot never gained any traction, neither in the MLH hackathon I submitted this or the tweets I had sent out to MLH and Digital Ocean :(</p><h3></h3><p>Hey @hacktoberfest I am taking part in @MLHacks weekend hackathon this week. We all know how people have been sending spammy PRs for free T shirts and swags, so I tried making a simple github bot which labels PRs as spam,invalid https://t.co/DQ9gNasIyJ</p><p>But there’s nothing like learning by doing, right?</p><p>GitHub repo <a href="https://github.com/Chinmay-KB/project-spampr">here</a></p><p>This project was submitted to MLH Hero Hacks <a href="https://devpost.com/software/project-spampr">Devpost link</a></p><p>This GitHub app was developed by Chinmay Kabi(that’s me)</p><p><a href="https://www.linkedin.com/in/chinmaykabi/">LinkedIn</a>, <a href="https://github.com/Chinmay-KB">GitHub</a>, <a href="https://twitter.com/ChinuKabi">Twitter</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bd415d07e6d9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/dsc-nit-rourkela/project-spampr-the-hero-that-tried-saving-hacktoberfest-20-bd415d07e6d9">project-spampr: The hero that tried saving Hacktoberfest ‘20</a> was originally published in <a href="https://medium.com/dsc-nit-rourkela">GDSC NIT Rourkela</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Developing the ICS NIT Rourkela app]]></title>
            <link>https://medium.com/dsc-nit-rourkela/developing-the-ics-nit-rourkela-app-b06037d5d50?source=rss-45255f4277bc------2</link>
            <guid isPermaLink="false">https://medium.com/p/b06037d5d50</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[counseling]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[google-developer-group]]></category>
            <dc:creator><![CDATA[Chinmay Kabi]]></dc:creator>
            <pubDate>Wed, 05 Feb 2020 10:48:51 GMT</pubDate>
            <atom:updated>2020-02-05T19:29:34.921Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Institute Counselling Services(formerly SCP and SCS) app is an effective bridge between the students and the counselling services. This article provides an insight into the thoughts of one of the developer of the app, the execution of the development process, and the user reception.</em></p><h4><strong>The Inspiration</strong></h4><p>Today, in the times of organizations using AI chatbots basic queries, Virtual Reality for a guided tour of their campus, and technologies like Actions on Google(AoG) to make the interaction more humane, our institute(NIT Rourkela) has had only one major app serving its populace with campus-related information on the go, the Monday Morning app. This was about to change, courtesy Developer Student Clubs NIT Rourkela Chapter(DSC NIT Rourkela, an initiate under Google Developers), who were relatively new a concept on the campus back in 2019(a decade ago!), and looking for the first big project.</p><p>With a large pool of student mentors, weekly scheduled counselor and psychiatrist visits, and a whole building to its name, Institute Counseling Services(ICS), was taking huge strides at ensuring counselling for Academic, Financial, Mental and Sociology-cultural issues to the students. We at DSC NITR saw this as a great opportunity to collaborate with ICS and come up with a mobile app, which would bridge the gap between the student and ICS.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/890/1*PmR1IX7MUY9coQ8aWNpYPg.jpeg" /><figcaption>The ICS app was developed under the project name of <strong>project-avocado</strong></figcaption></figure><p>As an outcome of lack of taxonomical intellect on our team, we resorted to the naming our projects akin to the nomenclature followed by Google for android versions, albeit a bit healthier, fruits! What better than starting off with an a̵p̵p̵l̵e̵, avocado? (No Apple, Google is watching us!)</p><h4><strong>The interaction</strong></h4><p>Every academic year, each of the fresher is allocated a mentor, which means that every academic year, we could reasonably estimate a minimum number of users downloading the app(more users are of course welcome). But the real credit to the app developer lies in the user retention and daily user interaction with the app, which in today&#39;s fast-paced day and age, is something large corporations would pay a fortune for!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*5ylS0eit_aNsjJNTUomAew.jpeg" /><figcaption>User interaction 💯</figcaption></figure><p>Our college uses a central timetable which is a nightmare to decode for the freshers, and a timetable decoder in the app would ensure that the student would surely click open the app to check for a free period the day India has a match!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/382/1*SUcw7EPX6ERvQJVpY7Lorw.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/697/1*yeiX_UR5e84CHMaanrjcFg.jpeg" /><figcaption>Functionalities offered by the ICS app(Image sizes are in compliance with user interaction!)</figcaption></figure><p>Earlier, the students had to book a slot for a counselor or a psychiatrist by going in person. ICS app aimed at making this a one click affair, by implementing means to simplify the slot booking process while maintaining the authenticity of it(no bogus slot bookings)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eJ0b_TeM2h6-3Y6zHMWTMw.jpeg" /><figcaption>Booking screens for slots</figcaption></figure><p>Decoding a central timetable has two parts, a theory section and a practical section, an intersection of these gives you the timetable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/352/1*d3uLgC46wr4uWVG7Byp_xA.gif" /><figcaption>The size of box of each subject suggests the length of the period</figcaption></figure><h4>The Implementation</h4><p>Flutter has taken the app development world by storm, starting from being one of the fastest growing frameworks to being able to run on just about anything, offering drool-worthy 60fps rendering and fancy animations. You can see why its the apple of our eye!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/848/1*_62gI5sYArEJgz_Umx-AoQ.jpeg" /><figcaption>Flutter is what makes our ♥ flutter now. So long Native, so long…</figcaption></figure><p>We had all our assets and databases at our disposal when we realized the format in which we had our FAQ database. The questions and answers contained basic HTML tags for billeting, hyperlinks etc, handling which was a pain in the rear for Flutter back when we were developing the app. So yeah, we had to use platform channels and develop FAQ using native framework</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g9fqTjTyE8d4ugxtloU0sA.jpeg" /><figcaption>Uncomfortable, right?(Yeah, they’re the same trio from the previos pic)</figcaption></figure><p>The main issue regarding this app was regarding prevention of bogus slot booking. We implemented Firebase Mobile Authentication and Firebase Firestore to maintain the slot booking database. Firebase helps us developing a full-fledged app while not worrying about backend, and there are a lot of features which could be implemented in the future, so we saw it as an absolute win!</p><p>From wire framing to beta testing, the app was developed over a course of two months during the summer of 2019, ready to be put to test on the onset of the new academic year.</p><h4>The Impression</h4><p>With ICS on our side, all the freshers were asked to make full utilization of the app, and by the numbers on our Firebase Dashboard, utilization of app they did!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/822/1*z9FU8iRL6tkaiRsfdQpPew.jpeg" /><figcaption>First month usage statistics</figcaption></figure><p>A key point to remember is that there are about 1000 first-year students, so having a user base of 1600 means that our app had gained users from other demographics as well. The cyclic nature of 1-day retention is due to the fact that no sane minded person would check his/her timetable on weekends.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/597/1*wV4gBLBmLgbAJzc43mYaFw.jpeg" /><figcaption>This is how happiness looks like :)</figcaption></figure><p>The near perfect crash free user experience is because of Flutter. While we developers took care of several edge cases, credit also goes to Flutter to handle the UI flexibly on different Android versions and various OEMs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/801/1*lkHCHO4athDkuscbW9owzg.png" /><figcaption>Usage statistics as of writing this article</figcaption></figure><p>We see about a two fold increase in 1 day usage, while we have retained about 80% of our user base as compared to our first month of usage, which means that while our user installs has decreased, our user retention and interaction has increased over time, which is a testimony of the usefulness of the app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/833/1*BaivbWorz4qNPuG5DymcYg.png" /><figcaption>Cruising at 4.5!</figcaption></figure><p>DSC NITR had taken part in HacktoberFest 2019, in which we had put up project-avocado as one of the projects where developers from far and wide could contribute, and contribute they did! We had contributions on 2 issues on this repository, good for a first-timer, right!</p><p>As of writing this article, our app has been downloaded over 2000 times, which is around a third of the total NIT Rourkela student populace. This is the first mobile app that any club/group had developed for the Institute in official capacity, and we hope that the institute continues placing their faith in DSC NITR and the developer community at large.</p><p>The artists - Reuben Abraham (UI &amp; UX), <a href="https://github.com/DesignrKnight">Abel Mathew</a> (DSC lead and Developer), <a href="https://github.com/ankank30">Ankesh Anku</a>(Developer), <a href="https://github.com/Thesmader">Smarak Das</a>(Developer) and <a href="https://github.com/Chinmay-KB">Chinmay Kabi</a>(Developer)</p><p>Contribute to our project- <a href="https://github.com/developer-student-clubs-nitr/project-avocado">https://github.com/developer-student-clubs-nitr/project-avocado</a></p><p>Link to our app- <a href="https://play.google.com/store/apps/details?id=in.ac.nitrkl.scp.scp">https://play.google.com/store/apps/details?id=in.ac.nitrkl.scp.scp</a></p><p>Read more about the design process of the app- <a href="https://medium.com/dsc-nit-rourkela/designing-for-easier-access-to-mental-healthcare-e35a14699de6">https://medium.com/dsc-nit-rourkela/designing-for-easier-access-to-mental-healthcare-e35a14699de6</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b06037d5d50" width="1" height="1" alt=""><hr><p><a href="https://medium.com/dsc-nit-rourkela/developing-the-ics-nit-rourkela-app-b06037d5d50">Developing the ICS NIT Rourkela app</a> was originally published in <a href="https://medium.com/dsc-nit-rourkela">GDSC NIT Rourkela</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>