<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ mobile app development - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ mobile app development - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 22 May 2026 17:39:46 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/mobile-app-development/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Singleton Design Pattern in Flutter: Lazy, Eager, and Factory Variations ]]>
                </title>
                <description>
                    <![CDATA[ In software engineering, sometimes you need only one instance of a class across your entire application. Creating multiple instances in such cases can lead to inconsistent behavior, wasted memory, or resource conflicts. The Singleton Design Pattern i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-the-singleton-design-pattern-in-flutter-lazy-eager-and-factory-variations/</link>
                <guid isPermaLink="false">69740b7bc3e68b8de44a179f</guid>
                
                    <category>
                        <![CDATA[ Singleton Design Pattern ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ood ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ flutter development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Factory Design Pattern ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mobile Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwaseyi Fatunmole ]]>
                </dc:creator>
                <pubDate>Fri, 23 Jan 2026 23:59:55 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769212761076/11d41d2a-8efa-4ddb-9ee2-218f5be00d9f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In software engineering, sometimes you need only one instance of a class across your entire application. Creating multiple instances in such cases can lead to inconsistent behavior, wasted memory, or resource conflicts.</p>
<p>The Singleton Design Pattern is a creational design pattern that solves this problem by ensuring that a class has exactly one instance and provides a global point of access to it.</p>
<p>This pattern is widely used in mobile apps, backend systems, and Flutter applications for managing shared resources such as:</p>
<ul>
<li><p>Database connections</p>
</li>
<li><p>API clients</p>
</li>
<li><p>Logging services</p>
</li>
<li><p>Application configuration</p>
</li>
<li><p>Security checks during app bootstrap</p>
</li>
</ul>
<p>In this article, we'll explore what the Singleton pattern is, how to implement it in Flutter/Dart, its variations (eager, lazy, and factory), and physical examples. By the end, you'll understand the proper way to use this pattern effectively and avoid common pitfalls.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-singleton-pattern">What is the Singleton Pattern?</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-when-to-use-the-singleton-pattern">When to Use the Singleton Pattern</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-singleton-class">How to Create a Singleton Class</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-eager-singleton">Eager Singleton</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lazy-singleton">Lazy Singleton</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-choosing-between-eager-and-lazy">Choosing Between Eager and Lazy</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-factory-constructors-in-the-singleton-pattern">Factory Constructors in the Singleton Pattern</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-are-factory-constructors">What Are Factory Constructors?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-implementing-singleton-with-factory-constructor">Implementing Singleton with Factory Constructor</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-when-not-to-use-a-singleton">When Not to Use a Singleton</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-singletons-can-be-problematic">Why Singletons Can Be Problematic</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-scenarios-where-you-should-avoid-singletons">Scenarios Where You Should Avoid Singletons</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-general-guidelines">General Guidelines</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into this tutorial, you should have:</p>
<ol>
<li><p>Basic understanding of the Dart programming language</p>
</li>
<li><p>Familiarity with Object-Oriented Programming (OOP) concepts, particularly classes and constructors</p>
</li>
<li><p>Basic knowledge of Flutter development (helpful but not required)</p>
</li>
<li><p>Understanding of static variables and methods in Dart</p>
</li>
<li><p>Familiarity with the concept of class instantiation</p>
</li>
</ol>
<h2 id="heading-what-is-the-singleton-pattern">What is the Singleton Pattern?</h2>
<p>The Singleton pattern is a creational design pattern that ensures a class has only one instance and that there is a global point of access to the instance.</p>
<p>Again, this is especially powerful when managing shared resources across an application.</p>
<h3 id="heading-when-to-use-the-singleton-pattern">When to Use the Singleton Pattern</h3>
<p>You should use a Singleton when you are designing parts of your system that must exist once, such as:</p>
<ol>
<li><p>Global app state (user session, auth token, app config)</p>
</li>
<li><p>Shared services (logger, API client, database connection)</p>
</li>
<li><p>Resource heavy logic (encryption handlers, ML models, cache manager)</p>
</li>
<li><p>Application boot security (run platform-specific root/jailbreak checks)</p>
</li>
</ol>
<p>For example, in a Flutter app, Android may check developer mode or root status, while iOS checks jailbroken device state. A Singleton security class is a perfect way to enforce that these checks run once globally during app startup.</p>
<h2 id="heading-how-to-create-a-singleton-class">How to Create a Singleton Class</h2>
<p>We have two major ways of creating a singleton class:</p>
<ol>
<li><p>Eager Instantiation</p>
</li>
<li><p>Lazy Instantiation</p>
</li>
</ol>
<h3 id="heading-eager-singleton">Eager Singleton</h3>
<p>This is where the Singleton is created at load time, whether it's used or not.</p>
<p>In this case, the instance of the singleton class as well as any initialization logic runs at load time, regardless of when this class is actually needed or used. Here's how it works:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EagerSingleton</span> </span>{
  EagerSingleton._internal();
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> EagerSingleton _instance = EagerSingleton._internal();

  <span class="hljs-keyword">static</span> EagerSingleton <span class="hljs-keyword">get</span> instance =&gt; _instance;

  <span class="hljs-keyword">void</span> sayHello() =&gt; <span class="hljs-built_in">print</span>(<span class="hljs-string">"Hello from Eager Singleton"</span>);
}

<span class="hljs-comment">//usage</span>
<span class="hljs-keyword">void</span> main() {
  <span class="hljs-comment">// Accessing the singleton globally</span>
  EagerSingleton.instance.sayHello();
}
</code></pre>
<h4 id="heading-how-the-eager-singleton-works">How the Eager Singleton Works</h4>
<p>Let's break down what's happening in this implementation:</p>
<p>First, <code>EagerSingleton._internal()</code> is a private named constructor (notice the underscore prefix). This prevents external code from creating new instances using <code>EagerSingleton()</code>. The only way to get an instance is through the controlled mechanism we're about to define.</p>
<p>Next, <code>static final EagerSingleton _instance = EagerSingleton._internal();</code> is the key line. This creates the single instance immediately when the class is first loaded into memory. Because it's <code>static final</code>, it belongs to the class itself (not any particular instance) and can only be assigned once. The instance is created right here, at declaration time.</p>
<p>The <code>static EagerSingleton get instance =&gt; _instance;</code> getter provides global access to that single instance. Whenever you call <code>EagerSingleton.instance</code> anywhere in your code, you're getting the exact same object that was created when the class loaded.</p>
<p>Finally, <code>sayHello()</code> is just a regular method to demonstrate that the singleton works. You could replace this with any business logic your singleton needs to perform.</p>
<p>When you run the code in <code>main()</code>, the class loads, the instance is created immediately, and <code>EagerSingleton.instance.sayHello()</code> accesses that pre-created instance to call the method.</p>
<h4 id="heading-pros">Pros:</h4>
<ol>
<li><p>This is simple and thread safe, meaning it's not affected by concurrency, especially when your app runs on multithreads.</p>
</li>
<li><p>It's ideal if the instance is lightweight and may be accessed frequently.</p>
</li>
</ol>
<h4 id="heading-cons">Cons:</h4>
<ol>
<li>If this instance is never used through the runtime, it results in wasted memory and could impact application performance.</li>
</ol>
<h3 id="heading-lazy-singleton">Lazy Singleton</h3>
<p>In this case, the singleton instance is only created when the class is called or needed in runtime. Here, a trigger needs to happen before the instance is created. Let's see an example:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LazySingleton</span> </span>{
  LazySingleton._internal(); 
  <span class="hljs-keyword">static</span> LazySingleton? _instance;

  <span class="hljs-keyword">static</span> LazySingleton <span class="hljs-keyword">get</span> instance {
    _instance ??= LazySingleton._internal();
    <span class="hljs-keyword">return</span> _instance!;
  }

  <span class="hljs-keyword">void</span> sayHello() =&gt; <span class="hljs-built_in">print</span>(<span class="hljs-string">"Hello from LazySingleton"</span>);
}

<span class="hljs-comment">//usage </span>
<span class="hljs-keyword">void</span> main() {
  <span class="hljs-comment">// Accessing the singleton globally</span>
  LazySingleton.instance.sayHello();
}
</code></pre>
<h4 id="heading-how-the-lazy-singleton-works">How the Lazy Singleton Works</h4>
<p>The lazy implementation differs from eager in one crucial way: timing.</p>
<p>Again, <code>LazySingleton._internal()</code> is a private constructor that prevents external instantiation.</p>
<p>But notice that <code>static LazySingleton? _instance;</code> is declared as nullable and not initialized. Unlike the eager version, no instance is created at load time. The variable simply exists as <code>null</code> until it's needed.</p>
<p>The magic happens in the getter: <code>_instance ??= LazySingleton._internal();</code> uses Dart's null-aware assignment operator. This line says "if <code>_instance</code> is null, create a new instance and assign it. Otherwise, keep the existing one." This is the lazy initialization: the instance is only created the first time someone accesses it.</p>
<p>The first time you call <code>LazySingleton.instance</code>, <code>_instance</code> is null, so a new instance is created. Every subsequent call finds that <code>_instance</code> already exists, so it just returns that same instance.</p>
<p>The <code>return _instance!;</code> uses the null assertion operator because we know <code>_instance</code> will never be null at this point (we just ensured it's not null in the previous line).</p>
<p>This approach saves memory because if you never call <code>LazySingleton.instance</code> in your app, the instance never gets created.</p>
<h4 id="heading-pros-1">Pros:</h4>
<ol>
<li><p>Saves application memory, as it only creates what is needed in runtime.</p>
</li>
<li><p>Avoids memory leaks.</p>
</li>
<li><p>Is ideal for resource heavy objects while considering application performance.</p>
</li>
</ol>
<h4 id="heading-cons-1">Cons:</h4>
<ol>
<li>Could be difficult to manage in multithreaded environments, as you have to ensure thread safety while following this pattern.</li>
</ol>
<h3 id="heading-choosing-between-eager-and-lazy">Choosing Between Eager and Lazy</h3>
<p>Now that we've broken down these two major types of singleton instantiation, it's worthy of note that you'll need to be intentional while deciding whether to create a singleton the eager or lazy way. Your use case/context should help you determine what singleton pattern you need to apply during object creation.</p>
<p>As an engineer, you need to ask yourself these questions when using a singleton for object creation:</p>
<ol>
<li><p>Do I need this class instantiated when the app loads?</p>
</li>
<li><p>Based on the user journey, will this class always be needed during every session?</p>
</li>
<li><p>Can a user journey be completed without needing to call any logic in this class?</p>
</li>
</ol>
<p>These three questions will determine what pattern (eager or lazy) you should use to fulfill best practices while maintaining scalability and high performance in your application.</p>
<h2 id="heading-factory-constructors-in-the-singleton-pattern">Factory Constructors in the Singleton Pattern</h2>
<p>Applying factory constructors in the Singleton pattern can be powerful if you use them properly. But first, let's understand what factory constructors are.</p>
<h3 id="heading-what-are-factory-constructors">What Are Factory Constructors?</h3>
<p>A factory constructor in Dart is a special type of constructor that doesn't always create a new instance of its class. Unlike regular constructors that must return a new instance, factory constructors can:</p>
<ol>
<li><p>Return an existing instance (perfect for singletons)</p>
</li>
<li><p>Return a subclass instance</p>
</li>
<li><p>Apply logic before deciding what to return</p>
</li>
<li><p>Perform validation or initialization before returning an object</p>
</li>
</ol>
<p>The <code>factory</code> keyword tells Dart that this constructor has the flexibility to return any instance of the class (or its subtypes), not necessarily a fresh one.</p>
<h3 id="heading-implementing-singleton-with-factory-constructor">Implementing Singleton with Factory Constructor</h3>
<p>This allows you to apply initialization logic while your class instance is being created before returning the instance.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FactoryLazySingleton</span> </span>{
  FactoryLazySingleton._internal();
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> FactoryLazySingleton _instance = FactoryLazySingleton._internal();

  <span class="hljs-keyword">static</span> FactoryLazySingleton <span class="hljs-keyword">get</span> instance =&gt; _instance;

  <span class="hljs-keyword">factory</span> FactoryLazySingleton() {
    <span class="hljs-comment">// Your logic runs here</span>
    <span class="hljs-built_in">print</span>(<span class="hljs-string">"Factory constructor called"</span>);
    <span class="hljs-keyword">return</span> _instance;
  }
}
</code></pre>
<h4 id="heading-how-the-factory-constructor-singleton-works">How the Factory Constructor Singleton Works</h4>
<p>This implementation combines aspects of both eager and lazy patterns with additional control.</p>
<p>The <code>FactoryLazySingleton._internal()</code> private constructor and <code>static final _instance</code> create an eager singleton. The instance is created immediately when the class loads.</p>
<p>The <code>static get instance</code> provides the traditional singleton access pattern we've seen before.</p>
<p>But the interesting part is the <code>factory FactoryLazySingleton()</code> constructor. This is a public constructor that looks like a normal constructor call, but behaves differently. When you call <code>FactoryLazySingleton()</code>, instead of creating a new instance, it runs whatever logic you've placed inside (in this case, a print statement), then returns the existing <code>_instance</code>.</p>
<p>This pattern is powerful because:</p>
<ol>
<li><p>You can log when someone tries to create an instance</p>
</li>
<li><p>You can validate conditions before returning the instance</p>
</li>
<li><p>You can apply configuration based on parameters passed to the factory</p>
</li>
<li><p>You can choose to return different singleton instances based on conditions</p>
</li>
</ol>
<p>For example, you might have different configuration singletons for development vs production:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">factory</span> FactoryLazySingleton({<span class="hljs-built_in">bool</span> isProduction = <span class="hljs-keyword">false</span>}) {
  <span class="hljs-keyword">if</span> (isProduction) {
    <span class="hljs-comment">// Apply production configuration</span>
    _instance.configure(productionSettings);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Apply development configuration</span>
    _instance.configure(devSettings);
  }
  <span class="hljs-keyword">return</span> _instance;
}
</code></pre>
<h4 id="heading-pros-2">Pros</h4>
<ol>
<li><p>You can add logic before returning an instance</p>
</li>
<li><p>You can cache or reuse the same object</p>
</li>
<li><p>You can dynamically return a subtype if needed</p>
</li>
<li><p>You avoid unnecessary instantiation</p>
</li>
<li><p>You can inject configuration or environment logic</p>
</li>
</ol>
<h4 id="heading-cons-2">Cons</h4>
<ol>
<li><p>Adds slight complexity compared to simple getter access</p>
</li>
<li><p>The factory constructor syntax might confuse developers unfamiliar with the pattern</p>
</li>
<li><p>If overused with complex logic, it can make debugging harder</p>
</li>
<li><p>Can create misleading code where <code>FactoryLazySingleton()</code> looks like it creates a new instance but doesn't</p>
</li>
</ol>
<h2 id="heading-when-not-to-use-a-singleton">When Not to Use a Singleton</h2>
<p>While singletons are powerful, they're not always the right solution. Understanding when to avoid them is just as important as knowing when to use them.</p>
<h3 id="heading-why-singletons-can-be-problematic">Why Singletons Can Be Problematic</h3>
<p>Singletons create global state, which can make your application harder to reason about and test. They introduce tight coupling between components that shouldn't necessarily know about each other, and they can make it difficult to isolate components for unit testing.</p>
<h3 id="heading-scenarios-where-you-should-avoid-singletons">Scenarios Where You Should Avoid Singletons</h3>
<p>Avoid using the Singleton pattern if:</p>
<h4 id="heading-you-need-multiple-independent-instances">You need multiple independent instances</h4>
<p>If different parts of your app need their own separate configurations or states, singletons force you into a one-size-fits-all approach.</p>
<p>For example, if you're building a multi-tenant application where each tenant needs isolated data, a singleton would cause data to bleed between tenants.</p>
<p><strong>Alternative</strong>: Use dependency injection to pass different instances to different parts of your app. Each component receives the specific instance it needs through its constructor or a service locator.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Instead of singleton</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRepository</span> </span>{
  <span class="hljs-keyword">final</span> DatabaseConnection db;
  UserRepository(<span class="hljs-keyword">this</span>.db); 
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">final</span> dbForTenantA = DatabaseConnection(tenantId: <span class="hljs-string">'A'</span>);
<span class="hljs-keyword">final</span> dbForTenantB = DatabaseConnection(tenantId: <span class="hljs-string">'B'</span>);
<span class="hljs-keyword">final</span> repoA = UserRepository(dbForTenantA);
<span class="hljs-keyword">final</span> repoB = UserRepository(dbForTenantB);
</code></pre>
<h4 id="heading-your-architecture-avoids-shared-global-state">Your architecture avoids shared global state</h4>
<p>Modern architectural patterns like BLoC, Provider, or Riverpod in Flutter specifically aim to avoid global mutable state. Singletons work against these patterns by reintroducing global state.</p>
<p><strong>Alternative</strong>: Use state management solutions designed for Flutter. Provider, Riverpod, BLoC, or GetX offer better ways to share data across your app while maintaining testability and avoiding tight coupling.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Using Provider instead of singleton</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppConfig</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> apiUrl;
  AppConfig(<span class="hljs-keyword">this</span>.apiUrl);
}

<span class="hljs-comment">// Provide it at the top level</span>
<span class="hljs-keyword">void</span> main() {
  runApp(
    Provider&lt;AppConfig&gt;(
      create: (_) =&gt; AppConfig(<span class="hljs-string">'https://api.example.com'</span>),
      child: MyApp(),
    ),
  );
}

<span class="hljs-comment">// Access it anywhere in the widget tree</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyWidget</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">final</span> config = Provider.of&lt;AppConfig&gt;(context);

  }
}
</code></pre>
<h4 id="heading-it-forces-tight-coupling-between-unrelated-classes">It forces tight coupling between unrelated classes</h4>
<p>When multiple unrelated classes depend on the same singleton, they become indirectly coupled. Changes to the singleton affect all these classes, making the codebase fragile and hard to refactor.</p>
<p><strong>Alternative</strong>: Use interfaces and dependency injection. Define what behavior you need through an interface, then inject implementations. This way, classes depend on abstractions, not concrete singletons.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Define an interface</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Logger</span> </span>{
  <span class="hljs-keyword">void</span> log(<span class="hljs-built_in">String</span> message);
}

<span class="hljs-comment">// Implementation</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConsoleLogger</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Logger</span> </span>{
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> log(<span class="hljs-built_in">String</span> message) =&gt; <span class="hljs-built_in">print</span>(message);
}

<span class="hljs-comment">// Classes depend on the interface, not a singleton</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PaymentService</span> </span>{
  <span class="hljs-keyword">final</span> Logger logger;
  PaymentService(<span class="hljs-keyword">this</span>.logger);

  <span class="hljs-keyword">void</span> processPayment() {
    logger.log(<span class="hljs-string">'Processing payment'</span>);
  }
}

<span class="hljs-comment">// Easy to test with mock</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MockLogger</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Logger</span> </span>{
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">String</span>&gt; logs = [];
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> log(<span class="hljs-built_in">String</span> message) =&gt; logs.add(message);
}
</code></pre>
<h4 id="heading-you-need-clean-isolated-testing">You need clean, isolated testing</h4>
<p>Singletons maintain state between tests, causing test pollution where one test affects another. This makes tests unreliable and order-dependent.</p>
<p><strong>Alternative</strong>: Use dependency injection and create fresh instances for each test. Most testing frameworks support this pattern, allowing you to inject mocks or fakes easily.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Testable code</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderService</span> </span>{
  <span class="hljs-keyword">final</span> PaymentProcessor processor;
  OrderService(<span class="hljs-keyword">this</span>.processor);
}

<span class="hljs-comment">// In tests</span>
<span class="hljs-keyword">void</span> main() {
  test(<span class="hljs-string">'processes order successfully'</span>, () {
    <span class="hljs-keyword">final</span> mockProcessor = MockPaymentProcessor();
    <span class="hljs-keyword">final</span> service = OrderService(mockProcessor); 

  });
}
</code></pre>
<h3 id="heading-general-guidelines">General Guidelines</h3>
<p>Use singletons sparingly and only when you truly need exactly one instance of something for the entire application lifecycle. Good candidates include logging systems, application-level configuration, and hardware interface managers.</p>
<p>For most other cases, prefer dependency injection, state management solutions, or simply passing instances where needed. These approaches make your code more flexible, testable, and maintainable.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The Singleton pattern is a powerful creational tool, but like every tool, you should use it strategically.</p>
<p>Overusing singletons can make apps tightly coupled, hard to test, and less maintainable.</p>
<p>But when used correctly, the Singleton pattern helps you save memory, enforce consistency, and control object lifecycle beautifully.</p>
<p>The key is understanding your specific use case and choosing the right implementation approach – whether eager, lazy, or factory-based – that best serves your application's needs while maintaining clean, testable code.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Google Play’s 16 KB Page Size Compatibility Requirement — What You Should Know, and How to Upgrade Your App ]]>
                </title>
                <description>
                    <![CDATA[ Android is always evolving, and sometimes those changes happen a bit under the hood. One such change that's been gaining traction—and now has a firm deadline from Google—is the move to a 16 KB page size. If you're an Android developer, especially wit... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/google-16-kb-page-size-requirement-what-to-do/</link>
                <guid isPermaLink="false">68d703052043890036a92cb0</guid>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ android app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Fri, 26 Sep 2025 21:17:57 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758921064544/80db1a03-73e1-48c3-b2a0-566f20244431.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Android is always evolving, and sometimes those changes happen a bit under the hood. One such change that's been gaining traction—and now has a firm deadline from Google—is the move to a 16 KB page size. If you're an Android developer, especially with native code in your app, understanding this shift is really important for keeping your apps smooth and compatible.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-page-size">What is a Page Size?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-is-this-change-being-implemented-now">Why is this Change Being Implemented Now?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-the-pros-and-cons-of-this-change">What are the Pros and Cons of this Change?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-should-you-worry-about-this-change">Should You worry About this Change?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-is-this-mandatory">Is this Mandatory?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-if-you-dont-upgrade-your-app">What if You Don’t Upgrade Your App?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-does-this-affect-hybrid-apps">How Does this Affect Hybrid Apps?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-would-be-the-code-change-for-this">What Would be the Code Change for This?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-verify-if-your-app-is-upgraded-to-a-16-kb-page-size">How to Verify if Your App is Upgraded to a 16 KB Page Size</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-page-size">What is a Page Size?</h2>
<p>Think of your device's memory like a book. An operating system doesn't read memory one tiny word at a time; it reads in chunks. These chunks are called "pages." For a long time, on most ARM64 Android devices, these pages were 4 KB in size. Now, for some newer Android devices (specifically those launching with Android 13 and later), that page size has quadrupled to 16 KB.</p>
<h2 id="heading-why-is-this-change-being-implemented-now">Why is this Change Being Implemented Now?</h2>
<p>It's all about making Android run better on modern hardware. Here are some of the reasons why is it being implemented:</p>
<p><strong>Better Performance:</strong> Modern processors can handle larger memory chunks more efficiently. A 16 KB page size means the CPU spends less time managing tiny bits of memory and more time doing actual work, which can lead to faster app performance.</p>
<p><strong>Smoother Operations:</strong> With fewer, larger pages to keep track of, the system itself has a little less overhead, making things a bit more streamlined.</p>
<p><strong>Keeping Up with Tech:</strong> This change helps Android align with how newer ARM64 processors are designed to work best.</p>
<h2 id="heading-what-are-the-pros-and-cons-of-this-change">What are the Pros and Cons of this Change?</h2>
<p>Every big change has its own pros and cons.</p>
<h3 id="heading-pros">Pros</h3>
<ul>
<li><p>Apps that move a lot of data around or are memory-intensive might just feel a bit snappier</p>
</li>
<li><p>The system could run a bit more efficiently, benefiting all apps indirectly</p>
</li>
</ul>
<h3 id="heading-cons">Cons</h3>
<ul>
<li><p>If your native code is constantly asking for very small bits of memory (less than 16 KB), each of those might now take up a full 16 KB page, potentially using a little more memory than before.</p>
</li>
<li><p>If your native code makes assumptions that "memory pages are always 4 KB," it could run into issues on 16 KB page devices.</p>
</li>
</ul>
<h2 id="heading-should-you-worry-about-this-change">Should You worry About this Change?</h2>
<p>You need to pay attention if:</p>
<ul>
<li><p>Your app includes native libraries (like <code>.so</code> files) written in C/C++. This is where the impact is most direct. If your native code does anything with memory mapping (mmap, shmem) or file I/O where it calculates offsets or sizes based on a fixed page size.</p>
</li>
<li><p>You're developing games or other highly performance-sensitive apps with native components.</p>
</li>
<li><p>You're targeting Android 15+ with your app updates.</p>
</li>
</ul>
<p>You need not worry if:</p>
<ul>
<li><p>Your app is built purely in Java or Kotlin with no native components. The Android Runtime (ART) handles memory for you, so these underlying page size changes are largely invisible. You'll still get the performance benefits!</p>
</li>
<li><p>You're using React Native or Flutter, unless you've added custom native modules that directly deal with memory mapping or page-size-dependent operations</p>
</li>
</ul>
<h2 id="heading-is-this-mandatory">Is this Mandatory?</h2>
<p>Yes. Google Play is making this a requirement for app updates. You would have received an email from Google Play if your app does not support 16 KB page size yet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758343797173/da2aff04-d5ae-4964-9d72-02f21b4a0d96.png" alt="Your app is affected by Google Play's 16KB page size requirements" class="image--center mx-auto" width="1472" height="704" loading="lazy"></p>
<p>As the screenshot clearly shows, "From Nov 1, 2025, if your app updates do not support 16 KB memory page sizes, you won't be able to release these updates" for apps targeting Android 15+. This gives us a solid timeframe to get things ready.</p>
<h2 id="heading-what-if-you-dont-upgrade-your-app">What if You Don’t Upgrade Your App?</h2>
<p>You could notice some serious issues if your app has native libraries that aren't ready for the 16 KB page size by the deadline. Here are a few:</p>
<ul>
<li><p><strong>Crashes:</strong> This is the most serious. Your app might crash unexpectedly (often with a "segmentation fault") if it tries to access memory incorrectly due to old page size assumptions.</p>
</li>
<li><p><strong>Wasted Memory:</strong> If your code allocates memory in smaller chunks than 16 KB, it could end up using more memory than necessary, potentially slowing things down or hitting memory limits.</p>
</li>
<li><p><strong>Performance Hit:</strong> Instead of gaining speed, your app might actually run slower if its memory operations aren't aligned with the larger page size.</p>
</li>
</ul>
<p>Essentially, your app might work fine today, but become unstable or inefficient on newer Android devices if its native components aren't updated.</p>
<h2 id="heading-how-does-this-affect-hybrid-apps">How Does this Affect Hybrid Apps?</h2>
<p>Generally, if you're building a standard hybrid app (React Native or Flutter app) without custom native modules, you're in a pretty good spot. The frameworks themselves, and the underlying runtimes (JavaScript engine for React Native, Dart VM for Flutter), usually handle memory management, abstracting away the page size.</p>
<p>However, if you've implemented custom native modules in C++ for performance-critical tasks or specific hardware interactions, then you do need to check those modules.</p>
<p>For the vast majority of standard React Native and Flutter apps, you likely won't need direct code changes related to page size, but always ensure you're using the latest SDK versions for your framework to benefit from any underlying platform updates.</p>
<h2 id="heading-what-would-be-the-code-change-for-this">What Would be the Code Change for This?</h2>
<p>The biggest thing to avoid in your native code is making assumptions about memory page sizes. Instead of hardcoding 4096 (for 4 KB), always ask the operating system what its current page size is.</p>
<h3 id="heading-steps-to-take"><strong>Steps to Take:</strong></h3>
<ol>
<li><p><strong>Audit Your Native Code:</strong> Search your <code>.cpp</code>, <code>.c</code>, and <code>.h</code> files for any direct use of 4096 or 4 KB in memory allocation, buffer sizing, or alignment calculations</p>
</li>
<li><p><strong>Replace with</strong> <code>sysconf(_SC_PAGESIZE)</code> <strong>or</strong> <code>getpagesize()</code><strong>:</strong> Update any fixed values to dynamically retrieve the actual page size.</p>
</li>
<li><p><strong>Recompile with Latest NDK:</strong> Make sure you're building your native libraries with a recent Android NDK (r25 or newer is a good target). This ensures your toolchain is aware of the 16 KB page size and provides correct system definitions.</p>
</li>
</ol>
<h2 id="heading-how-to-verify-if-your-app-is-upgraded-to-a-16-kb-page-size">How to Verify if Your App is Upgraded to a 16 KB Page Size</h2>
<p>You can verify if your app is upgraded by running extensive testing. However, here are the few more steps.</p>
<ol>
<li><p><strong>Check Your Test Device's Page Size:</strong></p>
<ul>
<li><p>Connect your Android 13+ test device (preferably a newer one like a Pixel) via ADB</p>
</li>
<li><p>Run <code>adb shell getconf PAGE_SIZE</code></p>
</li>
<li><p>If it returns 16384, you're testing on a 16 KB page device! If it returns 4096, you'll need to find a different device to properly test for this change</p>
</li>
<li><p>Here’s an example screenshot from my device</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758368982307/f5696dab-f23a-4731-95b4-0372159d2107.png" alt="Find page size of an Android device/emulator" class="image--center mx-auto" width="1167" height="281" loading="lazy"></p>
</li>
</ul>
</li>
<li><p><strong>Run Your App Extensively:</strong> Once you have a 16 KB page device, put your app through its paces. Try all features, especially those involving native code, heavy data loading, or complex operations.</p>
</li>
<li><p><strong>Monitor for Crashes:</strong> Keep a close eye on your crash reporting tools (like Crashlytics). Specifically look for native crashes (<code>SIGSEGV</code>, <code>SIGBUS</code>) coming from Android 13+ devices, as these could be related to page size issues.</p>
</li>
<li><p><strong>Memory Profiling:</strong> While less direct, if you suspect memory inefficiency in your native code, use Android Studio's Memory Profiler to see if allocations are unexpectedly large or if there's excessive memory usage.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this blog, we learnt about page size in Android, and why and how to upgrade your app to support 16 KB page size. I hope you have a clear idea about 16 KB page size in Android. By being proactive now, you can avoid last-minute scrambling and ensure your apps continue to perform beautifully on the latest Android devices, well past the November 2025 deadline!</p>
<p>You can follow my <a target="_blank" href="https://x.com/AI_Techie_Arun">Twitter/X account</a> to receive the top AI news everyday. If you wish to learn more about mobile app development, subscribe to my email newsletter (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_android_16kb_page_size">https://5minslearn.gogosoon.com/</a>) and follow me on social media.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Address Common Accessibility Challenges in iOS Mobile Apps Using SwiftUI ]]>
                </title>
                <description>
                    <![CDATA[ Mobile apps are essential tools in daily life, making accessibility a top priority. However, many apps still do not provide inclusive experiences for people with disabilities. This article highlights nine common accessibility challenges in mobile app... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-address-ios-accessibility-challenges-using-swiftui/</link>
                <guid isPermaLink="false">673dc0d9ed2a01b66ee9f37c</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SwiftUI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Namaswi Chandarana ]]>
                </dc:creator>
                <pubDate>Wed, 20 Nov 2024 10:58:33 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9e9PD9blAto/upload/43ed1bb84a1c0abad81192c63e920503.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Mobile apps are essential tools in daily life, making accessibility a top priority. However, many apps still do not provide inclusive experiences for people with disabilities.</p>
<p>This article highlights nine common accessibility challenges in mobile apps and demonstrates how SwiftUI features can help developers address these issues effectively.</p>
<p>Each challenge is paired with a SwiftUI solution, sample code, and testing tips to guide developers in creating accessible and user-friendly apps.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-mobile-apps-accessibility-issues-and-swiftui-solutions">Mobile Apps Accessibility Issues and SwiftUI Solutions</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-missing-labels-and-descriptions">Missing Labels and Descriptions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-insufficient-color-contrast">Insufficient Color Contrast</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-small-touch-targets">Small Touch Targets</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-inaccessible-navigation">Inaccessible Navigation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lack-of-feedback-for-actions">Lack of Feedback for Actions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-complex-or-confusing-user-interfaces">Complex or Confusing User Interfaces</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lack-of-support-for-assistive-technologies">Lack of Support for Assistive Technologies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-poorly-implemented-accessibility-features">Poorly Implemented Accessibility Features</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-insufficient-customization-options">Insufficient Customization Options</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-references">References</a></p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-mobile-apps-accessibility-issues-and-swiftui-solutions">Mobile Apps Accessibility Issues and SwiftUI Solutions</h2>
<h3 id="heading-missing-labels-and-descriptions">Missing Labels and Descriptions</h3>
<ul>
<li><p><strong>Challenge</strong>: Many apps lack appropriate labels or descriptions for buttons, images, and other interactive elements, making it difficult for screen readers to communicate their purpose to visually impaired users. Without these labels, users might struggle to understand the app’s functionality.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: SwiftUI’s <code>.accessibilityLabel(_:)</code> modifier allows developers to assign clear, descriptive labels to interactive elements. These labels improve navigation and understanding by giving screen readers the necessary context.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Label</span>(<span class="hljs-string">"Shop"</span>, systemImage: <span class="hljs-string">"cart"</span>)
      .accessibilityLabel(<span class="hljs-string">"Go to Shop"</span>)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Enable VoiceOver on an iOS device, navigate through the app, and ensure each element has an accurate label. VoiceOver should read labels clearly to help users understand each element’s purpose without needing additional explanation.</p>
</li>
</ul>
<h3 id="heading-insufficient-color-contrast">Insufficient Color Contrast</h3>
<ul>
<li><p><strong>Challenge</strong>: Low contrast between text and background colors can make it difficult for users with visual impairments to read the content, especially for those with color vision deficiencies or low vision.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Use SwiftUI’s dynamic system colors (<code>.primary</code> and <code>.secondary</code>), which automatically adapt to the light or dark mode setting on the device, ensuring good readability.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Text</span>(<span class="hljs-string">"Shop"</span>)
      .foregroundColor(.primary)  <span class="hljs-comment">// Adapts to light or dark mode automatically</span>
</code></pre>
</li>
<li><p>If custom colors are necessary, test them against WCAG standards for color contrast, using tools like Color Contrast Analyzer.</p>
</li>
<li><p><strong>Testing</strong>: Use Xcode’s Accessibility Inspector to verify contrast, and ensure that text remains readable in both light and dark modes. WCAG guidelines recommend a minimum contrast ratio of 4.5:1 for normal text.</p>
</li>
</ul>
<h3 id="heading-small-touch-targets">Small Touch Targets</h3>
<ul>
<li><p><strong>Challenge</strong>: Small buttons or other touch areas can be difficult for users with motor impairments to interact with accurately. Elements that are too small may require more precision than some users can provide.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Set minimum touch sizes by adding padding or using <code>.frame(minWidth:minHeight:)</code> to ensure a comfortable touch target size.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Button</span>(action: { <span class="hljs-comment">/* Action */</span> }) {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Tap Me"</span>)
          .frame(minWidth: <span class="hljs-number">44</span>, minHeight: <span class="hljs-number">44</span>)
  }.padding()
</code></pre>
</li>
<li><p><strong>Testing</strong>: Manually interact with touch elements in the app on an iOS device. Ensure they are easily tappable without precise effort. Verify touch target size with the Accessibility Inspector to confirm they meet recommended minimums (44x44 points).</p>
</li>
</ul>
<h3 id="heading-inaccessible-navigation">Inaccessible Navigation</h3>
<ul>
<li><p><strong>Challenge</strong>: Apps with limited navigability can cause frustration for users who rely on screen readers or keyboards. Without a clear reading order, navigating through the interface becomes challenging.</p>
</li>
<li><p><strong>SwiftUI Techniques for Accessible Navigation</strong>:</p>
<ul>
<li><p><strong>Group Elements</strong> with <code>.accessibilityElement(children:)</code>: Combine related elements into a single accessible unit for more streamlined navigation.</p>
<pre><code class="lang-swift">  <span class="hljs-type">VStack</span> {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Profile"</span>)
      <span class="hljs-type">Image</span>(<span class="hljs-string">"profile_picture"</span>)
  }
  .accessibilityElement(children: .combine)
</code></pre>
</li>
<li><p><strong>Set Focus</strong> with <code>.accessibilityFocused</code>: Programmatically control focus on specific elements.</p>
<pre><code class="lang-swift">  <span class="hljs-type">Text</span>(<span class="hljs-string">"Special Announcement"</span>)
      .accessibilityFocused($isFocused)
</code></pre>
</li>
<li><p><strong>Custom Actions</strong> with <code>.accessibilityAction</code>: Add specific actions for interactive controls like sliders or steppers.</p>
<pre><code class="lang-swift">  <span class="hljs-type">Slider</span>(value: $value)
      .accessibilityAction(named: <span class="hljs-string">"Increase"</span>) { value += <span class="hljs-number">10</span> }
</code></pre>
</li>
<li><p><strong>Hide Decorative Elements</strong> with <code>.accessibilityHidden</code>: Exclude non-essential visuals from screen readers.</p>
<pre><code class="lang-swift">  <span class="hljs-type">Image</span>(<span class="hljs-string">"decorative_image"</span>)
      .accessibilityHidden(<span class="hljs-literal">true</span>)
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Testing</strong>: Enable VoiceOver and use swipe gestures to confirm the intended focus order. Also, use a connected keyboard or switch control to test smooth transitions and confirm navigability.</p>
</li>
</ul>
<h3 id="heading-lack-of-feedback-for-actions">Lack of Feedback for Actions</h3>
<ul>
<li><p><strong>Challenge</strong>: Without feedback, users with visual or hearing impairments may struggle to confirm if an action has completed. Feedback like haptic, auditory, or visual cues can enhance usability.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Use <code>.accessibilityHint</code> to provide additional information about the action that will occur.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Button</span>(<span class="hljs-string">"Submit"</span>) {
      <span class="hljs-comment">// Submit action</span>
  }.accessibilityHint(<span class="hljs-string">"Submits the form"</span>)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Use VoiceOver to ensure that hints are read immediately after labels. Check that users can understand what each button does without extra explanation.</p>
</li>
</ul>
<h3 id="heading-complex-or-confusing-user-interfaces">Complex or Confusing User Interfaces</h3>
<ul>
<li><p><strong>Challenge</strong>: Cluttered interfaces can be overwhelming, particularly for users with cognitive impairments, who may struggle to navigate or process information effectively.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Simplify layouts and use <code>.accessibilitySortPriority</code> to organize the reading order logically.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">VStack</span> {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Main Content"</span>)
          .accessibilitySortPriority(<span class="hljs-number">1</span>)
      <span class="hljs-type">Button</span>(<span class="hljs-string">"Secondary Action"</span>)
          .accessibilitySortPriority(<span class="hljs-number">2</span>)
  }
</code></pre>
</li>
<li><p><strong>Testing</strong>: Use VoiceOver to verify the logical reading order and ensure only relevant elements are accessible. Use <code>.accessibilityHidden</code> to hide decorative elements that do not add meaningful information.</p>
</li>
</ul>
<h3 id="heading-lack-of-support-for-assistive-technologies">Lack of Support for Assistive Technologies</h3>
<ul>
<li><p><strong>Challenge</strong>: Inadequate support for screen readers or other assistive technologies can make apps unusable for some users.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Group elements with <code>.accessibilityElement(children: .combine)</code> for cohesive navigation. This improves readability and usability for screen reader users.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">VStack</span> {
      <span class="hljs-type">Text</span>(<span class="hljs-string">"Profile"</span>)
      <span class="hljs-type">Image</span>(<span class="hljs-string">"profile_picture"</span>)
  }
  .accessibilityElement(children: .combine)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Check with VoiceOver that grouped elements are announced as a single unit, improving navigation flow for visually impaired users.</p>
</li>
</ul>
<h3 id="heading-poorly-implemented-accessibility-features">Poorly Implemented Accessibility Features</h3>
<ul>
<li><p><strong>Challenge</strong>: Without regular testing and updates, accessibility features can degrade over time, negatively impacting the user experience.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Regular testing with VoiceOver and Xcode’s Accessibility Inspector helps maintain effective functionality.</p>
</li>
<li><p><strong>Testing</strong>: Conduct regular testing to detect regressions or improvements needed for accessibility. Recheck VoiceOver usability after UI updates to confirm features remain effective.</p>
</li>
</ul>
<h3 id="heading-insufficient-customization-options">Insufficient Customization Options</h3>
<ul>
<li><p><strong>Challenge</strong>: Limited customization options, such as font size or color schemes, restrict usability for users with specific visual needs.</p>
</li>
<li><p><strong>SwiftUI Solution</strong>: Use <code>.dynamicTypeSize()</code> to allow text scaling based on the user’s preferred settings.</p>
</li>
<li><p><strong>Example</strong>:</p>
<pre><code class="lang-swift">  <span class="hljs-type">Text</span>(<span class="hljs-string">"Adjustable Text"</span>)
      .dynamicTypeSize(.xxxLarge)
</code></pre>
</li>
<li><p><strong>Testing</strong>: Adjust text size in iOS Accessibility settings, and ensure the app’s text scales correctly without truncating or overlapping, preserving readability.</p>
</li>
</ul>
<h3 id="heading-references">References</h3>
<ol>
<li><p><strong>Apple Developer Documentation: SwiftUI Accessibility</strong></p>
<ul>
<li><p>Comprehensive guide to accessibility in SwiftUI, covering accessibility properties like <code>.accessibilityLabel</code>, <code>.accessibilityHint</code>, <code>.accessibilityElement</code>, and more.</p>
</li>
<li><p><a target="_blank" href="https://developer.apple.com/documentation/swiftui/accessibility">SwiftUI Accessibility Guide</a></p>
</li>
</ul>
</li>
<li><p><strong>Apple Human Interface Guidelines: Accessibility</strong></p>
<ul>
<li><p>Apple's best practices for designing accessible apps, including color contrast and touch target size recommendations.</p>
</li>
<li><p><a target="_blank" href="https://developer.apple.com/design/human-interface-guidelines/accessibility/overview/">Apple Human Interface Guidelines: Accessibility</a></p>
</li>
</ul>
</li>
<li><p><strong>Color Contrast Analyzer</strong></p>
<ul>
<li><p>A tool for testing contrast ratios to ensure color accessibility compliance with WCAG standards.</p>
</li>
<li><p>Color Contrast Analyzer</p>
</li>
</ul>
</li>
<li><p><strong>VoiceOver and Accessibility Inspector</strong></p>
<ul>
<li><p>Tools for testing accessibility features, available in iOS and Xcode for simulating screen reader usage and checking accessibility properties.</p>
</li>
<li><p><a target="_blank" href="https://support.apple.com/guide/voiceover/welcome/mac">VoiceOver Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://developer.apple.com/documentation/accessibility-testing/accessibility-inspector">Accessibility Inspector Documentation</a></p>
</li>
</ul>
</li>
<li><p><strong>Chandarana, N., &amp; Gada, T. (2024). Accessibility Challenges in Current Mobile Applications: A Comprehensive Overview.</strong></p>
<ul>
<li><p>This journal paper provides an in-depth analysis of common accessibility challenges faced in mobile applications, discussing real-world examples and potential solutions for developers.</p>
</li>
<li><p><em>International Journal of Innovative Research in Computer and Communication Engineering.</em></p>
</li>
</ul>
</li>
</ol>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Migrate a Flutter Application from GetIt to Bloc ]]>
                </title>
                <description>
                    <![CDATA[ When I first built an application using Flutter, I quickly ran into situations where I needed to pass state from widget to widget. These widgets weren’t directly related and all I knew back then was that there were only Stateless widgets or Stateful ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/migrate-a-flutter-application-from-getit-to-bloc/</link>
                <guid isPermaLink="false">66ba502f43a51af2a76f756e</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tomer ]]>
                </dc:creator>
                <pubDate>Fri, 19 Jul 2024 23:05:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/ryan-quintal-US9Tc9pKNBU-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When I first built an <a target="_blank" href="https://play.google.com/store/apps/details?id=com.tomerpacific.birthday_calendar&amp;hl=en">application</a> using Flutter, I quickly ran into situations where I needed to pass state from widget to widget. These widgets weren’t directly related and all I knew back then was that there were only Stateless widgets or Stateful ones.</p>
<p>I found it hard to understand how I could achieve letting a completely unrelated widget know about something that happens in another widget inside my application. </p>
<p>Take, for example, a feature I wanted to implement that would allow the user to choose the theme of the application (light/dark). Since I had a settings screen with this feature, I wondered how I could let the rest of the application know that the theme has changed and react to it.</p>
<p>Searching online for guidance, I noticed there was no shortage of solutions being offered. Each with it’s own degree of complexity. <strong>Bloc</strong> was a popular choice plenty of people online suggested, but in the same breath, it was said that the learning curve is quite steep. Wanting to deliver features to the application quicker, I chose to use <a target="_blank" href="https://pub.dev/packages/get_it">GetIt</a>.</p>
<p>Why did I choose GetIt? I think the package’s creator(s) pretty much sum it up best <a target="_blank" href="https://pub.dev/packages/get_it#why-getit">in their own words</a>:</p>
<blockquote>
<p><em>GetIt is:</em><br><em>- Extremely fast (O(1))</em><br><em>- Easy to learn/use</em><br><em>- Doesn’t clutter your UI tree with special Widgets to access your data like Provider or Redux does.</em></p>
</blockquote>
<p>It is mentioned that GetIt is not a state management solution, but rather a tool to help you access objects inside your application.</p>
<p>So I headed off in the direction of using GetIt with a combination of Provider and ChangeNotifier in my application. While it wasn’t pretty, it got the job done.</p>
<p>During the development of features for my application and making it more robust, I knew in the back of my head that I wasn’t using the correct tools to manage state properly in my application.</p>
<p>Recently, I decided that it was time to learn Bloc properly and to convert the code inside my application to use it. I knew that it wasn’t going to be an easy task, but after going through it, I can admit that after a few trail and error attempts, it got easier to handle. With each use case I encountered, my understanding grew.</p>
<p>In this article, I’ll present some actual use cases where I used GetIt in combination with Provider and ChangeNotifier and replaced them with Bloc. Hopefully you can use these examples to better understand how to use Bloc in your applications.</p>
<h2 id="heading-managing-the-darklight-theme">Managing the Dark/Light Theme</h2>
<p>I wanted my application to support different themes. To do that, I created a Settings screen where the user could control the theme color.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/1-1.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Settings Screen</em></p>
<p>Developing this was the first time I had to deal with changes in the application’s state that would be reflected in widgets that weren't directly related. So, besides creating a widget for the Settings screen,</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SettingsScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
              appBar: AppBar(
                title: <span class="hljs-keyword">new</span> Text(<span class="hljs-string">"Settings"</span>),
              ),
              body:
                  Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        Consumer&lt;SettingsScreenManager&gt;(
                            builder: (context, notifier, child) {
                              <span class="hljs-keyword">return</span>  SwitchListTile(
                                  title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Dark Mode'</span>),
                                  value: notifier.themeMode == ThemeMode.light ? <span class="hljs-keyword">false</span> : <span class="hljs-keyword">true</span>,
                                  secondary:
                                  <span class="hljs-keyword">new</span> Icon(
                                      Icons.dark_mode,
                                      color: notifier.themeMode == ThemeMode.light ? Color(<span class="hljs-number">0xFF642ef3</span>) : Color.fromARGB(<span class="hljs-number">200</span>, <span class="hljs-number">243</span>, <span class="hljs-number">231</span>, <span class="hljs-number">106</span>)
                                  ),
                                  onChanged:notifier.handleThemeModeSettingChange
                              );
                            }
                        ),
                        <span class="hljs-comment">//.....</span>
                      ],
                    ),
                  )
      );
  }
</code></pre>
<p>I also created a manager class for it called SettingsScreenManager, where I had this method:</p>
<pre><code class="lang-dart"> <span class="hljs-keyword">void</span> handleThemeModeSettingChange(<span class="hljs-built_in">bool</span> isDarkModeEnabled) {
    _themeMode = _themeMode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
    _storageService.saveThemeModeSetting(isDarkModeEnabled);
    notifyListeners();
  }
</code></pre>
<p>The connection between the screen and its manager happens when the widget is created, as that is where I create the manager class. Then, throughout the widget itself, I call methods on the manager class. To make the widget redraw itself, I used the Consumer widget.</p>
<p>This is not the best approach, and to rectify the situation I created a Bloc to handle the theme mode:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:birthday_calendar/service/storage_service/storage_service.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_bloc/flutter_bloc.dart'</span>;

<span class="hljs-keyword">enum</span> ThemeEvent { toggleDark, toggleLight }

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThemeBloc</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Bloc</span>&lt;<span class="hljs-title">ThemeEvent</span>, <span class="hljs-title">ThemeMode</span>&gt; </span>{
  ThemeBloc(StorageService storageService, <span class="hljs-built_in">bool</span> isDarkMode) : <span class="hljs-keyword">super</span>(isDarkMode ? ThemeMode.dark : ThemeMode.light) {
    <span class="hljs-keyword">on</span>&lt;ThemeEvent&gt;((event, emit) {
      ThemeMode themeMode = event == ThemeEvent.toggleDark ? ThemeMode.dark : ThemeMode.light;
      emit(themeMode);
      storageService.saveThemeModeSetting(themeMode == ThemeMode.dark ? <span class="hljs-keyword">true</span> : <span class="hljs-keyword">false</span>);
    });
  }
}
</code></pre>
<p>Let’s break down the components of this Bloc:</p>
<ol>
<li>I have declared an enum called <strong>ThemeEvent</strong> to signify the user’s choice of light/dark theme</li>
<li>Since the state of the Bloc is directly the <strong>ThemeMode</strong> object, there was no need to create a specific State object</li>
<li>Whenever the theme changes, I emit the chosen theme mode</li>
</ol>
<p>And I initialized this bloc inside my <strong>main.dart</strong> file in order for it to be accessible to any widget in the widget hierarchy. Also, I wanted any change that occurred due to this Bloc to be enacted on the entire application.</p>
<pre><code class="lang-dart"> <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MultiBlocProvider(
      providers: [
        BlocProvider(create: (context) =&gt; ThemeBloc(storageService, isDarkMode)),
        <span class="hljs-comment">//...</span>
      ],
      child: BlocBuilder&lt;ThemeBloc, ThemeMode&gt;(
        builder: (context, state) {
          <span class="hljs-keyword">return</span> MaterialApp(
              title: applicationName,
              theme: ThemeData.light(),
              themeMode: state,
              darkTheme: ThemeData.dark(),
              home: MainPage(
                  key: Key(<span class="hljs-string">"BirthdayCalendar"</span>),
                  notificationService: notificationService,
                  contactsService: contactsService,
                  storageService: storageService,
                  title: applicationName,
                  currentMonth: BirthdayCalendarDateUtils.getCurrentMonthNumber()));
        },
      ),
    );
  }
</code></pre>
<h2 id="heading-requesting-permission">Requesting Permission</h2>
<p>There is a feature in my application that allows users to import their contacts. In order to do so, there is a requirement to first ask a runtime permission. </p>
<p>Initially, I handled this using the same approach as in the previous section, utilizing the SettingsScreenManager class, a Consumer, and a Provider.</p>
<pre><code class="lang-dart">Consumer&lt;SettingsScreenManager&gt;(
   builder: (context, notifier, child) {
    <span class="hljs-keyword">return</span> ListTile(
      title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Import Contacts"</span>),
      leading: Icon(Icons.contacts,
          color: !notifier.isContactsPermissionPermanentlyDenied ? Colors.blue : Colors.grey
      ),
      onTap: () {
        Provider.of&lt;SettingsScreenManager&gt;(context, listen: <span class="hljs-keyword">false</span>).handleImportingContacts(context);
      },
      enabled: !notifier.isContactsPermissionPermanentlyDenied
  );
}),
</code></pre>
<p>Replacing this was a step up from creating the ThemeBloc since I needed to handle the different permission statuses and also to remember if the permission was permanently denied.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">enum</span> ContactsPermissionStatusEvent {
  PermissionUnknown,
  PermissionDenied,
  PermissionGranted,
  PermissionPermanentlyDenied
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ContactsPermissionStatusBloc</span>
    <span class="hljs-keyword">extends</span> <span class="hljs-title">Bloc</span>&lt;<span class="hljs-title">ContactsPermissionStatusEvent</span>, <span class="hljs-title">PermissionStatus</span>&gt; </span>{
  ContactsPermissionStatusBloc(ContactsService contactsService)
      : <span class="hljs-keyword">super</span>(PermissionStatus.denied) {
    <span class="hljs-keyword">on</span>&lt;ContactsPermissionStatusEvent&gt;((event, emit) <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">if</span> (event == ContactsPermissionStatusEvent.PermissionUnknown) {
        <span class="hljs-built_in">bool</span> permissionStatus =
            <span class="hljs-keyword">await</span> contactsService.isContactsPermissionsPermanentlyDenied();
        <span class="hljs-keyword">if</span> (permissionStatus) {
          emit(PermissionStatus.permanentlyDenied);
          <span class="hljs-keyword">return</span>;
        }
      }
      emit(_convertEventNameToPermissionStatus(event));
    });
  }

  PermissionStatus _convertEventNameToPermissionStatus(
      ContactsPermissionStatusEvent event) {
    <span class="hljs-keyword">switch</span> (event) {
      <span class="hljs-keyword">case</span> ContactsPermissionStatusEvent.PermissionDenied:
        <span class="hljs-keyword">return</span> PermissionStatus.denied;
      <span class="hljs-keyword">case</span> ContactsPermissionStatusEvent.PermissionGranted:
        <span class="hljs-keyword">return</span> PermissionStatus.granted;
      <span class="hljs-keyword">case</span> ContactsPermissionStatusEvent.PermissionPermanentlyDenied:
        <span class="hljs-keyword">return</span> PermissionStatus.permanentlyDenied;
      <span class="hljs-keyword">default</span>:
        <span class="hljs-keyword">return</span> PermissionStatus.denied;
    }
  }
}
</code></pre>
<p>This Bloc has the following:</p>
<ul>
<li>A <strong>ContactsPermissionStatusEvent</strong> enum that correlates with the different permissions status the OS has</li>
<li>The state for this Bloc can be easily represented with the <strong>PermissionStatus</strong> class</li>
<li>I have a private helper method called <strong>_convertEventNameToPermissionStatus</strong> to help in converting the event name to it’s corresponding permission status</li>
</ul>
<p>You might be asking yourself why I added an event called <strong>PermissionUnknown</strong>. I did this so I could get the permission status in advance of the user navigating to the SettingsScreen. In the case where the user previously chose to permanently deny the permission, I wanted to gray out the option to import contacts for them. </p>
<p>To achieve this, I created the Bloc in the main.dart file:</p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MultiBlocProvider(
      providers: [
        BlocProvider(create: (context) =&gt; ThemeBloc(storageService, isDarkMode)),
        BlocProvider(
            create: (context) =&gt; ContactsPermissionStatusBloc(contactsService)),
        BlocProvider(create: (context) =&gt; VersionBloc())
      ],
      child: BlocBuilder&lt;ThemeBloc, ThemeMode&gt;(
        builder: (context, state) {
          <span class="hljs-keyword">return</span> MaterialApp(
</code></pre>
<p>and I sent the event inside the initState method of the widget that is the parent of the SettingsScreen.</p>
<pre><code class="lang-dart"> <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> initState() {
    <span class="hljs-comment">//....</span>
    BlocProvider.of&lt;ContactsPermissionStatusBloc&gt;(context)
        .add(ContactsPermissionStatusEvent.PermissionUnknown);
    <span class="hljs-keyword">super</span>.initState();
  }
</code></pre>
<p>And instead of the huge chunk of code I had earlier, I now have this:</p>
<pre><code class="lang-dart">BlocBuilder&lt;ContactsPermissionStatusBloc, PermissionStatus&gt;(
              builder: (context, state) {
            <span class="hljs-keyword">return</span> ListTile(
                title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Import Contacts"</span>),
                leading: Icon(Icons.contacts, color: Colors.blue),
                onTap: () {
                  _handleImportingContacts(context);
                },
                enabled: state.isPermanentlyDenied ? <span class="hljs-keyword">false</span> : <span class="hljs-keyword">true</span>);
          }),
</code></pre>
<h2 id="heading-interacting-with-a-list">Interacting with a List</h2>
<p>Part of my application allows users to add/remove birthdays on specific calendar dates. As with previous features, here too I created a manager class to handle the state for if a user added/removed a birthday. </p>
<p>Part of the logic involved the presentation of an alert dialog with fields to add a birthday. This logic proved to be the most robust when trying to migrate to Bloc, as I had to think about all of the user flows.</p>
<p>This is what that widget looked like:</p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> ChangeNotifierProvider(
      create: (context) =&gt; BirthdaysForCalendarDayManager(<span class="hljs-keyword">this</span>.birthdays, <span class="hljs-keyword">this</span>.dateOfDay),
          builder: (context, provider) {
              <span class="hljs-keyword">return</span> Scaffold(
              appBar: AppBar(
              title: FittedBox(
                  fit: BoxFit.fitWidth,
                  child: Text(
                      <span class="hljs-string">"Birthdays for <span class="hljs-subst">${_dateService.convertMonthToWord(<span class="hljs-keyword">this</span>.dateOfDay.month)}</span> <span class="hljs-subst">${<span class="hljs-keyword">this</span>.dateOfDay.day}</span>"</span>)
              )
          ),
            body: Center(
                child: Column(
                  children: [
                      Consumer&lt;BirthdaysForCalendarDayManager&gt;(
                          builder: (context, data, child) =&gt;
                          Expanded(child:
                            ListView.builder(
                                  itemCount: data.birthdays.length,
                                  itemBuilder: (BuildContext context, <span class="hljs-built_in">int</span> index) {
                                  <span class="hljs-keyword">return</span> BirthdayWidget(
                                    key: Key(data.birthdays[index].name),
                                      birthdayOfPerson: data.birthdays[index],
                                      onDeletePressedCallback: () {
                                        Provider.of&lt;BirthdaysForCalendarDayManager&gt;(context, listen: <span class="hljs-keyword">false</span>).removeBirthdayFromList(data.birthdays[index]);
                                    },
                                    indexOfBirthday: index);
                                  },
                                 ),
                           ),
                          )
                      ],
                   )
                ),
                floatingActionButton: FloatingActionButton(
                onPressed: () {
                  Provider.of&lt;BirthdaysForCalendarDayManager&gt;(context, listen: <span class="hljs-keyword">false</span>).handleAddBirthdayBtnPressed(context, dateOfDay);
                  },
                child: Icon(Icons.add)),
              );
          },
    );
  }
</code></pre>
<p>And the manager class:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BirthdaysForCalendarDayManager</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ChangeNotifier</span> </span>{

  NotificationService _notificationService = getIt&lt;NotificationService&gt;();
  StorageService _storageService = getIt&lt;StorageService&gt;();
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;UserBirthday&gt; _currentBirthdays = [];
  <span class="hljs-built_in">DateTime</span> date = <span class="hljs-built_in">DateTime</span>.now();

  UnmodifiableListView&lt;UserBirthday&gt; <span class="hljs-keyword">get</span> birthdays =&gt; UnmodifiableListView(_currentBirthdays);

  BirthdaysForCalendarDayManager(<span class="hljs-built_in">List</span>&lt;UserBirthday&gt; birthdays, <span class="hljs-built_in">DateTime</span> dateTime) {
    <span class="hljs-comment">//....</span>
  }

  <span class="hljs-keyword">void</span> _handleUserInput(UserBirthday userBirthday) {
    <span class="hljs-comment">//....</span>
  }

  <span class="hljs-keyword">void</span> _addBirthdayToList(UserBirthday userBirthday) {
    <span class="hljs-comment">//....</span>
    notifyListeners();
  }

  <span class="hljs-keyword">void</span> removeBirthdayFromList(UserBirthday birthdayToRemove) <span class="hljs-keyword">async</span> {
    <span class="hljs-comment">//....</span>
    notifyListeners();
  }

  <span class="hljs-keyword">void</span> handleAddBirthdayBtnPressed(BuildContext context, <span class="hljs-built_in">DateTime</span> dateOfDay) <span class="hljs-keyword">async</span> {
    <span class="hljs-comment">//....</span>
  }
</code></pre>
<p>So how can we go about migrating all this logic to Bloc? Well, first let’s think of the different events we will need:</p>
<ol>
<li>Adding an item to the list</li>
<li>Removing an item to the list</li>
<li>Presenting the dialog that allows users to add an item to the list (this is used to be able to show the dialog)</li>
</ol>
<p>So our inner enum for events can look like:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">enum</span> BirthdayEvent { AddBirthday, RemoveBirthday, ShowAddBirthdayDialog }
</code></pre>
<p>But what will our BirthdaysEvent include?</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BirthdaysEvent</span> </span>{
  <span class="hljs-keyword">final</span> BirthdayEvent eventName;  <span class="hljs-comment">// 1</span>
  <span class="hljs-keyword">final</span> UserBirthday? birthday;   <span class="hljs-comment">// 2</span>
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">bool?</span> shouldShowAddBirthdayDialog; <span class="hljs-comment">// 3</span>
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;UserBirthday&gt; birthdays; <span class="hljs-comment">// 4</span>
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">DateTime?</span> date;  <span class="hljs-comment">//5</span>

  BirthdaysEvent(
      {<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.eventName,
      <span class="hljs-keyword">this</span>.birthday,
      <span class="hljs-keyword">this</span>.shouldShowAddBirthdayDialog,
      <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.birthdays,
      <span class="hljs-keyword">this</span>.date});
}
</code></pre>
<ol>
<li>The event name</li>
<li>The birthday we will either add or remove</li>
<li>A flag to indicate if we should present the dialog</li>
<li>The whole list of birthdays for the specific date</li>
<li>The date the user wants to add/remove birthdays to/from</li>
</ol>
<p>You may have noticed that not all fields are required to create a <strong>BirthdaysEvent</strong>. This is because not all of these fields are necessary for the different types of events. For example, when the user wants to add another birthday, the second argument (titled birthday) is irrelevant since we want to create a birthday.</p>
<p>Next, we need to think about what should be included in our state. Looking at the code above, it is clear that we need:</p>
<ul>
<li>To keep the list of birthdays, as we are either removing from or adding to it</li>
<li>A flag to indicate if we should show the add birthday dialog</li>
<li>The current date to add/remove birthdays to</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BirthdaysState</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">DateTime?</span> date;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;UserBirthday&gt;? birthdays;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">bool</span> showAddBirthdayDialog;

  BirthdaysState(
      {<span class="hljs-keyword">this</span>.date, <span class="hljs-keyword">this</span>.birthdays, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.showAddBirthdayDialog});
}
</code></pre>
<p>So we got our events in place and our state as well. Now it's time to implement the logic in our bloc that handles each of these events and create a new state:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BirthdaysBloc</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Bloc</span>&lt;<span class="hljs-title">BirthdaysEvent</span>, <span class="hljs-title">BirthdaysState</span>&gt; </span>{
  BirthdaysBloc(NotificationService notificationService,
      StorageService storageService, <span class="hljs-built_in">List</span>&lt;UserBirthday&gt; birthdaysForDate)
      : <span class="hljs-keyword">super</span>(BirthdaysState(
            date: <span class="hljs-built_in">DateTime</span>.now(),
            birthdays: birthdaysForDate,
            showAddBirthdayDialog: <span class="hljs-keyword">false</span>)) {
    <span class="hljs-keyword">on</span>&lt;BirthdaysEvent&gt;((event, emit) {
      <span class="hljs-keyword">switch</span> (event.eventName) {
        <span class="hljs-keyword">case</span> BirthdayEvent.AddBirthday:
          _handleAddEvent(event, emit, storageService, notificationService);
          <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> BirthdayEvent.RemoveBirthday:
          _handleRemoveEvent(event, emit, storageService, notificationService);
          <span class="hljs-keyword">break</span>;
        <span class="hljs-keyword">case</span> BirthdayEvent.ShowAddBirthdayDialog:
          emit(<span class="hljs-keyword">new</span> BirthdaysState(showAddBirthdayDialog: <span class="hljs-keyword">true</span>));
          <span class="hljs-keyword">break</span>;
      }
    });
  }
</code></pre>
<p>If we look at one event, <strong>ShowAddBirthdayDialog</strong>, you can see that we are just emitting a new BirthdayState where the <strong>showAddBirthdayDialog</strong> is set to true. But where is this handled? I had to heavily refactor the widget from above in order for it to respond for changes in the state.</p>
<pre><code class="lang-dart">  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
   <span class="hljs-keyword">return</span> BlocProvider(                            <span class="hljs-comment">// 1</span>
        create: (context) =&gt;
            BirthdaysBloc(notificationService, storageService, birthdays),
        child: BlocBuilder&lt;BirthdaysBloc, BirthdaysState&gt;(   <span class="hljs-comment">// 2</span>
            builder: (context, state) {
          <span class="hljs-keyword">return</span> Scaffold(
            appBar: AppBar(
                title: FittedBox(
                    fit: BoxFit.fitWidth,
                    child: Text(
                        <span class="hljs-string">"Birthdays for <span class="hljs-subst">${BirthdayCalendarDateUtils.convertMonthToWord(<span class="hljs-keyword">this</span>.dateOfDay.month)}</span> <span class="hljs-subst">${<span class="hljs-keyword">this</span>.dateOfDay.day}</span>"</span>))),
            body: Center(
                child: Column(
              children: [
                (state.birthdays == <span class="hljs-keyword">null</span> || state.birthdays!.length == <span class="hljs-number">0</span>)
                    ? Spacer()
                    : Expanded(
                        child: ListView.builder(
                          itemCount: state.birthdays != <span class="hljs-keyword">null</span>
                              ? state.birthdays!.length
                              : <span class="hljs-number">0</span>,
                          itemBuilder: (BuildContext context, <span class="hljs-built_in">int</span> index) {
                            <span class="hljs-keyword">return</span> BirthdayWidget(
                                key: Key(state.birthdays![index].name),
                                birthdayOfPerson: state.birthdays![index],
                                onDeletePressedCallback: () {  <span class="hljs-comment">// 3</span>
                                  BlocProvider.of&lt;BirthdaysBloc&gt;(context).add(
                                      <span class="hljs-keyword">new</span> BirthdaysEvent(
                                          eventName:
                                              BirthdayEvent.RemoveBirthday,
                                          birthday: state.birthdays![index],
                                          birthdays: birthdays));
                                },
                                indexOfBirthday: index,
                                storageService: storageService,
                                notificationService: notificationService);
                          },
                        ),
                      ),
                BlocListener&lt;BirthdaysBloc, BirthdaysState&gt;(  <span class="hljs-comment">// 4</span>
                  listener: (context, state) {
                    <span class="hljs-keyword">if</span> (state.showAddBirthdayDialog) {
                      showDialog(
                          context: context,
                          builder: (_) =&gt; BlocProvider.value(  <span class="hljs-comment">// 5</span>
                              value: BlocProvider.of&lt;BirthdaysBloc&gt;(context),
                              child: AddBirthdayForm(
                                  dateOfDay: dateOfDay,
                                  storageService: storageService)));
                    }
                  },
                  child: Spacer(),
                )
              ],
            )),
            floatingActionButton: FloatingActionButton(
                onPressed: () { <span class="hljs-comment">// 6</span>
                  BlocProvider.of&lt;BirthdaysBloc&gt;(context).add(BirthdaysEvent(
                      eventName: BirthdayEvent.ShowAddBirthdayDialog,
                      shouldShowAddBirthdayDialog: <span class="hljs-keyword">true</span>,
                      birthdays: birthdays));
                },
                child: Icon(Icons.add)),
          );
        }));
  }
</code></pre>
<p>There is a lot to unpack here, so let’s take it one step at a time.</p>
<ol>
<li>The BirthdaysBloc is created inside this widget since it is not needed anywhere else up the widget tree</li>
<li>We are using a BlocBuilder so the widget will re-draw itself when the state changes</li>
<li>When a birthday is chosen to be deleted, we create a RemoveBirthday event and pass along all the necessary information</li>
<li>We are using a BlocListener to handle the changes in the state in order to show the AlertDialog for adding a new birthday</li>
<li>Since our BirthdaysBloc is not found on the global level, it is necessary to pass it in to the <strong>AddBirthdayForm</strong> widget using BlocProvider</li>
<li>When the user presses the floating action button to signify an intent to add a birthday, we create a ShowAddBirthdayDialog event</li>
</ol>
<p>Notice that, after all these changes, the manager class was no longer needed and therefore, the code itself is more straightforward and easier to maintain.</p>
<p>You are more than welcome to check out the entirety of the code shown above in the GitHub repository here:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/TomerPacific/BirthdayCalendar">https://github.com/TomerPacific/BirthdayCalendar</a></div>
<p>And if you like, you can check out the application itself, <a target="_blank" href="https://play.google.com/store/apps/details?id=com.tomerpacific.birthday_calendar">here</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Mobile Quiz App with React Native, ChatGPT and Supabase ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you'll learn how to build a mobile quiz application that authenticates users, allows them to take tests, and ranks them based on their scores.  The application leverages some of Supabase's features, such as authentication and databa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-mobile-quiz-app/</link>
                <guid isPermaLink="false">66b8fc7a33470f39c663c1a4</guid>
                
                    <category>
                        <![CDATA[ chatgpt ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React Native ]]>
                    </category>
                
                    <category>
                        <![CDATA[ supabase ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Asaolu ]]>
                </dc:creator>
                <pubDate>Thu, 29 Feb 2024 17:30:26 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/Building-a-mobile-quiz-app-with-React-Native--ChatGPT-and-Supabase--1--1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you'll learn how to build a mobile quiz application that authenticates users, allows them to take tests, and ranks them based on their scores. </p>
<p>The application leverages some of Supabase's features, such as authentication and database storage, to build a secured full-stack mobile application.</p>
<p>Additionally, you'll learn how to create React Native applications with Expo, generate a set of questions and answers from ChatGPT, and perform CRUD operations and user authentication with Supabase.</p>
<p>To fully understand this tutorial, you'll need to have a basic knowledge of React Native and data fetching in React applications.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-mobile-application-demo">Mobile Application Demo</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-react-native-application-with-expo-1">How to set up a React Native application with Expo</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-react-native-application-with-expo-1">How to style the React Native application with Tailwind CSS</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-application-screens">How to build the application screens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-authentication-screens">How to build the authentication screens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-tab-screens">How to build the tab screens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-stack-screens">How to build the stack screens</a></li>
<li><a class="post-section-overview" href="#heading-how-to-generate-quiz-questions-and-answers-from-chatgpt">How to generate quiz questions and answers from ChatGPT</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-supabase-to-react-native">How to add Supabase to React Native</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-supabase-authentication-to-react-native-applications">How to add Supabase authentication to React Native applications</a></li>
<li><a class="post-section-overview" href="#heading-how-to-sign-up-new-users">How to sign up new users</a></li>
<li><a class="post-section-overview" href="#heading-how-to-sign-in-existing-users">How to sign in existing users</a></li>
<li><a class="post-section-overview" href="#heading-how-to-log-users-out-of-the-application">How to log users out of the application</a></li>
<li><a class="post-section-overview" href="#heading-how-to-protect-screens-from-unauthenticated-users">How to protect screens from unauthenticated users</a></li>
<li><a class="post-section-overview" href="#heading-how-to-interact-with-the-supabase-database">How to interact with the Supabase database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-save-the-users-score-to-the-database">How to save user's score to the database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-retrieve-data-from-supabase">How to retrieve data from Supabase</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-mobile-application-demo">Mobile Application Demo</h2>
<p>To preview the application, download <a target="_blank" href="https://expo.dev/client">Expo Go</a> and paste the links below into the app URL field:</p>
<p><strong>Android:</strong> <code>exp://u.expo.dev/update/a4774250-e156-4d34-bcfc-a4f2549c2e1d</code><br><strong>iOS:</strong> <code>exp://u.expo.dev/update/7e5f8ba5-89c4-4c1d-b219-a613ace642df</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/app-demo.png" alt="Image" width="600" height="400" loading="lazy">
<em>Scan the QR code to preview the mobile quiz application within the Expo Go application</em></p>
<h2 id="heading-how-to-set-up-a-react-native-application-with-expo">How to Set Up a React Native Application with Expo</h2>
<p>Expo is an open-source platform that allows you to create cross-platform applications easily with JavaScript. It saves us from the complex configurations required to create a native application with the React Native CLI, making it the easiest and fastest way to build and publish React Native apps.</p>
<p>Execute the code snippet below to create a new <a target="_blank" href="https://expo.dev/">Expo</a> project that uses <a target="_blank" href="https://docs.expo.dev/router/introduction/">Expo Router</a> for navigating between screens.</p>
<pre><code class="lang-bash">npx create-expo-app@latest --template tabs@50
</code></pre>
<p><a target="_blank" href="https://docs.expo.dev/router/introduction/">Expo Router</a> is an open-source file-based routing system that enables users to navigate between screens easily. It is similar to Next.js, where each file name represents its route name.</p>
<p>Start the development server to ensure that the app is working as expected.</p>
<pre><code class="lang-bash">npx expo start
</code></pre>
<h3 id="heading-how-to-style-the-react-native-application-with-tailwind-css">How to style the React Native application with Tailwind CSS</h3>
<p>Tailwind CSS is a CSS framework that lets you create modern and stunning applications easily. </p>
<p>However, to style Expo applications using Tailwind CSS, you need to install <a target="_blank" href="https://www.nativewind.dev/v4/getting-started/expo-router">NativeWind</a> – a library that uses Tailwind CSS as its scripting language.</p>
<p>Run the code snippet below to install NativeWind and its dependencies:</p>
<pre><code class="lang-bash">npx expo install nativewind@^4.0.1 react-native-reanimated tailwindcss
</code></pre>
<p>Execute <code>npx tailwindcss init</code> within your terminal to create a <code>tailwind.config.js</code> file. Update the file with the code snippet below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-attr">content</span>: [<span class="hljs-string">"./app/**/*.{js,jsx,ts,tsx}"</span>],
    <span class="hljs-attr">presets</span>: [<span class="hljs-built_in">require</span>(<span class="hljs-string">"nativewind/preset"</span>)],
    <span class="hljs-attr">theme</span>: {
        <span class="hljs-attr">extend</span>: {},
    },
    <span class="hljs-attr">plugins</span>: [],
};
</code></pre>
<p>Create a <code>globals.css</code> file within the root of your project and add the Tailwind directives below:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p>Update the <code>babel.config.js</code> file with the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">api</span>) </span>{
  api.cache(<span class="hljs-literal">true</span>);
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">presets</span>: [
      [<span class="hljs-string">"babel-preset-expo"</span>, { <span class="hljs-attr">jsxImportSource</span>: <span class="hljs-string">"nativewind"</span> }],
      <span class="hljs-string">"nativewind/babel"</span>,
    ],
  };
};
</code></pre>
<p>Create a <code>metro.config.js</code> file within the root of your project and paste the code snippet below into the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { getDefaultConfig } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"expo/metro-config"</span>);
<span class="hljs-keyword">const</span> { withNativeWind } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'nativewind/metro'</span>);

<span class="hljs-keyword">const</span> config = getDefaultConfig(__dirname)

<span class="hljs-built_in">module</span>.exports = withNativeWind(config, { <span class="hljs-attr">input</span>: <span class="hljs-string">'./globals.css'</span> })
</code></pre>
<p>Finally, import the <code>./globals.css</code> file into the <code>app/_layout.tsx</code> file to enable you to style your application with Tailwind CSS:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//👉🏻 Within ./app/_layout.tsx</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">"../globals.css"</span>;
</code></pre>
<p>Great job on creating the React Native project with Expo! Now, you're ready to add some style using Tailwind CSS. If you encounter any problems while installing NativeWind, check out the <a target="_blank" href="https://www.nativewind.dev/v4/getting-started/expo-router">documentation</a> for a step-by-step guide.</p>
<h2 id="heading-how-to-build-the-application-screens">How to Build the Application Screens</h2>
<p>Here, I'll guide you through building the application screens. They are divided into three categories:</p>
<ul>
<li>The Authentication screens – the register and login screens.</li>
<li>The Tab layout screens – the dashboard, leaderboard, and profile screens.</li>
<li>The Stack screens – the test and test completion screens.</li>
</ul>
<p>The application prompts new users to create an account and log in before allowing access to the Tab layout screens. </p>
<p>On the dashboard screen, users can take tests on various topics. The leaderboard screen showcases the top ten users. Users can log out or preview their previous attempts on the profile page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/application-demo.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Application Demo</em></p>
<h3 id="heading-how-to-build-the-authentication-screens">How to Build the Authentication Screens</h3>
<p>The authentication screens accept the user's email and password and ensure the credentials are valid before creating an account or granting access to the application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/auth-screens.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Authentication Screens</em></p>
<p>Create an <code>index.tsx</code> and a <code>register.tsx</code> file within the <code>app</code> folder and a component that accepts the user's email and password using the <a target="_blank" href="https://reactnative.dev/docs/textinput">React Native TextInput</a> component.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Text, View, TextInput, Pressable, Alert } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-native"</span>;
<span class="hljs-keyword">import</span> { Link, useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"expo-router"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LoginScreen</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [email, setEmail] = useState&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> [password, setPassword] = useState&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> [loading, setLoading] = useState&lt;<span class="hljs-built_in">boolean</span>&gt;(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> router = useRouter();

    <span class="hljs-comment">//👇🏻 triggered when the user submits the email &amp; password</span>
    <span class="hljs-keyword">const</span> handleLogin = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (!email.trim() || !password.trim())
            <span class="hljs-keyword">return</span> Alert.alert(<span class="hljs-string">"Error"</span>, <span class="hljs-string">"Please fill in all fields"</span>);
        setLoading(<span class="hljs-literal">true</span>);
        <span class="hljs-built_in">console</span>.log({
            email,
            password,
        });
        router.replace(<span class="hljs-string">"/(tabs)/"</span>);
    };

    <span class="hljs-keyword">return</span> (
        &lt;View&gt;
        {<span class="hljs-comment">/** -- user interface--*/</span>}
        &lt;/View&gt;
    );
}
</code></pre>
<p>The code snippet stores the user's email and password in states using the React useState hook. The <code>handleLogin</code> function accepts the user's email and password when the form is submitted and ensures that they are not empty before logging them to the console and redirecting the user to the Dashboard page.</p>
<p>You can create the user interface using the code snippet below. It displays the input fields for the user's credentials and an interactive Sign-in button that executes the <code>handleLogin</code> function. Additionally, the <code>loading</code> state ensures that the button is only pressed once.</p>
<pre><code class="lang-typescript">&lt;View className=<span class="hljs-string">' flex-1'</span>&gt;
    &lt;View className=<span class="hljs-string">'w-full px-4'</span>&gt;
        &lt;Text className=<span class="hljs-string">'text-3xl mb-4 font-bold text-white text-center'</span>&gt;
            Log <span class="hljs-keyword">in</span>
        &lt;/Text&gt;

        &lt;Text className=<span class="hljs-string">'text-lg text-gray-200'</span>&gt;Email Address&lt;/Text&gt;
        &lt;TextInput
            className=<span class="hljs-string">'w-full border-b-[1px] py-4 rounded-md mb-3 text-white font-bold'</span>
            value={email}
            onChangeText={setEmail}
        /&gt;
        &lt;Text className=<span class="hljs-string">'text-lg text-gray-200'</span>&gt;Password&lt;/Text&gt;
        &lt;TextInput
            className=<span class="hljs-string">'w-full border-b-[1px] py-4 rounded-md mb-3 text-white font-bold'</span>
            secureTextEntry
            value={password}
            onChangeText={setPassword}
        /&gt;
        &lt;Pressable
            className={<span class="hljs-string">`w-full <span class="hljs-subst">${
                loading ? <span class="hljs-string">"bg-orange-200"</span> : <span class="hljs-string">"bg-orange-600"</span>
            }</span> rounded-xl p-4 border-[1px] border-orange-200`</span>}
            disabled={loading}
            onPress={<span class="hljs-function">() =&gt;</span> handleLogin()}
        &gt;
            &lt;Text className=<span class="hljs-string">'text-white text-center font-bold text-xl'</span>&gt;
                {loading ? <span class="hljs-string">"Authenticating..."</span> : <span class="hljs-string">"Sign in"</span>}
            &lt;/Text&gt;
        &lt;/Pressable&gt;
        &lt;Text className=<span class="hljs-string">'text-center mt-2 text-orange-200'</span>&gt;
            Don<span class="hljs-string">'t have an account?{" "}
            &lt;Link href='</span>/register<span class="hljs-string">'&gt;
                &lt;Text className='</span>text-white<span class="hljs-string">'&gt;Register&lt;/Text&gt;
            &lt;/Link&gt;
        &lt;/Text&gt;
    &lt;/View&gt;
&lt;/View&gt;</span>
</code></pre>
<p>For instance, the <code>loading</code> state becomes true when a user clicks the Sign-in button. The Pressable component (button) has a <code>disabled</code> attribute set to the <code>loading</code> state to ensure that the user does not press the button multiple times. Additionally, you can use the loading state to notify the user that the request is processing.</p>
<p>The <code>register.tsx</code> file is also similar to the <code>login.tsx</code> file. You only need to change the words from Login to Register.</p>
<h3 id="heading-how-to-build-the-tab-screens">How to Build the Tab Screens</h3>
<p>The Tab Screens consist of the Dashboard, Leaderboard, and Profile screens.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/tab-screens.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Tab Screens</em></p>
<p>Create a <code>(tabs)</code> folder containing <code>index.tsx</code>, <code>leaderboard.tsx</code>, <code>profile.tsx</code>, and <code>_layout.tsx</code> files within the <code>app</code> folder.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> app
mkdir (tabs)
<span class="hljs-built_in">cd</span> (tabs)
touch index.tsx leaderboard.tsx profile.tsx _layout.tsx
</code></pre>
<p>After creating the <code>_layout.tsx</code> file within the (tabs) folder, update the <code>_layout.tsx</code> to specify Tab screen navigation for the newly created screens. The screens use icons from the <a target="_blank" href="https://icons.expo.fyi/Index">Expo Vector Icons library</a>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Tabs } <span class="hljs-keyword">from</span> <span class="hljs-string">"expo-router"</span>;
<span class="hljs-keyword">import</span> { Ionicons, MaterialIcons, FontAwesome5 } <span class="hljs-keyword">from</span> <span class="hljs-string">"@expo/vector-icons"</span>;
<span class="hljs-keyword">import</span> { ActivityIndicator } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-native"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TabScreen</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        &lt;Tabs
            screenOptions={{
                tabBarActiveTintColor: <span class="hljs-string">"#f97316"</span>,
                tabBarInactiveTintColor: <span class="hljs-string">"gray"</span>,
                tabBarShowLabel: <span class="hljs-literal">false</span>,
                headerShown: <span class="hljs-literal">false</span>,
                tabBarStyle: {
                    backgroundColor: <span class="hljs-string">"#ffedd5"</span>,
                    borderTopColor: <span class="hljs-string">"#ffedd5"</span>,
                },
            }}
        &gt;
            &lt;Tabs.Screen
                name=<span class="hljs-string">'index'</span>
                options={{
                    tabBarIcon: <span class="hljs-function">(<span class="hljs-params">{ color }</span>) =&gt;</span> (
                        &lt;Ionicons name=<span class="hljs-string">'home'</span> size={<span class="hljs-number">24</span>} color={color} /&gt;
                    ),
                }}
            /&gt;
            &lt;Tabs.Screen
                name=<span class="hljs-string">'leaderboard'</span>
                options={{
                    tabBarIcon: <span class="hljs-function">(<span class="hljs-params">{ color }</span>) =&gt;</span> (
                        &lt;MaterialIcons name=<span class="hljs-string">'leaderboard'</span> size={<span class="hljs-number">24</span>} color={color} /&gt;
                    ),
                }}
            /&gt;
            &lt;Tabs.Screen
                name=<span class="hljs-string">'profile'</span>
                options={{
                    tabBarIcon: <span class="hljs-function">(<span class="hljs-params">{ color }</span>) =&gt;</span> (
                        &lt;FontAwesome5 name=<span class="hljs-string">'user-alt'</span> size={<span class="hljs-number">24</span>} color={color} /&gt;
                    ),
                }}
            /&gt;
        &lt;/Tabs&gt;
    );
}
</code></pre>
<p>Next, update the <code>RootLayoutNav</code> component within the <code>_app/layout.tsx</code> file to render all the screens within the application.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayoutNav</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        &lt;Stack screenOptions={{ headerShown: <span class="hljs-literal">false</span> }}&gt;
            &lt;Stack.Screen name=<span class="hljs-string">'(tabs)'</span> /&gt;
            &lt;Stack.Screen name=<span class="hljs-string">'(stack)'</span> /&gt;
            &lt;Stack.Screen name=<span class="hljs-string">'index'</span> /&gt;
            &lt;Stack.Screen name=<span class="hljs-string">'register'</span> /&gt;
        &lt;/Stack&gt;
    );
}
</code></pre>
<h4 id="heading-the-dashboard-screen">The Dashboard Screen</h4>
<p>Update the component to allow users to select four categories from a list of categories.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomeScreen</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> greet = getGreeting();
    <span class="hljs-keyword">const</span> router = useRouter();
    <span class="hljs-keyword">const</span> { session } = useAuth();
    <span class="hljs-keyword">const</span> [loading, setLoading] = useState&lt;<span class="hljs-built_in">boolean</span>&gt;(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> [userCategories, setUserCategories] = useState&lt;<span class="hljs-built_in">string</span>[]&gt;([]);

    <span class="hljs-keyword">const</span> fetchQuestions = <span class="hljs-keyword">async</span> () =&gt; {};

    <span class="hljs-keyword">const</span> handleStartTest = <span class="hljs-keyword">async</span> () =&gt; {
        Alert.alert(<span class="hljs-string">"Start Test"</span>, <span class="hljs-string">"Are you sure you want to start the test?"</span>, [
            {
                text: <span class="hljs-string">"Cancel"</span>,
                style: <span class="hljs-string">"destructive"</span>,
            },
            {
                text: <span class="hljs-string">"Yes"</span>,
                onPress: <span class="hljs-function">() =&gt;</span> fetchQuestions(),
            },
        ]);
    };

    <span class="hljs-keyword">return</span> (
        &lt;SafeAreaView className=<span class="hljs-string">'flex-1 bg-orange-100 px-4 py-2'</span>&gt;
            &lt;View className=<span class="hljs-string">'flex flex-row items-center justify-between mb-2'</span>&gt;
                &lt;View&gt;
                    &lt;Text className=<span class="hljs-string">'font-bold text-2xl mb-[1px]'</span>&gt;
                        Good morning
                        &lt;Ionicons name=<span class="hljs-string">'partly-sunny-sharp'</span> size={<span class="hljs-number">24</span>} color=<span class="hljs-string">'orange'</span> /&gt;
                    &lt;/Text&gt;

                    &lt;Text className=<span class="hljs-string">'text-lg'</span>&gt;Welcome User&lt;/Text&gt;
                &lt;/View&gt;
            &lt;/View&gt;
            {userCategories.length === <span class="hljs-number">4</span> &amp;&amp; (
                &lt;Pressable
                    className={<span class="hljs-string">`w-full h-[70px] flex items-center justify-center <span class="hljs-subst">${
                        loading ? <span class="hljs-string">"bg-orange-300"</span> : <span class="hljs-string">"bg-orange-500"</span>
                    }</span> rounded-xl mb-2`</span>}
                    disabled={loading}
                    onPress={<span class="hljs-function">() =&gt;</span> handleStartTest()}
                &gt;
                    &lt;Text className=<span class="hljs-string">'text-xl font-bold text-orange-50'</span>&gt;
                        {loading ? <span class="hljs-string">"Loading questions..."</span> : <span class="hljs-string">"START TEST"</span>}
                    &lt;/Text&gt;
                &lt;/Pressable&gt;
            )}

            &lt;View className=<span class="hljs-string">'w-full flex-1'</span>&gt;
                &lt;Text className=<span class="hljs-string">'text-xl font-bold text-orange-500 mb-4'</span>&gt;
                    Available Categories
                &lt;/Text&gt;
                &lt;FlatList
                    data={categories}
                    numColumns={<span class="hljs-number">2</span>}
                    contentContainerStyle={{ width: <span class="hljs-string">"100%"</span>, gap: <span class="hljs-number">10</span> }}
                    columnWrapperStyle={{ gap: <span class="hljs-number">10</span> }}
                    renderItem={<span class="hljs-function">(<span class="hljs-params">{ item }</span>) =&gt;</span> (
                        &lt;Categories
                            item={item}
                            userCategories={userCategories}
                            setUserCategories={setUserCategories}
                        /&gt;
                    )}
                    showsVerticalScrollIndicator={<span class="hljs-literal">false</span>}
                    keyExtractor={<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item.id}
                /&gt;
            &lt;/View&gt;
        &lt;/SafeAreaView&gt;
    );
}
</code></pre>
<p>The code snippet above renders a list of categories where users can select only four categories to answer questions on and start the quiz.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/dashboard-screen.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The Dashboard Screen</em></p>
<h4 id="heading-the-leaderboard-screen">The Leaderboard Screen</h4>
<p>The Leaderboard screen displays the top ten users ranked in descending order.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Text, FlatList, SafeAreaView } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-native"</span>;
<span class="hljs-keyword">import</span> Board <span class="hljs-keyword">from</span> <span class="hljs-string">"../../components/Board"</span>;

<span class="hljs-keyword">interface</span> Props {
    total_score: <span class="hljs-built_in">number</span>;
    user_id: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LeaderboardScreen</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [leaderboard, setLeaderboard] = useState&lt;Props[]&gt;([]);

    <span class="hljs-keyword">return</span> (
        &lt;SafeAreaView className=<span class="hljs-string">'flex-1 bg-orange-100 p-4'</span>&gt;
            &lt;Text className=<span class="hljs-string">'text-2xl font-bold text-gray-500 text-center mb-6'</span>&gt;
                Leaderboard
            &lt;/Text&gt;

            &lt;FlatList
                data={leaderboard}
                renderItem={<span class="hljs-function">(<span class="hljs-params">{ item }</span>) =&gt;</span> &lt;Board item={item} /&gt;}
                keyExtractor={<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item.user_id}
                showsVerticalScrollIndicator={<span class="hljs-literal">false</span>}
            /&gt;
        &lt;/SafeAreaView&gt;
    );
}
</code></pre>
<p>The code snippet above renders a FlatList with ten items. You can create an array containing ten users and pass it into the FlatList for now.</p>
<h4 id="heading-the-profile-screen">The Profile Screen</h4>
<p>The Profile Screen displays the user's image, recent attempts, and a log-out button that enables the user to sign out of the application.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProfileScreen</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [loading, setLoading] = useState&lt;<span class="hljs-built_in">boolean</span>&gt;(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> [total_score, setTotalScore] = useState&lt;<span class="hljs-built_in">number</span>&gt;(<span class="hljs-number">0</span>);
    <span class="hljs-keyword">const</span> [attempts, setAttempts] = useState&lt;<span class="hljs-built_in">string</span>[]&gt;([]);

    <span class="hljs-keyword">const</span> handleSignOut = <span class="hljs-keyword">async</span> () =&gt; {
        setLoading(<span class="hljs-literal">true</span>);
    };

    <span class="hljs-keyword">return</span> (
        &lt;SafeAreaView className=<span class="hljs-string">'flex-1 bg-orange-100 p-4'</span>&gt;
            &lt;View className=<span class="hljs-string">'flex items-center justify-center mb-6'</span>&gt;
                &lt;Text className=<span class="hljs-string">'text-gray-600 mb-[1px]'</span>&gt;
                    &lt;FontAwesome name=<span class="hljs-string">'star'</span> size={<span class="hljs-number">20</span>} color=<span class="hljs-string">'red'</span> /&gt;
                    &lt;Text&gt;<span class="hljs-number">45</span>&lt;/Text&gt;
                &lt;/Text&gt;
                &lt;Text className=<span class="hljs-string">'text-gray-600 mb-2'</span>&gt;<span class="hljs-meta">@dhastix</span>&lt;/Text&gt;

                &lt;Pressable onPress={<span class="hljs-function">() =&gt;</span> handleSignOut()} disabled={loading}&gt;
                    &lt;Text className=<span class="hljs-string">'text-red-500'</span>&gt;
                        {loading ? <span class="hljs-string">"Logging out..."</span> : <span class="hljs-string">"Log out"</span>}
                    &lt;/Text&gt;
                &lt;/Pressable&gt;
            &lt;/View&gt;

            &lt;Text className=<span class="hljs-string">'font-bold text-xl text-gray-700 mb-3 px-4'</span>&gt;
                Recent Attempts
            &lt;/Text&gt;

            &lt;FlatList
                data={attempts}
                contentContainerStyle={{ padding: <span class="hljs-number">15</span> }}
                renderItem={<span class="hljs-function">(<span class="hljs-params">{ item }</span>) =&gt;</span> &lt;Attempts item={item} /&gt;}
                keyExtractor={<span class="hljs-function">(<span class="hljs-params">item, index</span>) =&gt;</span> index.toString()}
                showsVerticalScrollIndicator={<span class="hljs-literal">false</span>}
            /&gt;
        &lt;/SafeAreaView&gt;
    );
}
</code></pre>
<p>The code snippet above displays the user's image, the sign-out button, and all the user's attempts. You can create an array of items for testing purposes.</p>
<h3 id="heading-how-to-build-the-stack-screens">How to Build the Stack Screens</h3>
<p>The Stack Screens comprise two screens – the quiz screen and the screen that displays the user's score after completing a quiz session.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/test-screens-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Stack Screens</em></p>
<h4 id="heading-the-quiz-screen">The Quiz Screen</h4>
<p>The Quiz Screen displays a timer that countdowns from 15 seconds before moving to the next question. It shows the question, its category, available options, the Skip and Next buttons, and a cancel icon.</p>
<p>Create a similar screen to the one shown below. You can use <a target="_blank" href="https://github.com/dha-stix/techtest-app/blob/main/app/(stack)/test.tsx">this</a> as a guide.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/test-screen.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The Quiz Screen</em></p>
<h4 id="heading-the-quiz-completion-screen">The Quiz Completion Screen</h4>
<p>It displays the user's score after completing a test.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {
    SafeAreaView,
    Text,
    Pressable,
    View,
    ImageBackground,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"react-native"</span>;
<span class="hljs-keyword">import</span> { MaterialIcons } <span class="hljs-keyword">from</span> <span class="hljs-string">"@expo/vector-icons"</span>;
<span class="hljs-keyword">import</span> { useLocalSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"expo-router"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CompletedScreen</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { score } = useLocalSearchParams();

    <span class="hljs-keyword">return</span> (
        &lt;View className=<span class="hljs-string">'flex flex-1 bg-orange-400'</span>&gt;
            &lt;ImageBackground
                source={{ uri: <span class="hljs-string">"https://source.unsplash.com/NAP14GEjvh8"</span> }}
                className=<span class="hljs-string">'flex-1 p-4'</span>
            &gt;
                &lt;SafeAreaView /&gt;
                &lt;Pressable onPress={<span class="hljs-function">() =&gt;</span> router.replace(<span class="hljs-string">"/(tabs)/"</span>)}&gt;
                    &lt;MaterialIcons name=<span class="hljs-string">'cancel'</span> size={<span class="hljs-number">60</span>} color=<span class="hljs-string">'white'</span> /&gt;
                &lt;/Pressable&gt;

                &lt;View className=<span class="hljs-string">'flex-1 flex items-center justify-center'</span>&gt;
                    &lt;View className=<span class="hljs-string">'bg-orange-50 w-full py-[50px] rounded-xl p-4 flex items-center justify-center shadow-lg shadow-orange-500'</span>&gt;
                        &lt;Text className=<span class="hljs-string">'text-3xl text-orange-600 font-bold mb-4'</span>&gt;
                            {<span class="hljs-built_in">Number</span>(score) &gt; <span class="hljs-number">20</span> ? <span class="hljs-string">"Congratulations🥳"</span> : <span class="hljs-string">"Sorry! You lose 🥲"</span>}
                        &lt;/Text&gt;
                        &lt;Text className=<span class="hljs-string">'font-bold text-xl'</span>&gt;You scored {score}!&lt;/Text&gt;
                    &lt;/View&gt;
                &lt;/View&gt;
            &lt;/ImageBackground&gt;
        &lt;/View&gt;
    );
}
</code></pre>
<p>The code snippet above accepts the user's score as a parameter after completing the quiz and displays the score to the user.</p>
<h2 id="heading-how-to-generate-quiz-questions-and-answers-from-chatgpt">How to Generate Quiz Questions and Answers from ChatGPT</h2>
<p>When building a quiz application, the first question is: how do you get the questions and options for the application? You can either create a list of questions or search for a suitable public API.</p>
<p>However, I'll guide you through creating a list of questions and options in JSON format using ChatGPT. Use this prompt to generate questions and answers from ChatGPT:</p>
<blockquote>
<p><em>Generate 25 distinct questions on  and ensure they are in JSON format containing an id, category which is , a question attribute containing the question, an options array of 3 options, and an answer property.</em></p>
</blockquote>
<p>The prompt returns a JSON result containing the questions and answers. You can host them on GitHub or save them to a database.</p>
<p>The questions and answers I'm using in this mobile application are available on <a target="_blank" href="https://github.com/dha-stix/trivia-app/tree/main/questions">GitHub</a>. Feel free to clone or copy the files.</p>
<p>Once your questions and answers are ready, you can connect the application to Supabase.</p>
<h2 id="heading-how-to-add-supabase-to-react-native">How to Add Supabase to React Native</h2>
<p>Supabase is an open-source Firebase alternative that enables you to create secured and scalable software applications within a few minutes.</p>
<p>It provides a secured Postgres database, a complete user management system that handles various forms of authentication (including email and password, email sign-in, and social authentication), a file storage system that lets you store and serve files of any size, real-time communication, and many other features.</p>
<p>In this tutorial, I'll walk you through the following:</p>
<ul>
<li>How to authenticate users and control access to some application screens with Supabase.</li>
<li>How to save the users' scores to the database to enable you to rank them based on their scores.</li>
</ul>
<p>First, you need to install Supabase and its required dependencies. You can do that with the following commands:</p>
<pre><code class="lang-bash">npm install @supabase/supabase-js 
npm install react-native-elements @react-native-async-storage/async-storage react-native-url-polyfill
npx expo install expo-secure-store
</code></pre>
<p>Create a <code>supabase.ts</code> file within your project and copy the code snippet below into the file to initiate Supabase:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">"react-native-url-polyfill/auto"</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> SecureStore <span class="hljs-keyword">from</span> <span class="hljs-string">"expo-secure-store"</span>;
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/supabase-js"</span>;

<span class="hljs-keyword">const</span> ExpoSecureStoreAdapter = {
    getItem: <span class="hljs-function">(<span class="hljs-params">key: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> SecureStore.getItemAsync(key);
    },
    setItem: <span class="hljs-function">(<span class="hljs-params">key: <span class="hljs-built_in">string</span>, value: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
        SecureStore.setItemAsync(key, value);
    },
    removeItem: <span class="hljs-function">(<span class="hljs-params">key: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
        SecureStore.deleteItemAsync(key);
    },
};

<span class="hljs-keyword">const</span> supabaseUrl = <span class="hljs-string">"YOUR_REACT_NATIVE_SUPABASE_URL"</span>;
<span class="hljs-keyword">const</span> supabaseAnonKey = <span class="hljs-string">"YOUR_REACT_NATIVE_SUPABASE_ANON_KEY"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> supabase = createClient(supabaseUrl, supabaseAnonKey, {
    auth: {
        storage: ExpoSecureStoreAdapter <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>,
        autoRefreshToken: <span class="hljs-literal">true</span>,
        persistSession: <span class="hljs-literal">true</span>,
        detectSessionInUrl: <span class="hljs-literal">false</span>,
    },
});
</code></pre>
<p>Next, visit the <a target="_blank" href="https://supabase.com">Supabase homepage</a>, sign in, and create a new organization and project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/project.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create a new Supabase project</em></p>
<p>Click the Settings icon on the sidebar and select API to copy the project URL and the public API key.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-24-at-17.50.34.png" alt="Image" width="600" height="400" loading="lazy">
<em>Supabase API settings containing project credentials</em></p>
<p>Create a <code>.env.local</code> file and copy the credentials into the variables. Update the <code>supabase.ts</code> file to use the Supabase URL and API key.</p>
<pre><code class="lang-txt">EXPO_PUBLIC_API_URL=&lt;YOUR_SUPABASE_URL&gt;
EXPO_PUBLIC_API_KEY=&lt;YOUR_SUPABASE_API_KEY&gt;
</code></pre>
<p>Congratulations! You can now interact with Supabase from your application and access various features such as authentication, database, file storage, and so on.</p>
<h2 id="heading-how-to-add-supabase-authentication-to-react-native-applications">How to Add Supabase Authentication to React Native Applications</h2>
<p>Supabase offers various forms of authentication. But we only need the email and password method of authentication for this application.</p>
<h3 id="heading-how-to-sign-up-new-users">How to sign up new users</h3>
<p>The code snippet below accepts an email and a password and creates an account for the user. Otherwise, it returns an error if any of the credentials is invalid.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//👇🏻 import supabase from supabase file</span>
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/supabase"</span>;

<span class="hljs-comment">//👇🏻 sign up function</span>
<span class="hljs-keyword">const</span> handleRegister = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (!email.trim() || !password.trim())
        <span class="hljs-keyword">return</span> Alert.alert(<span class="hljs-string">"Error"</span>, <span class="hljs-string">"Please fill in all fields"</span>);
    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signUp({ email, password });
    <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> Alert.alert(<span class="hljs-string">"Error"</span>, error.message);
    router.replace(<span class="hljs-string">"/"</span>);
};
</code></pre>
<p>With the <code>supabase.auth.signUp()</code> function, Supabase handles the authentication process. If successful, the user is redirected to the login page. Otherwise, it displays an error message.</p>
<h3 id="heading-how-to-sign-in-existing-users">How to sign in existing users</h3>
<p>This function allows existing users to access the application. It accepts the user's email and password and logs the user into the application.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//👇🏻 import supabase from supabase file</span>
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/supabase"</span>;

<span class="hljs-comment">//👇🏻 register function</span>
<span class="hljs-keyword">const</span> handleLogin = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (!email.trim() || !password.trim())
        <span class="hljs-keyword">return</span> Alert.alert(<span class="hljs-string">"Error"</span>, <span class="hljs-string">"Please fill in all fields"</span>);
    <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signInWithPassword({ email, password });
    <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> Alert.alert(<span class="hljs-string">"Error"</span>, error.message);
    router.replace(<span class="hljs-string">"/(tabs)/"</span>);
};
</code></pre>
<p>The <code>supabase.auth.signInWithPassword()</code> function validates the user's email and password and redirects the user to the Dashboard screen. Otherwise, it returns the necessary authentication error.</p>
<h3 id="heading-how-to-log-users-out-of-the-application">How to log users out of the application</h3>
<p>Supabase also allows users to sign out of the application. You can execute this function when the user clicks a button within the Profile page.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">//👇🏻 import supabase from supabase file</span>
<span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/supabase"</span>;

<span class="hljs-comment">//👇🏻 sign out function</span>
<span class="hljs-keyword">const</span> handleSignOut = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { error } = <span class="hljs-keyword">await</span> supabase.auth.signOut();
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
    }
};
</code></pre>
<h3 id="heading-how-to-protect-screens-from-unauthenticated-users">How to protect screens from unauthenticated users</h3>
<p>You've been able to add the sign-up, sign-in, and log-out functionalities to the React Native application. But the Dashboard and other screens containing sensitive data are still accessible to unauthenticated users.</p>
<p>How do we fix this?</p>
<p>In this section, I'll walk you through how to protect screens from unauthorized users using the <a target="_blank" href="https://react.dev/reference/react/createContext">React Context API</a>.</p>
<p>The React Context API allows us to pass data through the component tree without needing to pass props down manually at every level.</p>
<p>Create an <code>AuthProvider.tsx</code> file. This is where the data to be passed down the application screens is stored. Copy the code snippet below into the file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { supabase } <span class="hljs-keyword">from</span> <span class="hljs-string">"./supabase"</span>;
<span class="hljs-keyword">import</span> { Session } <span class="hljs-keyword">from</span> <span class="hljs-string">"@supabase/supabase-js"</span>;
<span class="hljs-keyword">import</span> {
    PropsWithChildren,
    createContext,
    useContext,
    useEffect,
    useState,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">type</span> AuthData = {
    session: Session | <span class="hljs-literal">null</span>;
    loading: <span class="hljs-built_in">boolean</span>;
};

<span class="hljs-comment">//👇🏻 data to be passed down the components</span>
<span class="hljs-keyword">const</span> AuthContext = createContext&lt;AuthData&gt;({
    session: <span class="hljs-literal">null</span>,
    loading: <span class="hljs-literal">true</span>,
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AuthProvider</span>(<span class="hljs-params">{ children }: PropsWithChildren</span>) </span>{
    <span class="hljs-keyword">const</span> [session, setSession] = useState&lt;Session | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
    <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);

    <span class="hljs-comment">//👇🏻 fetches the current user's session</span>
    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> fetchSession = <span class="hljs-keyword">async</span> () =&gt; {
            <span class="hljs-keyword">const</span> {
                data: { session },
            } = <span class="hljs-keyword">await</span> supabase.auth.getSession();
            setSession(session);
            setLoading(<span class="hljs-literal">false</span>);
        };

        fetchSession();
        supabase.auth.onAuthStateChange(<span class="hljs-function">(<span class="hljs-params">_event, session</span>) =&gt;</span> {
            setSession(session);
            setLoading(<span class="hljs-literal">false</span>);
        });
    }, []);

    <span class="hljs-keyword">return</span> (
        &lt;AuthContext.Provider value={{ session, loading }}&gt;
            {children}
        &lt;/AuthContext.Provider&gt;
    );
}
<span class="hljs-comment">//👇🏻 custom hook for using the context (data)</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useAuth = <span class="hljs-function">() =&gt;</span> useContext(AuthContext);
</code></pre>
<p>The code snippet retrieves the current user's session. If the user is signed in, the session and loading state variables are updated to show that the user is active, and they are passed into other components within the application.</p>
<p>The <code>useAuth</code> custom hook allows you to access the state variables (session and loading) within the application screens.</p>
<p>To access the context (data) available within the application screens, wrap the entire application with the <code>AuthProvider</code>. So now, update the <code>RootLayoutNav</code> component within the <code>app/_layout.tsx</code> file as shown below:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> AuthProvider <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/AuthProvider"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayoutNav</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
        &lt;AuthProvider&gt;
            &lt;Stack screenOptions={{ headerShown: <span class="hljs-literal">false</span> }}&gt;
                &lt;Stack.Screen name=<span class="hljs-string">'(tabs)'</span> /&gt;
                &lt;Stack.Screen name=<span class="hljs-string">'(stack)'</span> /&gt;
                &lt;Stack.Screen name=<span class="hljs-string">'index'</span> /&gt;
                &lt;Stack.Screen name=<span class="hljs-string">'register'</span> /&gt;
            &lt;/Stack&gt;
        &lt;/AuthProvider&gt;
    );
}
</code></pre>
<p>Congratulations! You've successfully set up the context. Next, how do we read the context and ensure that only authenticated users can view some of the application screens?</p>
<p>You can do this using the custom <code>useAuth</code> hook. For example, you can protect the Tabs screens via the <code>(tabs)/_layout.tsx</code> file.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Tabs, Redirect } <span class="hljs-keyword">from</span> <span class="hljs-string">"expo-router"</span>;
<span class="hljs-keyword">import</span> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../lib/AuthProvider"</span>;
<span class="hljs-keyword">import</span> { ActivityIndicator } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-native"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TabScreen</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { session, loading } = useAuth();

    <span class="hljs-keyword">if</span> (!session) {
        <span class="hljs-keyword">return</span> &lt;Redirect href=<span class="hljs-string">'/'</span> /&gt;;
    }

    <span class="hljs-keyword">if</span> (loading) {
        <span class="hljs-keyword">return</span> &lt;ActivityIndicator size=<span class="hljs-string">'large'</span> color=<span class="hljs-string">'#f97316'</span> /&gt;;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> (
            &lt;Tabs
                screenOptions={{
                    tabBarActiveTintColor: <span class="hljs-string">"#f97316"</span>,
                    tabBarInactiveTintColor: <span class="hljs-string">"gray"</span>,
                    tabBarShowLabel: <span class="hljs-literal">false</span>,
                    headerShown: <span class="hljs-literal">false</span>,
                    tabBarStyle: {
                        backgroundColor: <span class="hljs-string">"#ffedd5"</span>,
                        borderTopColor: <span class="hljs-string">"#ffedd5"</span>,
                    },
                }}
            &gt;
                {<span class="hljs-comment">/**-- screens--*/</span>}
            &lt;/Tabs&gt;
        );
    }
}
</code></pre>
<p>The code snippet above checks if there is a session for the current user. If null, the application redirects the user to the login screen. If the application is yet to determine the user's status, it displays a loading icon.</p>
<h2 id="heading-how-to-interact-with-the-supabase-database">How to Interact with the Supabase Database</h2>
<p>In this section, I'll walk you through creating the database for the mobile application. You'll learn how to store and retrieve the user's scores and rank them based on their total score.</p>
<p>Before we proceed, note that the application calculates the user's score after answering each question on the test screen. Upon completion, the user's score is retrieved and displayed on the test completion screen.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> handleSave = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">//👇🏻 checks if the user has not completed the test</span>
    <span class="hljs-keyword">if</span> (count &lt; questions.length - <span class="hljs-number">1</span>) {
        <span class="hljs-comment">//👇🏻 updates the user's score if the selected answer is correct</span>
        <span class="hljs-keyword">if</span> (questions[count].answer === userAnswer) {
            setUserScore(<span class="hljs-function">(<span class="hljs-params">userScore</span>) =&gt;</span> userScore + <span class="hljs-number">1</span>);
        }
        <span class="hljs-comment">//👇🏻 change the question, refresh the selected answer and time</span>
        setCount(<span class="hljs-function">(<span class="hljs-params">count</span>) =&gt;</span> count + <span class="hljs-number">1</span>);
        setSelectedBox(<span class="hljs-literal">null</span>);
        setTime(<span class="hljs-number">15</span>);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">//👇🏻 test completed</span>
        router.push({
            pathname: <span class="hljs-string">"/(stack)/completed"</span>,
            params: { score: userScore },
        });
    }
};
</code></pre>
<p>Within your Supabase project, select Table Editor from the sidebar menu and create a new table containing the following columns:</p>
<ul>
<li><code>id</code> – contains a unique ID for each row of data.</li>
<li><code>created_at</code> – represents the time the data was created.</li>
<li><code>attempts</code> – a text array containing the score and date attributes.</li>
<li><code>total_score</code> – represents a user's cumulative score. We'll rank users using this score</li>
<li><code>user_id</code> – a unique ID used to identify each user's data.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-24-at-10.05.55.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Table Columns</em></p>
<p>Finally, you can add a Row Level Security that allows only authenticated users interact with the database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Screenshot-2024-02-24-at-10.20.51.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Table Row Level Security Policy</em></p>
<h3 id="heading-how-to-save-the-users-score-to-the-database">How to save the user's score to the database</h3>
<p>Before you can save a user's score to the database, you need to check if the user's data already exists – meaning the user has taken a test before. If true, you need to update the user's score with the latest test score. Otherwise, add the data to the database.</p>
<p>The code snippet below accepts the user's score and user's ID (from the session data) and saves the user's score to Supabase.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> saveScore = <span class="hljs-keyword">async</span> (userScore: <span class="hljs-built_in">number</span>, userID: <span class="hljs-built_in">string</span>) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">//👇🏻 check if the user data exists</span>
        <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
            .from(<span class="hljs-string">"scores"</span>)
            .select()
            .eq(<span class="hljs-string">"user_id"</span>, userID);
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;

        <span class="hljs-comment">//👇🏻 if the user data does not exist, insert a new one</span>
        <span class="hljs-keyword">if</span> (error || !data.length) {
            <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
                .from(<span class="hljs-string">"scores"</span>)
                .insert({
                    attempts: [{ score: userScore, date: getCurrentDate() }],
                    total_score: userScore,
                    user_id: userID,
                })
                .single();
            <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">//👇🏻 if the user data exists, update the attempts and total_score</span>
            <span class="hljs-keyword">const</span> { data: updateData, error } = <span class="hljs-keyword">await</span> supabase
                .from(<span class="hljs-string">"scores"</span>)
                .update({
                    attempts: [
                        ...data[<span class="hljs-number">0</span>].attempts,
                        { score: userScore, date: getCurrentDate() },
                    ],
                    total_score: data[<span class="hljs-number">0</span>].total_score + userScore,
                })
                .eq(<span class="hljs-string">"user_id"</span>, userID);
            <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
        }
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.log(err);
    }
};
</code></pre>
<h3 id="heading-how-to-retrieve-data-from-supabase">How to retrieve data from Supabase</h3>
<p>Recall that you need to rank the users based on their scores on the Leaderboard screen and retrieve the user's attempts on the Profile screen.</p>
<p>The code snippet below accepts a user's ID and retrieves the attempts and total score from the database.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getUserAttempts = <span class="hljs-keyword">async</span> (userID: <span class="hljs-built_in">string</span>) =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
            .from(<span class="hljs-string">"scores"</span>)
            .select(<span class="hljs-string">"attempts, total_score"</span>)
            .eq(<span class="hljs-string">"user_id"</span>, userID);
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
        <span class="hljs-keyword">return</span> { attempts: data[<span class="hljs-number">0</span>].attempts, total_score: data[<span class="hljs-number">0</span>].total_score };
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> { attempts: <span class="hljs-string">""</span>, total_score: <span class="hljs-number">0</span> };
    }
};
</code></pre>
<p>The code snippet below retrieves the top ten users from the database based on their score.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getLeaderBoard = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
            .from(<span class="hljs-string">"scores"</span>)
            .select(<span class="hljs-string">"total_score, user_id"</span>)
            .order(<span class="hljs-string">"total_score"</span>, { ascending: <span class="hljs-literal">false</span> })
            .limit(<span class="hljs-number">10</span>);
        <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">throw</span> error;
        <span class="hljs-keyword">return</span> data;
    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
    }
};
</code></pre>
<p>Congratulations! You've successfully completed the project for this tutorial.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you’ve learned how to:</p>
<ul>
<li>build React Native mobile applications with Expo,</li>
<li>style your mobile applications with <a target="_blank" href="https://www.nativewind.dev/">Tailwind CSS</a>,</li>
<li>create stack and tab screen navigations using <a target="_blank" href="https://docs.expo.dev/router/introduction/">Expo Router</a>,</li>
<li>use Supabase and leverage its authentication and database features to build full-stack applications.</li>
</ul>
<p>Supabase is an amazing tool that enables you to build a full-stack software application with no hassle. If you are looking forward to shipping great software products or side projects faster, consider using Supabase.</p>
<p>Expo also saves us from the complexities of setting up and developing mobile applications using the <a target="_blank" href="https://reactnative.dev/docs/environment-setup">React Native CLI</a>. It enables you to focus more on building your applications while it handles the necessary configurations, including deployment.</p>
<p>Feel free to customise the application using <a target="_blank" href="https://chat.openai.com/">ChatGPT</a> to generate questions and answers tailored to any niche or topic.</p>
<p>The source code for this tutorial is available in this <a target="_blank" href="https://github.com/dha-stix/techtest-app">GitHub repository</a>.</p>
<p>Thank you for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Mobile Swiping Component in React ]]>
                </title>
                <description>
                    <![CDATA[ Everyone wants to be able to access the web from their mobile phones these days. So it's important to consider the accessibility of your web app on Android and iPhones.  The most difficult part is building the navigation – and swiping in particular c... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-mobile-swiping-component-in-react/</link>
                <guid isPermaLink="false">66bc4cff3fc58765eaa843c8</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matéu.sh ]]>
                </dc:creator>
                <pubDate>Fri, 02 Feb 2024 17:43:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/MobileSwiping-splash--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Everyone wants to be able to access the web from their mobile phones these days. So it's important to consider the accessibility of your web app on Android and iPhones. </p>
<p>The most difficult part is building the navigation – and swiping in particular can cause a lot of headaches. There are libraries you can use to help with this, but why not build it on your own? </p>
<p>In this tutorial, I will teach you how to create your own mobile swiping component in React. You can do it in 50 lines of JavaScript. </p>
<p>Initially, I created this component for my pet project, the 2048 Game in React, and have now decided to share how I did it. </p>
<p>If you want to try it out before reading the whole article, you can <a target="_blank" href="https://mateuszsokola.github.io/2048-in-react/">play the game here</a> (use your mobile device). In this tutorial, we will focus on mobile swiping only.  </p>
<p>You can find the following resources on GitHub:</p>
<ul>
<li>📱 <a target="_blank" href="https://gist.github.com/mateuszsokola/80b2a939ad521eb26f488fcdc659e0ca">Source code of the component</a></li>
<li>🕹️ <a target="_blank" href="https://github.com/mateuszsokola/2048-in-react/">Source code of 2048 Game</a></li>
</ul>
<p>Here is the sneak peak (the quality isn't the best because I was trying to keep the size small):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/MobilePreview-low--1-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The final result in my pet project</em></p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-simulate-a-mobile-device-in-your-browser">How to Simulate a Mobile Device in Your Browser</a></li>
<li><a class="post-section-overview" href="#heading-the-mobileswiper-component">The MobileSwiper Component</a></li>
<li><a class="post-section-overview" href="#heading-lets-make-it-swipable">Let's Make it Swipable</a></li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
</ol>
<h2 id="heading-prerequisites">🛠️ P<strong>rerequisites</strong></h2>
<p>Before we start, make sure you know a little bit about React and JavaScript. You don't need any sophisticated tools, but if you want to run the example project on your computer, then you will need to install <a target="_blank" href="https://nodejs.org/en">Node.js</a> first.</p>
<p>Also, I'm using <a target="_blank" href="https://www.google.com/chrome/">Google Chrome</a> to simulate a mobile device on my computer. Keep in mind that if you use any different browser, then the steps might be slightly different.</p>
<h2 id="heading-how-to-simulate-a-mobile-device-in-your-browser">🔍 <strong>How to Simulate a Mobile Device in Your Browser</strong></h2>
<p>Before we start coding, I need to show you how to simulate a mobile device in Google Chrome. </p>
<p>Open your browser, right click on your page, and choose "<em>Inspect</em>" from the dropdown menu.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/MobileSwiper-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>How to open Developer Tools in Google Chrome</em></p>
<p>Your browser view should now be split into two parts. The second part contains Chrome's Developer Tools. </p>
<p>Now, click on the "laptop &amp; mobile" icon (1 in the image below) in top left corner of the Developer tools. Then select the "Dimensions" (2) of the device you want to simulate. I chose iPhone SE because this device has the smallest resolution supported by my game.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/MobileSwiper-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Choose device dimensions in Developer Tools (Google Chrome)</em></p>
<p>Now we are ready to simulate swiping by using our mouse or touchpad. Just pay attention to the GIF below – my cursor turned into a circle which is supposed to visualize the area covered by a person's finger. </p>
<p>When I try to swipe, my browser thinks I am actually scrolling through the website. In my case, this isn't an expected behavior. I would like to instead use swipes to play the game.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/game-v2-broken.gif" alt="Image" width="600" height="400" loading="lazy">
<em>By default, scrolling events are associated with swipes</em></p>
<h2 id="heading-the-mobileswiper-component">🤓 The MobileSwiper Component</h2>
<p>First, we need to create a <strong>mobile-swiper</strong>.<strong>jsx</strong> file. In this file, we declare a standard React component. Our component needs to accept two properties – <code>children</code> and <code>onSwipe</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>   
}
</code></pre>
<p>Let me briefly explain them:</p>
<ul>
<li><code>children</code> allows <code>MobileSwiper</code> to accept and render any content placed between its opening and closing tags. It enables you to inject the entire board inside this component – but we will get to this later.</li>
<li><code>onSwipe</code> is a callback that our component will trigger each time the user swipes within the "swipable" area. </li>
</ul>
<p>Let's define the swipable area now. First, you need to add a reference to the DOM element in which you want to allow swiping. You can do this by using the <code>useRef</code> hook. So declare a constant called <code>wrapperRef</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-keyword">const</span> wrapperRef = useRef(<span class="hljs-literal">null</span>)

    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>

}
</code></pre>
<p>Side note: The <code>useRef</code> is a React Hook that lets you reference a value that’s not needed for rendering. It’s particularly common to use it to manipulate the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API">DOM</a>. React has built-in support for this.</p>
<p>Now you just need to return the <code>&lt;div /&gt;</code> that references the constant you created using the <code>useRef</code> hook.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-keyword">const</span> wrapperRef = useRef(<span class="hljs-literal">null</span>)

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{wrapperRef}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
</code></pre>
<p>Let's think for a moment how we can detect swiping. I believe the easiest way is comparing the starting and ending position of the user's finger. </p>
<p>This means we need to store the initial position of the user's finger in state. Basically, we will store <code>x</code> and <code>y</code> coordinates using the <code>useState</code> hook.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-keyword">const</span> wrapperRef = useRef(<span class="hljs-literal">null</span>)
    <span class="hljs-keyword">const</span> [startX, setStartX] = useState(<span class="hljs-number">0</span>)
    <span class="hljs-keyword">const</span> [startY, setStartY] = useState(<span class="hljs-number">0</span>)    

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{wrapperRef}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
</code></pre>
<p>Now we need to create two event callbacks:</p>
<ul>
<li><code>handleTouchStart</code> will set the starting position of the user's finger.</li>
<li><code>handleTouchEnd</code> will set the final position of the user's finger and calculate the shift (delta) based on the starting point.</li>
</ul>
<p>Let's start with the <code>handleTouchStart</code> event handler:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useCallback, useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-keyword">const</span> wrapperRef = useRef(<span class="hljs-literal">null</span>)
    <span class="hljs-keyword">const</span> [startX, setStartX] = useState(<span class="hljs-number">0</span>)
    <span class="hljs-keyword">const</span> [startY, setStartY] = useState(<span class="hljs-number">0</span>)    

    <span class="hljs-keyword">const</span> handleTouchStart = useCallback(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!wrapperRef.current.contains(e.target)) {
              <span class="hljs-keyword">return</span>
        }

        e.preventDefault()

        setStartX(e.touches[<span class="hljs-number">0</span>].clientX)
        setStartY(e.touches[<span class="hljs-number">0</span>].clientY)
      }, [])

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{wrapperRef}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
</code></pre>
<p>Let me briefly explain it:</p>
<ol>
<li>I wrapped this helper into the <code>useCallback</code> hook to cache and improve its performance. If you don't know this hook, you can read about it in the official <a target="_blank" href="https://react.dev/reference/react/useCallback">React docs</a>.</li>
<li>The <code>if</code> statement checks if the user is swiping within the swipable area. If they swipe outside of this area, we will proceed with scrolling.</li>
<li><code>e.preventDefault()</code> disables the default scrolling event.</li>
<li>The last two lines store <code>x</code> and <code>y</code> coordinates in state.</li>
</ol>
<p>Now let's implement the <code>handleTouchEnd</code> event handler:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useCallback, useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-keyword">const</span> wrapperRef = useRef(<span class="hljs-literal">null</span>)
    <span class="hljs-keyword">const</span> [startX, setStartX] = useState(<span class="hljs-number">0</span>)
    <span class="hljs-keyword">const</span> [startY, setStartY] = useState(<span class="hljs-number">0</span>)    

    <span class="hljs-keyword">const</span> handleTouchStart = useCallback(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!wrapperRef.current.contains(e.target)) {
              <span class="hljs-keyword">return</span>
        }

        e.preventDefault()

        setStartX(e.touches[<span class="hljs-number">0</span>].clientX)
        setStartY(e.touches[<span class="hljs-number">0</span>].clientY)
    }, [])

      <span class="hljs-keyword">const</span> handleTouchEnd = useCallback(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!wrapperRef.current.contains(e.target)) {
            <span class="hljs-keyword">return</span>
        }

        e.preventDefault()

        <span class="hljs-keyword">const</span> endX = e.changedTouches[<span class="hljs-number">0</span>].clientX
        <span class="hljs-keyword">const</span> endY = e.changedTouches[<span class="hljs-number">0</span>].clientY
        <span class="hljs-keyword">const</span> deltaX = endX - startX
        <span class="hljs-keyword">const</span> deltaY = endY - startY

        onSwipe({ deltaX, deltaY })
    }, [startX, startY, onSwipe])

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{wrapperRef}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
</code></pre>
<p>As you can see, steps 1-3 are exactly the same as in the <code>handleTouchStart</code> callback. Now, we'll take the final <code>x</code> and <code>y</code> coordinates of user's finger and deduct the initial <code>x</code> and <code>y</code> from those. Thanks to that we can calculate horizontal and vertical shift of the user's finger (deltas).</p>
<p>Then we pass those deltas onto the <code>onSwipe</code> callback. If you remember, we declared it in the component's props at the beginning. </p>
<p>Now we need to connect those callbacks into the event listener. To do so, we can use the <code>useEffect</code> hook from React.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useCallback, useEffect, useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-keyword">const</span> wrapperRef = useRef(<span class="hljs-literal">null</span>)
    <span class="hljs-keyword">const</span> [startX, setStartX] = useState(<span class="hljs-number">0</span>)
    <span class="hljs-keyword">const</span> [startY, setStartY] = useState(<span class="hljs-number">0</span>)    

    <span class="hljs-keyword">const</span> handleTouchStart = useCallback(<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!wrapperRef.current.contains(e.target)) {
              <span class="hljs-keyword">return</span>
        }

        e.preventDefault()

        setStartX(e.touches[<span class="hljs-number">0</span>].clientX)
        setStartY(e.touches[<span class="hljs-number">0</span>].clientY)
      }, [])

      <span class="hljs-keyword">const</span> handleTouchEnd = useCallback(
    <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!wrapperRef.current.contains(e.target)) {
            <span class="hljs-keyword">return</span>
        }

        e.preventDefault()

        <span class="hljs-keyword">const</span> endX = e.changedTouches[<span class="hljs-number">0</span>].clientX
        <span class="hljs-keyword">const</span> endY = e.changedTouches[<span class="hljs-number">0</span>].clientY
        <span class="hljs-keyword">const</span> deltaX = endX - startX
        <span class="hljs-keyword">const</span> deltaY = endY - startY

        onSwipe({ deltaX, deltaY })
    }, [startX, startY, onSwipe])   

     useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"touchstart"</span>, handleTouchStart)
        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"touchend"</span>, handleTouchEnd)

        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
            <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"touchstart"</span>, handleTouchStart)
            <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"touchend"</span>, handleTouchEnd)
        }
      }, [handleTouchStart, handleTouchEnd])

    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{wrapperRef}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
</code></pre>
<p>You can read more about the <code>useEffect</code> hook in the official <a target="_blank" href="https://react.dev/reference/react/useEffect">React docs</a>.</p>
<p>The <strong>MobileSwiper</strong> component is ready now.</p>
<h2 id="heading-lets-make-it-swipable">🔌 Let's Make It Swipable</h2>
<p>The last thing we need to do is hook our component to the application. As I mentioned, I will be using this component in my 2048 Game (<a target="_blank" href="https://github.com/mateuszsokola/2048-in-react/">Source code</a>). If you want to use it somewhere else, the <code>handleSwipe</code> helper and the MobileSwiper component will remain the same.</p>
<p> Let's plug it into the Board component:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useCallback, useContext, useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { Tile <span class="hljs-keyword">as</span> TileModel } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/models/tile"</span>
<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">"@/styles/board.module.css"</span>
<span class="hljs-keyword">import</span> Tile <span class="hljs-keyword">from</span> <span class="hljs-string">"./tile"</span>
<span class="hljs-keyword">import</span> { GameContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/context/game-context"</span>
<span class="hljs-keyword">import</span> MobileSwiper <span class="hljs-keyword">from</span> <span class="hljs-string">"./mobile-swiper"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Board</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { getTiles, moveTiles, startGame } = useContext(GameContext);

    <span class="hljs-comment">// ... removed irrelevant parts ...</span>

    <span class="hljs-keyword">const</span> handleSwipe = useCallback(<span class="hljs-function">(<span class="hljs-params">{ deltaX, deltaY }</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.abs(deltaX) &gt; <span class="hljs-built_in">Math</span>.abs(deltaY)) {
            <span class="hljs-keyword">if</span> (deltaX &gt; <span class="hljs-number">0</span>) {
                moveTiles(<span class="hljs-string">"move_right"</span>)
            } <span class="hljs-keyword">else</span> {
                moveTiles(<span class="hljs-string">"move_left"</span>)
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">if</span> (deltaY &gt; <span class="hljs-number">0</span>) {
                moveTiles(<span class="hljs-string">"move_down"</span>)
            } <span class="hljs-keyword">else</span> {
                moveTiles(<span class="hljs-string">"move_up"</span>)
            }
        }
    }, [moveTiles])

     <span class="hljs-comment">// ... removed irrelevant parts ...</span>

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MobileSwiper</span> <span class="hljs-attr">onSwipe</span>=<span class="hljs-string">{handleSwipe}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.board}</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.tiles}</span>&gt;</span>{renderTiles()}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.grid}</span>&gt;</span>{renderGrid()}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">MobileSwiper</span>&gt;</span></span>
      )
}
</code></pre>
<p>Let's start with the <code>handleSwipe</code> handler. As you can see, we're comparing if <code>deltaX</code> is greater than <code>deltaY</code> to decide if the user swiped horizontally (left / right) or vertically (top / bottom).</p>
<p>If it was a horizontal swipe, then:</p>
<ul>
<li>negative <code>deltaX</code> means they swiped to the left.</li>
<li>positive <code>deltaX</code> means they swiped to the right.</li>
</ul>
<p>If it was a vertical swipe, then:</p>
<ul>
<li>negative <code>deltaY</code> means they swiped up.</li>
<li>positive <code>deltaY</code> means they swiped down.</li>
</ul>
<p>Now, let's focus on the MobileSwiper component. You can find it in the <code>return</code> statement. We're passing the <code>handleSwipe</code> helper to the <code>onSwipe</code> property and wrapping the entire HTML code of the Board component to enable swiping on it.</p>
<p>Now when we try it out, the result isn't ideal. Scrolling events are mixed with mobile swipes, as you can see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/game-v2-passive-true.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Board with duplicated events – swipes and scrolling</em></p>
<p>This is happening because modern browsers use passive event listeners to improve the scrolling experience on mobile devices. This means that the <code>preventDefault</code> we added to our event callbacks never happens. </p>
<p>To disable scrolling behavior, we need to disable passive listeners on the MobileSwiper component:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useCallback, useEffect, useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MobileSwiper</span>(<span class="hljs-params">{ children, onSwipe }</span>) </span>{
    <span class="hljs-comment">// ... removed to improve visibility ...</span>

     useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"touchstart"</span>, handleTouchStart, { <span class="hljs-attr">passive</span>: <span class="hljs-literal">false</span> })
        <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"touchend"</span>, handleTouchEnd, { <span class="hljs-attr">passive</span>: <span class="hljs-literal">false</span> })
        <span class="hljs-comment">// ... removed to improve visibility ...</span>
      }, [handleTouchStart, handleTouchEnd])

    <span class="hljs-comment">// ... removed to improve visibility ...</span>
}
</code></pre>
<p>Now the scrolling behavior is gone and the 2048 Game looks just awesome:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/game-v2-works.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Final result - swiping works!</em></p>
<h2 id="heading-summary">🏁 Summary</h2>
<p>Today I showed you that you don't always need libraries to handle mobile gestures in React. Some simple events such as swiping can be implemented using basic React features. We just used a bunch of React hooks and wrote two simple event handlers. </p>
<p>The entire implementation has exactly 50 lines of code. I hope I inspired you to try to deal with mobile events on your own.</p>
<p>If this article helped you, please <a target="_blank" href="https://twitter.com/msokola">let me know on Twitter</a>. Educators like me often feel like we are speaking into a vacuum and nobody cares what we teach. A simple "shoutout" shows it was worth an effort and inspires me to create more content like this.</p>
<p>Please share this article on your social media. Thank you!</p>
<h2 id="heading-create-your-own-2048-game">🎥 Create Your Own 2048 Game</h2>
<p>This article is a part of my course on Udemy where I teach how to create a fully-functional 2048 Game in Next.js from scratch. </p>
<h3 id="heading-join-my-nextjs-course-on-udemyhttpswwwudemycomcourse2048-in-react-and-nextjsreferralcodeac3fd6336bab9c402106">🧑‍🎓 Join my <a target="_blank" href="https://www.udemy.com/course/2048-in-react-and-nextjs/?referralCode=AC3FD6336BAB9C402106">Next.js course on Udemy</a></h3>
<p>Use code <strong>FREECODECAMP</strong> to enroll to get a 60% discount.</p>
<p>I believe programming should be fun and unleash creativity. You don't have to build yet another TODO list or a shopping cart. Instead, you can build something that you can show to your friends or maybe even a hiring manager!</p>
<p>PS. If you prefer to watch screencasts, then this lesson is available on Udemy for free. You can find it under the "<em>Responsive Layout and Missing Game Feature</em>" section in the lecture called "<em>Game layout and mobile swipes</em>".  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Custom Animations in Flutter – A Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ Animations play a crucial role in enhancing user experience and making mobile apps more engaging.  Flutter, Google's UI toolkit for building natively compiled applications for mobile, web, and desktop, offers a powerful animation system that allows d... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/creating-custom-animations-in-flutter/</link>
                <guid isPermaLink="false">66ba10a1d14c87384322b69f</guid>
                
                    <category>
                        <![CDATA[ animations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Wed, 26 Jul 2023 17:44:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/Flutter-Animation.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Animations play a crucial role in enhancing user experience and making mobile apps more engaging. </p>
<p>Flutter, Google's UI toolkit for building natively compiled applications for mobile, web, and desktop, offers a powerful animation system that allows developers to create stunning custom animations. </p>
<p>In this step-by-step guide, we will explore how to build beautiful custom animations in Flutter to take your app's UI to the next level.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>Before we start, make sure you have Flutter installed on your system. It's also useful to have a basic understanding of the framework's fundamental concepts, such as widgets, state management, and gesture handling.</p>
<p>Finally, but most importantly, muster up a small spark of interest in learning animation! :) Because once you see the widgets come to life with animation magic, that spark's gonna grow into a blazing inferno of excitement.</p>
<p>In this guide, we are going to see how to implement animation in two kinds of tasks:</p>
<ol>
<li>Animated List</li>
<li>Animated Loader</li>
</ol>
<p>We are going to create a simple Todo app with Animated List and Animated Loader. So, saddle up, and let's ride into the world of animating lists and loaders in Flutter. 🤠🐴.</p>
<h2 id="heading-how-to-build-an-animated-list-in-flutter">How to Build an Animated List in Flutter</h2>
<p>First, we will create a simple Flutter list with animation. Animated List is a Flutter widget that allows developers to create dynamic and animated lists with smooth and visually appealing transitions. It is part of the Flutter animation framework and is an extension of the ListView widget. </p>
<p>The Animated List automatically animates changes to the list's content, such as inserting or removing items, providing an engaging and interactive user experience.</p>
<h3 id="heading-key-features">Key Features</h3>
<h4 id="heading-insertion-and-removal-animations">Insertion and Removal Animations</h4>
<p>When you add or remove items from the list, the Animated List animates these changes with predefined or custom animations, making the list's modifications visually seamless.</p>
<h4 id="heading-built-in-animation-controllers">Built-in Animation Controllers</h4>
<p>Animated List comes with built-in animation controllers that handle the timing and ease curves of the animations, simplifying the process of creating smooth and fluid transitions.</p>
<h4 id="heading-customizable-animations">Customizable Animations</h4>
<p>While Animated List provides default animations, developers can also customize the animations to fit the app's unique visual style and requirements.</p>
<p>Now, while theory is essential, practical examples bring concepts to life. So, let's dive into a practical example of using an Animated List in Flutter.</p>
<h3 id="heading-project-setup-and-dependencies">Project Setup and Dependencies</h3>
<p>To create our Flutter app, we'll use Visual Studio Code as our development environment. </p>
<p>If you're not familiar with setting up a new Flutter project, don't worry – you can refer to my previous <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-simple-login-app-with-flutter/">blogs</a> for step-by-step instructions. If you're already comfortable creating Flutter projects, skip this part and proceed with the app development.</p>
<p>No need to install any external plugin to create an Animated List.</p>
<h2 id="heading-how-to-create-a-task-model">How to Create a Task Model</h2>
<p>In this blog, we will focus more on animation so we can keep the functionalities simple. Define a Task class that represents a single task with a title and status.</p>
<p>I created a file called <code>todo_list.dart</code> in the <code>lib</code> folder that will contain the Animated List. First I created a simple class that represents a Task with title and status describing whether it's completed or not.</p>
<p><code>todo_list.dart</code></p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
  <span class="hljs-built_in">String</span> title;
  bool isCompleted;
  Task(<span class="hljs-built_in">this</span>.title, <span class="hljs-built_in">this</span>.isCompleted);
}
</code></pre><h2 id="heading-how-to-create-a-simple-list-with-animation">How to Create a Simple List with Animation</h2>
<p>Technically our goal is to create a scrolling container that animates items when inserted or removed. This widget's <a target="_blank" href="https://api.flutter.dev/flutter/widgets/AnimatedListState-class.html">AnimatedListState</a> can be used to dynamically insert or remove items. </p>
<p>To refer to the AnimatedListState either provide a <a target="_blank" href="https://api.flutter.dev/flutter/widgets/GlobalKey-class.html">GlobalKey</a> or use the static <a target="_blank" href="https://api.flutter.dev/flutter/widgets/AnimatedList/of.html">of</a> method from an item's input callback.</p>
<p>To do that, let's create a StatefulWidget to create an Animated List.</p>
<p><code>todo_list.dart</code></p>
<pre><code class="lang-dart"><span class="hljs-comment">// todo_list.dart</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">void</span> main() {
  runApp(TodoListApp());
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
  <span class="hljs-built_in">String</span> title;
  <span class="hljs-built_in">bool</span> isCompleted;
  Task(<span class="hljs-keyword">this</span>.title, <span class="hljs-keyword">this</span>.isCompleted);
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TodoListApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  _TodoListAppState createState() =&gt; _TodoListAppState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_TodoListAppState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">TodoListApp</span>&gt; </span>{
  <span class="hljs-built_in">List</span>&lt;Task&gt; tasks = [];
  <span class="hljs-built_in">bool</span> isLoading = <span class="hljs-keyword">false</span>;

  <span class="hljs-keyword">final</span> GlobalKey&lt;AnimatedListState&gt; _animatedListKey = GlobalKey();

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'ToDo List'</span>)),
        body: AnimatedList(
          key: _animatedListKey,
          initialItemCount: tasks.length,
          itemBuilder: (context, index, animation) {
            <span class="hljs-keyword">return</span> _buildTaskItem(tasks[index], animation, index);
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _addTask,
          child: <span class="hljs-keyword">const</span> Icon(Icons.add),
        ),
        backgroundColor: Colors.white60,
      ),
    );
  }

  Widget _buildTaskItem(Task task, Animation&lt;<span class="hljs-built_in">double</span>&gt; animation, <span class="hljs-built_in">int</span> index) {
    <span class="hljs-keyword">return</span> SizeTransition(
        sizeFactor: animation,
        child: Card(
          color: Colors.white,
          child: ListTile(
            title: Text(task.title),
            onLongPress: () =&gt; _removeTask(index),
          ),
        ));
  }

  <span class="hljs-keyword">void</span> _addTask() <span class="hljs-keyword">async</span> {
    Task newTask = Task(<span class="hljs-string">'New Task <span class="hljs-subst">${tasks.length + <span class="hljs-number">1</span>}</span>'</span>, <span class="hljs-keyword">false</span>);
    tasks.add(newTask);
    _animatedListKey.currentState!.insertItem(tasks.length - <span class="hljs-number">1</span>);
  }

  <span class="hljs-keyword">void</span> _removeTask(<span class="hljs-built_in">int</span> index) <span class="hljs-keyword">async</span> {
    _animatedListKey.currentState!.removeItem(index,
        (context, animation) =&gt; _buildTaskItem(tasks[index], animation, index));
    tasks.removeAt(index);
  }
}
</code></pre>
<p>Here, we used <code>AnimatedList</code> (a default Flutter package ). The <code>AnimatedList</code> class in Flutter is a powerful widget that allows us to create dynamic and animated lists with smooth transitions. It is an extension of the ListView widget, providing built-in animation support for adding, removing, and updating items in the list. </p>
<p>The primary goal of  <code>AnimatedList</code> is to enhance the user experience by animating changes to the list's content, making the app feel more interactive and visually engaging.</p>
<p><code>AnimatedList</code> has multiple properties or parameters that control various aspects of the widget's behavior, appearance, and animations. Understanding and using these props correctly is crucial to achieving the desired behavior and visual effects in an <code>AnimatedList</code>. </p>
<p>To know about the properties and behavior of <code>AnimatedList</code> please refer to the official <a target="_blank" href="https://api.flutter.dev/flutter/widgets/AnimatedList-class.html">documentation</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/flutter_animated_list_demo.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Simple Animated List in Flutter</em></p>
<p>In this tutorial, we will be focusing on Animated List and Animated Loader. If you are not familiar with Flutter basics (like widgets, states, and so on) I would recommend that you read my previous <a target="_blank" href="https://www.freecodecamp.org/news/learn-state-management-in-flutter/">tutorial</a>.</p>
<h2 id="heading-how-to-build-the-animated-loader">How to Build the Animated Loader</h2>
<p>A loader is commonly used to provide visual feedback to users while waiting for data to load, processing content, or completing network requests. Loaders help improve the user experience by giving a sense of activity and preventing the app from appearing unresponsive during waiting periods.</p>
<p>There are various ways to implement loaders in Flutter, including using built-in widgets, third-party packages, or creating custom loaders. Additionally, "animated loaders" add an extra touch of dynamism to the loading process by incorporating smooth animations.</p>
<p>Let's add an animated loader in our TodoApp while creating and deleting a task.</p>
<h3 id="heading-how-to-add-the-flutter-loader-package">How to Add the Flutter Loader Package</h3>
<p>You'll need to install the package with the following command:</p>
<pre><code>flutter pub add loading_animation_widget
</code></pre><p>Then you should see the following screen:</p>
<p><img src="https://www.gogosoon.com/wp-content/uploads/2023/07/image-28-1024x208.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing loading animation package in Flutter</em></p>
<p>Now your package should be ready for use.</p>
<h3 id="heading-how-to-implement-animatedloader">How to Implement <code>AnimatedLoader</code></h3>
<p>The <code>loading_animation_widget</code> package offers various loader animations that we can use to display loading indicators in our app. By importing the package, we gain access to these loader animations and can utilize them to enhance the user experience during loading operations or any other asynchronous tasks.</p>
<p>All loading animation APIs follow the same straightforward implementation. There is a static method for each animation inside the LoadingAnimationWidget class, which returns the Object of that animation. Both <code>size</code> and <code>color</code> are required some animations need more than one color.</p>
<p><code>loading_animation_widget</code> offers multiple animated loaders with customized animation. Let's explore a few of those and integrate into our Todo App.</p>
<p>Now I created a file called <code>animated_loader.dart</code>, which has AnimatedLoader Widget.</p>
<pre><code class="lang-dart"><span class="hljs-comment">// animated_loader.dart</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:loading_animation_widget/loading_animation_widget.dart'</span>;

<span class="hljs-keyword">void</span> main() {
  runApp(AnimatedLoader());
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AnimatedLoader</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: MyLoaderScreen(),
    );
  }
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyLoaderScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      body: Center(
        child: LoadingAnimationWidget.staggeredDotsWave(
            size: <span class="hljs-number">75</span>, color: Colors.deepPurple),
      ),
      backgroundColor: Colors.transparent,
    );
  }
}
</code></pre>
<p>Let's show this animated loader in our animated list while adding or removing a task.</p>
<p><code>todo_list.dart</code></p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_animation/animated_loader.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:loader_overlay/loader_overlay.dart'</span>;

<span class="hljs-keyword">void</span> main() {
  runApp(TodoListApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Task</span> </span>{
  <span class="hljs-built_in">String</span> title;
  <span class="hljs-built_in">bool</span> isCompleted;
  Task(<span class="hljs-keyword">this</span>.title, <span class="hljs-keyword">this</span>.isCompleted);
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TodoListApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  _TodoListAppState createState() =&gt; _TodoListAppState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_TodoListAppState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">TodoListApp</span>&gt; </span>{
  <span class="hljs-built_in">List</span>&lt;Task&gt; tasks = [];
  <span class="hljs-built_in">bool</span> isLoading = <span class="hljs-keyword">false</span>;

  <span class="hljs-keyword">final</span> GlobalKey&lt;AnimatedListState&gt; _animatedListKey = GlobalKey();

  Future&lt;<span class="hljs-keyword">void</span>&gt; loadData() <span class="hljs-keyword">async</span> {
    setState(() {
      isLoading = <span class="hljs-keyword">true</span>;
    });
    <span class="hljs-keyword">await</span> Future.delayed(<span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">2</span>));
    setState(() {
      isLoading = <span class="hljs-keyword">false</span>;
    });
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'ToDo List'</span>)),
        body: Stack(
          children: [
            AnimatedList(
              key: _animatedListKey,
              initialItemCount: tasks.length,
              itemBuilder: (context, index, animation) {
                <span class="hljs-keyword">return</span> _buildTaskItem(tasks[index], animation, index);
              },
            ),
            <span class="hljs-keyword">if</span> (isLoading)
              <span class="hljs-keyword">const</span> Opacity(
                opacity: <span class="hljs-number">0</span>,
                child: ModalBarrier(dismissible: <span class="hljs-keyword">false</span>, color: Colors.black),
              ),
            <span class="hljs-keyword">if</span> (isLoading)
              Center(
                child: Center(child: AnimatedLoader()),
              ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _addTask,
          child: <span class="hljs-keyword">const</span> Icon(Icons.add),
        ),
        backgroundColor: Colors.white60,
      ),
    );
  }

  Widget _buildTaskItem(Task task, Animation&lt;<span class="hljs-built_in">double</span>&gt; animation, <span class="hljs-built_in">int</span> index) {
    <span class="hljs-keyword">return</span> SizeTransition(
        sizeFactor: animation,
        child: Card(
          color: Colors.white,
          child: ListTile(
            title: Text(task.title),
            onLongPress: () =&gt; _removeTask(index),
          ),
        ));
  }

  <span class="hljs-keyword">void</span> _addTask() <span class="hljs-keyword">async</span> {
    Task newTask = Task(<span class="hljs-string">'New Task <span class="hljs-subst">${tasks.length + <span class="hljs-number">1</span>}</span>'</span>, <span class="hljs-keyword">false</span>);
    <span class="hljs-keyword">await</span> loadData();
    tasks.add(newTask);
    _animatedListKey.currentState!.insertItem(tasks.length - <span class="hljs-number">1</span>);
  }

  <span class="hljs-keyword">void</span> _removeTask(<span class="hljs-built_in">int</span> index) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> loadData();
    _animatedListKey.currentState!.removeItem(index,
        (context, animation) =&gt; _buildTaskItem(tasks[index], animation, index));
    tasks.removeAt(index);
  }
}
</code></pre>
<p>To explore more about the Loader you can refer to the <a target="_blank" href="https://pub.dev/packages/loading_animation_widget">docs</a>. It has multiple loaders with customization options.</p>
<p><img src="https://www.gogosoon.com/wp-content/uploads/2023/07/flutter_animation_with_loader-2.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animated List with Animated Loader in Flutter</em></p>
<p>Hurray! We can see that the Animation Loader and Animation List are rendering very smoothly, and they look even better.</p>
<p>If you are implementing this from scratch, that's great and it'll really help you learn. But if you prefer, you can also clone the repo from <a target="_blank" href="https://github.com/5minslearn/flutter_animation">GitHub</a>. Either way, I'm excited to see the Animation Loader and Animation List in action from you.</p>
<p>Note: In the context of creating a task in real time, a loader might not be necessary since the creation of a task typically happens quickly and doesn't involve any lengthy processes like fetching data from an API or performing complex computations. But adding a loader during task creation can still be a useful visual cue to indicate that the task is being processed and provide immediate feedback to the user.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We explored the world of creating beautiful custom animations in Flutter, focusing on the implementation of Animated List and Animated Loader. By understanding the Animated List, we learned how to create dynamic and interactive lists with smooth item insertions and removals.</p>
<p>Through these examples, you saw Flutter's ability to make animation implementation enjoyable and straightforward. By incorporating custom animations into your apps, you can create engaging and visually appealing interfaces that captivate users and set your apps apart.</p>
<p>If you wish to learn more about Flutter, subscribe to my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_animation">email newsletter</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_animation">https://5minslearn.gogosoon.com/</a>) and follow me on social media.</p>
<p>Happy Animating and Fluttering! 🚀 </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Firebase Cloud Messaging in Flutter Using Firebase ]]>
                </title>
                <description>
                    <![CDATA[ In today's highly competitive mobile app landscape, effectively engaging your app's users and delivering timely information is key.  Firebase Cloud Messaging (FCM) is a powerful push notification service provided by Firebase. It offers a seamless way... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/set-up-firebase-cloud-messaging-in-flutter/</link>
                <guid isPermaLink="false">66ba10f07282cc17abcf0c68</guid>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Wed, 05 Jul 2023 16:38:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/A-Complete-Guide-to-FCM-Integration-in-Flutter-Using-Firebase.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In today's highly competitive mobile app landscape, effectively engaging your app's users and delivering timely information is key. </p>
<p>Firebase Cloud Messaging (FCM) is a powerful push notification service provided by Firebase. It offers a seamless way to connect with your app's users and keep them engaged. </p>
<p>In this tutorial, we will delve into the integration of FCM in Flutter. We'll explore its benefits and showcase real-world examples of how it can enhance user engagement and improve app performance. </p>
<h2 id="heading-what-is-firebase-cloud-messaging">What is Firebase Cloud Messaging?</h2>
<p>Firebase Cloud Messaging (FCM) provides a reliable and battery-efficient connection between your server and devices. It allows you to deliver and receive messages and notifications on iOS, Android, and the web at no cost. </p>
<p>In this tutorial, we will explore the process of setting up and using Firebase Cloud Messaging (FCM) in Flutter using Firebase as the backend service. While the main focus will be on Android implementation, it's worth noting that the process is similar for iOS and Android (with a few configuration differences).</p>
<p>Here is what we'll cover:</p>
<ol>
<li>How to create an app in Firebase</li>
<li>How to set up Firebase in Flutter</li>
<li>How to implement push notifications using FCM tokens</li>
</ol>
<p>In this tutorial, you'll learn how to send a simple notification using Firebase to the app running in Flutter. Let's get started.</p>
<h2 id="heading-how-to-create-an-app-in-firebase">How to Create an App in Firebase</h2>
<p>I'll create a new project in the Firebase console to get started. I'll walk through the necessary steps, including project setup, how to configure Firebase Cloud Messaging, and how to get the required credentials and configuration files for our Flutter app.</p>
<p>Before creating the app you need to signup for the Firebase <a target="_blank" href="https://console.firebase.google.com/">console</a> if you don't have an account. After sign up, try to create a project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-292.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create a Project in Firebase</em></p>
<p>It will take a little time to create a project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-293.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating project in Firebase</em></p>
<p>After creating the project, it will redirect you to the project dashboard.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Project Overview in Firebase Console</em></p>
<p>Once you've created the project in Firebase console, it's time to get started with our Flutter app.</p>
<h2 id="heading-how-to-set-up-firebase-in-flutter">How to Set Up Firebase in Flutter</h2>
<p>I have created a simple Flutter project using Visual Studio Code. If you are unfamiliar with building a Flutter project, you can refer to my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-simple-login-app-with-flutter/">previous tutorial</a>. (If you are already familiar, you can skip this step.)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-296.png" alt="Image" width="600" height="400" loading="lazy">
<em>Simple Flutter Application running on Android Device</em></p>
<p>Let's integrate Firebase into our Flutter project. To do this, we need a Firebase CLI command line tool. I have already installed the Firebase CLI. If you haven't done this, you can refer to the official <a target="_blank" href="https://firebase.google.com/docs/cli#setup_update_cli">documentation</a>.</p>
<p>Then we need to log in to Firebase using Firebase CLI.</p>
<pre><code>firebase login
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-305.png" alt="Image" width="600" height="400" loading="lazy">
<em>Login to Firebase using FirebaseCLI</em></p>
<p>This will navigate you to the browser to log in to Firebase. You'll be navigated back once the authentication is successfully completed.</p>
<p>After successful login, we need to install FlutterFire CLI. We can use the FlutterFire CLI to configure our Flutter apps to connect to Firebase. Run the following command to activate the FlutterFire CLI:</p>
<pre><code>dart pub <span class="hljs-built_in">global</span> activate flutterfire_cli
</code></pre><p>The FlutterFire CLI is a command-line interface tool that simplifies the integration of Firebase services into Flutter applications. It provides a convenient way to add, configure, and manage Firebase plugins in our Flutter project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-306.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing FlutterFireCLI</em></p>
<p>The next step is to add <code>firebase_core</code> library to our Flutter project.</p>
<p>The following command will automatically add the <code>firebase_core</code> package as a dependency in your project's <code>pubspec.yaml</code> file and fetch the latest version of the package from <code>pub.dev</code>. After running this command, you can import the <code>firebase_core</code> package into the Dart files and use Firebase services in our Flutter app.</p>
<pre><code>flutter pub add firebase_core
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-307.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing Firebase Core package</em></p>
<p>The <code>flutterfire configure</code> command is used to configure Firebase services in our Flutter project using the FlutterFire CLI. This command helps us set up Firebase authentication, Firestore, Cloud Messaging, and other Firebase services easily and efficiently.</p>
<pre><code>flutterfire configure
</code></pre><p>The first step is to choose the project,</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-308.png" alt="Image" width="600" height="400" loading="lazy">
<em>Connect Flutter App with Firebase app</em></p>
<p>The next is to choose the platform. I am using it for Android here, so I choose Android.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-309.png" alt="Image" width="600" height="400" loading="lazy">
<em>Choosing platform</em></p>
<p>After the successful configuration, the Firebase App Id will be displayed.</p>
<p>Finally, we need to add some code changes to our <code>main.dart</code> file.</p>
<p>Import the following packages:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'package:firebase_core/firebase_core.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'firebase_options.dart'</span>;
</code></pre><p>Add the following configuration to initialize the Firebase config inside the main function of the <code>main.dart</code> file.</p>
<pre><code><span class="hljs-keyword">await</span> Firebase.initializeApp(
  options: DefaultFirebaseOptions.currentPlatform,
);
</code></pre><p>Alright, we have successfully completed the Firebase configuration in our Flutter app! Let's take a moment to celebrate this milestone. Configuring Firebase services is a crucial step in building powerful and feature-rich applications.</p>
<h2 id="heading-how-to-implement-push-notification-using-fcm-tokens">How to Implement Push Notification using FCM Tokens</h2>
<p>We'll implement the process of registering devices for push notifications and retrieving the unique FCM tokens assigned to each device. This step is crucial for sending targeted notifications to specific devices.</p>
<p>We'll dive into the implementation of sending push notifications to devices using Firebase Cloud Messaging. We'll explore how to structure and send notification messages from the Firebase console and demonstrate how to handle these messages within our Flutter app.</p>
<pre><code>flutter pub add firebase_messaging
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-310.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing firebse messaging Package</em></p>
<p>Next, we need to trigger the <code>setAutoInitEnabled</code> function to enable automatic initialization of Firebase Cloud Messaging (FCM) in our Flutter app. This means that FCM will automatically initialize and retrieve a device token when the app starts. </p>
<p>Add the following function call in the <code>main</code> method:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'package:firebase_messaging/firebase_messaging.dart'</span>;
...
...
await FirebaseMessaging.instance.setAutoInitEnabled(<span class="hljs-literal">true</span>);
</code></pre><p>Let's run our Flutter app and verify if we receive the notification.</p>
<p>Navigate to the Firebase <a target="_blank" href="https://console.firebase.google.com/project/_/messaging/?_gl=1*gqfrc0*_ga*NDUwNTM5NDI0LjE2ODgwNTc3NjQ.*_ga_CW55HF8NVT*MTY4ODA5ODkyMC4yLjEuMTY4ODEwMjY2NS4wLjAuMA..">messaging console</a>. As it is our first message, we need to select "Create your first campaign". Select "Firebase Notification messages" and click "Create".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-311.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sample test messaging template</em></p>
<p>Now we need to enter the notification title, text, and name for the message.</p>
<p>Then we can get the FCM token manually for testing purposes using the code below. To retrieve the current registration token for an app instance, call <code>getToken()</code> in the <code>main()</code> method. This method will ask the user for notification permissions if notification permission has not been granted. Otherwise, it returns a token or rejects if there's any error.</p>
<pre><code>final fcmToken = <span class="hljs-keyword">await</span> FirebaseMessaging.instance.getToken();
log(<span class="hljs-string">"FCMToken $fcmToken"</span>);
</code></pre><p>Copy the FCM token printed on the console and paste it into the "Add an FCM registration token" input box.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sent test message using FCM Token</em></p>
<p>Click on the Test button. The targeted client device (with the app in the background) should receive the notification.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/image.png" alt="Image" width="600" height="400" loading="lazy">
<em>Received push notification in android device</em></p>
<p>Hurray! We got the notification on our Android device. If we click on the notification it will open the app by default.</p>
<p>When we tap a notification, the default behavior on both Android and iOS is to open the application. If the application is terminated, it will be started. If it is in the background, it will be brought to the foreground.</p>
<p>Here, we can see the basic configuration to initialize Firebase messaging.</p>
<p><code>main.dart</code></p>
<pre><code>
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:firebase_core/firebase_core.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:firebase_messaging/firebase_messaging.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'firebase_options.dart'</span>;

<span class="hljs-keyword">void</span> main() <span class="hljs-keyword">async</span> {
  runApp(<span class="hljs-keyword">const</span> MyApp());
  <span class="hljs-keyword">await</span> Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  final fcmToken = <span class="hljs-keyword">await</span> FirebaseMessaging.instance.getToken();
  <span class="hljs-keyword">await</span> FirebaseMessaging.instance.setAutoInitEnabled(<span class="hljs-literal">true</span>);
  log(<span class="hljs-string">"FCMToken $fcmToken"</span>);
}
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial we have covered the essential steps for implementing push notifications in Flutter using Firebase Cloud Messaging (FCM). </p>
<p>By following the outlined steps, you can set up Firebase, integrate it into your Flutter project, and implement push notification functionality. </p>
<p>With the ability to send and receive notifications seamlessly, you can enhance the user experience and engage with your app's users effectively. Stay tuned for more advanced topics and features in future tutorials.</p>
<p>If you wish to learn more about Flutter, subscribe to my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_firebase">email newsletter</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_firebase">https://5minslearn.gogosoon.com/</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Custom Widget in Flutter ]]>
                </title>
                <description>
                    <![CDATA[ Flutter has been getting more and more popular lately. You can use it to build complex applications that work smoothly on MacOS, Windows, and Linux.  But building these applications is not always a simple process. You often have to refactor your code... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-custom-widget-in-flutter/</link>
                <guid isPermaLink="false">66ba10b4052fa53219e0a376</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Tue, 06 Jun 2023 15:12:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/Custom-Widget-in-Flutter---Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Flutter has been getting more and more popular lately. You can use it to build complex applications that work smoothly on MacOS, Windows, and Linux. </p>
<p>But building these applications is not always a simple process. You often have to refactor your code to maintain the app’s performance. </p>
<p>One such refactoring technique is extracting duplicated code and components and reusing them in multiple places. </p>
<p>In this tutorial, you'll learn how to replace a duplicated component by building a custom widget in Flutter.</p>
<h2 id="heading-what-is-a-custom-widget">What is a Custom Widget?</h2>
<p>In Flutter, a custom widget refers to a user-defined widget that encapsulates a specific set of functionalities or visual representations. </p>
<p>Custom widgets are the building blocks of a Flutter application. They allow developers to create reusable UI components that can be used throughout the application. </p>
<p>If you're switching from React Native, you can think about custom widgets as custom React components. And what we call <code>props</code> in React are called <code>parameters</code> in Flutter. </p>
<h2 id="heading-why-use-custom-widgets">Why Use Custom Widgets?</h2>
<p>Custom widgets help you encapsulate complex UI elements. They also promote code re-usability and enhance the maintainability of your Flutter applications. </p>
<p>There are a number of reasons to build build custom widgets in Flutter. Let's look at some of them.</p>
<h3 id="heading-code-reusability">Code Reusability</h3>
<p>Custom widgets allow developers to encapsulate complex functionality and appearance into reusable components. </p>
<p>Once created, custom widgets can be used multiple times throughout the application, reducing code duplication and promoting a modular development approach.</p>
<h3 id="heading-maintainability">Maintainability</h3>
<p>Custom widgets contribute to the maintainability of the codebase. By encapsulating specific functionality or visual representation, custom widgets create a separation of concerns. This separation makes it easier to locate, modify, and debug code related to a particular UI component.</p>
<h3 id="heading-consistent-ui">Consistent UI</h3>
<p>They also enable developers to define a consistent and unified UI design across their application.</p>
<h3 id="heading-abstraction">Abstraction</h3>
<p>And finally, custom widgets provide a level of abstraction that hides the implementation details and complexity of a particular UI element. </p>
<p>You can create high-level widgets that expose a simplified interface and handle the internal logic. This allows other developers to use the widget without worrying about its internal workings. This abstraction promotes modularity, making it easier to understand, test, and maintain the code. </p>
<h2 id="heading-how-to-build-a-custom-widget-in-flutter">How to Build a Custom Widget in Flutter</h2>
<p>Let’s start building our custom widget. </p>
<h3 id="heading-clone-the-repo">Clone the Repo</h3>
<p>Instead of starting from the scratch, I’ve created a Flutter app in <a target="_blank" href="https://github.com/5minslearn/Flutter-Custom-Widget">GitHub</a> and added duplicated code/components in that repo. Let’s begin from there.</p>
<p>Pull the code from GitHub by running the below command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/5minslearn/Flutter-Custom-Widget.git

or

git <span class="hljs-built_in">clone</span> git@github.com:5minslearn/Flutter-Custom-Widget.git
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-67.png" alt="Image" width="600" height="400" loading="lazy">
<em>Clone the Flutter Custom Widget repo from GitHub</em></p>
<p>By default, it’ll be in the <code>master</code> branch. I’m switching to a <code>refactor</code> branch (you don’t need to) because I want you all to have a look at my initial and final code. The initial code will be in the <code>master</code> branch and the final code will be in the <code>refactor</code> branch. </p>
<p>Run the following command to install all the dependencies:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> Flutter-Custom-Widget/
flutter pub get
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-68.png" alt="Image" width="600" height="400" loading="lazy">
<em>Install Flutter dependencies</em></p>
<h3 id="heading-run-the-app">Run the App</h3>
<p>Open the repo in Visual Studio Code and spin up your emulator (you may connect your mobile device, too). Once your emulator is up and running, press <code>F5</code> to run the app in the emulator. </p>
<p>Here’s the view of your app on the first run. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-69.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial app run screen</em></p>
<p>If you’ve come this far, that’s great. </p>
<h3 id="heading-analyze-the-code">Analyze the Code</h3>
<p>Let’s look at the code. Open the <code>lib/main.dart</code> file.</p>
<p>We have a <code>MyApp</code> class called at the beginning. This in-turn calls the <code>MyHomePage</code> class.</p>
<p>This is our code for the entire UI which is defined in <code>_MyHomePageState</code> class:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Welcome to Flutter Refactoring Tutorial'</span>,
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: <span class="hljs-number">20</span>)),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">16</span>),
            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Press the below button to follow me on Twitter'</span>),
            ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  <span class="hljs-keyword">const</span> SnackBar(
                    content: Text(<span class="hljs-string">"Pressed Follow on Twitter button"</span>),
                    duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
                  ),
                );
                <span class="hljs-comment">// Open Twitter app</span>
              },
              child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Follow on Twitter"</span>),
            ),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">16</span>),
            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Press the below button to follow me on Instagram'</span>),
            ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  <span class="hljs-keyword">const</span> SnackBar(
                    content: Text(<span class="hljs-string">"Pressed Follow on Instagram button"</span>),
                    duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
                  ),
                );
                <span class="hljs-comment">// Open Instagram app</span>
              },
              child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Follow on Instagram"</span>),
            ),
          ],
        ),
      ),
    );
  }
}
</code></pre>
<p>And so you can reference the line numbers, here's a visual:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-72.png" alt="Image" width="600" height="400" loading="lazy">
<em>Code for the app UI</em></p>
<p>If you’re someone who loves writing clean code, you would definitely say that this is ugly code. </p>
<p>Here’s the reason for it. Look at the code carefully – lines 44 to 56 and lines 58 to 70 are completely duplicated except for a very few handpicked words. For example, the word “Twitter” has been replaced with the word “Instagram”. </p>
<p>The clean coder will definitely refactor this code before working on adding new features/functionalities. Let's follow those clean coding practices now, too. </p>
<h3 id="heading-refactor-the-code-and-build-a-custom-widget">Refactor the Code and Build a Custom Widget</h3>
<p>We have to extract the text and button into a separate component. This component should accept the <code>platform</code> and <code>onPressed</code> as its parameters. We can template out the common text from them. </p>
<p>So, our code to build the custom widget looks like this:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomButton</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> platform;
  <span class="hljs-keyword">final</span> VoidCallback onPressed;
  <span class="hljs-keyword">const</span> CustomButton(
      {<span class="hljs-keyword">super</span>.key, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.platform, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.onPressed});
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Center(
        child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
      Text(<span class="hljs-string">"Press the below button to follow me on <span class="hljs-subst">$platform</span>"</span>),
      ElevatedButton(
        onPressed: () {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text(<span class="hljs-string">"Pressed Follow on <span class="hljs-subst">$platform</span> button"</span>),
              duration: <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
            ),
          );
          onPressed();
        },
        child: Text(<span class="hljs-string">"Follow on <span class="hljs-subst">$platform</span>"</span>),
      )
    ]));
  }
}
</code></pre>
<p>As we discussed above, the template text and accept <code>platform</code> and <code>onPressed</code> parameters. We replaced <code>platform</code> wherever we need and call the <code>onPressed</code> method as the extension of showing a snack bar. </p>
<p>Add the above code at the very end of the <code>main.dart</code> file. </p>
<h3 id="heading-integrate-the-custom-widget">Integrate the Custom Widget</h3>
<p>Let’s integrate our custom widget into our code.</p>
<p>Pick the first block of code from the line 44 to 56 as shown below</p>
<pre><code class="lang-dart">            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Press the below button to follow me on Twitter'</span>),
            ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  <span class="hljs-keyword">const</span> SnackBar(
                    content: Text(<span class="hljs-string">"Pressed Follow on Twitter button"</span>),
                    duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
                  ),
                );
                <span class="hljs-comment">// Open Twitter app</span>
              },
              child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Follow on Twitter"</span>),
            ),
</code></pre>
<p>Replace it with the following code:</p>
<pre><code class="lang-dart">CustomButton(
  platform: <span class="hljs-string">'Twitter'</span>,
  onPressed: () {
    <span class="hljs-comment">// Open Twitter App</span>
  },
),
</code></pre>
<p>Similarly, pick the next block of code from the line 58 to 70 as shown below</p>
<pre><code class="lang-dart">            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Press the below button to follow me on Instagram'</span>),
            ElevatedButton(
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  <span class="hljs-keyword">const</span> SnackBar(
                    content: Text(<span class="hljs-string">"Pressed Follow on Instagram button"</span>),
                    duration: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>),
                  ),
                );
                <span class="hljs-comment">// Open Instagram app</span>
              },
              child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Follow on Instagram"</span>),
            ),
</code></pre>
<p>Replace it with the following code:</p>
<pre><code class="lang-dart">CustomButton(
  platform: <span class="hljs-string">'Instagram'</span>,
  onPressed: () {
    <span class="hljs-comment">// Open Instagram App</span>
  },
),
</code></pre>
<p>Here's the final code of <code>_MyHomePageState</code> class after we complete our refactoring process. </p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Welcome to Flutter Refactoring Tutorial'</span>,
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: <span class="hljs-number">20</span>)),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">16</span>),
            CustomButton(
              platform: <span class="hljs-string">'Twitter'</span>,
              onPressed: () {
                <span class="hljs-comment">// Open Twitter App</span>
              },
            ),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">16</span>),
            CustomButton(
              platform: <span class="hljs-string">'Instagram'</span>,
              onPressed: () {
                <span class="hljs-comment">// Open Instagram App</span>
              },
            ),
          ],
        ),
      ),
    );
  }
}
</code></pre>
<p>And again, here's the screenshot for line number reference:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-73.png" alt="Image" width="600" height="400" loading="lazy">
<em>After refactoring your code</em></p>
<p>Run your app now. </p>
<p>Unfortunately, you’ll not notice any change in the UI. But your underlying code has changed. That’s exactly what refactoring is. </p>
<p>Quoting from Martin Fowler, </p>
<blockquote>
<p><strong>Refactoring</strong> is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. – https://refactoring.com/</p>
</blockquote>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-74.png" alt="Image" width="600" height="400" loading="lazy">
<em>Final app</em></p>
<p>You may be wondering something after looking at the above code. Lines 43 and 50 also contain the same code (<code>const SizedBox(height: 16),</code>). So why don’t we include that into the component?</p>
<p>That’s great if you had this question.</p>
<p>There is no need for the custom widget component to include the <code>SizedBox</code> component. This is because the <code>SizedBox</code> component is added in the Home page to give some space between each component. But it's not necessary that whenever we use this button, we give a space at the top/bottom of the widget. </p>
<p>Still, if such cases arise, you can add the <code>SizedBox</code> widget inside your custom widget. </p>
<h3 id="heading-why-build-a-custom-widget">Why Build a Custom Widget?</h3>
<p>You might not see a direct benefit right away. But you may experience it in the future. Here’s a quick example for you. </p>
<p>Let’s assume you’ve built this app for a client. It has become a complex app and you’ve used this custom widget around 20 places in your app. The app is released and people enjoy using it. </p>
<p>About 6 months later, your client come back to you with the next version of changes. One of the items in the huge list is, “We’re coming up with a slight change in theme. Replace all the social media referral buttons so that they're an outlined shape and change the color to green”. </p>
<p>It is one simple configuration change in the custom widget. But imagine if you hadn't built the custom widget and had to copy/pasted the same code in all the 20 places. Then you'd have to carefully look at each place and replace each instance with care without touching other pieces of code. </p>
<p>These are the only 2 lines we have to change in our custom widget in this example:</p>
<pre><code class="lang-dart">OutlinedButton(
        style: OutlinedButton.styleFrom(foregroundColor: Colors.green),
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-75.png" alt="Image" width="600" height="400" loading="lazy">
<em>Changes in our custom widget</em></p>
<p>But if you hadn't refactored your code, you'd have to make this change in 20 places. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/image-76.png" alt="Image" width="600" height="400" loading="lazy">
<em>Small change reflects everywhere</em></p>
<p>I’ve pushed my code to the same <a target="_blank" href="https://github.com/5minslearn/Flutter-Custom-Widget">GitHub repo</a>. Refer to the <code>master</code> branch for the non-refactored code and the <code>refactor</code> branch for the refactored code. </p>
<h2 id="heading-use-cases-for-custom-widgets">Use Cases for Custom Widgets</h2>
<p>Always use custom widgets for their specific use cases. For example, in our case, it is for Social media redirects. This widget should not be used in places which are unrelated to its context. </p>
<p>If you do, remember the above case where the client requirement was to change the design of only the social media referral buttons...but our change would be applied to all the other places where this widget was used. This would lead to unexpected bugs. </p>
<p>You should always write unit test cases for Custom Widgets which will help you mitigate any bugs earlier.</p>
<p>One more tip is to name your component in a more readable way. This helps other developers know what the widget does just by reading its name. </p>
<p>In our case, I've named it <code>CustomButton</code> which makes no sense. Instead, some good alternatives would be <code>SocialMediaButton</code>, <code>SocialButton</code>, and so on which fit into our use case. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned about building a custom widget by removing duplicated code/components. </p>
<p>Building custom widgets in Flutter promotes code reusability, maintainability, consistency, abstraction, flexibility, and community collaboration. </p>
<p>Custom widgets are a powerful tool in the Flutter developer’s toolkit, enabling you to create beautiful and functional user interfaces while maximizing efficiency and maintainability. </p>
<p>If you wish to learn more about Flutter, subscribe to my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_custom_widget">email newsletter</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_custom_widget">https://5minslearn.gogosoon.com/</a>) and follow me on social media.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Networking in Flutter By Building a Simple App ]]>
                </title>
                <description>
                    <![CDATA[ Almost all apps you use today run by accessing the internet. You can hardly find an app that runs without connecting to the internet.  The internet has become an integral part of our lives, as it solves one of the most critical problems we have to ha... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-networking-in-flutter/</link>
                <guid isPermaLink="false">66ba10e3228e16bed602a8a5</guid>
                
                    <category>
                        <![CDATA[ computer networking ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Mon, 15 May 2023 18:42:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/Networking-in-Flutter---Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Almost all apps you use today run by accessing the internet. You can hardly find an app that runs without connecting to the internet. </p>
<p>The internet has become an integral part of our lives, as it solves one of the most critical problems we have to handle: data transfer. We're constantly either receiving or sending data to someone – whether it's a social media app, news app, or whatever type it may be, there's some form of data transfer. </p>
<p>Because of this, it's super important to learn networking if you're learning mobile app development. In this article I'll be explaining how to build a super simple mobile app that fetches data from internet and renders it on the app. </p>
<h2 id="heading-how-to-create-the-project">How to Create the Project</h2>
<p>Navigate to the folder where you want to create your project in the terminal and run the following command:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/5minslearn/Flutter-Boilerplate.git
</code></pre>
<p>Navigate to the Flutter-Boilerplate folder and run the <code>flutter pub get</code> command to install the dependencies. </p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> Flutter-Boilerplate/
flutter pub get
</code></pre>
<p>That's it. We've got our dependencies installed.</p>
<p>Open the project in Visual Studio Code by running the <code>code ./</code> command in the terminal.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-40.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create a Flutter app from boiler plate</em></p>
<p>Start your emulator/connect your device and press <code>F5</code> in VS Code to run your app.</p>
<p>At the moment, the app will just contain an empty screen as shown in the below screenshot. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-41.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter app with empty screen</em></p>
<p>Let's build our networking app. </p>
<h2 id="heading-where-to-get-the-data">Where to Get the Data</h2>
<p>This is the most obvious question. If we were to fetch something from the internet and render, we need an API server exposing the data we need. But, most people cannot afford to do that for learning purposes. To overcome this, many people are offering free API services. </p>
<p>You can consume the data from their API services for learning purposes. But, we cannot validate the originality of the data, as most of them will be random. </p>
<p>In this tutorial, we'll be using the API exposed by <a target="_blank" href="https://sampleapis.com/">https://sampleapis.com/</a>. They expose an API endpoint that lists Coding Resources. The URL of the endpoint is <a target="_blank" href="https://api.sampleapis.com/codingresources/codingResources">https://api.sampleapis.com/codingresources/codingResources</a>. </p>
<p>In our app, we'll fetch the data from this endpoint and list them in our app. </p>
<h2 id="heading-install-the-dependencies">Install the Dependencies</h2>
<p>Let's install the dependencies we need to build this app. They are:</p>
<ol>
<li>The <code>http</code> package</li>
<li>The <code>url_launcher</code> package</li>
</ol>
<p>We'll use the <code>http</code> package to make a call to the API endpoint. And we'll use the <code>url_launcher</code> package to open a URL in an external browser. </p>
<p>Open the <code>pubspec.yml</code> file and add the following two packages in the dependencies section:</p>
<pre><code class="lang-bash">  http: ^0.13.6
  url_launcher: ^6.1.11
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-42.png" alt="Image" width="600" height="400" loading="lazy">
<em>Add dependencies</em></p>
<p>If you're using VS Code as your IDE, the dependencies will be installed automatically by saving this file. For the other IDEs, run <code>flutter pub get</code> on your project root folder to install the dependencies. </p>
<h2 id="heading-how-to-fetch-the-data-from-the-api">How to Fetch the Data from the API</h2>
<p>We got our dependencies ready. Let's make a request to our API and get the data. </p>
<p>Import the <code>http</code> package in the <code>lib/main.dart</code> file. </p>
<pre><code class="lang-bash">import <span class="hljs-string">'package:http/http.dart'</span> as http;
</code></pre>
<p>Initialize a list object in the <code>_MyHomePageState</code> class by adding the following code:</p>
<pre><code class="lang-dart"><span class="hljs-built_in">List</span> _resources = [];
</code></pre>
<p>Let’s write a method that makes a call to our API endpoint and decode them into a JSON object. </p>
<pre><code class="lang-dart">  <span class="hljs-keyword">void</span> _fetchResources() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">final</span> response = <span class="hljs-keyword">await</span> http.<span class="hljs-keyword">get</span>(<span class="hljs-built_in">Uri</span>.parse(
        <span class="hljs-string">'https://api.sampleapis.com/codingresources/codingResources'</span>));
    <span class="hljs-keyword">if</span> (response.statusCode == <span class="hljs-number">200</span>) {
      <span class="hljs-keyword">final</span> data = json.decode(response.body) <span class="hljs-keyword">as</span> <span class="hljs-built_in">List</span>;
      setState(() {
        _resources = data;
      });
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">throw</span> Exception(<span class="hljs-string">'Failed to load resources'</span>);
    }
  }
</code></pre>
<p>Paste the above code into the <code>MyHomePageState</code> class. In the above method, we’re making a call to the API endpoint (<a target="_blank" href="https://api.sampleapis.com/codingresources/codingResources">https://api.sampleapis.com/codingresources/codingResources</a>). From the response, we’re validating if it's successful in receiving the data by checking if its status code is <code>200</code> (and throwing an error if it’s not). We then decode the received data and save it in our app’s state. </p>
<p>You may notice an error after pasting the above code at the <code>json.decode</code> part. In order to decode JSON, we need import a <code>convert</code> package in our file. Add the following code at the top of the file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:convert'</span>;
</code></pre>
<p>The error should be gone now. </p>
<p>We have a method that makes a call to the API endpoint and saves the data in the state. Our next step is to trigger this method when we open the app. </p>
<p>We can do that by overriding the <code>initState</code> method. </p>
<pre><code class="lang-dart">  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> initState() {
    <span class="hljs-keyword">super</span>.initState();
    _fetchResources();
  }
</code></pre>
<p>Quoting from the Flutter <a target="_blank" href="https://api.flutter.dev/flutter/widgets/State/initState.html">documentation</a>, </p>
<blockquote>
<p>"<code>initState</code> is called when this object is inserted into the tree. The framework will call this method exactly once for each <a target="_blank" href="https://api.flutter.dev/flutter/widgets/State-class.html">State</a> object it creates."</p>
</blockquote>
<p>In the above code, we called our method <code>_fetchResources()</code> in the <code>initState()</code> method. </p>
<h2 id="heading-how-to-build-the-ui">How to Build the UI</h2>
<p>We got the list of items whenever we open the app. Our next step is to render them on the UI. </p>
<p>Copy the below code and replace it with the <code>build</code> method of the <code>_MyHomePageState</code> class. </p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: _resources.isEmpty
            ? <span class="hljs-keyword">const</span> Center(
                child: CircularProgressIndicator(),
              )
            : ListView.builder(
                itemCount: _resources.length,
                itemBuilder: (context, index) {
                  <span class="hljs-keyword">final</span> resource = _resources[index];
                  <span class="hljs-keyword">return</span> InkWell(
                      onTap: () =&gt; {},
                      child: Card(
                          child: ListTile(
                        title: Text(resource[<span class="hljs-string">'description'</span>]),
                        subtitle: Text(resource[<span class="hljs-string">'url'</span>]),
                        leading: <span class="hljs-keyword">const</span> CircleAvatar(
                            backgroundImage: NetworkImage(
                                <span class="hljs-string">"https://images.unsplash.com/photo-1547721064-da6cfb341d50"</span>)),
                        trailing: Text(resource[<span class="hljs-string">'types'</span>].join(<span class="hljs-string">', '</span>)),
                      )));
                }));
  }
</code></pre>
<p>Let’s understand the above code. </p>
<p>We show a loader if our state has empty values. If it has some values in it, we’ll iterate through as a ListView builder and we render a card widget for each item, displaying the <code>description</code>, <code>url</code>, and <code>types</code> of the resource. </p>
<p>That’s it. </p>
<p>Run the app by pressing <code>F5</code> and you should be able to see the following: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-43.png" alt="Image" width="600" height="400" loading="lazy">
<em>Loading the resources</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-44.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing the resources</em></p>
<p>That’s awesome, isn’t it? </p>
<h2 id="heading-lets-fix-the-missing-part">Let's Fix the Missing Part</h2>
<p>But I feel there’s one small thing that’s missing at this point.</p>
<p>We’re able to see the list of the resources. But, we’re not able to view those resources. Some resources have a short link that we can easily remember and type. But, a few of them have a long URL which would be hard for a typical human being to remember. Let’s add a small enhancement that when we click on a resource, its link should be opened in our default browser. </p>
<p>This is very simple to implement in Flutter. This is the reason we added the <code>url_launcher</code> package at the beginning of this tutorial. </p>
<p>Import the <code>url_launcher</code> package in your app like this</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:url_launcher/url_launcher.dart'</span>;
</code></pre>
<p>Add the following method in the <code>_MyHomePageState</code> class:</p>
<pre><code class="lang-dart">_launchURL(<span class="hljs-built_in">String</span> url) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">await</span> canLaunch(url)) {
      <span class="hljs-keyword">await</span> launch(url);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">throw</span> <span class="hljs-string">'Could not launch <span class="hljs-subst">$url</span>'</span>;
    }
  }
</code></pre>
<p>The above method accepts a URL, validates the link, and opens it in the browser. </p>
<p>We have to call this method on tapping the card. We can achieve that by calling this method in the <code>onTap</code> property of the <code>InkWell</code> widget. </p>
<p>Here’s the code for it:</p>
<pre><code class="lang-dart">onTap: () =&gt; {_launchURL(resource[<span class="hljs-string">'url'</span>])},
</code></pre>
<p>Let’s run our app and test this. </p>
<p>You were likely disappointed on tapping a card – I certainly was while working on this. </p>
<p>You should have seen this error:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-45.png" alt="Image" width="600" height="400" loading="lazy">
<em>Error on opening a url: Exception has occurred. "Could not launch https://www.youtube.com/bocajs"</em></p>
<p>Though the URL is right, why is our system not opening this in a browser?</p>
<h2 id="heading-what-are-intent-actions">What are Intent Actions?</h2>
<p>Well, now we have to learn about intent actions. </p>
<p>Quoting it from Android Developers <a target="_blank" href="https://developer.android.com/reference/android/content/Intent">documentation</a>, </p>
<blockquote>
<p>"An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed."</p>
</blockquote>
<p>This basically means that when we hand over something to the external app, we have to declare that in our app. For Android, we have to define it in <code>AndroidManifest.xml</code> and for iOS most of these configurations go into the <code>Info.plist</code> file. </p>
<p>Add the <code>queries</code> block in the following code to your <code>AndroidManifest.xml</code> file. </p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">manifest</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">application</span>&gt;</span>
        ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">application</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">queries</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">intent</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">action</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.intent.action.VIEW"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">category</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.intent.category.BROWSABLE"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">data</span> <span class="hljs-attr">android:scheme</span>=<span class="hljs-string">"https"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">intent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">queries</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">manifest</span>&gt;</span>
</code></pre>
<p>Uninstall the app from your mobile and run the app again. </p>
<p>Hopefully you should be able to see the link opened in the browser. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-46.png" alt="Image" width="600" height="400" loading="lazy">
<em>Link opened on a browser</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you’ve learned about networking in Flutter. We made a request to an API, rendered the list, and opened the URL in the browser. </p>
<p>This <a target="_blank" href="https://github.com/5minslearn/Flutter-Networking">repo</a> has my code. You can use it for your reference. </p>
<p>To learn more about Flutter, subscribe to my email newsletter on my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_networking">site</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_networking">https://5minslearn.gogosoon.com</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Navigation in Flutter – How to Add Stack, Tab, and Drawer Navigators to Your Apps ]]>
                </title>
                <description>
                    <![CDATA[ Almost any app that you design or develop will use some type of navigation.  There are three types of navigation that are common to all apps – stack, tab, and drawer navigation. Flutter supports all three types, and implementing them is similar to ho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/navigation-in-flutter/</link>
                <guid isPermaLink="false">66ba10ee90067134b63982c9</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Fri, 21 Apr 2023 18:10:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/04/Types-of-Navigations-in-Flutter---Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Almost any app that you design or develop will use some type of navigation. </p>
<p>There are three types of navigation that are common to all apps – stack, tab, and drawer navigation.</p>
<p>Flutter supports all three types, and implementing them is similar to how you do it in other apps. But I found it super smooth to build navigation into my Flutter app.</p>
<p>In this article, we'll build a Flutter app that uses all three types of navigation in a single app so you can learn how they work.</p>
<h2 id="heading-types-of-navigation">Types of Navigation</h2>
<p>As I mentioned above, there are three main types of navigation that you might use in your apps. Again, they are:</p>
<ol>
<li>Stack Navigation</li>
<li>Tab Navigation</li>
<li>Drawer Navigation</li>
</ol>
<p>Let's understand how each one works.</p>
<h3 id="heading-stack-navigation">Stack Navigation</h3>
<p>Picture a deck of cards, where you can add or remove cards from the top of the stack. Stack Navigation in Flutter works in a similar fashion. It helps you navigate between pages or screens by stacking new pages on top of existing ones. </p>
<p>When you move to a new screen, the current screen is pushed onto the navigation stack, and when you return, the top screen is popped off the stack. </p>
<p>This navigation type is commonly used for hierarchical and linear flows within an app. </p>
<h3 id="heading-tab-navigation">Tab Navigation</h3>
<p>Tabs are a staple of mobile app navigation, allowing users to quickly switch between different sections or views without losing their current context. </p>
<p>Flutter makes it easy to implement tabbed navigation with its built-in widgets, such as TabBar and TabBarView. By using these widgets, you can create a beautiful and functional tab navigation experience, perfect for organizing content into logical sections. </p>
<p>You also have the freedom to customize the appearance of your tabs, making it simple to create a unique look and feel for your app. </p>
<h3 id="heading-drawer-navigation">Drawer Navigation</h3>
<p>The Drawer Navigation pattern, also known as the "hamburger menu" or "side menu," is a popular navigation style in mobile apps. It consists of a hidden panel that slides out from the side of the screen, revealing a menu with various navigation options. </p>
<p>This space-saving technique keeps your app's main content visible while providing easy access to additional features or sections. </p>
<p>Let's start building the app and see how to implement each of these navigation features.</p>
<h2 id="heading-how-to-create-the-project">How to Create the Project</h2>
<p>Instead of creating a new project every time from scratch, I've created a boilerplate app and uploaded in <a target="_blank" href="https://github.com/5minslearn/Flutter-Boilerplate">GitHub</a>. You can pull the code and run. I hope that makes creating this project a bit simpler. </p>
<p>Navigate to the folder where you want to create your project in the terminal and run the following command. </p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/5minslearn/Flutter-Boilerplate.git
</code></pre>
<p>Navigate to the <code>Flutter-Boilerplate</code> folder and run the <code>flutter pub get</code> command to install the dependencies. </p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> Flutter-Boilerplate/
flutter pub get
</code></pre>
<p>That's it. We've got our dependencies installed. </p>
<p>Open the project in Visual Studio Code by running the <code>code ./</code> command in the terminal. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-147.png" alt="Image" width="600" height="400" loading="lazy">
<em>Clone repo and install dependencies</em></p>
<p>Start your emulator/connect your device and press <code>F5</code> in VS Code to run your app. </p>
<p>At the moment, the app will just contain an empty screen as shown in the below screenshot. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-148.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter app with empty screen</em></p>
<p>Let's build all 3 types of navigation into our app. </p>
<p>But before that, let's see what our final app will look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-155.png" alt="Image" width="600" height="400" loading="lazy">
<em>Look of our final app</em></p>
<p>We'll have both drawer and tab navigators at the top. Pressing on the button in the first tab will take us to the next page via the stack navigator. </p>
<h2 id="heading-how-to-build-the-tab-navigation">How to Build the Tab Navigation</h2>
<p>Let's begin with building the tab navigator. Let's assume the tab will be on the home page (ideally that's where it would be). </p>
<p>Create a new file named <code>tab.dart</code> in the <code>lib/</code> directory. Add the following code:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./tabs/tab1.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./tabs/tab2.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./tabs/tab3.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomePage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> HomePage({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> DefaultTabController(
      length: <span class="hljs-number">3</span>,
      child: Scaffold(
          appBar: AppBar(
            title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Home"</span>),
            bottom: <span class="hljs-keyword">const</span> TabBar(
              tabs: [
                Tab(icon: Icon(Icons.phone_android)),
                Tab(icon: Icon(Icons.tablet_android)),
                Tab(icon: Icon(Icons.laptop_windows)),
              ],
            ),
          ),
          body: <span class="hljs-keyword">const</span> TabBarView(
            children: &lt;Widget&gt;[
              Tab1(),
              Tab2(),
              Tab3(),
            ],
          )),
    );
  }
}
</code></pre>
<p>In the above code, we're creating a class named <code>HomePage</code>. In the build method, we return the <code>DefaultTabController</code> widget, which is basically a tab view. We define that we need 3 tabs in the <code>length</code> property. </p>
<p>At the bottom of the <code>appBar</code> property we have defined icons for each tab (Phone, Tablet, and Computer icons). Below that we define the <code>body</code> property with a <code>TabBarView</code> rendering all the tabs inside it. </p>
<p>Immediately when you paste in the above code, you'll notice lot of errors being highlighted in your VS Code editor.</p>
<p> This is because, if you look at the top four lines, the first line is the import of Flutter's Material UI package and the other three are imports from the user defined files. But we haven't created them yet. So, your code editor will throw an error in those lines and at the last three lines where we call <code>Tab1()</code>, <code>Tab2()</code>, and <code>Tab3()</code> (because, these classes are imported from those files). Let's resolve this issue now. </p>
<p>Create a new folder named <code>tabs</code> inside the <code>lib/</code> directory and create three files named <code>tab1.dart</code>, <code>tab2.dart</code>, and <code>tab3.dart</code>. </p>
<p>Copy the below content into the <code>tab1.dart</code> file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tab1</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> Tab1({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> SizedBox(
      width: <span class="hljs-built_in">double</span>.infinity,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: &lt;Widget&gt;[
          <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Mobiles"</span>),
          Padding(
            padding: <span class="hljs-keyword">const</span> EdgeInsets.only(top: <span class="hljs-number">16.0</span>),
            child: ElevatedButton(
              onPressed: () {
                Navigator.of(context).pushNamed(<span class="hljs-string">"/secret"</span>);
              },
              child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Disclose Secret'</span>),
            ),
          ),
        ],
      ),
    );
  }
}
</code></pre>
<p>Copy the below content into the <code>tab2.dart</code> file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tab2</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> Tab2({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> SizedBox(
      width: <span class="hljs-built_in">double</span>.infinity,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <span class="hljs-keyword">const</span> &lt;Widget&gt;[
          Text(<span class="hljs-string">"Tablets"</span>),
        ],
      ),
    );
  }
}
</code></pre>
<p>Copy the below code into the <code>tab3.dart</code> file:</p>
<pre><code><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Tab3</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> Tab3({<span class="hljs-built_in">super</span>.key});

  @override
  Wid<span class="hljs-keyword">get</span> <span class="hljs-title">build</span>(<span class="hljs-params">BuildContext context</span>) {
    <span class="hljs-keyword">return</span> SizedBox(
      width: double.infinity,
      <span class="hljs-attr">child</span>: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        <span class="hljs-attr">children</span>: <span class="hljs-keyword">const</span> &lt;Widget&gt;[
          Text(<span class="hljs-string">"Laptops"</span>),
        ],
      ),
    );
  }
}
</code></pre><p>If you look at the code for all three files, you'll notice everything is the same except that the first tab file (<code>tab1.dart</code>) has an additional button called "Disclose Secret". Pressing that will navigate the user to the <code>/secret</code> route. It won't throw any error as this route has not been defined yet. The other two files (<code>tab2.dart</code> and <code>tab3.dart</code>) will show only the text. </p>
<p>All the errors you saw in the <code>tab.dart</code> file will be resolved now. But if you run your app, you will not notice any changes in the output. This is because we have just created the tab layout and we haven't mapped it to our <code>main.dart</code> file. </p>
<p>Add the following line at the top of the <code>main.dart</code> file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'./tab.dart'</span>;
</code></pre>
<p>Replace <code>home: const MyHomePage(title: 'Home')</code> with <code>home: const HomePage()</code>, in the <code>build</code> method of the <code>MyApp</code> class. </p>
<p>Save the file and run your app. You should be able to see the tab layout on your screen now. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-157.png" alt="Image" width="600" height="400" loading="lazy">
<em>Tab Layout in Flutter App</em></p>
<p>Don't press the "Disclose Secret" button. If you press it, it will throw an error. Because, as I mentioned earlier, we set up a route navigation in the <code>onPress</code> property of this button, but the route is not yet defined. </p>
<p>"Let's click that and see what happens"...</p>
<p>Hopefully, this thought will have entered your mind by now. It's not a mistake, it's human nature. We're curious to explore the things even if they're not recommended to do. </p>
<p>By the way, if you do that you'll see the following error (Exception in programming terminology):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-156.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter Router Exception</em></p>
<p>In a nutshell, this error screenshot describes that the provided route does not exist. </p>
<h2 id="heading-how-to-build-the-drawer-navigation">How to Build the Drawer Navigation</h2>
<p>Our next target is to add the drawer navigation. But before that, we have to create two files:</p>
<ol>
<li><code>drawer.dart</code>: to show the Navigation Drawer</li>
<li><code>about.dart</code>: an option will be provided on the Drawer Navigator to navigate here</li>
</ol>
<p>Create the <code>drawer.dart</code> file inside the <code>lib/</code> directory and not inside the <code>tab/</code> directory. The <code>tab/</code> directory is only for tabs and we don't need to touch that further as we're done with the tabs. Copy the below code into the <code>drawer.dart</code> file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyDrawer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> MyDrawer({<span class="hljs-keyword">super</span>.key});

  navigateTo(<span class="hljs-built_in">String</span> route, BuildContext context) {
    Navigator.of(context).pushReplacementNamed(route);
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Drawer(
      child: ListView(
        padding: <span class="hljs-keyword">const</span> EdgeInsets.all(<span class="hljs-number">16.0</span>),
        children: &lt;Widget&gt;[
          ListTile(
            leading: <span class="hljs-keyword">const</span> Icon(Icons.home),
            title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Home'</span>),
            onTap: () {
              navigateTo(<span class="hljs-string">"/home"</span>, context);
            },
          ),
          ListTile(
            leading: <span class="hljs-keyword">const</span> Icon(Icons.info),
            title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'About'</span>),
            onTap: () {
              navigateTo(<span class="hljs-string">"/about"</span>, context);
            },
          ),
        ],
      ),
    );
  }
}
</code></pre>
<p>In this file, we define the class named <code>MyDrawer</code>. In the <code>build</code> method we render the <code>Drawer</code> widget with <code>Home</code> and <code>About</code> options in the list. Clicking on those options will navigate us to the appropriate routes. </p>
<p>Create an <code>about.dart</code> file in the same directory and copy the below code: </p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'./drawer.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">About</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> About({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      drawer: <span class="hljs-keyword">const</span> MyDrawer(),
      appBar: AppBar(title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"About"</span>)),
      body: <span class="hljs-keyword">const</span> Center(child: Text(<span class="hljs-string">"About"</span>)),
    );
  }
}
</code></pre>
<p>In this file, we create a class named <code>About</code> which returns a <code>Scaffold</code> widget containing the drawer which we defined right before this file. The <code>appBar</code> and the <code>body</code> will show the text "About". </p>
<p>Again, you'll not be able to see these changes immediately in the app. This is because we haven't linked it into the <code>main.dart</code> file. </p>
<p>Before we link them, we have one item in our backlog. Let's finish it and come back to linking them all together. </p>
<p>Create a file named <code>secret.dart</code> in the <code>lib/</code> directory and copy the below code:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecretPage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> SecretPage({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
        appBar: AppBar(
          <span class="hljs-comment">// backgroundColor: Colors.red,</span>
          title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Secret"</span>),
        ),
        body: SizedBox(
          width: <span class="hljs-built_in">double</span>.infinity,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <span class="hljs-keyword">const</span> &lt;Widget&gt;[
              Text(<span class="hljs-string">"Nothing to show"</span>),
            ],
          ),
        ));
  }
}
</code></pre>
<p>In this file, we have created a class named <code>SecretPage</code> and returned just a <code>Text</code> in the <code>body</code>. Nothing fancy here. It's a super simple Flutter widget. </p>
<p>Our backlog item is also done. This is what you've been waiting for: we're going to define our routes now. </p>
<p>Open the <code>main.dart</code> file and add the following imports at the top of the file: </p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'./about.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./secret.dart'</span>;
</code></pre>
<p>Replace the <code>build</code> method of the <code>MyApp</code> class with the below code:</p>
<pre><code class="lang-dart">  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      routes: &lt;<span class="hljs-built_in">String</span>, WidgetBuilder&gt;{
        <span class="hljs-string">"/about"</span>: (BuildContext context) =&gt; <span class="hljs-keyword">const</span> About(),
        <span class="hljs-string">"/home"</span>: (BuildContext context) =&gt; <span class="hljs-keyword">const</span> HomePage(),
        <span class="hljs-string">"/secret"</span>: (BuildContext context) =&gt; <span class="hljs-keyword">const</span> SecretPage(),
      },
      initialRoute: <span class="hljs-string">"/home"</span>,
      title: <span class="hljs-string">'Flutter Navigation'</span>,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: <span class="hljs-keyword">const</span> HomePage(),
    );
  }
</code></pre>
<p>In the above code, you can see we're defining the MaterialApp to contain routes. They're defined as key-value pairs, mapping a route with a Widget. We have defined three routes:</p>
<ul>
<li><code>/about</code> – the route for the drawer navigator</li>
<li><code>/home</code> – the route for the tab navigator</li>
<li><code>/secret</code> – the route for the stack navigator</li>
</ul>
<p>We have set the initial route to be <code>/home</code>, which has the tab navigator. </p>
<p>Run the app and you should be able to see the following output on your device:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-158.png" alt="Image" width="600" height="400" loading="lazy">
<em>Merged Tab and Drawer View</em></p>
<p>On pressing the "Disclose Secret" button you'll be taken to the Secret page which we created (ideally it does not have a secret). You should also be able to scroll through the tabs smoothly. </p>
<p>By now, I hope you will have noticed an error here. If not, here's what it is: the back button is shown on the first screen of our app. </p>
<p>"Why would we need to show the back button on the first screen?"</p>
<p>That's an error and we have to resolve it. Press the back button and let's see what happens. Hopefully, you see what I saw. The back button was hidden and we see just the "Home" title in the <code>appBar</code> (similar to the below screenshot):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-160.png" alt="Image" width="600" height="400" loading="lazy">
<em>Back button issue</em></p>
<p>But there's an another issue on the same screen. Hopefully you saw that too. If not, don't worry, I'll reveal it right here. </p>
<p>"Can you access the drawer navigator by any means?"</p>
<p>No. Right? </p>
<p>But fortunately, the fix for the above two issues is the same. If we fix the second issue, the first issue will automatically be fixed. </p>
<p>That's great. But how do we fix the second issue? </p>
<p>You have to show the drawer navigator button (Hamburger icon) on the top left. This will eventually hide the back button. </p>
<p>Open the <code>tab.dart</code> file and import the drawer file at the top of this file. </p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'./drawer.dart'</span>;
</code></pre>
<p>Add the following line inside the <code>Scaffold</code> widget of the <code>build</code> method:</p>
<pre><code class="lang-dart">drawer: <span class="hljs-keyword">const</span> MyDrawer(),
</code></pre>
<p>And that's it!</p>
<p>Here's the output you can see when you run your app:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/04/image-163.png" alt="Image" width="600" height="400" loading="lazy">
<em>App look after the issues are fixed</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you've learned how to implement navigation in a Flutter app. We've included all three types of navigation in a single app in this tutorial for educational purposes. Ideally, you wouldn't do this with any real app you're building. Most apps will be built on either one or two types of navigation. </p>
<p>This <a target="_blank" href="https://github.com/5minslearn/Flutter-Navigation-Types">repo</a> has my code. You can use it for your reference. </p>
<p>To learn more about Flutter, subscribe to my email newsletter on my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_navigation">site</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_navigation">https://5minslearn.gogosoon.com</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use part in Dart – Splitting Files for Scoped Access ]]>
                </title>
                <description>
                    <![CDATA[ By Rutvik Tak When you're coding in Dart, you may come across these  following situations: A class/method is associated with a particular file of your codebase and you want to keep it private only to that one file. You want to break your one big fil... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-part-in-dart/</link>
                <guid isPermaLink="false">66d460c5e39d8b5612bc0ded</guid>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 03 Apr 2023 16:17:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/parts-in-dart-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rutvik Tak</p>
<p>When you're coding in Dart, you may come across these  following situations:</p>
<ol>
<li>A class/method is associated with a particular file of your codebase and you want to keep it private only to that one file.</li>
<li>You want to break your one big file in different parts but avoid accidentally using any private members of that file in other sections of your codebase.</li>
</ol>
<p>Now to solve the first problem, you might say that it’s quite simple, right? You just make the <code>class/method</code> private in that file, so it’s accessible only within it. Like this:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Private class which is accessible only in the file it's declared.</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyPrivateClassOne</span> </span>{    

}
</code></pre>
<p>Yes, that’s one way of doing it. But, it may not be the most suitable way in some cases.</p>
<p>If you keep on doing this, you’ll end up with the second problem we mentioned. You’ll soon have one very large file with multiple members inside it. And it will very quickly become a pain to manage and navigate different parts of that file.</p>
<h2 id="heading-how-to-use-part-in-dart"><strong>How to use <code>part</code> in Dart</strong></h2>
<p>That’s where <code>part</code>  comes in. It is an interesting feature of the <strong>Dart</strong> language that makes it easy to split a file into different parts to better manage and navigate file as it gets big.</p>
<p>We'll take a look at the following example:</p>
<pre><code><span class="hljs-comment">// main_file.dart</span>

part <span class="hljs-string">"private_class2.dart"</span> 

<span class="hljs-keyword">void</span> main() { 

final privateClassOne = _PrivateClassOne();
final privateClassTwo = _PrivateClassTwo();

}

<span class="hljs-comment">// private_class1.dart</span>

part <span class="hljs-keyword">of</span> <span class="hljs-string">"main_file.dart"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_PrivateClassOne</span></span>{

}

<span class="hljs-comment">// private_class2.dart</span>

part <span class="hljs-keyword">of</span> <span class="hljs-string">"main_file.dart"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_PrivateClassTwo</span></span>{

}
</code></pre><p>Let's break down the above example and understand what we are doing here:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// #1 Declaring private parts</span>

<span class="hljs-keyword">part</span> <span class="hljs-string">"private_class1.dart"</span>

<span class="hljs-keyword">part</span> <span class="hljs-string">"private_class2.dart"</span> 

<span class="hljs-keyword">void</span> main() { 

<span class="hljs-keyword">final</span> privateClassOne = _PrivateClassOne();
<span class="hljs-keyword">final</span> privateClassTwo = _PrivateClassTwo();

}
</code></pre>
<p>In the first step, we declared the files into which we want to split our main file.</p>
<p>Secondly, in the respective files <code>private_class1.dart</code> and <code>private_class2.dart</code>, we need to add the following line at the top of those files to associate them with the main file:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// #2 Associating the file with the main file for access.</span>

<span class="hljs-keyword">part</span> of <span class="hljs-string">"main_file.dart"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_PrivateClassOne</span></span>{

}
</code></pre>
<p>This way, you’re able to split ur one big file into multiple parts for better management and readability.</p>
<h2 id="heading-other-examples-of-using-part"><strong>Other examples of using <code>part</code></strong></h2>
<p>One popular package that makes use of <code>part</code> is <strong><a target="_blank" href="https://pub.dev/packages/freezed">Freezed</a></strong>. It’s a package for code generation for <code>data-classes/unions/pattern-matching/cloning</code>. You can, for example, use it to create helper methods on your model like <code>fromJson/toJson</code> which allows you to take in some JSON data and convert it to your model or vice-versa.</p>
<p>To learn more about <strong>Freezed</strong>, you can check it out on <a target="_blank" href="https://pub.dev/packages/freezed">pub.dev</a>.</p>
<p>Whenever you generate a <strong>Freezed</strong> model – for example, <code>Screenshot</code> and is in a file <code>screenshot.dart</code> – you’ll notice that it generates two other files, <code>screenshot.freezed.dart</code> and <code>screenshot.g.dart</code>. This includes the helper methods like <code>fromJson/toJson/copyWith</code> in them.</p>
<p>You’ll notice that, at the start of your actual <strong>Freezed</strong> model file, you need to add these two lines:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// #1 Declaring separate private files</span>

<span class="hljs-keyword">part</span> <span class="hljs-string">'screenshot.freezed.dart'</span>;

<span class="hljs-keyword">part</span> <span class="hljs-string">'screenshot.g.dart'</span>;
</code></pre>
<p>As we discussed in our above example, here you're mentioning the parts of your main file <code>screenshot.dart</code> model.</p>
<p>And these two generated files have the following line added to them at the start:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// #2 Associating the respected private files with the main file</span>

<span class="hljs-keyword">part</span> of <span class="hljs-string">'screenshot.dart'</span>;
</code></pre>
<p>Here, <strong>Freezed</strong> is generating these other helper methods that your model utilizes. But it splits them in these different files to keep parts of the generated code away from you which you don’t need to worry about.</p>
<h2 id="heading-use-cases-for-part"><strong>Use Cases for part</strong></h2>
<p>Currently I’m working on my side project, <a target="_blank" href="https://appshots.co/">AppShots</a> where I needed to use <code>part</code> to solve an actual problem.</p>
<p>I’ve two database layers, <code>PrimaryDatabaseLayer</code> and <code>_SecondaryDatabaseLayer</code> in my flutter app. The <code>_SecondaryDatabaseLayer</code>  would talk to the local database directly for adding/updating/deleting items.   </p>
<p>Lets see how the <code>PrimaryDatabaseLayer</code>  looks like,</p>
<pre><code class="lang-dart"><span class="hljs-comment">// primary_database_layer.dart</span>

<span class="hljs-keyword">part</span> <span class="hljs-string">"secondary_database_layer.dart"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PrimaryDatabaseLayer</span> </span>{

    Future&lt;Screenshot1&gt; addScreenshot(....){
      <span class="hljs-comment">// convert the model from Screenshot1 to Screenshot2 and call       // addScreenshot method from _SecondaryDatabase with Screenshot2</span>
        ....
        .......
    }

    Future&lt;Screenshot1&gt; updateScreenshot(....){
        <span class="hljs-comment">// update screenshot to local db</span>
        ....
        .......
    }

    Future&lt;Screenshot1&gt; deleteScreenshot(....){
        <span class="hljs-comment">// delete screenshot from local db</span>
        ....
        .......
    }

}
</code></pre>
<p>Then I had the second layer as follows:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// secondary_database_layer.dart</span>

<span class="hljs-keyword">part</span> of <span class="hljs-string">"primary_database_layer.dart"</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_SecondaryDatabaseLayer</span> </span>{

    Future&lt;Screenshot2&gt; addScreenshot(....){
        <span class="hljs-comment">// add screenshot to local db</span>
        ....
        .......
    }

    Future&lt;Screenshot2&gt; updateScreenshot(....){
        <span class="hljs-comment">// update screenshot to local db</span>
        ....
        .......
    }

    Future&lt;Screenshot2&gt; deleteScreenshot(....){
        <span class="hljs-comment">// delete screenshot from local db</span>
        ....
        .......
    }

}
</code></pre>
<p>The main reason to have two db layers here was, I had two different models, <code>Screenshot1</code> and <code>Screenshot2</code>. The <code>Screenshot2</code> is the model that's suitable for interacting with the actual local db and <code>Screenshot1</code> is the model I used in the <strong>apps business logic and the ui views</strong>.</p>
<p>Now, as you can see the <code>PrimaryDatabaseLayer</code> is just a wrapper around the <code>_SecondaryDatabaseLayer</code> for convenient conversion of data models.</p>
<p>Adding the <code>_SecondaryDatabaseLayer</code> in the same file as <code>PrimaryDatabaseLayer</code> makes it difficult to mange and navigate as the layers grow in terms of their functionality. So, I used <code>part</code> here to make the <code>_SecondaryDatabaseLayer</code> a part of the <code>PrimaryDatabaseLayer</code> .</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this tutorial, we discussed how to use <code>part</code> in <strong>Dart</strong> to improve your codebase. And you learned about a few examples where using <code>part</code> is beneficial and makes your life a little bit easier managing your code.</p>
<p>☺️ I hope you enjoyed this article. I'm planning to release more content where I'll be sharing my experiences/challenges building personal/work projects in Dart and Flutter to help you become a better developer.💪</p>
<p>If you liked this article and have any questions or would like to get in touch, you can connect with me on Twitter <a target="_blank" href="https://twitter.com/TakRutvik"><strong>@TakRutvik</strong></a> where I'm active and share all of my learnings and interesting projects I'm working on. ✨</p>
<p>Have a great day!☺️<br>Keep Fluttering 💙</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn State Management in Flutter by Building a Simple Todo App ]]>
                </title>
                <description>
                    <![CDATA[ State management is a complex topic in mobile application development. But it's also a necessary topic that plays a major role in building dynamic mobile apps.  If you master state management, you'll be able to build any kind of dynamic application. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-state-management-in-flutter/</link>
                <guid isPermaLink="false">66ba10e6439ed06e055759fa</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ State Management  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Mon, 03 Apr 2023 13:55:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/Flutter-State-Management---Todo-App---Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>State management is a complex topic in mobile application development. But it's also a necessary topic that plays a major role in building dynamic mobile apps. </p>
<p>If you master state management, you'll be able to build any kind of dynamic application. This is because the UI that's being rendered on the mobile device will be determined by the state of the data that your app holds at that time. This is why it's critical to master state management in front-end application development. </p>
<p>In this article, we'll learn state management by building a Todo app in Flutter. </p>
<p>First, let's look at some theory on state management before we dive into app development. </p>
<h2 id="heading-what-is-state-in-flutter-apps">What is State in Flutter Apps?</h2>
<p>State defines the user interface of your app. In other words, the user interface is built by the current state of the app. </p>
<p>When the state of a Flutter app changes, it'll trigger the re-draw of the user interface. This is called Declarative UI, which Flutter uses – whereas native mobile apps (Android &amp; iOS) are built with Imperative UI, where the user interface is defined earlier. </p>
<h2 id="heading-types-of-state">Types of State</h2>
<p>There are 2 types of state. They are:</p>
<ol>
<li>Ephemeral State</li>
<li>App State</li>
</ol>
<h3 id="heading-ephemeral-state">Ephemeral State</h3>
<p>Ephemeral state is the state that is contained in a single widget or a screen/page of an app. </p>
<h3 id="heading-app-state">App State</h3>
<p>App state is the state that is shared between user sessions and is used across many parts of the app. </p>
<h3 id="heading-how-to-choose-the-state-for-your-app">How to Choose the State for Your App</h3>
<p>There is no single rule as to which state to choose. It's depends on your use case. It's often a good idea to use Ephemeral state at first and then refactor your code in the future if you face any need to use App state. </p>
<h2 id="heading-what-well-build">What We'll Build</h2>
<p>In this tutorial, we'll be building a Todo app. This app will have the functionality to create a todo item, list all the added items, update an item, and delete an item. Here's the sneak peak (screenshot) for you. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-257.png" alt="Image" width="600" height="400" loading="lazy">
<em>Todo App</em></p>
<h2 id="heading-app-development">App Development</h2>
<p>Let's put on our development shoes and start building our app. </p>
<h2 id="heading-create-the-project">Create the Project</h2>
<p>Here are the super simple steps to create your Flutter project. If you want a detailed explanation, please read the <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-simple-login-app-with-flutter/">"How to Create the Project" section in the blog</a> and come back here. </p>
<ol>
<li>Open your VS Code</li>
<li>Hit "CTRL+SHIFT+P" (Mac users replace CTRL with CMD)</li>
<li>Type "Flutter"</li>
<li>Select the "Flutter: New Project" option</li>
<li>Select "Application" from the next list</li>
<li>Select the folder to create your project in the next prompt</li>
<li>On the final prompt, enter your app name and press "Enter"</li>
</ol>
<p>That's it! Our boilerplate app is ready. </p>
<p>Select the preferred device to run your app on the bottom right and hit "F5". Your app will run on your selected device. You should see the following screen in a few seconds. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-258.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter Boilerplate App</em></p>
<h2 id="heading-time-to-refactor-the-code">Time to Refactor the Code</h2>
<p>We have a Flutter boilerplate app. By default, it'll have a lot of items, so let's refactor our code. We'll be working on the <code>main.dart</code> file in the <code>lib/</code> folder to build this entire app. </p>
<h3 id="heading-initialize-git">Initialize Git</h3>
<p>Initialize Git by running <code>git init</code> in the root folder of your repo. </p>
<h3 id="heading-remove-comments">Remove comments</h3>
<p>I've removed all the comments in the <code>main.dart</code> file and added a commit. </p>
<h3 id="heading-rename-classes">Rename Classes</h3>
<p>Rename <code>MyApp</code> to <code>TodoApp</code> in the main method by pressing <code>F2</code> in VS Code. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-263.png" alt="Image" width="600" height="400" loading="lazy">
<em>Rename class name</em></p>
<p>On the first page, we'll be listing the created to-do items. Let's rename it from <code>MyHomePage</code> to <code>TodoList</code>. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-264.png" alt="Image" width="600" height="400" loading="lazy">
<em>Rename <code>MyHomePage</code> to <code>TodoList</code> class</em></p>
<p>In the above screenshot, the title of the MaterialApp is set to "Flutter Demo" and the title passed in TodoList is set to "Flutter Demo Home Page". Let's change both of those to "Todo Manager". </p>
<h2 id="heading-how-to-build-the-todo-app">How to Build the Todo App</h2>
<p>Let's build the core functionality of our app. </p>
<p>We need a <code>Todo</code> class. This class will define the properties of a todo. In our case, we'll have the following items:</p>
<ol>
<li>Name of the todo</li>
<li>Status of the todo (Backlog / Completed)</li>
</ol>
<p>Let's define a <code>Todo</code> class with the above properties:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Todo</span> </span>{
  Todo({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.name, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.completed});
  <span class="hljs-built_in">String</span> name;
  <span class="hljs-built_in">bool</span> completed;
}
</code></pre>
<p>Add the above code at the bottom of the <code>main.dart</code> file. </p>
<h3 id="heading-how-to-add-a-todo">How to Add a Todo</h3>
<p>Look at your code for a class named <code>_TodoListState</code>. In the body of the <code>build</code> method, set the children property to an empty array. Refer to the below screenshot:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/1.-Remove-Center-Text.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Before and After removing the <code>Text</code> widgets</em></p>
<p>Remove the two <code>Text</code> widgets inside that children property. </p>
<p>Now we'll replace the counter variable with a todo list. </p>
<pre><code class="lang-dart"><span class="hljs-built_in">int</span> _counter = <span class="hljs-number">0</span>;
</code></pre>
<p>Replace the above line with the following code. The first line is the todo list and the second line defines the controller to get the name of the todo from the user:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span>&lt;Todo&gt; _todos = &lt;Todo&gt;[];
<span class="hljs-keyword">final</span> TextEditingController _textFieldController = TextEditingController();
</code></pre>
<p>Remove the <code>_incrementCounter</code> method and add the method to add a todo:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> _addTodoItem(<span class="hljs-built_in">String</span> name) {
    setState(() {
      _todos.add(Todo(name: name, completed: <span class="hljs-keyword">false</span>));
    });
    _textFieldController.clear();
}
</code></pre>
<p>So far we have defined our todo list and an input controller. We've also created a method that accepts input text and adds that to the todo list with a completed status set to <code>false</code> and a clear input field. </p>
<p>The reason we have used the <code>setState</code> method is to refresh the UI after we update the todo list. As our component is a stateful widget, whenever a change in state is detected, the UI will render again with the updated state. </p>
<p>We have built the functionality code to add a todo. Let's build the UI code. Let's ask the user the name of the todo on pressing the Floating action button at the bottom right. When the user tries to save the todo, we'll call the <code>_addTodoItem</code> method defined above. </p>
<pre><code class="lang-dart">floatingActionButton: FloatingActionButton(
    onPressed: () =&gt; _displayDialog(),
    tooltip: <span class="hljs-string">'Add a Todo'</span>,
    child: <span class="hljs-keyword">const</span> Icon(Icons.add),
),
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/2.-Floating-Action-Button.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Before and After of Floating Action Button code</em></p>
<p>In the above method, we have changed the <code>onPressed</code> property to call the <code>_displayDialog</code> method. As it's not defined yet, it'll show an error. We'll define the method next. We have also changed the <code>tooltip</code> property to "Add a Todo". </p>
<p>Here's the code (<code>_displayDialog</code> method) to show a dialog box with an input field, add, and cancel button. Add this method inside the <code>_TodoListState</code> class:</p>
<pre><code>Future&lt;<span class="hljs-keyword">void</span>&gt; _displayDialog() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">return</span> showDialog&lt;<span class="hljs-keyword">void</span>&gt;(
      context: context,
      <span class="hljs-attr">T</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">builder</span>: (BuildContext context) {
        <span class="hljs-keyword">return</span> AlertDialog(
          title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Add a todo'</span>),
          <span class="hljs-attr">content</span>: TextField(
            controller: _textFieldController,
            <span class="hljs-attr">decoration</span>: <span class="hljs-keyword">const</span> InputDecoration(hintText: <span class="hljs-string">'Type your todo'</span>),
            <span class="hljs-attr">autofocus</span>: <span class="hljs-literal">true</span>,
          ),
          <span class="hljs-attr">actions</span>: <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Widget</span>&gt;</span>[
            OutlinedButton(
              style: OutlinedButton.styleFrom(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
              ),
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: const Text('Cancel'),
            ),
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(12),
                ),
              ),
              onPressed: () {
                Navigator.of(context).pop();
                _addTodoItem(_textFieldController.text);
              },
              child: const Text('Add'),
            ),
          ],
        );
      },
    );
  }</span>
</code></pre><p>Let's understand this huge piece of code. </p>
<p>The <code>Future</code> class is used for asynchronous computation.</p>
<p>Quoting from the <a target="_blank" href="https://api.flutter.dev/flutter/dart-async/Future-class.html">documentation</a>, </p>
<blockquote>
<p>"An asynchronous computation may need to wait for something external to the program (reading a file, querying a database, fetching a web page) which takes time. Instead of blocking all computation until the result is available, the asynchronous computation immediately returns a <code>Future</code> which will <strong><em>eventually</em></strong> 'complete' with the result. "</p>
</blockquote>
<p>In our case, it'll wait for the user to tap the Add or Cancel button. </p>
<p>The <code>_displayDialog</code> method will return the <code>showDialog</code> method by building the UI. </p>
<p>The <code>barrierDismissible</code> property is used to define if the pop up has to be closed if the user taps outside of the alert dialog. We have set that to <code>false</code> which means the alert dialog will not be closed on taping outside. </p>
<p>The <code>builder</code> of this <code>showDialog</code> method returns an <code>AlertDialog</code> consisting of <code>title</code>, <code>content</code>, and <code>actions</code> property. The <code>title</code> is set to display the text "Add a todo". The <code>content</code> property will render an text input field with automatic focus enabled and the hint "Type your todo". </p>
<p>The <code>actions</code> property will render 2 buttons, <code>Cancel</code> and <code>Add</code>. The <code>Cancel</code> button is an outlined button, and pressing it will close the dialog. The <code>Add</code> button adds the text to the todo list and closes the dialog. </p>
<p>Let's test our app. Click on the floating action button and you should see the UI similar to the one below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-262.png" alt="Image" width="600" height="400" loading="lazy">
<em>Add Todo UI</em></p>
<p>If you try to add a todo, it'll be added to our todo list. But, you'll not be able to see any change on the UI. </p>
<h3 id="heading-how-to-list-the-todos">How to List the Todos</h3>
<p>We have added the code to add todos to the list. But wait – how can we verify that? We have to find if the todo has actually been added to the list. </p>
<p>Let's verify that by rendering the list of todo items in the UI. To do so, we have to design the UI for a single todo. Let's do that. </p>
<p>Add the following code at the end of <code>main.dart</code> file:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TodoItem</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  TodoItem({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.todo}) : <span class="hljs-keyword">super</span>(key: ObjectKey(todo));

  <span class="hljs-keyword">final</span> Todo todo;

  TextStyle? _getTextStyle(<span class="hljs-built_in">bool</span> checked) {
    <span class="hljs-keyword">if</span> (!checked) <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> TextStyle(
      color: Colors.black54,
      decoration: TextDecoration.lineThrough,
    );
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> ListTile(
      onTap: () {},
      leading: Checkbox(
        checkColor: Colors.greenAccent,
        activeColor: Colors.red,
        value: todo.completed,
        onChanged: (value) {},
      ),
      title: Row(children: &lt;Widget&gt;[
        Expanded(
          child: Text(todo.name, style: _getTextStyle(todo.completed)),
        ),
        IconButton(
          iconSize: <span class="hljs-number">30</span>,
          icon: <span class="hljs-keyword">const</span> Icon(
            Icons.delete,
            color: Colors.red,
          ),
          alignment: Alignment.centerRight,
          onPressed: () {},
        ),
      ]),
    );
  }
}
</code></pre>
<p>Here's the brief explanation of the above code. </p>
<p>First, we created a class with the <code>TodoItem</code> and we extended it from the <code>StatelessWidget</code> class as we don't need to maintain state for this class. </p>
<p>We accept a <code>Todo</code>, which is passed via constructor to our class. The code in the <code>build</code> method determines the UI. It renders the <code>ListTile</code> widget with the <code>Checkbox</code> widget passed to the <code>leading</code> property. </p>
<p>The <code>title</code> property renders a row of <code>Text</code> and <code>IconButton</code> widgets. The <code>Text</code> widget shows the name of the todo and the <code>IconButton</code> widget displays the <code>delete</code> icon. </p>
<p>Notice the <code>_getTextStyle</code> method passed to the <code>style</code> property of the <code>Text</code> widget. This method strikes out the text if the todo is marked as complete. Nothing changes on tapping any of these widgets, as the corresponding properties are left empty (onTap, onChanged, and onPressed). </p>
<p>Change the <code>body</code> property of the <code>build</code> method in <code>_TodoListState</code> with the following code:</p>
<pre><code class="lang-dart">ListView(
    padding: <span class="hljs-keyword">const</span> EdgeInsets.symmetric(vertical: <span class="hljs-number">8.0</span>),
    children: _todos.map((Todo todo) {
      <span class="hljs-keyword">return</span> TodoItem(
        todo: todo,
      );
    }).toList(),
),
</code></pre>
<p>Here's the highlighted screenshot showing the changes on the <code>build</code> method of the <code>_TodoListState</code> class:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-265.png" alt="Image" width="600" height="400" loading="lazy">
<em>Rendering the list of todo items</em></p>
<p>The above code defines a <code>ListView</code> widget iterating over the created todos and passing each todo to the <code>TodoItem</code> widget. </p>
<p>We're done with listing the todos. Let's verify if both creating and viewing a todo works fine. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-266.png" alt="Image" width="600" height="400" loading="lazy">
<em>List of created todos</em></p>
<p>Cool! There are our todos. </p>
<p>But tapping on either the Checkbox or Delete button will have no effect. </p>
<p>I hope you can guess what we'll be doing next. Yes, we'll be adding the code to mark the todo as completed and delete a todo item. </p>
<h3 id="heading-how-to-update-a-todo">How to Update a Todo</h3>
<p>Let's mark the todo as complete on pressing the checkbox near each todo. </p>
<p>We have 2 fields in our Todo class. They're name and completed status. Whenever a Todo is created, the default value of the completed field is set to <code>false</code>. This means the todo is in progress. We can change that to <code>true</code> whenever we complete the task. </p>
<p>Define a method called <code>_handleTodoChange</code> in the <code>_TodoListState</code> class. Add this method below the <code>_addTodoItem</code> method which we defined to add a todo to the list. </p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> _handleTodoChange(Todo todo) {
  setState(() {
    todo.completed = !todo.completed;
  });
}
</code></pre>
<p>In the above code, we accept a todo and change the completed status of the todo. So, whenever this method is called with a todo, it's completed status will change from <code>true</code> to <code>false</code> or vice versa. Remember that we have wrapped this inside a <code>setState</code> method to render the UI after making the change. </p>
<p>We have to trigger this method when a user taps on a todo or taps on a checkbox. We should pass this method to the <code>TodoItem</code> class. While calling the <code>TodoItem</code> in the build method of the <code>_TodoListState</code> class, pass the <code>_handleTodoChange</code> method as shown below:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">return</span> TodoItem(
    todo: todo,
    onTodoChanged: _handleTodoChange,
);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/4.-Change-Todo-Status-2.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Before and After adding a method to change todo status</em></p>
<p>As we're passing the method to the <code>TodoItem</code> class, we should receive the same method in the <code>TodoItem</code> class. To do so, we have to define this method in the constructor of the <code>TodoItem</code> class. Go to <code>TodoItem</code> and change the constructor to include the <code>onTodoChanged</code> method. </p>
<pre><code class="lang-dart">TodoItem({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.todo, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.onTodoChanged})
      : <span class="hljs-keyword">super</span>(key: ObjectKey(todo));
</code></pre>
<p>You may notice in the above code that we use <code>**this**.onTodoChanged</code>, which means we're binding the method passed to a method in this <code>TodoItem</code> class. </p>
<p>Let's define a method with the same name and set the return type to <code>void</code> (as we don't expect anything from that method). </p>
<pre><code class="lang-dart"><span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-built_in">Function</span>(Todo todo) onTodoChanged;
</code></pre>
<p>So, wherever we call this method in our code, the status of our todo will be changed to the opposite. Let's call this method in the <code>onTap</code> property of the <code>ListTile</code> widget and <code>onChanged</code> property of the <code>Checkbox</code> widget. </p>
<pre><code class="lang-dart">onTap: () {
    onTodoChanged(todo);
},
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/4.-Change-Todo-Status---Method-Call.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Call <code>onTodoChanged</code> method on tapping the todo or checkbox</em></p>
<p>That's it. We're done. Let's run our app and verify if we're able to complete the todo. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-267.png" alt="Image" width="600" height="400" loading="lazy">
<em>Mark todo as complete</em></p>
<p>That's awesome right? We're able to mark the todo as complete and revert back. </p>
<h3 id="heading-how-to-delete-a-todo">How to Delete a Todo</h3>
<p>We have only one item left to complete this app. We should be able to delete a todo, if we create one by mistake or if it's no longer applicable. </p>
<p>Steps to delete a todo are similar to updating a todo. We'll doing the exact 4 steps as we did for updating a todo. </p>
<ol>
<li>Define the <code>_deleteTodo</code> method</li>
<li>Pass the method on <code>TodoItem</code> render</li>
<li>Receive the method on <code>TodoItem</code> constructor</li>
<li>Bind the method</li>
<li>Call the method on button tap</li>
</ol>
<p>I would recommend that you try this by yourself as we'll be repeating the steps we did earlier. After you're done, you can verify your implementation by cross checking with my steps. </p>
<p>Here's the method to delete the todo. Add this in the <code>_TodoListState</code> class below the <code>_handleTodoChange</code> method:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> _deleteTodo(Todo todo) {
  setState(() {
    _todos.removeWhere((element) =&gt; element.name == todo.name);
  });
}
</code></pre>
<p>This method accepts a todo, compares it with the todo list, and identifies the todo which matches with this name. Then it deletes it from the list and finally updates the state. </p>
<p>Let's pass the method reference to <code>TodoItem</code> in the <code>build</code> method of the <code>_TodoListState</code> class. </p>
<pre><code class="lang-dart"><span class="hljs-keyword">return</span> TodoItem(
  todo: todo,
  onTodoChanged: _handleTodoChange,
  removeTodo: _deleteTodo);
</code></pre>
<p>Change the constructor to accept the <code>removeTodo</code> method. </p>
<pre><code>  TodoItem(
      {required <span class="hljs-built_in">this</span>.todo,
      required <span class="hljs-built_in">this</span>.onTodoChanged,
      required <span class="hljs-built_in">this</span>.removeTodo})
      : <span class="hljs-built_in">super</span>(key: ObjectKey(todo));
</code></pre><p>Define a method with the same name and set the return type to <code>void</code> (as we don't expect anything from this method). </p>
<p>Our final step is to call this method on pressing the delete button. </p>
<pre><code class="lang-dart">IconButton(
  iconSize: <span class="hljs-number">30</span>,
  icon: <span class="hljs-keyword">const</span> Icon(
    Icons.delete,
    color: Colors.red,
  ),
  alignment: Alignment.centerRight,
  onPressed: () {
    removeTodo(todo);
  },
),
</code></pre>
<p>That's it. I hope it's super simple. Let's test our app. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/5.-Delete-Todo.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Last todo is deleted</em></p>
<p>Wow! It works. </p>
<p>In the above screenshot, you can see I created a todo with the name "Call SC service men" which should be created as "Call AC service men". So, that was a mistake. I don't want that todo now as it'll confuse me. I would rather create a new todo with the right spelling. So, I pressed the delete button which almost instantly deleted my todo. </p>
<p>Cool! We have built our own todo app. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you've learnt about state management in Flutter. Along with that, we've built a simple todo app in Flutter implementing CRUD functionality. </p>
<p>CRUD stands for Create, Read, Update, and Delete. We created a todo, listed it on the UI, updated its status, and finally deleted it. </p>
<p>This <a target="_blank" href="https://github.com/5minslearn/Flutter-Todo-App">repo</a> has my code. You can use it for your reference. </p>
<p>Here are few exercise to challenge yourself. Try to extend this app by adding the following functionalities. </p>
<ol>
<li>Show a message saying "No todo exists. Please create one and track your work", if no todo was created.</li>
<li>I know about a bug in this app. I hope you don't know – so I'm revealing it here. But you have to fix it. Create two todos with same name and try to delete one. You'll be amazed to see both of them deleted together. Here's a tip for you to fix. Assign a random id for each todo and while deleting, filter the todo by id. </li>
<li>Add functionality to edit the name of a todo</li>
<li>This app was completely built on Ephemeral state. So, if you close and open the app again, your old todo items will not be there. Add a functionality to store the todo in the device storage. Show the todos to the user when they reopen the app by reading them from your device storage. </li>
</ol>
<p>To learn more about Flutter, subscribe to my email newsletter on my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_todo_app">site</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_todo_app">https://5minslearn.gogosoon.com</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Simple Login App with Flutter ]]>
                </title>
                <description>
                    <![CDATA[ Flutter is one of the most popular frameworks for building mobile and desktop applications. And many companies are using it today. This is in part because of its outstanding performance, having a benchmark of 60 Frames Per Second (FPS). This helps it... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-simple-login-app-with-flutter/</link>
                <guid isPermaLink="false">66ba10b7c003a1736007f4b5</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Tue, 14 Mar 2023 16:39:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/Flutter-Login-App---Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Flutter is one of the most popular frameworks for building mobile and desktop applications. And many companies are using it today.</p>
<p>This is in part because of its outstanding performance, having a benchmark of 60 Frames Per Second (FPS). This helps it outperform other cross-platform technologies, and it performs better even when compared with native languages. </p>
<p>I'm a React Native enthusiast. But after hearing all the advantages of Flutter, I decided to try it out. I would like to share my learning experience with you through this tutorial.</p>
<p>In this article, we'll learn how to create a Flutter app with a login layout and a few functionalities. </p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>In this article, I'll not cover the steps to install Flutter on your machine. I feel it's better explained on their <a target="_blank" href="https://docs.flutter.dev/get-started/install">official documentation site</a>. </p>
<p>I would highly recommend that you try this <a target="_blank" href="https://docs.flutter.dev/get-started/codelab">exercise</a> offered by the official Flutter community. It will give you a quick understanding of Flutter so you can get started. </p>
<p>Don't worry if you don't understand a few concepts mentioned there. I'll be writing about them in my upcoming tutorials. I used that exercise to start my own Flutter journey, and I felt more confident after completing it on my own. </p>
<p>Let's get started building our app!</p>
<p>I believe in the saying, "Setting a goal is half the work done". So, whenever I try to do something, I will set a goal to see where I want to be when I finish. So what's the goal for you reading this tutorial? </p>
<h2 id="heading-required-tools">Required Tools</h2>
<p>To build this app, you need the following items installed on your machine:</p>
<ol>
<li>Visual Studio Code (One of Flutter's recommended IDEs)</li>
<li>Android Emulator / iOS Simulator / Original device</li>
<li>Flutter Installed (I would recommend following <a target="_blank" href="http://docs.flutter.dev/get-started/install">this guide</a> to install it if you don't have it already)</li>
<li>Flutter plugin for VS Code (<a target="_blank" href="https://docs.flutter.dev/get-started/editor?tab=vscode">Recommended Guide</a>)</li>
</ol>
<h2 id="heading-how-to-create-the-project">How to Create the Project</h2>
<p>Navigate to the folder where you want to create your app. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-61.png" alt="Image" width="600" height="400" loading="lazy">
<em>Navigate to the project directory</em></p>
<p>Open Visual Studio Code from that directory. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-62.png" alt="Image" width="600" height="400" loading="lazy">
<em>Open Visual Studio Code</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-63.png" alt="Image" width="600" height="400" loading="lazy">
<em>Visual Studio Code IDE</em></p>
<p>Open the command palette by pressing <code>CTRL + SHIFT + P</code> and type <code>Flutter</code>. Choose <code>Flutter: New Project</code> from the listed options. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-64.png" alt="Image" width="600" height="400" loading="lazy">
<em>Use the command palette to create a Flutter project</em></p>
<p>Select <code>Application</code> from the next list. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-65.png" alt="Image" width="600" height="400" loading="lazy">
<em>Choose to build Flutter <code>Application</code></em></p>
<p>It'll ask you to Select the target folder to create the project. By default, it'll be in the same folder where you opened VS Code. Type your app name in the text input and hit <code>Enter</code>. I'm naming mine <code>loginapp</code>, but you can type any name you wish. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-66.png" alt="Image" width="600" height="400" loading="lazy">
<em>Enter your project name</em></p>
<p>In the next few seconds, VS Code will create a new Flutter project and you'll see a screen like the one below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-67.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter project created</em></p>
<p>By default, <code>main.dart</code> file will be opened. This is where Flutter begins to run the app. At the bottom, you will see a notification saying "Your Flutter project is ready! Press F5 to start running ...". </p>
<h2 id="heading-how-to-spin-up-the-device">How to Spin Up the Device</h2>
<p>To run your app, you need to have either a virtual device or an actual device running and connected to your machine. </p>
<p>I'll be using an Android Emulator to run our app. You may either run a virtual device or connect your mobile phone to your machine. But remember to turn on "USB Debugging" if you're debugging via an Android phone. </p>
<p>Once you're connected or spin up a virtual device, look at the bottom right of VS Code and press the device option. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-68.png" alt="Image" width="600" height="400" loading="lazy">
<em>Devices option</em></p>
<p>Sometimes, VS Code will select the device by default, but for the first time, you have to select it on your own. Press the "No Device" text in the above screenshot or whatever the device name is shown to you there. </p>
<p>You'll be shown the list of virtual devices that are available and connected. Click on the device where you want to run your app. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-69.png" alt="Image" width="600" height="400" loading="lazy">
<em>List of available devices to run the app</em></p>
<p>Once you've selected your device, the bottom panel will show your selected device name similar to the below screenshot. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-70.png" alt="Image" width="600" height="400" loading="lazy">
<em>Selected my Android emulator</em></p>
<h2 id="heading-how-to-run-the-app">How to Run the App</h2>
<p>Are you ready for the Rocket Launch? </p>
<p>Press <code>F5</code> to run your app. This will take some time. It'll be compiling and building your project. Once it's ready, the app will be running on your device. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-71.png" alt="Image" width="600" height="400" loading="lazy">
<em>Running your app</em></p>
<p>You'll see a similar kind of interface. At the bottom, you can see the notification saying "Running Gradle task 'assembleDebug...'". </p>
<p>Excited for the output? Here you go:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-72.png" alt="Image" width="600" height="400" loading="lazy">
<em>Output of the default app</em></p>
<p>Don't make any changes to the code now. Your changes will not be tracked as Git is not initialized for this repo. </p>
<p>This is one part that I like about React Native. Whenever you create a React Native app, it'll make an initial commit. You can just go forward and make your changes and you'll be able to see all your changes being tracked. </p>
<p>This is not available in Flutter as of now (Mar 2023), but I hope the Flutter team may add this in the future. </p>
<p>Let's make the commit on our own. </p>
<p>Navigate to the project location in the Terminal:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> &lt;project_location&gt;
</code></pre>
<p>Initialize Git by running <code>git init</code> command. </p>
<p>As it's our first commit, we'll do <code>git add .</code> to add all the changes to our commit. </p>
<p>Let's make the initial commit:</p>
<pre><code>git commit -m <span class="hljs-string">"Initial commit"</span>
</code></pre><p>Here's the screenshot of the above process:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-73.png" alt="Image" width="600" height="400" loading="lazy">
<em>Commit the changes to git</em></p>
<p>Let's verify if our changes are committed by running the <code>git status</code> command:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-74.png" alt="Image" width="600" height="400" loading="lazy">
<em>Verifying after commit</em></p>
<p>Looks Good. Our changes are committed. Let's proceed. </p>
<h2 id="heading-how-to-remove-comments">How to Remove Comments</h2>
<p>I don't like comments in my code. I love writing readable code. Let's remove all the comments in the <code>main.dart</code> file. Don't touch the other files. </p>
<p>All the Flutter files will reside under the <code>lib/</code> directory and they'll have the <code>.dart</code> file extension. For this entire tutorial, we'll be working only on the <code>main.dart</code> file. </p>
<p>You can read the comments and get some insights from them. They'll give you a clear understanding about how the default app works which can be really helpful for beginners. </p>
<p>But, it does not make any sense if you're building the app for 2nd or 3rd time. There is no point in reading the same comments again and again as you will have gained context on your 1st read. </p>
<p>You can ignore this step if you want to keep the comments as they are. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Full-code.png" alt="Image" width="600" height="400" loading="lazy">
<em>App Code</em></p>
<p>My code has become super simple now. I've made a commit here (after removing the comments). If you have come this far, after committing just ensure your app is running fine and there have been no changes on the UI. </p>
<h2 id="heading-how-to-change-the-name">How to Change the Name</h2>
<p>Let's change the name of the title bar and the internal class names. On the <code>MyApp</code> class, inside the <code>build</code> method, change the title in the home field from "Flutter Demo Home Page" to "Login App".  </p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> MyApp({Key? key}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      title: <span class="hljs-string">'Flutter Demo'</span>,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: <span class="hljs-keyword">const</span> MyHomePage(title: <span class="hljs-string">'Login App'</span>),
    );
  }
}
</code></pre>
<p>Let's change our class name from "MyHomePage" to "Login". Place the cursor on the "MyHomePage" text and press <code>F2</code>. <code>F2</code> is the shortcut key to rename and refactor in VS Code. This means, it renames at the current place and replaces all its usages. Here's the screenshot of how it looks when you press <code>F2</code> (on refactoring). </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-76.png" alt="Image" width="600" height="400" loading="lazy">
<em>Rename class name from <code>MyHomePage</code> to <code>Login</code></em></p>
<p>Let's commit our changes. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-77.png" alt="Image" width="600" height="400" loading="lazy">
<em>Commit the changes to the names</em></p>
<p>You should be able to see the title "Login App" in your app. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-78.png" alt="Image" width="600" height="400" loading="lazy">
<em>The title bar of the app changed to "Login App"</em></p>
<h2 id="heading-how-to-build-the-app">How to Build the App</h2>
<p>Now let's build our app. Copy the below code and replace it with the <code>_LoginState</code> class in the <code>main.dart</code> file. </p>


<p>Immediately after you paste and save the file, your UI will change like magic. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-79.png" alt="Image" width="600" height="400" loading="lazy">
<em>UI Changed to ask for Login credentials</em></p>
<p>Let's dismantle the code you copied into parts and try to understand each block. </p>
<pre><code class="lang-dart">  <span class="hljs-keyword">final</span> _formKey = GlobalKey&lt;FormState&gt;();
  TextEditingController emailController = TextEditingController();
  TextEditingController passwordController = TextEditingController();
</code></pre>
<p>The first line indicates that you're creating a key for a form. In our context, it is the login form. You're creating it to identify the form uniquely. It is set to final, so that it won't change. </p>
<p>The next 2 lines are definitions of controllers. A controller in our context is used to read the values from the input. Using a controller, you'll be able to control its associated component. </p>
<p>Let's dismantle the <code>build</code> method. You use the <code>build</code> method in Flutter to build the UI. It contains the design code. The content returned from this method will be rendered on the UI. </p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Form(
        key: _formKey,
</code></pre>
<p>The Scaffold is a widget in Flutter used to implement the basic material design visual layout structure. Assume the widget is a simple UI component. </p>
<p>We're setting the title passed as a parameter to this class. We can access the parameters using the widget object. So, it goes like <code>widget.{key_name}</code>. </p>
<p>If you want to access the title property, then it'll be <code>widget.title</code>. This is similar to passing <code>props</code> in React. </p>
<pre><code>body: Form(
  key: _formKey,
  <span class="hljs-attr">child</span>: Padding(
    padding: <span class="hljs-keyword">const</span> EdgeInsets.symmetric(horizontal: <span class="hljs-number">8</span>, <span class="hljs-attr">vertical</span>: <span class="hljs-number">16</span>),
    <span class="hljs-attr">child</span>: Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      <span class="hljs-attr">children</span>: [
</code></pre><p>The next section is <code>body</code>. As we're building a simple login app, we need a form to be filled out by the user to authenticate. We're setting the unique key which we created above to this form. The <code>Form</code> accepts a child. It can accept only one component. </p>
<p>We are creating a layout with horizontal padding of 8px and vertical padding of 16px. This <code>Padding</code> widget also accepts only one child. </p>
<p><code>Column</code> is a widget in Flutter that is used to display its children in a vertical array. We set <code>crossAxisAlignment</code> to horizontally center the contents of the <code>Column</code> widget. </p>
<p>As we saw, the <code>Column</code> widget displays its children in a vertical array. We can pass multiple widgets in its <code>children</code> property. </p>
<pre><code class="lang-dart">Padding(
  padding:
      <span class="hljs-keyword">const</span> EdgeInsets.symmetric(horizontal: <span class="hljs-number">8</span>, vertical: <span class="hljs-number">16</span>),
      child: TextFormField(
        controller: emailController,
        decoration: <span class="hljs-keyword">const</span> InputDecoration(
          border: OutlineInputBorder(), labelText: <span class="hljs-string">"Email"</span>),
        validator: (value) {
          <span class="hljs-keyword">if</span> (value == <span class="hljs-keyword">null</span> || value.isEmpty) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">'Please enter your email'</span>;
          }
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
        },
     ),
  ),
</code></pre>
<p>The first item we want to display in the UI is an input box to get the email address of a user. So, we used the <code>TextFormField</code> widget and set the controller to <code>emailController</code>. </p>
<p>In order to get the floating text, we need to use the decoration option which asks for the type of <code>border</code> and the <code>labelText</code> of the input. </p>
<p>We can add any default validation to be applied when this form is submitted in the <code>validator</code> field. We're validating if it's either a <code>null</code> or empty value and we return an error if any of them match. If it has some value, then we're not throwing any errors and returning <code>null</code>. </p>
<pre><code>Padding(
  padding:
  <span class="hljs-keyword">const</span> EdgeInsets.symmetric(horizontal: <span class="hljs-number">8</span>, <span class="hljs-attr">vertical</span>: <span class="hljs-number">16</span>),
    <span class="hljs-attr">child</span>: TextFormField(
      controller: passwordController,
      <span class="hljs-attr">obscureText</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">decoration</span>: <span class="hljs-keyword">const</span> InputDecoration(
        border: OutlineInputBorder(), <span class="hljs-attr">labelText</span>: <span class="hljs-string">"Password"</span>),
      <span class="hljs-attr">validator</span>: (value) {
        <span class="hljs-keyword">if</span> (value == <span class="hljs-literal">null</span> || value.isEmpty) {
          <span class="hljs-keyword">return</span> <span class="hljs-string">'Please enter your password'</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
      },
   ),
),
</code></pre><p>The second item is the input box to get the <code>Password</code> from the user. This is similar to the <code>email</code> field except for one thing: we should hide the password in the input field and display a dot for each typed character. </p>
<p>To do that, we have to pass an <code>obscureText</code> property to the <code>TextFormField</code> widget and set it to <code>true</code>. The decoration, validation, and other items remain the same as that of <code>Email</code>. </p>
<pre><code class="lang-dart">Padding(
  padding:
    <span class="hljs-keyword">const</span> EdgeInsets.symmetric(horizontal: <span class="hljs-number">8</span>, vertical: <span class="hljs-number">16.0</span>),
      child: Center(
        child: ElevatedButton(
          onPressed: () {
            <span class="hljs-keyword">if</span> (_formKey.currentState!.validate()) {
              <span class="hljs-comment">// Navigate the user to the Home page</span>
            } <span class="hljs-keyword">else</span> {
              ScaffoldMessenger.of(context).showSnackBar(
                <span class="hljs-keyword">const</span> SnackBar(content: Text(<span class="hljs-string">'Please fill input'</span>)),
              );
            }
          },
        child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Submit'</span>),
      ),
    ),
),
</code></pre>
<p>This is the final piece of our form, which is a submit button. We're using a <code>ElevatedButton</code> widget and passing the button text in the <code>child</code> property of the button. We define the action that should be followed when pressing this button in the <code>onPressed</code> property. </p>
<p>In our case, we're validating the input fields (remember the <code>validator</code> property we defined for the <code>email</code> and the <code>password</code> input box). If the validation passes, we should navigate the user to the next screen (which we'll be adding later). If not, we show a message asking the user to fill in the inputs ("Please fill input"). </p>
<p>It's time to verify if our code is working properly. Check your app. Try to submit without entering any input and you should notice the Snackbar at the bottom with the text "Please fill input". Fill in the input boxes with some random values and try to submit and you should not be seeing the error now. </p>
<p>If you're facing any errors in viewing the UI, most of the time (almost 90%) it'll be with brackets. We'll be using a lot of brackets in Flutter which is often confusing for beginners. Make sure you have the proper opening and closing brackets. The Flutter app may terminate in the middle in case of any errors. In these cases, after applying the fix, press <code>F5</code> to restart the app. </p>
<h2 id="heading-navigate-on-login">Navigate on Login</h2>
<p>Let's navigate the user to the Home page on successful login and show the email address they entered on the Login page. Something similar to the below screenshot:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-87.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home page</em></p>
<p>Go to the last line of the <code>main.dart</code> file and copy and paste the below content:</p>


<p>In this code, we are creating a new class called "HomePage" and extending it from "StatelessWidget". We receive an email from the previous page. </p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
        appBar: AppBar(
          title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Home Page'</span>),
        ),
        body: Column(
          children: [
            Text(email),
            Center(
              child: ElevatedButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                child: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Go back!"</span>),
              ),
            ),
          ],
        ));
</code></pre>
<p>On the <code>build</code> method, we define the title of the page to be "Home Page" and its body contains a <code>Text</code> and <code>ElevatedButton</code> widget. The <code>Text</code> widget will display the email address passed from the previous screen. The <code>ElevatedButton</code> widget will navigate the user to the previous screen whenever it's pressed. We use <code>Navigator.pop(context);</code> to navigate to the previous screen. </p>
<p>Let's understand how to navigate from the <code>Login</code> page to the <code>Home</code> page. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-89.png" alt="Image" width="600" height="400" loading="lazy">
<em>Code to navigate to the next page</em></p>
<p>Remove the comment we made on <code>validation</code> condition ("Navigate the user to the Home page") as shown in above screenshot and replace it with the below content. </p>
<pre><code class="lang-dart"><span class="hljs-keyword">if</span> (emailController.text == <span class="hljs-string">"arun@gogosoon.com"</span> &amp;&amp; passwordController.text == <span class="hljs-string">"qazxswedcvfr"</span>) {
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) =&gt; HomePage(
        email: emailController.text,
    )),
  );
} <span class="hljs-keyword">else</span> {
  ScaffoldMessenger.of(context).showSnackBar(
    <span class="hljs-keyword">const</span> SnackBar(
      content: Text(<span class="hljs-string">'Invalid Credentials'</span>)),
    );
}
</code></pre>
<p>Here's the final code for the Submit button. </p>
<pre><code>Padding(
  padding:
    <span class="hljs-keyword">const</span> EdgeInsets.symmetric(horizontal: <span class="hljs-number">8</span>, <span class="hljs-attr">vertical</span>: <span class="hljs-number">16.0</span>),
      <span class="hljs-attr">child</span>: Center(
        child: ElevatedButton(
          onPressed: () {
            <span class="hljs-keyword">if</span> (_formKey.currentState!.validate()) {
              <span class="hljs-keyword">if</span> (emailController.text == <span class="hljs-string">"arun@gogosoon.com"</span> &amp;&amp;
                            passwordController.text == <span class="hljs-string">"qazxswedcvfr"</span>) {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: <span class="hljs-function">(<span class="hljs-params">context</span>) =&gt;</span> HomePage(
                      email: emailController.text,
                    )),
                );
              } <span class="hljs-keyword">else</span> {
                ScaffoldMessenger.of(context).showSnackBar(
                  <span class="hljs-keyword">const</span> SnackBar(
                    content: Text(<span class="hljs-string">'Invalid Credentials'</span>)),
                  );
              }
            } <span class="hljs-keyword">else</span> {
              ScaffoldMessenger.of(context).showSnackBar(
                <span class="hljs-keyword">const</span> SnackBar(content: Text(<span class="hljs-string">'Please fill input'</span>)),
              );
            }
          },
        <span class="hljs-attr">child</span>: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Submit'</span>),
      ),
    ),
),
</code></pre><p>Let's try to understand this code. </p>
<p>In addition to form validation, we are adding another layer of validation which checks if the user has typed the email address as "arun@gogosoon.com", (which is my email address, you can replace it with whatever you want) and the password as "qazxswedcvfr". We navigate the user to the Home page if the entered credentials match, and show "Invalid Credentials" in the Snackbar otherwise. </p>
<p>That's it. We have covered a very basic login validation. Try to run the app and check if your app works as expected. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-91.png" alt="Image" width="600" height="400" loading="lazy">
<em>Login Page</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/image-92.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home Page</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you have learned to build a basic version of a login app using Flutter. Hope you're clear on the flow of building the Flutter app. </p>
<p>If you're curious to learn Flutter further, try out the exercise I'm adding below. Searching, applying the code, and getting the result by yourself will make you more confident in Flutter app development. </p>
<ol>
<li>Try to add an eye icon at the end of the "Password" input field. Clicking on it should toggle showing the password in plain text and hidden text</li>
<li>Clear the Email and Password input fields before navigating to the Home page</li>
<li>Add additional regex validation for email input</li>
<li>Add validation to the password field if the user has entered at least one number, letter, and a symbol</li>
<li>Add a "Signup" button below the "Submit" button which should navigate the user to a new "Signup" page</li>
</ol>
<p>To learn more about Flutter, subscribe to my email newsletter on my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_login_app">site</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_flutter_login_app">https://5minslearn.gogosoon.com</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Mobile Apps with Flutter ]]>
                </title>
                <description>
                    <![CDATA[ Flutter is a mobile app development framework from Google that lets you build beautiful, high-performance iOS and Android applications.  In this article, let’s look at what Flutter is and how to work with it. What is Flutter? Flutter is an open-sourc... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-mobile-apps-with-flutter/</link>
                <guid isPermaLink="false">66d035e064be048ac359a302</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Tue, 28 Feb 2023 01:10:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/flutter.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Flutter is a mobile app development framework from Google that lets you build beautiful, high-performance iOS and Android applications. </p>
<p>In this article, let’s look at what Flutter is and how to work with it.</p>
<h2 id="heading-what-is-flutter">What is Flutter?</h2>
<p>Flutter is an open-source mobile application development framework created by Google. It helps you create high-quality, fast, and beautiful apps for iOS, Android, and the web – all from a single codebase.</p>
<p>Flutter has quickly become a popular choice among developers. Thanks to its ease of use and performance, you can build beautiful mobile applications using Flutter.</p>
<h2 id="heading-benefits-of-flutter">Benefits of Flutter</h2>
<p>Flutter uses Google’s <a target="_blank" href="https://dart.dev/">Dart programming language</a>. Dart is similar to JavaScript or TypeScript and offers a reactive programming model for building user interfaces.</p>
<p>This means that instead of having to update the UI when you change your code, the framework will do it for you. This makes it easier and more efficient for building dynamic and responsive UIs.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/flutter1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter hot-reloading. Image by the author.</em></p>
<p>Flutter also has a fast development cycle. Flutter has a hot reload feature that helps you see the changes you make to the code immediately. With Flutter, you don’t have to wait for the code to compile every time you change a piece of code.</p>
<p>The core strength of Flutter is widgets.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/flutter2.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter widgets</em></p>
<p>While building an app, you usually have to write functionality from scratch. For example, if you want to embed a Google map within your code, you have to write the code to import Google Maps into your app.</p>
<p>But Flutter provides ready-made widgets for almost all common app functions. Think of it like working with a lego set. Flutter provides a rich set of pre-designed widgets that you can customize to create beautiful interfaces.</p>
<p>These widgets are not simple UI elements like buttons and text boxes. They include complex widgets like scrolling lists, navigations, sliders, and many others. These widgets help save you time and let you focus on the business logic of your application. </p>
<p><a target="_blank" href="https://docs.flutter.dev/development/ui/widgets">Here is a full list of in-built Flutter widgets</a> that you can peruse.</p>
<p>Another advantage of Flutter is its performance.</p>
<p>Flutter’s graphics engine, Skia, draws every pixel on the screen. This makes it possible to achieve smooth, 60 frames per second animations, even on lower-end devices.</p>
<p>Flutter also has a large and growing community of developers who contribute to the framework. It also comes with detailed documentation and a vast library of packages and plugins. You can easily integrate those plugins into your app to add features like maps, network communication, and local storage.</p>
<p>Now that you know what Flutter is and why it's useful, let's look at how it compares with another popular library, React-Native.</p>
<h2 id="heading-react-native-vs-flutter">React Native vs. Flutter</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-153.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter vs React Native</em></p>
<p>React Native and Flutter are two of the most popular cross-platform mobile app development frameworks available today. Both offer the ability to build high-performance and visually appealing mobile apps for multiple platforms.</p>
<p>But there are some key differences between the two frameworks that you should consider when choosing the right one for your project.</p>
<p>React Native is JavaScript-based and is an extension of the <a target="_blank" href="https://reactjs.org/">React library</a>. React-native uses native components for building the UI, which provides a native look and feel for the app.</p>
<p>React Native has a large and established community compared to Flutter and is a great choice if your existing products use JavaScript or React.</p>
<p>Flutter offers a unique approach to building user interfaces by using its own set of customizable widgets. This approach gives Flutter a unique look and feel compared to other mobile development frameworks.</p>
<p>Flutter’s fast development cycle and hot reload feature allow developers to build applications faster than other alternatives.</p>
<p>React Native has an easier learning curve compared to Flutter. Since most developers know JavaScript, they don't have to learn a new language like Dart to build apps with Flutter.</p>
<p>But React Native’s reliance on native components makes it difficult to achieve consistent performance across multiple platforms. It can also lead to inconsistencies in the UI between iOS and Android.</p>
<p>Flutter offers better performance, with its graphics engine drawing every pixel on the screen. With Flutter, you can get smooth and fluid animations even on lower-end hardware. Flutter also offers a unified and consistent look and feel for the app across all platforms, as developers use the same set of widgets for building the UI.</p>
<p>So React Native and Flutter both have their own strengths and weaknesses, and the right choice depends on your specific needs and requirements. </p>
<p>React Native is a good choice for businesses with existing investments in JavaScript and React. Flutter is a better choice for projects that need high-performance, unique, and responsive UIs along with a fast development cycle.</p>
<h2 id="heading-how-to-install-flutter">How to Install Flutter</h2>
<p>The best way to install Flutter is to follow the <a target="_blank" href="https://docs.flutter.dev/get-started/install">official installation page</a>. You can choose your operating system and follow the instructions.</p>
<p>Once you have installed Flutter, you can use its inbuilt tool called Flutter doctor to check the components. For example, on Mac, you should see a similar response on running <code>flutter doctor</code> .</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-154.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter doctor</em></p>
<h2 id="heading-hello-world-in-flutter">Hello World in Flutter</h2>
<p>Let’s create a simple hello world app using Flutter.</p>
<p>We can use the <code>flutter create &lt;app name&gt;</code> to create a new app.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-155.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter create</em></p>
<p>Now we can <code>cd</code> into the directory and change the main file. It will be located under /lib/main.dart. Replace the code in the main.dart file with the following code.import 'package:flutter/material.dart':</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-keyword">void</span> main() {
  runApp(MyApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      title: <span class="hljs-string">'Hello, World!'</span>,
      home: Scaffold(
        appBar: AppBar(
          title: <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Hello, World!'</span>),
        ),
        body: <span class="hljs-keyword">const</span> Center(
          child: Text(<span class="hljs-string">'Hello, World!'</span>),
        ),
      ),
    );
  }
}
</code></pre>
<p>This code defines a Flutter app that will display “Hello, World!” in the center of the screen. The main() function will call the runApp() function with an instance of the MyApp class.</p>
<p>In the build() method of MyApp, a MaterialApp widget with the title “Hello, World!” is created. The Scaffold widget contains an AppBar with the title “Hello, World!” and the Center widget will place the text on the center of the screen.</p>
<p>This is how the output will look after you run the <code>flutter run</code> command.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/image-156.png" alt="Image" width="600" height="400" loading="lazy">
<em>Flutter hello world</em></p>
<h2 id="heading-what-is-flutterflow">What is Flutterflow?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/flutter3.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Flutterflow. Credits: Flutterflow.io</em></p>
<p>Before we end, I want to share a tool that has massively improved my productivity when building apps with Flutter. This isn't an endorsement – I just really like the tool and want you to know about it, too.</p>
<p><a target="_blank" href="https://flutterflow.io/">Flutter Flow</a> is a visual design tool that lets you create Flutter apps using a drag-and-drop interface. You can build complex and interactive user interfaces for your Flutter apps without writing any code.</p>
<p>Flutterflow works by providing a visual interface for designing your app’s UI, which is then translated into Flutter code. It makes it easy to create and iterate on your app’s design, as you can see the changes you make in real-time.</p>
<p>Flutterflow also offers collaborative development, so you can build your apps along with a team. Flutterflow comes with a lot of integrations like Firebase, Stripe, and even OpenAI’s API.</p>
<p>Once you have built your app, you can publish it to the app store or play store using built-in Codemagic integration.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Flutter is an awesome framework for building mobile apps. It offers fast development times, beautiful and responsive designs, and a single codebase for both iOS and Android. Its hot-reload feature allows developers to see changes in real time, reducing overall development time. </p>
<p>Additionally, Flutter’s widget library allows for the creation of custom and complex designs with ease. In terms of performance, Flutters races far ahead of alternatives like React-Native.</p>
<p><em>Hope this article helped you to understand Flutter in detail. You can learn more about me at</em> <a target="_blank" href="http://manishmshiva.com"><em>manishmshiva.com</em></a><em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
