<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ashton Jones</title>
    <description>The latest articles on DEV Community by Ashton Jones (@tjgrapes).</description>
    <link>https://dev.to/tjgrapes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F307150%2Fd1b37d5a-9f3e-4232-b74f-4b0a782ce20a.jpg</url>
      <title>DEV Community: Ashton Jones</title>
      <link>https://dev.to/tjgrapes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tjgrapes"/>
    <language>en</language>
    <item>
      <title>Building a Flutter Chat Application with Stream: Building the App (Part 3)</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Tue, 20 Oct 2020 13:13:13 +0000</pubDate>
      <link>https://dev.to/tjgrapes/building-a-flutter-chat-application-with-stream-building-the-app-part-3-5g64</link>
      <guid>https://dev.to/tjgrapes/building-a-flutter-chat-application-with-stream-building-the-app-part-3-5g64</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xiCcBmgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AHw0DRh6aJvQALyyIM7v0zg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xiCcBmgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AHw0DRh6aJvQALyyIM7v0zg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is part of a series on building a fully functional Flutter app with Stream. All other parts, as well as the finished code, can be found below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/building-a-flutter-chat-application-with-stream-introduction-part-1-901977551169"&gt;Part 1: Introduction&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/building-a-flutter-chat-application-with-stream-configuration-part-2-de92959ce7"&gt;Part 2: Configuration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;SpikeChat Github Project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the configuration is all done, it is time to get to coding 👨🏻‍💻. Let’s do it!&lt;/p&gt;

&lt;h2&gt;
  
  
  App Flow:
&lt;/h2&gt;

&lt;p&gt;Here is how the app works. When someone opens it for the first time, they need to enter a passcode to continue. Once they enter the passcode, they get to choose a username. After choosing a username, they are authenticated and brought to the Spikeball chat screen.&lt;/p&gt;

&lt;p&gt;After opening the app for the first time, they are brought to a screen that shows their username and allows them to go to the Spikeball chat screen. When they click ‘continue’, they are re-authenticated with the app using their original username they set.&lt;/p&gt;

&lt;p&gt;Let’s dive into the code and see how this works!&lt;/p&gt;

&lt;h3&gt;
  
  
  main.dart
&lt;/h3&gt;

&lt;p&gt;The main.dart file is pretty simple. All I do is initialize the shared preferences and decide which screen to load depending if they have already entered the passcode or not.&lt;/p&gt;



&lt;p&gt;If they have not entered the passcode (using the app for the first time), they will be brought to the Entry Screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GFztilpH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A1O7HRzxBtQvvhf6bD6R5rA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GFztilpH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A1O7HRzxBtQvvhf6bD6R5rA.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once they successfully enter the passcode, I set the ‘isValidated’ setting in shared preferences to true. So next time they open the app, they will not have to enter it again. If they do not enter the correct passcode, they will not be able to access the app, thus I know that only my friends who I share the passcode with will be able to use the app.&lt;/p&gt;

&lt;p&gt;Here’s the code for the Entry Point screen:&lt;/p&gt;



&lt;p&gt;If they have already entered the passcode, I load the HomeScreen. If it is the first time opening the app, I have them set their username and create a user with the username. If they have already set a username, I show the username and a continue button to go to the chat. Again, I use shared preferences to save the username, so I can re-authenticate my friend with the username they already set.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x0VG97gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ALoD1DLz7YXQEv8d-OxFocg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x0VG97gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ALoD1DLz7YXQEv8d-OxFocg.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y4fm6_ea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfauZH2cIWK0AMPNQ3jFlQw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y4fm6_ea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfauZH2cIWK0AMPNQ3jFlQw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is the code for Home.dart:&lt;/p&gt;



&lt;h2&gt;
  
  
  Authenticating the User with Stream
&lt;/h2&gt;

&lt;p&gt;To authenticate the user, I use the &lt;a href="https://pub.dev/packages/start_jwt/"&gt;start_jwt&lt;/a&gt; plugin to generate a token with the Stream app secret. The Stream client has an argument ‘tokenProvider’ which allows us to pass a function we want to use to generate an authentication token. I put all the code into a separate class ‘ChatModel’. Although I am not implementing the provider functionality, I made this class extend it in case I want to build upon this app in the future and add multiple chats, which would would be a great use case for provider.&lt;/p&gt;



&lt;p&gt;When my friend enters a username, I authenticate the client and set the user. I call the setUserWithProvider method on the client, set the id as the username they entered, set the channel type to ‘mobile’, and name the channel “Spikeball”. Channels represent chat rooms. The ‘extraData’ parameter can be used to set additional fields such as images.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*await *client.setUserWithProvider(User(
    id: 'id_$userId',
    extraData: {
      'name': '$userId',
      'image': 'https://picsum.photos/100/100'
    }));

*final *channel = client
    .channel('mobile', id: 'Spikeball', extraData: {
  'image':
      'https://scheels.scene7.com/is/image/Scheels/85375900555?wid=400&amp;amp;hei=400&amp;amp;qlt=50'
});
channel.watch();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Similarly when returning to the app, I authenticate the user with nearly identical code. The only difference is that I use the username they already entered, so they do not have to enter it again and so another user is not created:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*await *client.setUserWithProvider(User(
    id: 'id_${sharedPrefs.username}',
    extraData: {
      'name': '${sharedPrefs.username}',
      'image': 'https://picsum.photos/100/100'
    }));

*final *channel =
    client.channel('mobile', id: 'Spikeball', extraData: {
  'image':
      'https://scheels.scene7.com/is/image/Scheels/85375900555?wid=400&amp;amp;hei=400&amp;amp;qlt=50'
});
channel.watch();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Using the Stream Chat Widgets
&lt;/h2&gt;

&lt;p&gt;Implementing the Stream chat widgets is pretty simple. We just need to put a ‘StreamChat’ widget at the top of the widget tree and pass the client to it, add a ‘StreamChannel’ widget as the child and specify the channel, and add the (visual) Stream chat widgets we want to use; those will be the widgets in the ‘ChannelPage’ widget I created.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Navigator.*of*(context).push(MaterialPageRoute(
      builder: (_) =&amp;gt; StreamChat(
            client: client,
            child: StreamChannel(
              channel: channel,
              child: ChannelPage(),
            ),
          )));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;ChannelPage widget:&lt;/p&gt;



&lt;p&gt;In the ChannelPage widget, I ‘ChannelHeader’ is a Stream widget for an AppBar, ‘MessageListView’ is where the messages are displayed, and ‘MessageInput’ is the text input field where messages are typed.&lt;/p&gt;

&lt;p&gt;Here is what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9k7GjNkv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AgKJSCUNt-NE1KiKfxtrwaw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9k7GjNkv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AgKJSCUNt-NE1KiKfxtrwaw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Shared Preferences
&lt;/h2&gt;

&lt;p&gt;If you are curious about how I implemented shared preferences, I followed &lt;a href="https://dev.to/simonpham/using-sharedpreferences-in-flutter-effortlessly-3e29"&gt;this article&lt;/a&gt; to make shared preferences easily accessible from anywhere in the app. I just created an ‘init’ method that I call in main.dart to initialize shared preferences and created getters and setters for the username and validation. I can access _sharedPreferences anywhere in my code.&lt;/p&gt;

&lt;p&gt;Here’s the code for my shared preferences:&lt;/p&gt;



&lt;h2&gt;
  
  
  The Final Product:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wwoErT3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfHFF3266NItKnAgyFAd7yQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wwoErT3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfHFF3266NItKnAgyFAd7yQ.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;SpikeChat Github project&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/simonpham/using-sharedpreferences-in-flutter-effortlessly-3e29"&gt;SharedPreferences article&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;There are currently some bugs with building the Android APK, but if you run the app on an Android emulator or device, it should work just fine. I also needed to update Gradle to the latest version to get the Android app to work. If you have any other issues, please comment on this post- I’d be happy to help :)&lt;/p&gt;

&lt;p&gt;Hi, I’m Ash 👋🏼 Let’s connect!&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://ashtonjones.dev/#/"&gt;ashtonjones.dev&lt;/a&gt;|👥 &lt;strong&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/tjgrapes"&gt;@tjgrapes&lt;/a&gt;
&lt;/strong&gt;|✉️ &lt;a href="//mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👨‍💻 Google Certified Android Engineer |&lt;br&gt;
✍ Writer |&lt;br&gt;
🧘‍♂️ Stoic &amp;amp;&amp;amp; Meditator&lt;/p&gt;

&lt;p&gt;📱 Need an app built? Contact me &lt;a href="//mailto:ashtonjones.dev?subject=Hi%20Ashton!"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5HcFrL4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5HcFrL4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mobileappdevelopment</category>
      <category>flutter</category>
      <category>stream</category>
      <category>chatapplication</category>
    </item>
    <item>
      <title>Building a Flutter Chat Application with Stream: Configuration (Part 2)</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Tue, 20 Oct 2020 13:11:00 +0000</pubDate>
      <link>https://dev.to/tjgrapes/building-a-flutter-chat-application-with-stream-configuration-part-2-18hc</link>
      <guid>https://dev.to/tjgrapes/building-a-flutter-chat-application-with-stream-configuration-part-2-18hc</guid>
      <description>&lt;h2&gt;
  
  
  Building a Flutter Chat Application with Stream: Configuration (Part 2)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xiCcBmgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AHw0DRh6aJvQALyyIM7v0zg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xiCcBmgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AHw0DRh6aJvQALyyIM7v0zg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is part of a series on building a fully functional Flutter app with Stream. All other parts, as well as the finished code, can be found below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/building-a-flutter-chat-application-with-stream-introduction-part-1-901977551169"&gt;Part 1: Introduction&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/building-a-flutter-chat-application-with-stream-building-the-app-part-3-f18f9c810ba8"&gt;Part 3: Building the App&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;SpikeChat Github Project&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration:
&lt;/h2&gt;

&lt;p&gt;There is quite a bit of configuration I had to do before I could start using Stream’s SDK. Below is a synopsis of all the configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pubspec.yaml dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configuration of Stream App&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code for constants class&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Co-dependencies configuration for iOS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code for authorization configuration using &lt;a href="https://pub.dev/packages/start_jwt/"&gt;start_jwt&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pubspec.yaml Dependencies
&lt;/h3&gt;

&lt;p&gt;In order to use Stream, I needed to add the &lt;a href="https://pub.dev/packages/stream_chat_flutter"&gt;stream_chat_flutter&lt;/a&gt;, along with &lt;a href="http://flutter_file_picker%20plugin"&gt;flutter_file_picker&lt;/a&gt;, &lt;a href="https://pub.dev/packages/video_player"&gt;video_player&lt;/a&gt;, and &lt;a href="https://pub.dev/packages/image_picker"&gt;image_picker&lt;/a&gt;, which are required to enable full functionality of Stream’s APIs on iOS.&lt;/p&gt;



&lt;h3&gt;
  
  
  Configuration of Stream App
&lt;/h3&gt;

&lt;p&gt;First, I needed to create an account with &lt;a href="https://getstream.io/"&gt;Stream&lt;/a&gt;. They allow developers a 30 day trial period to try out their Chat and Feed APIs.&lt;/p&gt;

&lt;p&gt;After creating an account, I created a Stream project called “SpikeChat” for my Flutter application with development mode selected. After creating the app, an app key and app secret is generated, which will be used to authenticate the app with Stream.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W5joCZP5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3840/1%2AFPjMaC5inlM7aRCvmt8NMQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W5joCZP5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3840/1%2AFPjMaC5inlM7aRCvmt8NMQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, I created a chat type called “mobile” by selecting the app then clicking chat-&amp;gt; chat overview-&amp;gt; add chat type.&lt;/p&gt;

&lt;p&gt;In order to allow users to write and read (send and see) messages, I had to scroll down to permissions and add the “user” in “roles” to give users the same access as the administrator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rI58IcMN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3840/1%2AyOKtnNgJJAg8R9l1useDyA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rI58IcMN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3840/1%2AyOKtnNgJJAg8R9l1useDyA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration for Constants class:
&lt;/h3&gt;

&lt;p&gt;After configuring the Stream app, I put the Stream app key and secret in a constants class that are used when authenticating with the Stream client:&lt;/p&gt;



&lt;h3&gt;
  
  
  Co-dependencies Configuration for iOS:
&lt;/h3&gt;

&lt;p&gt;In order to get the full functionality of Stream to work on iOS, I had to do some additional configuration. I needed to add permissions to the info.plist file, highlighted between the comments below. Most of the co-dependencies are good to go with Android, but you may need to do some additional configuration if you are targeting older APIs. If you want to read more in depth about why you need these and ensure you are correctly configured for Android, check out the &lt;a href="https://pub.dev/packages/stream_chat_flutter"&gt;stream_chat_flutter plugin’s readme&lt;/a&gt;.&lt;/p&gt;



&lt;h3&gt;
  
  
  Code for Authorization Configuration Using start_jwt
&lt;/h3&gt;

&lt;p&gt;I was stuck for awhile trying to figure out how to authorize my app with Stream’s APIs. Unfortunately, the &lt;a href="https://getstream.io/chat/docs/tokens_and_authentication/?language=dart"&gt;documentation for authentication on Flutter &lt;/a&gt;is lacking. This was pretty frustrating because I was stuck for a couple days and unable to move forward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E4rrvVDW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3840/1%2Ai1fi8EpvO6UK2xRMtK9U3A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E4rrvVDW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3840/1%2Ai1fi8EpvO6UK2xRMtK9U3A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luckily I was able to figure out how to implement authentication. In order to authenticate the user, I used the &lt;a href="https://pub.dev/packages/start_jwt/"&gt;start_jwt&lt;/a&gt; plugin to generate a JSON web token with my Stream app secret. The method ‘tokenProvider’ uses the Stream app secret to create a token, and also adds the username to the client. I explain more about how this works in part 3.&lt;/p&gt;



&lt;h2&gt;
  
  
  Up Next:
&lt;/h2&gt;

&lt;p&gt;In part 3, I’ll explain how I built the app using Stream’s widgets.&lt;/p&gt;

&lt;p&gt;If you want to follow along, here is the SpikeChat project:&lt;br&gt;
(&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;https://github.com/ashtonjonesdev/spike_chat&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;SpikeChat Github project&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/"&gt;Stream website&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/chat/docs/init_and_users/?language=dart"&gt;Stream Initialization and Users in Dart&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/chat/docs/tokens_and_authentication/?language=dart"&gt;Stream Tokens and Authentication in Dart&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/packages/stream_chat_flutter"&gt;stream_chat_flutter plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/miguelpruivo/flutter_file_picker"&gt;flutter_file_picker plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/packages/video_player"&gt;video_player plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/packages/image_picker"&gt;image_picker plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pub.dev/packages/start_jwt/"&gt;start_jwt plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hi, I’m Ash 👋🏼 Let’s connect!&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://ashtonjones.dev/#/"&gt;ashtonjones.dev&lt;/a&gt;|👥 &lt;strong&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/tjgrapes"&gt;@tjgrapes&lt;/a&gt;
&lt;/strong&gt;|✉️ &lt;a href="//mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👨‍💻 Google Certified Android Engineer |&lt;br&gt;
✍ Writer |&lt;br&gt;
🧘‍♂️ Stoic &amp;amp;&amp;amp; Meditator&lt;/p&gt;

&lt;p&gt;📱 Need an app built? Contact me &lt;a href="//mailto:ashtonjones.dev?subject=Hi%20Ashton!"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5HcFrL4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5HcFrL4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jzDyEanp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2AAuT0GXEd7j21RI6uXlxYTQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jzDyEanp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2AAuT0GXEd7j21RI6uXlxYTQ.png" alt="[https://www.twitter.com/FlutterComm](https://www.twitter.com/FlutterComm)"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mobiledevelopment</category>
      <category>flutter</category>
      <category>stream</category>
      <category>chatapplication</category>
    </item>
    <item>
      <title>Building a Flutter Chat Application with Stream: Introduction (Part 1)</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Tue, 20 Oct 2020 13:08:40 +0000</pubDate>
      <link>https://dev.to/tjgrapes/building-a-flutter-chat-application-with-stream-introduction-part-1-2jei</link>
      <guid>https://dev.to/tjgrapes/building-a-flutter-chat-application-with-stream-introduction-part-1-2jei</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xiCcBmgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AHw0DRh6aJvQALyyIM7v0zg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xiCcBmgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AHw0DRh6aJvQALyyIM7v0zg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is part of a series on building a fully functional Flutter app with Stream. All other parts, as well as the finished code, can be found below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/building-a-flutter-chat-application-with-stream-configuration-part-2-de92959ce7"&gt;Part 2: Configuration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/building-a-flutter-chat-application-with-stream-building-the-app-part-3-f18f9c810ba8"&gt;Part 3: Building the App&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;SpikeChat Github Project&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I discovered &lt;a href="https://getstream.io/chat/get_started/"&gt;Stream’s chat API&lt;/a&gt; and challenged myself to build a fully functional Flutter messaging app with it.&lt;/p&gt;

&lt;p&gt;I decided to build &lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;SpikeChat&lt;/a&gt;, a group chat application for me and my friends to plan times to play &lt;a href="https://www.youtube.com/watch?v=xngJzsSbiI8&amp;amp;t=89s"&gt;Spikeball&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wwoErT3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfHFF3266NItKnAgyFAd7yQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wwoErT3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfHFF3266NItKnAgyFAd7yQ.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience
&lt;/h2&gt;

&lt;p&gt;Stream made it effortless to build a messaging application with Flutter! They have their own Flutter widgets that you use to build the chat features. At first, I thought I would have to build my own database (i.e. Cloud Firestore) to keep the chat in sync on multiple devices. But Stream’s SDK already has local persistent storage AND cloud storage, which means you are not required to implement a database layer.&lt;/p&gt;

&lt;p&gt;However, the Flutter documentation is a bit lacking, so I needed to do some work to figure out how to authorize a client with their API. In this series, I’ll explain everything you will need to know to build a fully functional Flutter chat app with Stream.&lt;/p&gt;

&lt;h2&gt;
  
  
  SpikeChat Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7Op_vy8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AoghybRyh9gvwtJq_xrgo6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Op_vy8G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AoghybRyh9gvwtJq_xrgo6g.png" alt="SpikeChat logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A fully functional chat application built with Flutter and Stream!&lt;/p&gt;

&lt;p&gt;I wanted to keep the messaging app simple, so I build the application with one channel (chat room) called “Spikeball”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--087Ayfrz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfUQ7qY8M20ONNAK00CmdAg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--087Ayfrz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AfUQ7qY8M20ONNAK00CmdAg.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The chat contains the following features, which come by default with Stream’s SDK:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;✅ Join the chat room&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Send text, images, audio, and video in the chat&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ React to messages (i.e. &lt;em&gt;heart react&lt;/em&gt;) and see the reaction count&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ See when the chat was last active&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, there is quite a bit of configuration in order to get everything to work on both iOS and Android, which I will cover in part 2.&lt;/p&gt;

&lt;p&gt;The app requires a passcode in order to enter the chat. I did this as simple a way to implement a private chat only my friends and I can join, without over-engineering the application. The user will not be able to get past this first screen if they do not have the passcode. For the intents of this application, it is sufficient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GFztilpH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A1O7HRzxBtQvvhf6bD6R5rA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GFztilpH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A1O7HRzxBtQvvhf6bD6R5rA.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After entering the correct passcode, my friend gets to choose a username. I use the username to authenticate him/her with the Stream client and create a user for the channel with that username.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x0VG97gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ALoD1DLz7YXQEv8d-OxFocg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x0VG97gb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ALoD1DLz7YXQEv8d-OxFocg.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that’s done, they are logged into the application and brought to the Spikeball chat screen. The chat screen is built using Stream’s Flutter chat widgets. Here, my friends and I can send messages, photos, videos, and audio. We can see when the chat was last active, who sent messages, and react to messages, all in real time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sWFuGaOS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_INUfO1l1yBm6iZXsKlMfA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sWFuGaOS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_INUfO1l1yBm6iZXsKlMfA.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Up Next:
&lt;/h2&gt;

&lt;p&gt;In part 2, I’ll explain how to configure the Stream client and other parts of the project.&lt;/p&gt;

&lt;p&gt;If you want to follow along, here is the SpikeChat project:&lt;br&gt;
(&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;https://github.com/ashtonjonesdev/spike_chat&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ashtonjonesdev/spike_chat"&gt;SpikeChat Github project&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://getstream.io/"&gt;Stream website&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=xngJzsSbiI8&amp;amp;t=89s"&gt;Spikeball&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hi, I’m Ash 👋🏼 Let’s connect!&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://ashtonjones.dev/#/"&gt;ashtonjones.dev&lt;/a&gt;|👥 &lt;strong&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/tjgrapes"&gt;@tjgrapes&lt;/a&gt;
&lt;/strong&gt;|✉️ &lt;a href="//mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👨‍💻 Google Certified Android Engineer |&lt;br&gt;
✍ Writer |&lt;br&gt;
🧘‍♂️ Stoic &amp;amp;&amp;amp; Meditator&lt;/p&gt;

&lt;p&gt;📱 Need an app built? Contact me &lt;a href="//mailto:ashtonjones.dev?subject=Hi%20Ashton!"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5HcFrL4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5HcFrL4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twitter.com/FlutterComm"&gt;https://www.twitter.com/FlutterComm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mobiledevelopment</category>
      <category>flutter</category>
      <category>stream</category>
      <category>chatapplication</category>
    </item>
    <item>
      <title>Looking for Flutter Roles</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Fri, 25 Sep 2020 13:30:43 +0000</pubDate>
      <link>https://dev.to/tjgrapes/looking-for-flutter-roles-3a5n</link>
      <guid>https://dev.to/tjgrapes/looking-for-flutter-roles-3a5n</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_zcrkaYr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bj2ails639owa7bk2zaz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_zcrkaYr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bj2ails639owa7bk2zaz.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hey everyone, I am looking for a new role as a &lt;strong&gt;Flutter developer or Flutter developer advocate&lt;/strong&gt;. My expertise is in Flutter and native Android mobile app development.&lt;/p&gt;

&lt;p&gt;My skillset includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flutter (Flutter SDK, Dart)&lt;/li&gt;
&lt;li&gt;Native Android (Android SDK, Java)&lt;/li&gt;
&lt;li&gt;Firebase (Cloud Firestore, Authentication)&lt;/li&gt;
&lt;li&gt;Google and Apple Authentication&lt;/li&gt;
&lt;li&gt;Google Play Store and Apple App Store (Uploading and configuring apps)&lt;/li&gt;
&lt;li&gt;Observer patterns (Provider- Flutter; LiveData and Observer- Android)&lt;/li&gt;
&lt;li&gt;Material Design&lt;/li&gt;
&lt;li&gt;Writing&lt;/li&gt;
&lt;li&gt;Entrepreneurship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am looking for roles where I can grow my skills, work remotely, and have autonomy. If you know of any opportunities, please let me know!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ashtonjones.dev/#/"&gt;https://ashtonjones.dev/#/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>roles</category>
      <category>flutter</category>
      <category>flutterdev</category>
      <category>opentowork</category>
    </item>
    <item>
      <title>Cloud Firestore Basics in Flutter: How to Get, Add, Edit, and Delete Data in Cloud Firestore, Demonstrated in a
Real Flutter App</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Mon, 17 Aug 2020 14:50:55 +0000</pubDate>
      <link>https://dev.to/tjgrapes/cloud-firestore-basics-in-flutter-how-to-get-add-edit-and-delete-data-in-cloud-firestore-demonstrated-in-a-real-flutter-app-2d06</link>
      <guid>https://dev.to/tjgrapes/cloud-firestore-basics-in-flutter-how-to-get-add-edit-and-delete-data-in-cloud-firestore-demonstrated-in-a-real-flutter-app-2d06</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2uT4wiYy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A32IIQORIjoowKCizb3XTog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2uT4wiYy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A32IIQORIjoowKCizb3XTog.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post, I will be demonstrating how to do the basic database operations in&lt;br&gt;
Cloud Firestore in a Flutter app, using a published app I built as a practical&lt;br&gt;
example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will learn how to implement the core database operations in Cloud&lt;br&gt;
Firestore: how to get (read), add (write), edit, and delete data in the database&lt;br&gt;
in a Flutter app.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;This article does not cover setting up Cloud Firestore, Firebase&lt;br&gt;
Authentication/Sign in for Flutter, and documents/collections in Cloud&lt;br&gt;
Firestore, which are prerequisites for this tutorial. *If you are unfamiliar&lt;br&gt;
with these topics,&lt;/em&gt; *I highly encourage you to &lt;a href="https://pub.dev/packages/cloud_firestore"&gt;read the Cloud Firestore&lt;br&gt;
plugin’s Readme&lt;/a&gt; and &lt;a href="https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html?index=..%2F..index#6"&gt;check out this&lt;br&gt;
code lab to setup Firebase with&lt;br&gt;
Flutter&lt;/a&gt;,&lt;br&gt;
check out the &lt;a href="https://github.com/ashtonjonesdev/reply_flutter"&gt;_Reply project as a&lt;br&gt;
guide&lt;/a&gt;, and &lt;a href="https://www.youtube.com/watch?v=v_hR4K4auoQ&amp;amp;list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ"&gt;watch this video&lt;br&gt;
to learn about documents and collections in Cloud&lt;br&gt;
Firestore&lt;/a&gt;&lt;br&gt;
before returning to this article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  _Reply App Background
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ESxkXkq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AWVxIVN4qWMnIdGy9P6hOWw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ESxkXkq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AWVxIVN4qWMnIdGy9P6hOWw.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;_&lt;a href="https://medium.com/@TJgrapes/introducing-reply-3d0b57ec6744"&gt;Reply&lt;/a&gt; is a&lt;br&gt;
Flutter app I built from scratch and published to the Google Play Store and&lt;br&gt;
Apple App Store. This is a rebuild of &lt;a href="https://medium.com/@TJgrapes/introducing-reply-3d0b57ec6744"&gt;my previous native Android app&lt;br&gt;
“Reply”&lt;/a&gt;; I rebuilt&lt;br&gt;
it using Flutter to make it available on both iOS and Android.&lt;/p&gt;

&lt;p&gt;I will use this app to provide clear, practical examples of how to implement the&lt;br&gt;
core Cloud Firestore operations.&lt;/p&gt;

&lt;p&gt;I have the &lt;a href="https://github.com/ashtonjonesdev/reply_flutter"&gt;code available on&lt;br&gt;
Github&lt;/a&gt; and you can download&lt;br&gt;
the app on the &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.reply_flutter&amp;amp;fbclid=IwAR337t9fh0YFMAQpwQxMu6gZTGZTx0NR8QFbvw5fSaY-RZjhPQ3OiTT9Qyw"&gt;Google Play&lt;br&gt;
Store&lt;/a&gt;&lt;br&gt;
and the &lt;a href="https://apps.apple.com/us/app/reply/id1522893504?fbclid=IwAR254wWiJaeF17cSLv1N9xi85p8DSLbet5dX3jW9rlkWJnSndVF2tVlLJOo"&gt;Apple App&lt;br&gt;
Store&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;_Reply helps you easily create your own custom, pre-defined messages through&lt;br&gt;
any platform.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the app, you create your custom message templates which you can categorize&lt;br&gt;
based on the type of message (i.e. personal, social, and business messages).&lt;br&gt;
Each tab corresponds to a category.&lt;/p&gt;

&lt;p&gt;Once you create your own messages, you can preview, send, edit, and delete them&lt;br&gt;
using the main button in the bottom right corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cJFx3aT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A8YKDXaEYWWaEdaS0R_1vRw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cJFx3aT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A8YKDXaEYWWaEdaS0R_1vRw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Registering and Signing in Users
&lt;/h3&gt;

&lt;p&gt;You can also use Firebase Authentication to register and sign in users. If you&lt;br&gt;
are implementing Firebase Authentication for the first time, I recommend reading&lt;br&gt;
the &lt;a href="https://github.com/ashtonjonesdev/reply_flutter"&gt;_Reply source code&lt;/a&gt;, which&lt;br&gt;
will show you how to implement the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign in with email and password&lt;/li&gt;
&lt;li&gt;Sign in with Google&lt;/li&gt;
&lt;li&gt;Sign in with Apple&lt;/li&gt;
&lt;li&gt;Sign out&lt;/li&gt;
&lt;li&gt;Register with email and password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these methods can be found in the project’s &lt;a href="https://github.com/ashtonjonesdev/reply_flutter/blob/master/lib/core/services/AuthService.dart"&gt;AuthService.dart&lt;br&gt;
class&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❗️❗️Please note that authenticating/signing/registering a user does NOT create&lt;br&gt;
a user for you in the database.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signing in a user and creating a user in the database are two separate&lt;br&gt;
operations you must implement.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This can be confusing because once a user has signed in, you will see an&lt;br&gt;
authenticated user with a &lt;code&gt;uid&lt;/code&gt; within the Authentication tab in the Firebase&lt;br&gt;
console. &lt;em&gt;These are the Firebase users. *&lt;/em&gt;&lt;em&gt;After a successful initial sign in or&lt;br&gt;
registration, a *&lt;/em&gt;&lt;code&gt;FirebaseUser&lt;/code&gt;** is created and signed into the app.** A&lt;br&gt;
&lt;code&gt;FirebaseUser&lt;/code&gt; contains data such as name (called ‘display name’), email, and an&lt;br&gt;
automatically generated &lt;code&gt;uid&lt;/code&gt; to identify the &lt;code&gt;FirebaseUser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M3LZM6qR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2AF8VsWEptWLP5g8CQmM56MQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M3LZM6qR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2AF8VsWEptWLP5g8CQmM56MQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we start adding user data to the database, we &lt;em&gt;first need to create users&lt;br&gt;
which we will save the user data to&lt;/em&gt; in the database. This should be done after&lt;br&gt;
registering/signing in to the app and &lt;em&gt;only if it is a new user&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To create users in our actual database, &lt;em&gt;we will use the data provided by the&lt;br&gt;
*&lt;code&gt;FirebaseUser&lt;/code&gt;*s to create users in our database; namely, we will use the&lt;br&gt;
*&lt;code&gt;uid&lt;/code&gt;&lt;/em&gt; and the name.*&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking For New Users
&lt;/h3&gt;

&lt;p&gt;After a successful sign in, we should have a &lt;code&gt;FirebaseUser&lt;/code&gt; signed in.&lt;/p&gt;

&lt;p&gt;We do not need to check if it is a new user when signing in with email, because&lt;br&gt;
if the account does not exist, we will show a message to first register the&lt;br&gt;
account:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PEi7A426--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AuQx9WSV9ImlvBXr-422ZxQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PEi7A426--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AuQx9WSV9ImlvBXr-422ZxQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To check if it is a new user when signing in, we will&lt;/strong&gt; *&lt;em&gt;compare the creation&lt;br&gt;
time stamp and last sign in time stamp of the *&lt;/em&gt;&lt;code&gt;FirebaseUser&lt;/code&gt;. This is what we&lt;br&gt;
will do for the sign in with Google and sign in with Apple options. We can do&lt;br&gt;
this like so:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(firebaseUser.metadata.creationTime
        .difference(firebaseUser
            .metadata.lastSignInTime)
        .abs() &amp;lt;
    Duration(seconds: 1))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let’s take a look at how this is done when signing in with Google.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KKJ_mwMB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AZ-S8I4JRkbLDNUjAATOe0A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KKJ_mwMB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AZ-S8I4JRkbLDNUjAATOe0A.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the sign in with Google button is pressed, we will execute the following.&lt;br&gt;
Notice how after the user has been authenticated (signed in) with Google, we&lt;br&gt;
compare the creation time and last sign in time to check if it is a new user. If&lt;br&gt;
a user is signing in for the first time, we create a new user in the database,&lt;br&gt;
passing the &lt;code&gt;FirebaseUser&lt;/code&gt; to the method so we can utilize the data it contains.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;* I ran into a quirk when comparing the creation time and last sign in&lt;br&gt;
time. For some reason during the initial sign in, the time stamps were off by a&lt;br&gt;
thousandth of a second, when they should have been the same. Thus, I could not&lt;br&gt;
compare them using equality, because they were always off. To address this, I&lt;br&gt;
compared the difference between the two, checking to see if there is at least a&lt;br&gt;
one second difference.*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Creating a New User in the Database
&lt;/h3&gt;

&lt;p&gt;To create a new user in the database, we will do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the authenticated FirebaseUser to get the user’s name and email.&lt;/li&gt;
&lt;li&gt;Create a collection called “users” and add a user (a document) to it, setting
the document id as the FirebaseUser uID, the name field as the FirebaseUser’s
display name, and the email field as the FirebaseUser’s email.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If done successfully, we should see a users collection with a user document:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--osB-tcwZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2Ae86cqmK6sG9AEvJM2XQ_-A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--osB-tcwZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2Ae86cqmK6sG9AEvJM2XQ_-A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Each document in Cloud Firestore has a document ID to identify it. We use the&lt;br&gt;
*&lt;code&gt;setData&lt;/code&gt;&lt;/em&gt; method instead of the &lt;em&gt;&lt;code&gt;add&lt;/code&gt;&lt;/em&gt; method so we can explicitly set a&lt;br&gt;
document ID instead of it being automatically generated. We do this to easily&lt;br&gt;
retrieve the document later. However, please be aware this could cause potential&lt;br&gt;
conflicts.*&lt;/p&gt;

&lt;p&gt;When a user is signed to our app, we can call:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FirebaseUser firebaseUser = FirebaseAuth.instance.currentUser()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since we set the document ID (for the document of the FirebaseUser) to be the&lt;br&gt;
same as the corresponding FirebaseUser uID , we can simply retrieve the document&lt;br&gt;
using the &lt;code&gt;FirebaseUser&lt;/code&gt;’s &lt;code&gt;uid&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firestoreInstance.collection(
).document(firebaseUser.uid).updateData({
// Update document
)}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now let’s get to the meat of this article and learn how to work with data and&lt;br&gt;
the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Data to the Database
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Setting Up Security Rules
&lt;/h4&gt;

&lt;p&gt;Setting up Cloud Firestore Security Rules is important to keep your users’ data&lt;br&gt;
secure. Furthermore, if you don’t change the initial security rules, your app‘s&lt;br&gt;
Cloud Firestore database access will expire after 30 days. I recommend &lt;a href="https://firebase.google.com/docs/firestore/security/rules-structure"&gt;reading&lt;br&gt;
how to structure security&lt;br&gt;
rules&lt;/a&gt; to&lt;br&gt;
apply the appropriate restrictions to your app. The following set of rules&lt;br&gt;
ensure that only authenticated users can read and write their own data:&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding Initial Data
&lt;/h4&gt;

&lt;p&gt;Before we get into the add feature of &lt;em&gt;_Reply&lt;/em&gt;, let’s learn how to add data when&lt;br&gt;
we first create users in the database. This is useful to have placeholder data,&lt;br&gt;
such as welcome messages when the user first signs in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--59O37gSw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2Aa49HV-RhyHUdZw2tLMEdMQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--59O37gSw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2Aa49HV-RhyHUdZw2tLMEdMQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;span class="figcaption_hack"&gt;Placeholder message in _Reply&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In this case, we want to add placeholder messages when the user is first created&lt;br&gt;
so we can show welcome messages.&lt;/p&gt;

&lt;p&gt;We are going to use the &lt;code&gt;MessageCard&lt;/code&gt; model class to add messages. Notice the&lt;br&gt;
&lt;code&gt;toJson()&lt;/code&gt; and &lt;code&gt;fromJson()&lt;/code&gt; methods. *&lt;em&gt;To add custom objects to Cloud Firestore&lt;br&gt;
in Flutter, we must first serialize the data. *&lt;/em&gt;&lt;em&gt;In this case, we are&lt;br&gt;
serializing the inside the *&lt;code&gt;MessageCard&lt;/code&gt;&lt;/em&gt; model class, converting our objects&lt;br&gt;
into a map that Cloud Firestore will accept.*&lt;/p&gt;

&lt;p&gt;If you would like to read more about serialization in Flutter, check out &lt;a href="https://medium.com/codespace69/flutter-working-with-data-json-json-and-serialization-f90165b659d0"&gt;this&lt;br&gt;
post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we can simply add fields when we are saving the user to the database. Here&lt;br&gt;
we are adding 5 new fields, one for each category of messages, and adding&lt;br&gt;
MessageCards (messages) that display the user’s name, using the &lt;code&gt;toJson()&lt;/code&gt;&lt;br&gt;
method to serialize the data.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Adding Data to an Existing Document&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;span class="figcaption_hack"&gt;Add Message in _Reply&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Adding data to Cloud Firestore can be implemented in multiple different ways.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The *&lt;code&gt;add&lt;/code&gt;&lt;/em&gt;, &lt;em&gt;&lt;code&gt;setData&lt;/code&gt;&lt;/em&gt;, and &lt;em&gt;&lt;code&gt;updateData&lt;/code&gt;&lt;/em&gt;, and &lt;em&gt;&lt;code&gt;updateData&lt;/code&gt;&lt;/em&gt; +&lt;br&gt;
&lt;em&gt;&lt;code&gt;FieldArray.union&lt;/code&gt;&lt;/em&gt; methods can all be used to add data.*&lt;/p&gt;

&lt;p&gt;I recommend &lt;a href="https://firebase.google.com/docs/firestore/manage-data/add-data"&gt;reading the&lt;br&gt;
documentation&lt;/a&gt;&lt;br&gt;
to fully understand when to use each add method, but here is a brief overview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;add()&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt; Add a document with an auto-generated id&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setData()&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt; Add or overwrite a document with an explicit id. If the
document does not exist, it will be created. If the document does exist, its
contents will be overwritten with the newly provided data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateData()&lt;/code&gt;: Add fields to document without overwriting the entire document&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateData() + FieldArray.union():&lt;/code&gt;Add an element to an array field of a
document.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Adding New Data to an Existing Array Field
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we are going to learn how to add data. This is how data is added in &lt;em&gt;_Reply&lt;/em&gt;&lt;br&gt;
when a user adds a new message.&lt;/p&gt;

&lt;p&gt;Since we created placeholder data, we already have a fields for the messages,&lt;br&gt;
which are lists. In Cloud Firestore, lists are stored as arrays, so we are&lt;br&gt;
actually working with an array field.&lt;/p&gt;

&lt;p&gt;In this case, we have to update an existing array field; we must add an element&lt;br&gt;
(message) to the list while retaining the existing elements (messages). To do&lt;br&gt;
this, we use &lt;code&gt;updateData&lt;/code&gt; + &lt;code&gt;FieldArray.arrayUnion&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Notice we must first serialize the data using the *&lt;code&gt;toJson()&lt;/code&gt;&lt;/em&gt; method to save&lt;br&gt;
the data to the database. To store it as a list of items instead of a map, we&lt;br&gt;
convert the map to a list.*&lt;/p&gt;

&lt;p&gt;If executed correctly, we should see the new message added to the existing array&lt;br&gt;
field. (In this case, the &lt;code&gt;personalMessages&lt;/code&gt; field)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bi__cZtE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2Ai9meNZWDHn6unv2PKoroPA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bi__cZtE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2Ai9meNZWDHn6unv2PKoroPA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting Data From the Database
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mxbugt6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AoorE4l3O6vn54ptlwpEdLQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mxbugt6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AoorE4l3O6vn54ptlwpEdLQ.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deleting data from Cloud Firestore can be implemented in multiple different&lt;br&gt;
ways.&lt;/p&gt;

&lt;p&gt;Again, I recommend &lt;a href="https://firebase.google.com/docs/firestore/manage-data/delete-data"&gt;reading the&lt;br&gt;
documentation&lt;/a&gt;&lt;br&gt;
to get a full grasp of when to use each method. Here is a brief overview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;delete():&lt;/code&gt; Delete data from a document&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateData() + FieldValue.delete():&lt;/code&gt; Delete a field from a document&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateData() + FieldArray.remove():&lt;/code&gt; Remove an element from an array field
within a document&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similar to the add message case, we need to update an existing array field; we&lt;br&gt;
must remove an element (message) from the list while retaining the existing&lt;br&gt;
elements (messages). To do this, we use &lt;code&gt;updateData() + FieldArray.remove().&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If implemented correctly, the message should be deleted and the field,&lt;br&gt;
personalMessages, should still contain the other messages. Here we removed the&lt;br&gt;
the “Get Together” message, which happened to be 1st element in the array field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MZViwOZW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2Avb_EiaaMSXrjjZYqq1IpJw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MZViwOZW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1320/1%2Avb_EiaaMSXrjjZYqq1IpJw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Editing Data in the Database
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SU2kOwcD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2ASWzHUXDThYoKpQgQqNIhcQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SU2kOwcD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2ASWzHUXDThYoKpQgQqNIhcQ.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Continuing with our trend, editing data also has multiple implementations and&lt;br&gt;
use cases. Let’s take a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;updateData():&lt;/code&gt; Update fields of a document without overwriting the entire
document&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setData() with merge:true&lt;/code&gt;Update fields in a document or create it if it do not
exist&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateData() + FieldValue.arrayRemove() + updateData() +
FieldValue.arrayUnion():&lt;/code&gt;Update elements in an array field within a document&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;updateData() + FieldValue.increment():&lt;/code&gt;Increment a numeric field within a
document&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the &lt;em&gt;_Reply&lt;/em&gt; app, what we need to do is &lt;em&gt;replace&lt;/em&gt; the old message with the&lt;br&gt;
new message. To do this, we will use &lt;code&gt;updateData() + FieldValue.arrayRemove() +&lt;br&gt;
updateData() + FieldValue.arrayUnion():&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Notice what is going on here. To update the message, we are actually just&lt;br&gt;
deleting the old value, then adding a new one- a clever way to edit something.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Data From the Database
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fZABbO9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AQd8kH7lBfCykh_Y5pIC-qQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fZABbO9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AQd8kH7lBfCykh_Y5pIC-qQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have data in the database, we can retrieve it. I saved getting data&lt;br&gt;
for last because it is the most cumbersome and complex data operation to&lt;br&gt;
implement.&lt;/p&gt;

&lt;p&gt;Fortunately, there is really only one method we need to know when getting data:&lt;br&gt;
&lt;code&gt;get()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is what we need to do to retrieve our data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We first create an empty &lt;code&gt;List&lt;/code&gt; to hold the data we will get from our database&lt;/li&gt;
&lt;li&gt;We then query the database for the data we need&lt;/li&gt;
&lt;li&gt;Since the data is returned to us as a &lt;code&gt;Map&lt;/code&gt;, we need to convert it to
&lt;code&gt;MessageCard&lt;/code&gt; objects so we can easily retrieve the data; to do this, we use the
&lt;code&gt;fromJson()&lt;/code&gt; method in our MessageCard class&lt;/li&gt;
&lt;li&gt;Once our data is converted to &lt;code&gt;MessageCard&lt;/code&gt; objects, we can get the data we
need; in this case, we are retrieving the &lt;code&gt;MessageCard&lt;/code&gt;s and adding them to a
list.&lt;/li&gt;
&lt;li&gt;Finally, we return the list of messages to show them in the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Since the data returned from Cloud Firestore will be a Map, we need to convert&lt;br&gt;
it to deserialize it and convert it to a custom object.&lt;/strong&gt; This is the opposite&lt;br&gt;
of what we had to do when saving the MessageCard objects to Cloud Firestore. We&lt;br&gt;
use the &lt;code&gt;fromJson()&lt;/code&gt; method to do this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Let’s recap. We learned how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check for new users upon sign in&lt;/li&gt;
&lt;li&gt;Create new users in a Cloud Firestore Database&lt;/li&gt;
&lt;li&gt;Set basic security rules&lt;/li&gt;
&lt;li&gt;Add placeholder data for our users&lt;/li&gt;
&lt;li&gt;Add new data to the database&lt;/li&gt;
&lt;li&gt;Delete data in the database&lt;/li&gt;
&lt;li&gt;Edit data in the database&lt;/li&gt;
&lt;li&gt;Get data from the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know that was a lot, but you made it!&lt;/p&gt;

&lt;p&gt;Now you can truly be a (Fire)base User. 🔥&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ashtonjonesdev/reply_flutter"&gt;https://github.com/ashtonjonesdev/reply_flutter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html?index=..%2F..index#6"&gt;https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html?index=..%2F..index#6&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=v_hR4K4auoQ&amp;amp;list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ&amp;amp;index=2&amp;amp;t=0s"&gt;https://www.youtube.com/watch?v=v_hR4K4auoQ&amp;amp;list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ&amp;amp;index=2&amp;amp;t=0s&lt;/a&gt;&lt;/p&gt;



</description>
      <category>cloudfirestore</category>
      <category>flutter</category>
      <category>dart</category>
      <category>firebase</category>
    </item>
    <item>
      <title>Cloud Firestore Basics in Android: How to Get, Add, Edit, and Delete Data in Cloud Firestore in an Android App</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Fri, 31 Jul 2020 17:40:03 +0000</pubDate>
      <link>https://dev.to/tjgrapes/cloud-firestore-basics-in-android-how-to-get-add-edit-and-delete-data-in-cloud-firestore-in-an-android-app-552h</link>
      <guid>https://dev.to/tjgrapes/cloud-firestore-basics-in-android-how-to-get-add-edit-and-delete-data-in-cloud-firestore-in-an-android-app-552h</guid>
      <description>&lt;p&gt;In this post, I will be demonstrating how to do the basic database operations in&lt;br&gt;
Cloud Firestore in an Android App, using a published app I built as a practical&lt;br&gt;
example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You will learn how to implement the core database operations in Cloud&lt;br&gt;
Firestore: how to get (read), add (write), edit, and delete data in the database&lt;br&gt;
in an Android app.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;This article does not cover setting up Cloud Firestore, Firebase&lt;br&gt;
Authentication for Android, and documents/collections in Cloud Firestore, which&lt;br&gt;
are prerequisites for this tutorial. *If you are unfamiliar with these topics,&lt;/em&gt;&lt;br&gt;
*I highly encourage you to read &lt;a href="https://medium.com/u/5b62548cef5e"&gt;Evana&lt;br&gt;
Margain&lt;/a&gt;’s &lt;a href="https://medium.com/better-programming/how-to-set-up-a-database-with-firebase-firestore-to-use-with-android-architecture-components-992ab5df8223"&gt;article to set up Cloud&lt;br&gt;
Firestore&lt;/a&gt;,&lt;br&gt;
read &lt;a href="https://firebase.google.com/docs/auth/android/firebaseui"&gt;how to implement FirebaseUI for&lt;br&gt;
authentication&lt;/a&gt;, and&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=v_hR4K4auoQ&amp;amp;list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ"&gt;watch this video to learn about documents and collections in Cloud&lt;br&gt;
Firestore&lt;/a&gt;&lt;br&gt;
before returning to this article.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reply App Background
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ESxkXkq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AWVxIVN4qWMnIdGy9P6hOWw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ESxkXkq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AWVxIVN4qWMnIdGy9P6hOWw.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@TJgrapes/introducing-reply-3d0b57ec6744"&gt;Reply&lt;/a&gt; is an&lt;br&gt;
Android app I built from scratch and published to the Google Play Store. I will&lt;br&gt;
use this app to provide clear, practical examples of how to implement the core&lt;br&gt;
Cloud Firestore operations.&lt;/p&gt;

&lt;p&gt;I have the&lt;a href="https://github.com/ashtonjonesdev/Reply"&gt; code available on Github&lt;/a&gt;&lt;br&gt;
and you can &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.reply"&gt;download the app&lt;br&gt;
here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reply helps you easily create your own custom, pre-defined messages through any&lt;br&gt;
platform.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With the app, you create your custom message templates which you can categorize&lt;br&gt;
based on the type of message (i.e. personal, social, and business messages).&lt;br&gt;
Each tab corresponds to a category.&lt;/p&gt;

&lt;p&gt;Once you create your own messages, you can preview, send, edit, and delete them&lt;br&gt;
using the main button in the bottom right corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cJFx3aT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A8YKDXaEYWWaEdaS0R_1vRw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cJFx3aT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A8YKDXaEYWWaEdaS0R_1vRw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 0: Creating Users in the Database
&lt;/h4&gt;

&lt;p&gt;Before we start adding user data in the database, we &lt;em&gt;first need to create users&lt;br&gt;
which we will save the user data to&lt;/em&gt; in the database. This should be done after&lt;br&gt;
registering/signing in to the app and only if it is a new user.&lt;/p&gt;

&lt;p&gt;If you are using Cloud Firestore, you can also use Firebase Authentication to&lt;br&gt;
register and sign in users. If you are implementing Firebase Authentication for&lt;br&gt;
the first time, I recommend using&lt;br&gt;
&lt;a href="https://firebase.google.com/docs/auth/android/firebaseui"&gt;FirebaseUI&lt;/a&gt;, because&lt;br&gt;
it provides a pre-built UI and requires less work.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❗️❗️Please note that authenticating/signing in a user does NOT create a user&lt;br&gt;
for you in the database.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signing in a user and creating a user in the database are two separate&lt;br&gt;
operations you must implement.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This can be confusing because once a user has signed, you will see an&lt;br&gt;
authenticated user with a uID in the Authentication tab in the Firebase console.&lt;br&gt;
*These are the Firebase Users. *After a successful initial sign in or&lt;br&gt;
registration, a FirebaseUser is created. A FirebaseUser contains data such as&lt;br&gt;
name (called ‘display name’), email, and an automatically generated uID to&lt;br&gt;
identify the FirebaseUser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PXg5WcCd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2AxF0qiC1VkmqO45btBhf1RQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PXg5WcCd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2AxF0qiC1VkmqO45btBhf1RQ.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;span class="figcaption_hack"&gt;Reply Authentication in Firebase Console&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To create users in our actual database, &lt;em&gt;we will use the data provided by the&lt;br&gt;
FirebaseUsers to create users in our database; namely, we will use the uID and&lt;br&gt;
the name.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before we begin adding users to the database, we need to create a simple User&lt;br&gt;
model class. We will be using instances of this to create Users in our database.&lt;br&gt;
*In other words, these are the objects we will actually be saving to Cloud&lt;br&gt;
Firestore. *Since Cloud Firestore supports custom objects, we do not need to be&lt;br&gt;
concerned about converting or serializing the data before saving it to the&lt;br&gt;
database. For example, we can start with a simple model which will just contain&lt;br&gt;
a name and a user ID:&lt;/p&gt;

&lt;p&gt;If you are using FirebaseUI to sign in users, you should have code similar to&lt;br&gt;
the gist below. The code below is from my app; the only difference between the&lt;br&gt;
&lt;a href="https://firebase.google.com/docs/auth/android/firebaseui"&gt;FirebaseUI Sign in&lt;br&gt;
Example&lt;/a&gt; and my code&lt;br&gt;
is that I put some of the code to handle the sign in response into a method.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The important parts to pay attention to are the IdpResponse and the current&lt;br&gt;
FirebaseUser.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We are going to use the IdpResponse to check if it is a new user and the&lt;br&gt;
FirebaseUser to create a user in the database using the FirebaseUser uID and&lt;br&gt;
display name.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To check if we have a new user (signing in for the first time), we can call&lt;br&gt;
isNewUser() on our IdpResponse. If it is a new user, we should create a user in&lt;br&gt;
the database, using our User model class.&lt;/p&gt;

&lt;p&gt;To create a new user in the database, we will do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get the current FirebaseUser. This should return the user who just signed in.&lt;/li&gt;
&lt;li&gt;Create a new User object from our User model class, using the uID and the
display name from the FirebaseUser to set the uID and name of the User object.&lt;/li&gt;
&lt;li&gt;Create a collection called “users” and add a user (a document) to it, setting
the document id as the FirebaseUser uID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If done successfully, we should see a users collection with a user document:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6f4dMlAQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2Asm5ZUsR4fS47Eal741vd0A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6f4dMlAQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2Asm5ZUsR4fS47Eal741vd0A.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;span class="figcaption_hack"&gt;Reply Cloud Firestore Database in Firebase Console&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Each document in Cloud Firestore has a document ID to identify it. We use the&lt;br&gt;
‘set’ method instead of the ‘add’ method so we can explicitly set a document ID&lt;br&gt;
instead of it being automatically generated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❗️❗️ *&lt;/em&gt;&lt;em&gt;We set the document ID to be the same as the corresponding FirebaseUser&lt;br&gt;
uID. We do this so we can easily retrieve the user data later.&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;When a user is signed to our app, we can call:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will return the id of the signed in user.&lt;/p&gt;

&lt;p&gt;Since we set the document ID (for the document of the FirebaseUser) to be the&lt;br&gt;
same as the corresponding FirebaseUser uID , we can simply retrieve the document&lt;br&gt;
(and thus, the data) by calling the following, passing in the signed in user’s&lt;br&gt;
id:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DocumentReference userDocument =&lt;br&gt;
firebaseFirestore.collection("users").document(uID)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These calls are compartmentalized into methods below:&lt;/p&gt;

&lt;p&gt;We will use these two methods over and over whenever we need to access data in&lt;br&gt;
the database, as you will see shortly.&lt;/p&gt;

&lt;p&gt;Now let’s get to the meat of this article and learn how to work with data and&lt;br&gt;
the database.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding Data to the Database
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;span class="figcaption_hack"&gt;Add Message in Reply&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding data to Cloud Firestore can be implemented in multiple different&lt;br&gt;
ways:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The ‘add’, ‘set’, and ‘update’, and ‘update + FieldArray.union’ methods can all&lt;br&gt;
be used to add data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I recommend &lt;a href="https://firebase.google.com/docs/firestore/manage-data/add-data"&gt;reading the&lt;br&gt;
documentation&lt;/a&gt;&lt;br&gt;
to fully understand when to use each add method, but here is a brief overview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;‘add’:&lt;/strong&gt; Add a document with an auto-generated id&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;‘set’:&lt;/strong&gt; Add or overwrite a document with an explicit id. If the document does
not exist, it will be created. If the document does exist, its contents will be
overwritten with the newly provided data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;‘update’&lt;/strong&gt;: Add fields to document without overwriting the entire document&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;‘update + FieldArray.union’:&lt;/strong&gt; Add an element to an array field of a document.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adding initial data when we create the users in the database:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we get into the add feature of Reply, let’s learn how to add data when we&lt;br&gt;
first create users in the database. This is useful to have placeholder data,&lt;br&gt;
such as welcome messages when the user first signs in:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--59O37gSw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2Aa49HV-RhyHUdZw2tLMEdMQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--59O37gSw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2Aa49HV-RhyHUdZw2tLMEdMQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;span class="figcaption_hack"&gt;Placeholder message in Reply&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To do this, we first need to add the data we want to our User model class. For&lt;br&gt;
the Reply app, I added a message list for each category to show a placeholder&lt;br&gt;
message in each one:&lt;/p&gt;

&lt;p&gt;&lt;span class="figcaption_hack"&gt;Reply User Model with Placeholder Data&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Then when I created a User to save to Cloud Firestore, I added a placeholder&lt;br&gt;
message to each list which displays their name:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding new data to an existing array field&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aRtrnY-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A3bX4QXkEQrErQ7gLBq9zjA.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we are going to learn how to add data. This is how data is added in Reply&lt;br&gt;
when a user adds a new message.&lt;/p&gt;

&lt;p&gt;Since we created placeholder data, we already have a fields for the messages,&lt;br&gt;
which are lists. In Cloud Firestore, lists are stored as arrays, so we are&lt;br&gt;
actually working with an array field.&lt;/p&gt;

&lt;p&gt;In this case, we have to update an existing array field; we must add an element&lt;br&gt;
(message) to the list while retaining the existing elements (messages). To do&lt;br&gt;
this, we use ‘update + FieldArray.arrayUnion’.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Notice we are using the two methods I mentioned earlier to access data in the&lt;br&gt;
database. Here they are in action. We are retrieving the user document which&lt;br&gt;
corresponds to the user who is signed in.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If executed correctly, we should see the new message added to the existing array&lt;br&gt;
field. (In this case, the personalMessages field)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QLogA5Oo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2A-JAFSQ_7WYPr0jp_FshkcQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QLogA5Oo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2A-JAFSQ_7WYPr0jp_FshkcQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Deleting Data From the Database:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mxbugt6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AoorE4l3O6vn54ptlwpEdLQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mxbugt6R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AoorE4l3O6vn54ptlwpEdLQ.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deleting data from Cloud Firestore can be implemented in multiple different&lt;br&gt;
ways.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again, I recommend &lt;a href="https://firebase.google.com/docs/firestore/manage-data/delete-data"&gt;reading the&lt;br&gt;
documentation&lt;/a&gt;&lt;br&gt;
to get a full grasp of when to use each method. Here is a brief overview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;‘delete’:&lt;/strong&gt; Delete an entire document&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;‘update + FieldValue.delete’:&lt;/strong&gt; Delete a field from a document&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;‘update + FieldValue.arrayRemove’:&lt;/strong&gt; Remove an element from an array field
within a document&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similar to the add message case, we need to update an existing array field; we&lt;br&gt;
must remove an element (message) from the list while retaining the existing&lt;br&gt;
elements (messages). To do this, we use ‘update + FieldArray.arrayRemove’.&lt;/p&gt;

&lt;p&gt;If implemented correctly, the message should be deleted and the field,&lt;br&gt;
personalMessages, should still contain the other messages. Here we removed the&lt;br&gt;
the “Get Together” message, which happened to be 1st element in the array field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rvohohjq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2AJJe45TqK17jcq0johZwowg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rvohohjq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2600/1%2AJJe45TqK17jcq0johZwowg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Editing Data in the Database:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SU2kOwcD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2ASWzHUXDThYoKpQgQqNIhcQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SU2kOwcD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2ASWzHUXDThYoKpQgQqNIhcQ.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Continuing with our trend, editing data also has multiple implementations and&lt;br&gt;
use cases. Let’s take a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;‘update’:&lt;/strong&gt; Update fields of a document without overwriting the entire
document&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;‘update + dot notation’:&lt;/strong&gt; Update nested fields within a document&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;‘update + FieldArray.union’ &amp;amp; ‘update + FieldArray.remove’:&lt;/strong&gt; Update elements
in an array field within a document&lt;/li&gt;
&lt;li&gt;**‘update + FieldValue.increment’ &amp;amp; ‘update + FieldValue.decrement’: **Increment
or decrement a numeric field within a document&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the Reply app, what we need to do is &lt;em&gt;replace&lt;/em&gt; the old message with the new&lt;br&gt;
message. To do this, we will use ‘update + FieldArray.union’ &amp;amp; ‘update +&lt;br&gt;
FieldArray.remove’:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Notice what is going on here. To ‘update’ the message, we are actually just&lt;br&gt;
deleting the old value, then adding a new one- a clever way to ‘edit’&lt;br&gt;
something.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Getting Data From the Database:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fZABbO9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AQd8kH7lBfCykh_Y5pIC-qQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fZABbO9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2AQd8kH7lBfCykh_Y5pIC-qQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have data in the database, we can retrieve it. I saved getting data&lt;br&gt;
for last because it is the most cumbersome and complex data operation to&lt;br&gt;
implement.&lt;/p&gt;

&lt;p&gt;Fortunately, there is really only one method we need to know when getting data:&lt;br&gt;
&lt;strong&gt;‘get’&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is what we need to do to retrieve our data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We first create an empty ArrayList to hold the data we will get from our
database&lt;/li&gt;
&lt;li&gt;We then query the database for the data we need&lt;/li&gt;
&lt;li&gt;Since the data is returned to us as a Map, we need to convert it to our User
model class so we can easily retrieve the data; to do this, we use the
‘toObject’ method from the DocumentSnapshot class&lt;/li&gt;
&lt;li&gt;Once our data is converted to a User object, we can get the data we need; in
this case, we are retrieving the list of personal messages&lt;/li&gt;
&lt;li&gt;Finally, we return the list of messages to show them in the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whew, I know that was a lot, but you made it!&lt;/p&gt;

&lt;p&gt;Now you can truly be a (Fire)base User. 🔥&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you learned something from this article, *&lt;a href="https://www.buymeacoffee.com/ashtonjonesdev"&gt;please consider buying me a&lt;br&gt;
coffee&lt;/a&gt;&lt;/em&gt;.*&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CeX0oCc_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CeX0oCc_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/880/1%2A8D0WQH0Y7-hCiy_AxI-Xnw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hi, I’m Ash 👋🏼 Let’s connect!&lt;/p&gt;

&lt;p&gt;🌐 &lt;a href="https://ashtonjones.dev/"&gt;ashtonjones.dev&lt;/a&gt; | 👥&lt;br&gt;
&lt;a href="https://twitter.com/TJgrapes"&gt;@TJgrapes&lt;/a&gt; | ✉️&lt;br&gt;
&lt;a href="//mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👨‍💻 &lt;a href="https://developers.google.com/certification/directory"&gt;Google Certified Android&lt;br&gt;
Engineer&lt;/a&gt; |&lt;br&gt; ✍ &lt;a href="https://medium.com/@TJgrapes"&gt;Writer&lt;/a&gt; |&lt;br&gt; 🧘‍♂️ &lt;a href="https://medium.com/antidotes-for-chimps/stoicism-a-masterclass-in-emotion-regulation-622546bd25d5"&gt;Stoic&lt;/a&gt; &amp;amp;&amp;amp; &lt;a href="https://www.calm.com/"&gt;Meditator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📱 Need an app built? Contact me &lt;a href="https://www.ashtonjones.dev/consulting"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>android</category>
      <category>mobiledevelopment</category>
      <category>firebase</category>
      <category>cloudfirestore</category>
    </item>
    <item>
      <title>Introducing: Torch</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Mon, 18 May 2020 19:07:22 +0000</pubDate>
      <link>https://dev.to/tjgrapes/introducing-torch-21b4</link>
      <guid>https://dev.to/tjgrapes/introducing-torch-21b4</guid>
      <description>&lt;p&gt;A simple app that helps you discover and stay focused on what is most important to you&lt;/p&gt;

&lt;p&gt;Torch is an app I built that helps you stay focused on your primary goal, focus, or purpose in life.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RSUHVjNi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6mq8ylvunzalg3zj8rvy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RSUHVjNi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6mq8ylvunzalg3zj8rvy.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Torch allows you to:&lt;/p&gt;

&lt;p&gt;✅ Discover your torch with guiding questions&lt;br&gt;
✅ Stay focused on your torch by limiting you to only being able to set one goal at a time&lt;br&gt;
✅ Check-in daily to help you reflect if your actions are aligned with your goal&lt;br&gt;
✅ Change your torch at any time&lt;br&gt;
✅ See yourself progress by climbing up a mountain the more days you are aligned&lt;/p&gt;

&lt;p&gt;In this post, I will explain the motivation behind the app and showcase its features. If you want to download it and use it while reading the article, you can download it &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.torch"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Motivation:
&lt;/h2&gt;

&lt;p&gt;I personally like to build things I think are useful.&lt;/p&gt;

&lt;p&gt;I had three main reasons to build this app:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a simple, focused "goal tracking" app:&lt;/strong&gt;: I am someone who likes to focus on one major thing in my life at a time and give it 100% of my attention. There are plenty of goal-tracking apps, but they allow you to set multiple goals, which can be distract you from your most important. I was intentional when designing Torch to only allow one, overarching goal to be set at one time. I put goal tracking in quotes, because it focuses on progressing each day rather than achieving a certain outcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build my portfolio&lt;/strong&gt;: I am building my professional portfolio to showcase my Android development skills. Although it is a relatively small application, it shows I am able to develop entire Android apps on my own from the initial idea to publishing the completed app, implementing the UI, functionalities, logic, app architecture, database, and user experience along the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practice my skills&lt;/strong&gt;: I wanted to build another Android app that uses Android Architecture Components and MVVM architecture in conjunction with Firebase Cloud Firestore as the database to improve my skills. I learned more about working with data in Cloud Firestore, nested Navigation flows, and building an app using clean architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  🕹 Features
&lt;/h2&gt;

&lt;p&gt;The app helps you discover your "torch"- the primary goal, focus, or purpose that is guiding you in life, and stay focused by aligning your actions with it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the app is first opened, you will be guided through a series of questions to help you discover your torch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--15bTGXud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/20m6si9ny86rl3coov3o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--15bTGXud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/20m6si9ny86rl3coov3o.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the end, you will have answered three questions that should help you discover you ultimate goal and set your torch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xf0XNgA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p7quyhvdjzx2h7idnp8t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xf0XNgA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p7quyhvdjzx2h7idnp8t.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Torch:
&lt;/h2&gt;

&lt;p&gt;Once you set your torch, it will be displayed front and center when you open the app, which helps you stay focused. You can change your torch at any time, but you can only have one torch set at a time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wyBzRda1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a420tn7rn5j2a0cq62ra.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wyBzRda1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a420tn7rn5j2a0cq62ra.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Progress:
&lt;/h2&gt;

&lt;p&gt;You will have a daily notification that asks you if your actions were aligned with your torch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uO-8KMBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wuishjibak401nc34ypa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uO-8KMBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wuishjibak401nc34ypa.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you continue to record your small wins each day, you will gradually climb up the mountain. Will you (align yourself for 100 days) reach the top?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BqBvWQf6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oc7173lrsa77lltjwbpv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BqBvWQf6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oc7173lrsa77lltjwbpv.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Discover:
&lt;/h2&gt;

&lt;p&gt;The discover section displays answers to all of the discovery questions you answered when you first opened the app, your current torch, and asks if there is a misalignment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fX05gNbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m81torrs3bh1tjl3z71v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fX05gNbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m81torrs3bh1tjl3z71v.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you feel there is a misalignment or need to change your torch, you can choose 'yes' to re-evaluate and change your answers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xe2T7bQp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vz5wl0erq1wsyd5gir2h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xe2T7bQp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vz5wl0erq1wsyd5gir2h.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🖥 Technical Brief:
&lt;/h2&gt;

&lt;p&gt;I built the app natively with Java, using Android Architecture Components (LiveData View Model, View Binding, and Navigation), MVVM architecture, Material Design, and Firebase Cloud Firestore. The app follows Google's recommended Single-Activity architecture and uses Navigation best practices to navigate through the app.&lt;/p&gt;

&lt;p&gt;I used the following technologies to build the app:&lt;/p&gt;

&lt;p&gt;MVVM Architecture&lt;br&gt;
Java&lt;br&gt;
Android SDK&lt;br&gt;
ViewModel&lt;br&gt;
LiveData&lt;br&gt;
View Binding&lt;br&gt;
Navigation Component&lt;br&gt;
Firebase Authentication&lt;br&gt;
Cloud Firestore&lt;br&gt;
Material Design&lt;/p&gt;

&lt;p&gt;If you are interested in the code for the app, you can find it &lt;a href="https://github.com/ashtonjonesdev/Torch"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙌🏼 Appreciation:
&lt;/h2&gt;

&lt;p&gt;I want to thank my friend Jonathan Batchelor for his interest in the app and suggestions for the purpose discovery questions. Jonathan is really passionate about helping people find their purpose and is aspiring to build a mentorship program designed to empower youth in underprivileged communities through harnessing passion and purpose.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check It Out:
&lt;/h2&gt;

&lt;p&gt;You can download the app &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.torch"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am always looking to improve it, so please feel free to send me feedback and leave a review on Google Play. I hope you enjoy using Reply! 😃&lt;/p&gt;

&lt;p&gt;📱 &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.torch"&gt;Torch app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⌨️  &lt;a href="https://github.com/ashtonjonesdev/Torch"&gt;Torch code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm going to use this &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.reply"&gt;awesome app called Reply&lt;/a&gt; to easily share Torch with all of my friends and post it on all my social platforms from mobile!&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://play.google.com/store/apps/dev?"&gt;my other apps.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm looking for Android development opportunities; contact me at &lt;a href="mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt; if you are looking for an Android developer or know of available positions!&lt;/p&gt;




&lt;p&gt;Hi, I'm Ash 👋🏼 Let's connect!&lt;br&gt;
🌐 ashtonjones.dev|👥 &lt;a class="comment-mentioned-user" href="https://dev.to/tjgrapes"&gt;@tjgrapes&lt;/a&gt;
|✉️ &lt;a href="mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt;&lt;br&gt;
👨‍💻 Google Certified Android Engineer |&lt;br&gt;
✍ Writer |&lt;br&gt;
🧘‍♂️ Stoic &amp;amp;&amp;amp; Meditator&lt;/p&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>java</category>
      <category>database</category>
    </item>
    <item>
      <title>Introducing: Reply</title>
      <dc:creator>Ashton Jones</dc:creator>
      <pubDate>Sat, 16 May 2020 17:35:46 +0000</pubDate>
      <link>https://dev.to/tjgrapes/introducing-reply-174j</link>
      <guid>https://dev.to/tjgrapes/introducing-reply-174j</guid>
      <description>&lt;p&gt;An Android app to easily send your own predefined messages through any platform.&lt;/p&gt;

&lt;p&gt;Reply is an app I built which makes it easy to send your own predefined messages through any platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nNMSQ-cJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8wocjb3th7r7m72as0mb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nNMSQ-cJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8wocjb3th7r7m72as0mb.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;It allows you to:&lt;/p&gt;

&lt;p&gt;✅ Create and store your own message templates&lt;br&gt;
✅ Easily send your messages through any platform&lt;br&gt;
✅ Organize your messages into categories&lt;br&gt;
✅ Add, edit, and delete your messages&lt;br&gt;
✅ Preview and edit your message before you send it&lt;br&gt;
✅ Set a timer to remind you to reply with one of your messages at a later time&lt;/p&gt;

&lt;p&gt;In this post, I will be explaining its features, use cases, and tips to help you get the most out of it.&lt;br&gt;
If you want to download it and use it while reading the article, you can find it &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.reply"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Motivation:
&lt;/h2&gt;

&lt;p&gt;I personally like to build things I think are useful. &lt;br&gt;
I had three main reasons to build this app:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solve a problem&lt;/strong&gt;: I was tired of repeatedly typing the same message over and over and having to copy and paste the same message to each platform I wanted to post it to. And I know there are other people who feel the same. That frustration was a core motivator to create Reply, which makes it easy to send messages you frequently send through any platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build my portfolio&lt;/strong&gt;: I am building my professional portfolio to showcase my Android development skills. Although it is a relatively small application, it shows I am able to develop entire Android apps on my own from the initial idea to publishing the completed app, implementing the UI, functionalities, logic, app architecture, database, and user experience along the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn something new&lt;/strong&gt;: I wanted to learn how to build an Android app that uses Android Architecture Components and MVVM architecture in conjunction with Firebase Cloud Firestore as the database. This was my first experience implementing a remote database in an Android application and using Firebase products. In addition to learning how to implement Cloud Firestore with Architecture Components and MVVM architecture, I learned how to authenticate users with Firebase, sign in and sign out users, implement complex Navigation flows using the Navigation component, and how to publish an app to the Google Play Store.&lt;/p&gt;




&lt;h2&gt;
  
  
  🕹 Features
&lt;/h2&gt;

&lt;p&gt;I wanted to make Reply easy to use and as customizable as possible.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Add Messages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adding messages is the core of the app! Add messages you frequently send or post to multiple platforms. You can edit or delete the messages at any time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preview Messages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Previewing a message is useful to remind yourself what the exact message is and if you need to edit it before sending.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send Messages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The beauty of Reply is the flexibility to send your message through any platform you want (e.g. any messaging app, social media, email, etc.). Once you select where or who you are sending your message to, you still can edit it before sending it. The message is there for you, but can still be customized before posting or sending it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Respond Later&lt;/strong&gt;&lt;br&gt;
If you need to send a message, but don't want to do it immediately, you can use the reply later feature to remind you to respond with one of your messages at a later time.&lt;/p&gt;




&lt;h2&gt;
  
  
  📱Use Cases:
&lt;/h2&gt;

&lt;p&gt;Reply is most useful for people who frequently send identical messages through different or multiple platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commonly Sent Messages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you find yourself sending the same message repeatedly, composing it each time? If you have a message you send often, add it as a message to one of your categories to easily send it just by tapping it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conserve Mental Energy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes we just spend way too much time overthinking a message we need to send to someone. Especially if we are working, we want to minimize the disruption of our workflow. If you create a solid template to use, you will spend less brain power thinking of how to phrase your message. Remember, you can always edit your message before sending it to better fit the context and situation. Even better, you can use the respond later feature to remind you to reply at a later time with one of your messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time-Saving&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Typing and composing messages on phones is tedious and time-consuming. Utilizing this app can save you time, especially if you have multiple identical messages you frequently send.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mass Texting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Mass texting is sending the same message to multiple people with individual chats for each person. Want to check-in monthly with your friends? Instead of copying and pasting the same message across your platforms and contacts, use a message template to effortlessly send out your message.&lt;/p&gt;




&lt;h2&gt;
  
  
  👉🏼 Pro Tips:
&lt;/h2&gt;

&lt;p&gt;Here are some tips for you to get the most benefit out of Reply:&lt;/p&gt;

&lt;p&gt;Think of all the identical, similar, or frequent messages you send and create templates for them (i.e. a message to introduce yourself).&lt;/p&gt;

&lt;p&gt;Think of the processes where you repeat a certain series of messages and create a series of messages to have reusable templates (i.e. applying to jobs).&lt;/p&gt;

&lt;p&gt;If you want to mass text (send the same message to multiple people using individual chats), go to your default messaging app and set the "Group conversation" setting to off. If you want to group text (send the same message to multiple people in one chat) leave this setting on.&lt;/p&gt;

&lt;p&gt;Create groups in your contacts app to send a message to everyone in the group without having to select each person.&lt;/p&gt;

&lt;h2&gt;
  
  
  🖥 Technical Brief:
&lt;/h2&gt;

&lt;p&gt;This is for the nerds (and recruiters).&lt;br&gt;
I built the app natively with Java, using Android Architecture Components (LiveData View Model, View Binding, and Navigation), MVVM architecture, Material Design, and Firebase Cloud Firestore. The app follows Google's recommended Single-Activity architecture and uses Navigation best practices to navigate through the app.&lt;br&gt;
I used the following technologies to build the app:&lt;/p&gt;

&lt;p&gt;MVVM Architecture&lt;br&gt;
Java&lt;br&gt;
Android SDK&lt;br&gt;
ViewModel&lt;br&gt;
LiveData&lt;br&gt;
View Binding&lt;br&gt;
Navigation Component&lt;br&gt;
Firebase Authentication&lt;br&gt;
Cloud Firestore&lt;br&gt;
Material Design&lt;/p&gt;

&lt;p&gt;If you are interested in the code for the app, you can find it here.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙌🏼 Recognition:
&lt;/h2&gt;

&lt;p&gt;I want to thank the following people for enabling me to develop this app:&lt;br&gt;
Elijah Dangerfield for his tutorial to implementing an Android app using MVVM with Firebase in Kotlin&lt;br&gt;
Evana Margain for her series on connecting an Android app with Cloud Firestore in Java&lt;br&gt;
Riyaz Ahamed for making implementing RecyclerView much easier and cleaner&lt;br&gt;
Roberto Leinardi for recreating the awesome FAB from Google Inbox&lt;br&gt;
Gaëlle Minisini for providing fantastic README examples&lt;br&gt;
Thanks to your guides, libraries, and knowledge, I was able to build Reply.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check It Out:
&lt;/h2&gt;

&lt;p&gt;You can download the app &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.reply"&gt;here&lt;/a&gt;. &lt;br&gt;
I am always looking to improve it, so please feel free to send me feedback and leave a review on Google Play. I hope you enjoy using Reply! 😃&lt;/p&gt;

&lt;p&gt;📱 &lt;a href="https://play.google.com/store/apps/details?id=dev.ashtonjones.reply"&gt;Reply app&lt;/a&gt;&lt;br&gt;
⌨️  &lt;a href="https://github.com/ashtonjonesdev/Reply"&gt;Reply code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm looking for Android development opportunities; contact me at &lt;a href="mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt; if you are looking for an Android developer or know of available positions!&lt;/p&gt;




&lt;p&gt;Hi, I'm Ash 👋🏼 Let's connect!&lt;br&gt;
🌐 ashtonjones.dev|👥 &lt;a class="comment-mentioned-user" href="https://dev.to/tjgrapes"&gt;@tjgrapes&lt;/a&gt;
|✉️ &lt;a href="mailto:ashtonjonesdev@gmail.com"&gt;ashtonjonesdev@gmail.com&lt;/a&gt;&lt;br&gt;
👨‍💻 Google Certified Android Engineer |&lt;br&gt;
✍ Writer |&lt;br&gt;
🧘‍♂️ Stoic &amp;amp;&amp;amp; Meditator&lt;/p&gt;

</description>
      <category>android</category>
      <category>architecture</category>
      <category>java</category>
      <category>database</category>
    </item>
  </channel>
</rss>
