<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Aditya's Blog]]></title><description><![CDATA[I convert scrap to sculptures!]]></description><link>https://blog.adityasharma.co</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 18:59:59 GMT</lastBuildDate><atom:link href="https://blog.adityasharma.co/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Scalable Microfrontends: Architecting a Decoupled UI with Module Federation]]></title><description><![CDATA[Have you ever worked on a frontend codebase so large that you feared deploying a CSS change to the Settings page because it might somehow break the Checkout flow? Or perhaps you've struggled to align three different teams working on the same React re...]]></description><link>https://blog.adityasharma.co/scalable-microfrontends-architecting-a-decoupled-ui-with-module-federation</link><guid isPermaLink="true">https://blog.adityasharma.co/scalable-microfrontends-architecting-a-decoupled-ui-with-module-federation</guid><category><![CDATA[React]]></category><category><![CDATA[Microfrontend]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Wed, 19 Nov 2025 07:13:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1763536062182/2941dcbc-787b-4892-9dad-d0671898a96b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever worked on a frontend codebase so large that you feared deploying a CSS change to the <em>Settings</em> page because it might somehow break the <em>Checkout</em> flow? Or perhaps you've struggled to align three different teams working on the same React repo, constantly stepping on each other's toes with merge conflicts?</p>
<p>The "Frontend Monolith" is a real struggle. The solution? <strong>Microfrontends (MFEs).</strong></p>
<p>In this guide, we won't just build a "Hello World" MFE. We are going to architect a <strong>production-grade system</strong> using React, Vite, and Module Federation. We will implement a specific, highly scalable pattern: <strong>Separating the UI Layer (the MFE) from the Data Layer (a Headless NPM package).</strong></p>
<h2 id="heading-what-are-microfrontends">What are Microfrontends?</h2>
<p>Microfrontends apply the "Microservices" concept to the frontend. Instead of one giant application, you break your website into smaller, independent applications (e.g., User Profile, Product Catalog, Cart).</p>
<p><strong>The Problems They Solve:</strong></p>
<ol>
<li><p><strong>Independent Deployment:</strong> Team A can deploy the "User Profile" MFE without waiting for Team B to finish the "Checkout" MFE.</p>
</li>
<li><p><strong>Tech Stack Agnostic:</strong> Theoretically, one MFE could be React while another is Vue (though sticking to one framework is usually better for performance).</p>
</li>
<li><p><strong>Scalability:</strong> Teams can work in parallel on separate repositories.</p>
</li>
<li><p><strong>Incremental Upgrades:</strong> You can rewrite legacy code piece by piece.</p>
</li>
</ol>
<h2 id="heading-the-architecture-the-split-layer-pattern">The Architecture: The "Split-Layer" Pattern</h2>
<p>Most MFE tutorials shove API calls, logic, and UI into one bundle. We are going to do better. We will split our MFE into two distinct layers managed in separate repositories:</p>
<ol>
<li><p><strong>The Data Layer (Headless):</strong> A TypeScript NPM package containing API clients, models, and business logic. It knows <em>nothing</em> about React or the DOM.</p>
</li>
<li><p><strong>The UI Layer (The MFE):</strong> A React application that consumes the Data Layer to render the interface. It is exposed to the "Host" via Module Federation.</p>
</li>
</ol>
<h3 id="heading-the-high-level-diagram">The High-Level Diagram</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763533226756/3594deb1-43df-4d8a-bab8-1f8f576a99f3.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-part-1-the-headless-data-layer">Part 1: The Headless Data Layer</h2>
<p>This layer is the "brain." It handles data fetching and transformation. It is published as a private NPM package (e.g., to GitHub Packages) so both the MFE and potentially the Host can use it with type safety.</p>
<h3 id="heading-1-the-configuration-pattern-inversion-of-control">1. The Configuration Pattern (Inversion of Control)</h3>
<p>The Data Layer shouldn't hardcode URLs or Auth tokens. It should ask for them. We use a configuration function.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// data-layer/src/config.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> DataLayerConfig {
  <span class="hljs-comment">// The Host decides the API location</span>
  apiBaseUrl: <span class="hljs-built_in">string</span>;
  <span class="hljs-comment">// The Host provides a way to get the CURRENT token</span>
  getToken: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span> | <span class="hljs-literal">undefined</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span> | <span class="hljs-literal">undefined</span>&gt;;
}

<span class="hljs-keyword">let</span> internalConfig: DataLayerConfig | <span class="hljs-literal">null</span> = <span class="hljs-literal">null</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> configureDataLayer = <span class="hljs-function">(<span class="hljs-params">config: DataLayerConfig</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (!config.apiBaseUrl || !config.getToken) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Invalid Data Layer Configuration"</span>);
  }
  internalConfig = config;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getConfig = <span class="hljs-function">() =&gt;</span> internalConfig;
</code></pre>
<h3 id="heading-2-the-intelligent-api-client">2. The Intelligent API Client</h3>
<p>We create an Axios instance that "pulls" the token dynamically before every request. This handles token rotation automatically!</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// data-layer/src/api/apiClient.ts</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { getConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'../config'</span>;

<span class="hljs-comment">// We defer instance creation until we have the Base URL</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getApiClient = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> config = getConfig();
  <span class="hljs-keyword">if</span> (!config) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Data Layer not configured!"</span>);

  <span class="hljs-keyword">const</span> instance = axios.create({
    baseURL: config.apiBaseUrl,
  });

  <span class="hljs-comment">// Request Interceptor: The Secret Sauce</span>
  instance.interceptors.request.use(<span class="hljs-keyword">async</span> (reqConfig) =&gt; {
    <span class="hljs-comment">// Call the function provided by the HOST to get the latest token</span>
    <span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.resolve(config.getToken());
    <span class="hljs-keyword">if</span> (token) {
      reqConfig.headers.Authorization = <span class="hljs-string">`Bearer <span class="hljs-subst">${token}</span>`</span>;
    }
    <span class="hljs-keyword">return</span> reqConfig;
  });

  <span class="hljs-keyword">return</span> instance;
};
</code></pre>
<hr />
<h2 id="heading-part-2-the-ui-layer-react-mfe">Part 2: The UI Layer (React MFE)</h2>
<p>We build this using <strong>Vite</strong>, which offers a fantastic plugin for Module Federation: <code>@originjs/vite-plugin-federation</code>.</p>
<h3 id="heading-1-vite-configuration">1. Vite Configuration</h3>
<p>We expose a <code>bootstrap</code> file. We don't just expose a component because we need to handle initialization (configuring the data layer) before rendering.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ui-mfe/vite.config.ts</span>
<span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'vite'</span>;
<span class="hljs-keyword">import</span> react <span class="hljs-keyword">from</span> <span class="hljs-string">'@vitejs/plugin-react'</span>;
<span class="hljs-keyword">import</span> federation <span class="hljs-keyword">from</span> <span class="hljs-string">'@originjs/vite-plugin-federation'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  plugins: [
    react(),
    federation({
      name: <span class="hljs-string">'my_app_ui_mfe'</span>,
      filename: <span class="hljs-string">'remoteEntry.js'</span>,
      exposes: {
        <span class="hljs-comment">// We expose a mount function, not just a component</span>
        <span class="hljs-string">'./bootstrap'</span>: <span class="hljs-string">'./src/bootstrap.tsx'</span>,
      },
      shared: {
        react: { singleton: <span class="hljs-literal">true</span> },
        <span class="hljs-string">'react-dom'</span>: { singleton: <span class="hljs-literal">true</span> },
        <span class="hljs-string">'react-router-dom'</span>: { singleton: <span class="hljs-literal">true</span> }
      },
    }),
  ],
  build: {
    target: <span class="hljs-string">'esnext'</span>, <span class="hljs-comment">// Required for top-level await support in MF</span>
  },
});
</code></pre>
<h3 id="heading-2-styling-isolation">2. Styling Isolation</h3>
<p>To prevent your MFE's CSS from breaking the Host app (and vice versa), use <strong>Tailwind CSS with a prefix</strong>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ui-mfe/tailwind.config.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">content</span>: [<span class="hljs-string">"./src/**/*.{js,ts,jsx,tsx}"</span>],
  <span class="hljs-attr">prefix</span>: <span class="hljs-string">'mfe-user-'</span>, <span class="hljs-comment">// All classes will be .mfe-user-bg-red-500</span>
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<h3 id="heading-3-the-bootstrap-entry-point">3. The Bootstrap Entry Point</h3>
<p>This is the interface between the Host and the MFE. It accepts <code>props</code>, configures the Data Layer, and mounts the React app.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// ui-mfe/src/bootstrap.tsx</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> { RouterProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> { createHostedRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'./routes'</span>;
<span class="hljs-keyword">import</span> { configureDataLayer } <span class="hljs-keyword">from</span> <span class="hljs-string">'@your-org/my-app-data-layer'</span>;

<span class="hljs-comment">// The Contract: What the Host must provide</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> MountProps {
  config: {
    apiBaseUrl: <span class="hljs-built_in">string</span>;
    getAuthToken: <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">string</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">string</span> | <span class="hljs-literal">null</span>&gt;;
  };
  hostCallbacks?: {
    onNavigateRequest?: <span class="hljs-function">(<span class="hljs-params">path: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
    onHostEvent?: <span class="hljs-function">(<span class="hljs-params">event: <span class="hljs-built_in">string</span>, payload: <span class="hljs-built_in">any</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
  };
  basename?: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> mount = <span class="hljs-function">(<span class="hljs-params">el: Element, props: MountProps</span>) =&gt;</span> {
  <span class="hljs-comment">// 1. Configure the internal Data Layer with Host's values</span>
  configureDataLayer({
    apiBaseUrl: props.config.apiBaseUrl,
    getToken: props.config.getAuthToken,
  });

  <span class="hljs-comment">// 2. Initialize Router (MemoryRouter is best for MFEs)</span>
  <span class="hljs-keyword">const</span> router = createHostedRouter(props.basename);

  <span class="hljs-comment">// 3. Render</span>
  <span class="hljs-keyword">const</span> root = ReactDOM.createRoot(el);
  root.render(
     &lt;React.StrictMode&gt;
        &lt;RouterProvider router={router} /&gt;
     &lt;/React.StrictMode&gt;
  );

  <span class="hljs-comment">// 4. Return cleanup function</span>
  <span class="hljs-keyword">return</span> {
    unmount: <span class="hljs-function">() =&gt;</span> root.unmount()
  };
};

<span class="hljs-keyword">export</span> { mount };
</code></pre>
<hr />
<h2 id="heading-part-3-the-integration-the-host-app">Part 3: The Integration (The Host App)</h2>
<p>The Host is the orchestrator. It provides the "Environment" (Auth, URL) and the "Container" (DOM Element).</p>
<h3 id="heading-1-module-federation-config-host">1. Module Federation Config (Host)</h3>
<p>Tell the host where to find the MFE.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// host/vite.config.ts (or webpack.config.js)</span>
federation({
  <span class="hljs-attr">name</span>: <span class="hljs-string">'host_app'</span>,
  <span class="hljs-attr">remotes</span>: {
    <span class="hljs-comment">// The URL can be dynamic in production!</span>
    <span class="hljs-attr">my_app_ui_mfe</span>: <span class="hljs-string">'http://localhost:3001/assets/remoteEntry.js'</span>,
  },
  <span class="hljs-attr">shared</span>: { <span class="hljs-attr">react</span>: { <span class="hljs-attr">singleton</span>: <span class="hljs-literal">true</span> }, ... }
})
</code></pre>
<h3 id="heading-2-the-mfe-loader-component">2. The MFE Loader Component</h3>
<p>This component handles the dynamic import and the lifecycle of the MFE.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// host/src/components/MfeLoader.tsx</span>
<span class="hljs-keyword">import</span> React, { useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// Helper to load the module dynamically</span>
<span class="hljs-comment">// In a real app, wrap this in React.Suspense</span>
<span class="hljs-keyword">const</span> MfeLoader = <span class="hljs-function">(<span class="hljs-params">{ mountProps }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> ref = useRef(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">let</span> mfeInstance;

    <span class="hljs-keyword">const</span> loadMfe = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-comment">// Dynamic import matches the 'remotes' key and 'exposes' key</span>
      <span class="hljs-keyword">const</span> <span class="hljs-keyword">module</span> = await import('my_app_ui_mfe/bootstrap');

      if (ref.current) {
        <span class="hljs-comment">// Mount the MFE and pass the PROPS</span>
        mfeInstance = <span class="hljs-built_in">module</span>.mount(ref.current, mountProps);
      }
    };

    loadMfe();

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// Cleanup when Host unmounts this component</span>
      mfeInstance?.unmount();
    };
  }, []); <span class="hljs-comment">// Re-run if mountProps change deeply? Use caution.</span>

  <span class="hljs-keyword">return</span> &lt;div ref={ref} /&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MfeLoader;
</code></pre>
<h3 id="heading-3-using-the-mfe-in-the-host">3. Using the MFE in the Host</h3>
<p>This is where the magic happens. The Host passes its own Auth logic <em>into</em> the MFE.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// host/src/App.tsx</span>
<span class="hljs-keyword">import</span> React, { useCallback } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> MfeLoader <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/MfeLoader'</span>;
<span class="hljs-keyword">import</span> { useAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">'./hooks/useAuth'</span>; <span class="hljs-comment">// Host's Auth hook</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { getToken, logout } = useAuth();

  <span class="hljs-comment">// The MFE calls this function before EVERY API request.</span>
  <span class="hljs-comment">// This ensures the MFE always uses the freshest token.</span>
  <span class="hljs-keyword">const</span> provideTokenToMfe = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> getToken(); 
  }, [getToken]);

  <span class="hljs-keyword">const</span> handleMfeEvent = <span class="hljs-function">(<span class="hljs-params">event, payload</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (event === <span class="hljs-string">'authExpired'</span>) {
      logout(); <span class="hljs-comment">// Host handles the logout!</span>
    }
  };

  <span class="hljs-keyword">const</span> mfeProps = {
    config: {
      apiBaseUrl: <span class="hljs-string">'https://api.production.com/v1'</span>,
      getAuthToken: provideTokenToMfe, <span class="hljs-comment">// Pass the function reference</span>
    },
    hostCallbacks: {
      onHostEvent: handleMfeEvent
    }
  };

  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"host-layout"</span>&gt;
      &lt;h1&gt;My Super App&lt;/h1&gt;
      &lt;div className=<span class="hljs-string">"mfe-container"</span>&gt;
        &lt;MfeLoader mountProps={mfeProps} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2 id="heading-handling-errors-amp-communication">Handling Errors &amp; Communication</h2>
<h3 id="heading-standardized-errors">Standardized Errors</h3>
<p>Your Data Layer should intercept 4xx/5xx errors and reject with a standardized <code>DataLayerError</code> object.</p>
<ul>
<li><p><strong>MFE Responsibility:</strong> Catch <code>DataLayerError</code>. If it's a 401, emit an event to the host. If it's a 400, show a validation error in the UI.</p>
</li>
<li><p><strong>Host Responsibility:</strong> Listen for <code>authExpired</code> events and handle redirects.</p>
</li>
</ul>
<h3 id="heading-the-fallback-iframe">The Fallback (Iframe)</h3>
<p>If you ever need to run this MFE in an Iframe (e.g., legacy integration), Module Federation won't work.</p>
<ul>
<li><p><strong>Host:</strong> Listen to <code>window.postMessage</code>.</p>
</li>
<li><p><strong>MFE:</strong> In your communication layer, check if <a target="_blank" href="http://window.top"><code>window.top</code></a> <code>!== window.self</code>. If so, send <code>postMessage</code> instead of calling the <code>hostCallbacks</code> prop.</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>By separating the <strong>Data Layer</strong> (Headless, Type-safe, Configurable) from the <strong>UI Layer</strong> (Visuals, Module Federation), and orchestrating them via a <strong>Host App</strong> that controls Authentication, you achieve a highly scalable architecture.</p>
<p><strong>Benefits of this approach:</strong></p>
<ul>
<li><p><strong>Zero Auth Logic Duplication:</strong> The MFE doesn't implement login/refresh flows. It just asks the Host for a token.</p>
</li>
<li><p><strong>Type Safety:</strong> Shared models via the Data Layer package.</p>
</li>
<li><p><strong>Style Isolation:</strong> Tailwind prefixing prevents CSS nightmares.</p>
</li>
<li><p><strong>Framework Agnostic Data:</strong> The Data Layer can be reused in a React Native app or even an Angular MFE.</p>
</li>
</ul>
<p>Ready to break up your monolith? Start small, extract the data layer first, and happy coding! ✨</p>
]]></content:encoded></item><item><title><![CDATA[Mastering WebSockets in Flutter: A Comprehensive Guide]]></title><description><![CDATA[WebSockets provide a powerful way to establish a full-duplex communication channel between the client and server, allowing real-time data exchange. This is particularly useful in applications that require live updates, such as chat apps, online gamin...]]></description><link>https://blog.adityasharma.co/mastering-websockets-in-flutter-a-comprehensive-guide</link><guid isPermaLink="true">https://blog.adityasharma.co/mastering-websockets-in-flutter-a-comprehensive-guide</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[websockets]]></category><category><![CDATA[app development]]></category><category><![CDATA[Flutter Examples]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Tue, 03 Sep 2024 09:31:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725355834204/675ae9ac-bcfd-49cf-b9e5-923718f17489.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>WebSockets provide a powerful way to establish a full-duplex communication channel between the client and server, allowing real-time data exchange. This is particularly useful in applications that require live updates, such as chat apps, online gaming, financial dashboards, and collaborative tools. In this blog post, we’ll explore how to effectively implement WebSockets in Flutter, using a robust and well-structured approach.</p>
<h2 id="heading-why-websockets"><strong>Why WebSockets?</strong></h2>
<p>Imagine you’re building a chat app. You want messages to appear instantly without the user having to refresh the page or wait for updates. WebSockets make this happen by keeping a continuous connection open between your app and the server. This allows data to flow back and forth instantly, giving your users that smooth, real-time experience.</p>
<h2 id="heading-setting-up-websockets-in-flutter"><strong>Setting Up WebSockets in Flutter</strong></h2>
<p>To get started with WebSockets in Flutter, you first need to import the necessary Dart packages in pubspec.yaml:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
  <span class="hljs-attr">retry:</span> <span class="hljs-string">^3.1.0</span>
</code></pre>
<h3 id="heading-meet-the-websocket-manager"><strong>Meet the WebSocket Manager</strong></h3>
<p>A well-structured approach to handling WebSocket connections in Flutter is to use a singleton class. This class will handle everything related to WebSockets, from connecting to the server to managing incoming data.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:async'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'dart:developer'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'dart:io'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSocketManager</span> </span>{
  <span class="hljs-comment">// Singleton pattern - only one instance of WebSocketManager will exist</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> WebSocketManager _singleton = WebSocketManager._internal();

  <span class="hljs-comment">// StreamController to manage the flow of data</span>
  <span class="hljs-keyword">final</span> StreamController&lt;<span class="hljs-built_in">Object</span>&gt; streamController = StreamController.broadcast(<span class="hljs-keyword">sync</span>: <span class="hljs-keyword">true</span>);

  <span class="hljs-comment">// Variable to store the WebSocket URL</span>
  <span class="hljs-keyword">late</span> <span class="hljs-built_in">String</span> wsUrl;
  WebSocket? socket;
  WebSocketStatus status = WebSocketStatus.closed;

  <span class="hljs-comment">// Factory constructor to return the singleton instance</span>
  <span class="hljs-keyword">factory</span> WebSocketManager(<span class="hljs-built_in">String</span> url) {
    _singleton.wsUrl = url;
    <span class="hljs-keyword">return</span> _singleton;
  }

  <span class="hljs-comment">// Private constructor for the singleton pattern</span>
  WebSocketManager._internal();

  <span class="hljs-comment">// Initialize the WebSocket connection</span>
  Future&lt;<span class="hljs-keyword">void</span>&gt; initWebSocketConnection() <span class="hljs-keyword">async</span> {
    <span class="hljs-comment">// Check if the WebSocket is closed before connecting</span>
    <span class="hljs-keyword">if</span> (status == WebSocketStatus.closed) {
      status = WebSocketStatus.connecting;
      log(<span class="hljs-string">"Socket Connecting..."</span>);
      socket = <span class="hljs-keyword">await</span> connectWs();

      <span class="hljs-comment">// If the connection is successful, open the WebSocket and start listening for data</span>
      <span class="hljs-keyword">if</span> (socket?.readyState == WebSocket.open) {
        socket!.pingInterval = <span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">5</span>);
        status = WebSocketStatus.open;
        log(<span class="hljs-string">"Connection OPEN"</span>);
        broadcast();
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// If the connection fails, log the error and close the WebSocket</span>
        log(<span class="hljs-string">"Connection DONE inside initWebSocketConnection()"</span>);
        log(<span class="hljs-string">"Close Code: <span class="hljs-subst">${socket?.closeCode}</span>"</span>);
        status = WebSocketStatus.closed;
        streamController.addError(<span class="hljs-string">'Connection Done with close code: <span class="hljs-subst">${socket?.closeCode}</span>'</span>);
      }
    }
  }

  <span class="hljs-comment">// Broadcast data received from the WebSocket to all listeners</span>
  <span class="hljs-keyword">void</span> broadcast() {
    socket?.listen(
      (<span class="hljs-built_in">dynamic</span> streamData) {
        <span class="hljs-keyword">try</span> {
          streamController.add(streamData <span class="hljs-keyword">as</span> <span class="hljs-built_in">String</span>);
        } <span class="hljs-keyword">catch</span> (e) {
          streamController.addError(e.toString());
        }
      },
      onDone: () {
        status = WebSocketStatus.closed;
        log(<span class="hljs-string">"Connection DONE"</span>);
        streamController.addError(<span class="hljs-string">'Connection Done with close code: <span class="hljs-subst">${socket?.closeCode}</span>'</span>);
      },
      onError: (<span class="hljs-built_in">dynamic</span> e) <span class="hljs-keyword">async</span> {
        status = WebSocketStatus.closed;
        streamController.addError(e.toString());
      },
    );
  }

  <span class="hljs-comment">// Connect to the WebSocket server with retry logic</span>
  Future&lt;WebSocket?&gt; connectWs() <span class="hljs-keyword">async</span> {
    <span class="hljs-comment">// Retry connection with exponential backoff</span>
    <span class="hljs-keyword">const</span> r = RetryOptions(maxAttempts: <span class="hljs-number">20</span>, delayFactor: <span class="hljs-built_in">Duration</span>(seconds: <span class="hljs-number">1</span>));
    WebSocket? response;

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Attempt to connect to the WebSocket server</span>
      response = <span class="hljs-keyword">await</span> r.retry(
        () =&gt; WebSocket.connect(wsUrl),
        retryIf: (e) {
          <span class="hljs-comment">// You can provide any condition for retrying</span>
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
        },
        onRetry: (e) {
          log(<span class="hljs-string">"Socket Connection Error: <span class="hljs-subst">$e</span>"</span>);
          log(<span class="hljs-string">"Retrying!"</span>);
        },
      );
    } <span class="hljs-keyword">on</span> TimeoutException {
      <span class="hljs-comment">// If the connection times out, try again</span>
      log(<span class="hljs-string">"Socket TimeoutException!"</span>);
      initWebSocketConnection();
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    } <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-comment">// If there's another type of error, log it or handle it accordingly</span>
      log(<span class="hljs-string">"Socket connection error: <span class="hljs-subst">$e</span>"</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }

    <span class="hljs-keyword">return</span> response;
  }

  <span class="hljs-comment">// Function for dispose of the WebSocket connection</span>
  Future&lt;<span class="hljs-keyword">void</span>&gt; dispose() <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">await</span> socket?.close();
    socket = <span class="hljs-keyword">null</span>;
    status = WebSocketStatus.closed;
  }
}
</code></pre>
<p><strong>Key Components of the WebSocketManager Class</strong></p>
<ul>
<li><p><strong>Singleton Pattern</strong>: The class uses a singleton pattern to ensure only one instance of WebSocketManager exists, managing the WebSocket connection across the entire app.</p>
</li>
<li><p><strong>StreamController</strong>: This is used to broadcast incoming messages from the WebSocket to multiple listeners within the app.</p>
</li>
<li><p><strong>WebSocket Status</strong>: The WebSocketStatus enum tracks the state of the WebSocket connection (open, closed, or connecting).</p>
</li>
<li><p><strong>Retry Logic</strong>: Exponential backoff with jitter is implemented using the retry package, allowing the WebSocket to automatically retry the connection multiple times if it fails.</p>
</li>
</ul>
<h3 id="heading-adding-websocketmanager-to-your-flutter-app"><strong>Adding WebSocketManager to Your Flutter App</strong></h3>
<p>Once you’ve set up the WebSocketManager class, the next step is to integrate it into your Flutter application. Below is an example of how to use the WebSocketManager in your app:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Initialize the WebSocketManager with the appropriate WebSocket URL</span>
wsManager = WebSocketManager(<span class="hljs-string">"https://echo.websocket.org/"</span>);

<span class="hljs-comment">// Establish the WebSocket connection</span>
wsManager?.initWebSocketConnection();

<span class="hljs-comment">// Retrieve the StreamController from the WebSocketManager</span>
<span class="hljs-keyword">final</span> streamController = wsManager?.streamController;

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

<span class="hljs-comment">// Listen to the WebSocket stream and handle incoming data</span>
StreamBuilder&lt;<span class="hljs-built_in">dynamic</span>&gt;(
  stream: streamController?.stream, <span class="hljs-comment">// The stream of data from the WebSocket</span>
  builder: (BuildContext context, AsyncSnapshot&lt;<span class="hljs-built_in">dynamic</span>&gt; snapshot) {
    <span class="hljs-keyword">if</span> (snapshot.hasError) {
      <span class="hljs-comment">// Show an error message in the UI</span>
      <span class="hljs-keyword">return</span> Text(<span class="hljs-string">'Error: <span class="hljs-subst">${snapshot.error}</span>'</span>);
    }

    <span class="hljs-keyword">if</span> (snapshot.connectionState == ConnectionState.waiting) {
      <span class="hljs-comment">// Show a loading indicator while waiting for the stream to emit data</span>
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> CircularProgressIndicator();
    }

    <span class="hljs-keyword">if</span> (snapshot.hasData) {
      <span class="hljs-comment">// Display the received data in the UI</span>
      <span class="hljs-keyword">return</span> Text(<span class="hljs-string">'Received data: <span class="hljs-subst">${snapshot.data}</span>'</span>); 
    }

    <span class="hljs-comment">// Show a default message if no data is received</span>
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'No data available'</span>);
  },
)
</code></pre>
<p><strong>What’s Going On Here?</strong></p>
<ul>
<li><p><strong>WebSocket Initialization</strong>: We start by creating our WebSocketManager with a URL. This URL tells the WebSocket where to connect.</p>
</li>
<li><p><strong>Connection Setup</strong>: Next, we call <code>initWebSocketConnection()</code> to start the connection. This gets our WebSocket up and running.</p>
</li>
<li><p><strong>StreamController</strong>: Remember that radio broadcaster? We’re tuning into it here. We grab the StreamController from our WebSocketManager to listen to any messages coming through.</p>
</li>
<li><p><strong>StreamBuilder</strong>: This function builds the UI every time a new snapshot of data arrives on the stream. It also runs when the stream’s connection state changes.</p>
</li>
</ul>
<p>This approach ensures that your UI stays responsive and up-to-date with real-time data from the WebSocket.</p>
<hr />
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>WebSockets in Flutter might sound a bit intimidating at first, but with a solid understanding of how to manage connections and data, you’ll be up and running in no time. Remember, the key is to keep it simple, handle errors gracefully, and enjoy the process of bringing real-time communication to life in your app!</p>
<p>Happy coding! 🎉</p>
]]></content:encoded></item><item><title><![CDATA[Mastering FCM in Flutter: Your Ultimate Guide to Engaging Notifications]]></title><description><![CDATA[Introduction
Hey there, fellow Flutter enthusiast! Are you ready to level up your app's notification game? Buckle up because we're about to dive into the world of Firebase Cloud Messaging (FCM) and Flutter. In this guide, we'll explore how to set up ...]]></description><link>https://blog.adityasharma.co/mastering-fcm-in-flutter-your-ultimate-guide-to-engaging-notifications</link><guid isPermaLink="true">https://blog.adityasharma.co/mastering-fcm-in-flutter-your-ultimate-guide-to-engaging-notifications</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[Flutter Examples]]></category><category><![CDATA[Firebase]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Fri, 16 Feb 2024 02:30:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708024953706/32db23ef-4729-49ff-a9fd-ccb8a47f56ce.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction"><strong>Introduction</strong></h2>
<p>Hey there, fellow Flutter enthusiast! Are you ready to level up your app's notification game? Buckle up because we're about to dive into the world of Firebase Cloud Messaging (FCM) and Flutter. In this guide, we'll explore how to set up FCM for your Flutter app, utilizing the power of Firebase and the magic of Dart. By the end of this journey, you'll be a notification ninja, delivering timely and engaging messages to your users like a pro.</p>
<hr />
<h2 id="heading-getting-started-with-firebase-cloud-messaging"><strong>Getting Started with Firebase Cloud Messaging</strong></h2>
<h3 id="heading-what-is-firebase-cloud-messaging"><strong>What is Firebase Cloud Messaging?</strong></h3>
<p>Firebase Cloud Messaging, or FCM for short, is a cross-platform messaging solution that allows you to send notifications and data messages to your users on Android, iOS, and the web. It's a powerful tool that enables you to engage with your audience in real time, keeping them informed and connected to your app.</p>
<h3 id="heading-setting-up-firebase-for-your-flutter-app"><strong>Setting up Firebase for your Flutter App</strong></h3>
<p>First things first, let's set up Firebase for our Flutter app. Follow these steps:</p>
<ol>
<li><p>Create a new Flutter project or open an existing one.</p>
</li>
<li><p>Head over to the Firebase Console (<a target="_blank" href="http://console.firebase.google.com">console.firebase.google.com</a>) and create a new project.</p>
</li>
<li><p>Follow the on-screen instructions to add your Flutter app to the Firebase project.</p>
</li>
<li><p>Download the <code>google-services.json</code> file for Android or <code>GoogleService-Info.plist</code> file for iOS and place it in the respective directories of your Flutter app.</p>
</li>
</ol>
<p>You can read more about the FCM setup here: <a target="_blank" href="https://firebase.google.com/docs/cloud-messaging/flutter/client">https://firebase.google.com/docs/cloud-messaging/flutter/client</a></p>
<hr />
<h2 id="heading-dependency-setup"><strong>Dependency Setup</strong></h2>
<p>To use Firebase Cloud Messaging in your Flutter app, you need to add the <code>firebase_messaging</code> package to your <code>pubspec.yaml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
  <span class="hljs-attr">flutter:</span>
    <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>
  <span class="hljs-attr">firebase_messaging:</span> <span class="hljs-string">^14.7.2</span>
  <span class="hljs-attr">flutter_local_notifications:</span> <span class="hljs-string">^16.1.0</span>
</code></pre>
<p>Run <code>flutter pub get</code> to install the packages.</p>
<blockquote>
<p>Note: Before using Firebase Cloud Messaging, you must first have ensured you have <a target="_blank" href="https://firebase.flutter.dev/docs/overview#initializing-flutterfire">initialized FlutterFire.</a></p>
</blockquote>
<hr />
<h2 id="heading-initializing-firebase-messaging"><strong>Initializing Firebase Messaging</strong></h2>
<p>Before we move on to implementing Firebase Messaging in our app, we must look at understand different message types:</p>
<h3 id="heading-message-types"><strong>Message types</strong></h3>
<p>A message payload can be viewed as one of three types:</p>
<ol>
<li><p>Notification-only message: The payload contains a <code>notification</code> property, which will be used to present a visible notification to the user.</p>
</li>
<li><p>Data-only message: Also known as a "silent message", this payload contains custom key/value pairs within the <code>data</code> property which can be used how you see fit. These messages are considered "low priority".</p>
</li>
<li><p>Notification &amp; Data messages: Payloads with both <code>notification</code> and <code>data</code> properties.</p>
</li>
</ol>
<p>Based on your application's current state, incoming payloads require different implementations to handle them:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>Foreground</td><td>Background</td><td>Terminated</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Notification</strong></td><td><code>onMessage</code></td><td><code>onBackgroundMessage</code></td><td><code>onBackgroundMessage</code></td></tr>
<tr>
<td><strong>Data</strong></td><td><code>onMessage</code></td><td><code>onBackgroundMessage</code></td><td><code>onBackgroundMessage</code></td></tr>
<tr>
<td><strong>Notification &amp; Data</strong></td><td><code>onMessage</code></td><td><code>onBackgroundMessage</code></td><td><code>onBackgroundMessage</code></td></tr>
</tbody>
</table>
</div><p>We'll dive into the implementation part soon!</p>
<blockquote>
<p>Note: Data-only messages are considered low priority by devices when your application is in the background or terminated, and will be ignored. You can however explicitly increase the priority by sending additional properties on the FCM payload:</p>
<ul>
<li><p>On Android, set the <code>priority</code> field to <code>high</code>.</p>
</li>
<li><p>On Apple (iOS &amp; macOS), set the <code>content-available</code> field to <code>true</code>.</p>
</li>
</ul>
</blockquote>
<p>Let's initialize Firebase Messaging in our app. We'll create a <code>NotificationService</code> class to handle all things related to notifications in a file named <code>notification_service.dart</code>.</p>
<pre><code class="lang-dart"><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">'package:flutter_local_notifications/flutter_local_notifications.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationService</span> </span>{
<span class="hljs-keyword">final</span> FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
<span class="hljs-keyword">final</span> FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
<span class="hljs-built_in">String</span> fcmToken = <span class="hljs-string">''</span>;

  NotificationService() {
    <span class="hljs-comment">// Initialize Firebase Messaging</span>
    _initializeFCM();
    <span class="hljs-comment">// Initialize Flutter Local Notifications</span>
    _initializeFlutterLocalNotifications();
  }

  <span class="hljs-keyword">void</span> _initializeFCM() <span class="hljs-keyword">async</span> {
    _firebaseMessaging.setAutoInitEnabled(<span class="hljs-keyword">true</span>);

    <span class="hljs-comment">// Request permission</span>
    _firebaseMessaging.requestPermission(sound: <span class="hljs-keyword">true</span>, badge: <span class="hljs-keyword">true</span>, alert: <span class="hljs-keyword">true</span>);
    fcmToken = <span class="hljs-keyword">await</span> _firebaseMessaging.getToken() ?? <span class="hljs-string">''</span>;
    debugPrint(<span class="hljs-string">'FCM Token: <span class="hljs-subst">$fcmToken</span>'</span>);

    <span class="hljs-comment">// Handle background messages</span>
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    <span class="hljs-comment">// Handle messages when the app is in the foreground</span>
    FirebaseMessaging.onMessage.listen((RemoteMessage message) <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">if</span> (message.notification != <span class="hljs-keyword">null</span>) {
        showLocalNotification(message);
      }
    });
  }

  <span class="hljs-keyword">void</span> _initializeFlutterLocalNotifications() {
    <span class="hljs-comment">// Initialize Flutter Local Notifications</span>
    <span class="hljs-comment">// We'll add code here later...</span>
  }

  <span class="hljs-keyword">void</span> showLocalNotification(RemoteMessage message) {
    <span class="hljs-comment">// Show local notification</span>
    <span class="hljs-comment">// We'll add code here later...</span>
  }
}

NotificationService notificationService = NotificationService();
</code></pre>
<p>Handling messages whilst your application is in the background is a little different. Messages can be handled via the onBackgroundMessage handler. When received, an isolate is spawned (Android only, iOS/macOS does not require a separate isolate) allowing you to handle messages even when your application is not running.</p>
<p>There are a few things to keep in mind about your background message handler:</p>
<ul>
<li><p>It must not be an anonymous function.</p>
</li>
<li><p>It must be a top-level function (e.g. not a class method which requires initialization).</p>
</li>
</ul>
<p>Hence, add the following code at the top of <code>notification_service.dart</code>, outside the <code>NotificationService</code> class</p>
<pre><code class="lang-dart"><span class="hljs-meta">@pragma</span>(<span class="hljs-string">'vm:entry-point'</span>)
Future&lt;<span class="hljs-keyword">void</span>&gt; _firebaseMessagingBackgroundHandler(RemoteMessage message) <span class="hljs-keyword">async</span> {
  debugPrint(message.toMap().toString());
  notificationService.showLocalNotification(message);
}
</code></pre>
<hr />
<h2 id="heading-handling-notification-on-tap-action"><strong>Handling Notification On-Tap Action</strong></h2>
<p>We also need to handle on-tap action on our notification banners when the app is in the foreground, background and when it's launched from a terminated state. So, in the same class <code>NotificationService</code> add the following:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationService</span> </span>{
  <span class="hljs-comment">// ...</span>

  <span class="hljs-keyword">void</span> handlePendingNotifications() {
    <span class="hljs-comment">// Handle initial notification when the app is started from a terminated state</span>
    _firebaseMessaging.getInitialMessage().then((message) {
      <span class="hljs-keyword">if</span> (message != <span class="hljs-keyword">null</span>) {
        _handleNotificationTap(message);
      }
    });
  }

  <span class="hljs-keyword">void</span> _handleNotificationTap(RemoteMessage message) {
    <span class="hljs-comment">// Add your notification tap handling logic</span>
  }
}
</code></pre>
<p>To handle the notification tap when the app is starting up from a terminated state, you must call the <code>handlePendingNotifications()</code> method once when your app starts up. You can do so in <code>initState()</code> your HomeScreen Widget which gets initialized at the beginning of the app.</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">const</span> HomeScreen({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  State&lt;HomeScreen&gt; createState() =&gt; _HomeScreenState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_HomeScreenState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">HomeScreen</span>&gt; </span>{
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> initState() {
    <span class="hljs-comment">// Handle the initial notification when the app is started from a terminated state</span>
    notificationService.handlePendingNotifications();

    <span class="hljs-keyword">super</span>.initState();
  }

  <span class="hljs-comment">// ...</span>
}
</code></pre>
<hr />
<h2 id="heading-configuring-local-notifications"><strong>Configuring Local Notifications</strong></h2>
<p>Notification messages which arrive whilst the application is in the foreground will not display a visible notification by default, on both Android &amp; iOS. It is, however, possible to override this behavior:</p>
<p>On Android, notification messages are sent to Notification Channels which are used to control how a notification is delivered. The default FCM channel used is hidden from users, however provides a "default" importance level. Heads up notifications (shown when our app is in the foreground) require a "max" importance level.</p>
<p>This means that we need to first create a new channel with a maximum importance level &amp; then assign incoming FCM notifications to this channel. Although this is outside of the scope of <strong>FlutterFire</strong>, we can take advantage of the <a target="_blank" href="https://pub.dev/packages/flutter_local_notifications">flutter_local_notifications</a> package to help us.</p>
<h3 id="heading-initialization"><strong>Initialization</strong></h3>
<p>Let's initialize <code>FlutterLocalNotificationsPlugin</code> in our <code>NotificationService</code>.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> _initializeFlutterLocalNotifications() {
  <span class="hljs-keyword">var</span> initializationSettingsAndroid = <span class="hljs-keyword">const</span> AndroidInitializationSettings(<span class="hljs-string">'@drawable/ic_launcher'</span>);
  <span class="hljs-keyword">var</span> initializationSettingsIOS = DarwinInitializationSettings(
    onDidReceiveLocalNotification: (id, title, body, payload) <span class="hljs-keyword">async</span> {},
  );
  <span class="hljs-keyword">var</span> initializationSettings = InitializationSettings(
    android: initializationSettingsAndroid,
    iOS: initializationSettingsIOS,
  );
  _flutterLocalNotificationsPlugin.initialize(
    initializationSettings,
    onDidReceiveNotificationResponse: (details) {
      <span class="hljs-keyword">final</span> message = RemoteMessage.fromMap({<span class="hljs-string">'data'</span>: jsonDecode(details.payload ?? <span class="hljs-string">'{}'</span>)});
      _handleNotificationTap(message);
    },
  );

  _flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation&lt;AndroidFlutterLocalNotificationsPlugin&gt;()
      ?.requestNotificationsPermission();

  _flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation&lt;IOSFlutterLocalNotificationsPlugin&gt;()
      ?.requestPermissions(
        alert: <span class="hljs-keyword">true</span>,
        badge: <span class="hljs-keyword">true</span>,
        sound: <span class="hljs-keyword">true</span>,
      );
}
</code></pre>
<h3 id="heading-showing-local-notifications"><strong>Showing Local Notifications</strong></h3>
<p>Finally, let's define a method to show local notifications inside the <code>NotificationService</code> class.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> showLocalNotification(RemoteMessage message) {
  <span class="hljs-keyword">var</span> androidPlatformChannelSpecifics = <span class="hljs-keyword">const</span> AndroidNotificationDetails(
    <span class="hljs-string">'channel_id'</span>,
    <span class="hljs-string">'Channel Name'</span>,
    channelDescription: <span class="hljs-string">'Channel Description'</span>,
    importance: Importance.max,
    priority: Priority.max,
  );
  <span class="hljs-keyword">var</span> iOSPlatformChannelSpecifics = <span class="hljs-keyword">const</span> DarwinNotificationDetails();
  <span class="hljs-keyword">var</span> platformChannelSpecifics = NotificationDetails(
    android: androidPlatformChannelSpecifics,
    iOS: iOSPlatformChannelSpecifics,
  );

  <span class="hljs-comment">// Define the ID of the notification</span>
  <span class="hljs-keyword">final</span> id = <span class="hljs-built_in">DateTime</span>.now().millisecondsSinceEpoch ~/ <span class="hljs-number">1000</span>;

  _flutterLocalNotificationsPlugin.<span class="hljs-keyword">show</span>(
    id,
    message.notification?.title ?? <span class="hljs-string">''</span>,
    message.notification?.body ?? <span class="hljs-string">''</span>,
    platformChannelSpecifics,
    payload: jsonEncode(message.data),
  );
}
</code></pre>
<hr />
<h2 id="heading-final-showdown">Final Showdown</h2>
<p>Here's the complete code example of our Notification Service:</p>
<pre><code class="lang-dart"><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">'package:flutter_local_notifications/flutter_local_notifications.dart'</span>;

<span class="hljs-comment">// Top level background notification handler</span>
<span class="hljs-meta">@pragma</span>(<span class="hljs-string">'vm:entry-point'</span>)
Future&lt;<span class="hljs-keyword">void</span>&gt; _firebaseMessagingBackgroundHandler(RemoteMessage message) <span class="hljs-keyword">async</span> {
  debugPrint(message.toMap().toString());
  notificationService.showLocalNotification(message);
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NotificationService</span> </span>{
<span class="hljs-keyword">final</span> FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
<span class="hljs-keyword">final</span> FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
<span class="hljs-built_in">String</span> fcmToken = <span class="hljs-string">''</span>;

  NotificationService() {
    <span class="hljs-comment">// Initialize Firebase Messaging</span>
    _initializeFCM();
    <span class="hljs-comment">// Initialize Flutter Local Notifications</span>
    _initializeFlutterLocalNotifications();
  }

  <span class="hljs-keyword">void</span> _initializeFCM() <span class="hljs-keyword">async</span> {
    _firebaseMessaging.setAutoInitEnabled(<span class="hljs-keyword">true</span>);

    <span class="hljs-comment">// Request permission</span>
    _firebaseMessaging.requestPermission(sound: <span class="hljs-keyword">true</span>, badge: <span class="hljs-keyword">true</span>, alert: <span class="hljs-keyword">true</span>);
    fcmToken = <span class="hljs-keyword">await</span> _firebaseMessaging.getToken() ?? <span class="hljs-string">''</span>;
    debugPrint(<span class="hljs-string">'FCM Token: <span class="hljs-subst">$fcmToken</span>'</span>);

    <span class="hljs-comment">// Handle background messages</span>
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    <span class="hljs-comment">// Handle messages when the app is in the foreground</span>
    FirebaseMessaging.onMessage.listen((RemoteMessage message) <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">if</span> (message.notification != <span class="hljs-keyword">null</span>) {
        showLocalNotification(message);
      }
    });
  }

  <span class="hljs-keyword">void</span> handlePendingNotifications() {
    <span class="hljs-comment">// Handle initial notification when the app is started from a terminated state</span>
    _firebaseMessaging.getInitialMessage().then((message) {
      <span class="hljs-keyword">if</span> (message != <span class="hljs-keyword">null</span>) {
        _handleNotificationTap(message);
      }
    });
  }

  <span class="hljs-keyword">void</span> _handleNotificationTap(RemoteMessage message) {
    <span class="hljs-comment">// Add your notification tap handling logic</span>
  }

  <span class="hljs-keyword">void</span> _initializeFlutterLocalNotifications() {
    <span class="hljs-keyword">var</span> initializationSettingsAndroid = <span class="hljs-keyword">const</span> AndroidInitializationSettings(<span class="hljs-string">'@drawable/ic_launcher'</span>);
    <span class="hljs-keyword">var</span> initializationSettingsIOS = DarwinInitializationSettings(
      onDidReceiveLocalNotification: (id, title, body, payload) <span class="hljs-keyword">async</span> {},
    );
    <span class="hljs-keyword">var</span> initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
    );
    _flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
      onDidReceiveNotificationResponse: (details) {
        <span class="hljs-keyword">final</span> message = RemoteMessage.fromMap({<span class="hljs-string">'data'</span>: jsonDecode(details.payload ?? <span class="hljs-string">'{}'</span>)});
        _handleNotificationTap(message);
      },
    );

    _flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation&lt;AndroidFlutterLocalNotificationsPlugin&gt;()
        ?.requestNotificationsPermission();

    _flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation&lt;IOSFlutterLocalNotificationsPlugin&gt;()
        ?.requestPermissions(
          alert: <span class="hljs-keyword">true</span>,
          badge: <span class="hljs-keyword">true</span>,
          sound: <span class="hljs-keyword">true</span>,
        );
    }

  <span class="hljs-keyword">void</span> showLocalNotification(RemoteMessage message) {
    <span class="hljs-keyword">var</span> androidPlatformChannelSpecifics = <span class="hljs-keyword">const</span> AndroidNotificationDetails(
      <span class="hljs-string">'channel_id'</span>,
      <span class="hljs-string">'Channel Name'</span>,
      channelDescription: <span class="hljs-string">'Channel Description'</span>,
      importance: Importance.max,
      priority: Priority.max,
    );
    <span class="hljs-keyword">var</span> iOSPlatformChannelSpecifics = <span class="hljs-keyword">const</span> DarwinNotificationDetails();
    <span class="hljs-keyword">var</span> platformChannelSpecifics = NotificationDetails(
      android: androidPlatformChannelSpecifics,
      iOS: iOSPlatformChannelSpecifics,
    );

    <span class="hljs-comment">// Define the ID of the notification</span>
    <span class="hljs-keyword">final</span> id = <span class="hljs-built_in">DateTime</span>.now().millisecondsSinceEpoch ~/ <span class="hljs-number">1000</span>;

    _flutterLocalNotificationsPlugin.<span class="hljs-keyword">show</span>(
      id,
      message.notification?.title ?? <span class="hljs-string">''</span>,
      message.notification?.body ?? <span class="hljs-string">''</span>,
      platformChannelSpecifics,
      payload: jsonEncode(message.data),
    );
  }
}

NotificationService notificationService = NotificationService();
</code></pre>
<hr />
<h2 id="heading-wrapping-up-and-next-steps"><strong>Wrapping Up and Next Steps</strong></h2>
<p>Congratulations! You've successfully set up Firebase Cloud Messaging for your Flutter app. Now, you can send notifications to your users and keep them engaged with your app's content. But remember, this is just the beginning. There's so much more you can do with FCM, like sending data messages, handling user interactions, and targeting specific user segments.</p>
<p>Happy Coding! 🚀</p>
<hr />
<h2 id="heading-references">References</h2>
<ul>
<li><p><a target="_blank" href="https://firebase.google.com/docs/cloud-messaging/flutter/client">https://firebase.google.com/docs/cloud-messaging/flutter/client</a></p>
</li>
<li><p><a target="_blank" href="https://firebase.google.com/docs/cloud-messaging/flutter/receive">https://firebase.google.com/docs/cloud-messaging/flutter/receive</a></p>
</li>
<li><p><a target="_blank" href="https://firebase.flutter.dev/docs/messaging/notifications/#foreground-notifications">https://firebase.flutter.dev/docs/messaging/notifications/#foreground-notifications</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Building Flutter Apps with Clean Architecture Using GetX]]></title><description><![CDATA[Hello, Flutter aficionados! 🚀 In this blog post, we're about to embark on an exciting journey into the world of Flutter clean architecture using the incredible GetX package. Whether you're a seasoned developer or just starting your Flutter adventure...]]></description><link>https://blog.adityasharma.co/building-flutter-apps-with-clean-architecture-using-getx</link><guid isPermaLink="true">https://blog.adityasharma.co/building-flutter-apps-with-clean-architecture-using-getx</guid><category><![CDATA[Flutter]]></category><category><![CDATA[app development]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[clean code]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Thu, 05 Oct 2023 10:12:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696485327830/8b86432c-2243-4136-8241-d2224d5cee4f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello, Flutter aficionados! 🚀 In this blog post, we're about to embark on an exciting journey into the world of Flutter clean architecture using the incredible GetX package. Whether you're a seasoned developer or just starting your Flutter adventure, this guide will help you build organized and maintainable Flutter apps. So, grab your coding capes, and let's dive in!</p>
<h2 id="heading-what-is-clean-architecture">What is Clean Architecture?</h2>
<p>Before we delve into the nitty-gritty of Flutter clean architecture with GetX, let's start with a quick introduction to clean architecture.</p>
<p><strong>Pros of Clean Architecture:</strong></p>
<ul>
<li><p><strong>Modularity:</strong> Clean architecture promotes a modular approach, making your codebase easier to understand and maintain.</p>
</li>
<li><p><strong>Testability:</strong> It encourages writing unit tests and makes your codebase more test-friendly.</p>
</li>
<li><p><strong>Scalability:</strong> Your app can grow and evolve without major architectural changes.</p>
</li>
<li><p><strong>Independence:</strong> The architecture keeps external frameworks and libraries at bay, preventing them from tightly coupling with your code.</p>
</li>
</ul>
<p><strong>Cons of Clean Architecture:</strong></p>
<ul>
<li><p><strong>Initial Complexity:</strong> Setting up a clean architecture project might seem more daunting compared to a simple structure.</p>
</li>
<li><p><strong>Learning Curve:</strong> Developers new to clean architecture may take some time to fully grasp its concepts.</p>
</li>
</ul>
<p>Now that we're clear on the basics, let's roll up our sleeves and get started!</p>
<hr />
<h2 id="heading-project-setup">Project Setup</h2>
<p>This project is written using the current latest stable versions of:</p>
<ul>
<li><p><a target="_blank" href="https://docs.flutter.dev/development/tools/sdk/releases"><strong>Flutter</strong></a>: v3.10.6</p>
</li>
<li><p><a target="_blank" href="https://dart.dev/guides/language/evolution"><strong>Dart</strong></a>: v3.0.6</p>
</li>
</ul>
<h3 id="heading-packages">Packages</h3>
<p>Before we start coding, let's gather our tools and libraries. Here are the essential packages we'll use:</p>
<ul>
<li><p><a target="_blank" href="https://pub.dev/packages/get"><strong>getX</strong></a><strong>:</strong> The Swiss Army knife for state management. (You can use any kind of state management you prefer to work with such as <a target="_blank" href="https://pub.dev/packages/provider"><strong>provider</strong></a><strong>or</strong><a target="_blank" href="https://pub.dev/packages/flutter_bloc"><strong>flutter_bloc</strong></a>)</p>
</li>
<li><p><a target="_blank" href="https://pub.dev/packages/freezed"><strong>freezed</strong></a><strong>:</strong> A code generation package for creating immutable data models.</p>
</li>
<li><p><a target="_blank" href="https://pub.dev/packages/retrofit"><strong>retrofit</strong></a> <strong>&amp;</strong> <a target="_blank" href="https://pub.dev/packages/dio"><strong>dio</strong></a><strong>:</strong> For handling HTTP requests.</p>
</li>
<li><p><a target="_blank" href="https://pub.dev/packages/get_it"><strong>get_it</strong></a> <strong>&amp;</strong> <a target="_blank" href="https://pub.dev/packages/injectable"><strong>injectable</strong></a><strong>:</strong> For dependency injection.</p>
</li>
<li><p><a target="_blank" href="https://pub.dev/packages/go_router"><strong>go_router</strong></a><strong>:</strong> A declarative routing package that provides a convenient, URL-based API for navigating between different screens.</p>
</li>
<li><p><a target="_blank" href="https://pub.dev/packages/pretty_dio_logger"><strong>pretty_dio_logger</strong></a><strong>:</strong> A delightful logger for HTTP requests.</p>
</li>
</ul>
<p>Let's include these packages in our <code>pubspec.yaml</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
  <span class="hljs-attr">get:</span> <span class="hljs-string">^4.6.6</span>
  <span class="hljs-attr">retrofit:</span> <span class="hljs-string">^4.0.2</span>
  <span class="hljs-attr">dio:</span> <span class="hljs-string">^5.3.3</span>
  <span class="hljs-attr">get_it:</span> <span class="hljs-string">^7.6.4</span>
  <span class="hljs-attr">injectable:</span> <span class="hljs-string">^2.3.0</span>
  <span class="hljs-attr">go_router:</span> <span class="hljs-string">^11.1.2</span>
  <span class="hljs-attr">pretty_dio_logger:</span> <span class="hljs-string">^1.3.1</span>

<span class="hljs-attr">dev_dependencies:</span>
  <span class="hljs-attr">flutter_test:</span>
    <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>
  <span class="hljs-attr">flutter_lints:</span> <span class="hljs-string">^2.0.0</span>
  <span class="hljs-attr">build_runner:</span> <span class="hljs-string">^2.4.6</span>
  <span class="hljs-attr">freezed:</span> <span class="hljs-string">^2.4.3</span>
  <span class="hljs-attr">json_serializable:</span> <span class="hljs-string">^6.7.1</span>
  <span class="hljs-attr">retrofit_generator:</span> <span class="hljs-string">^7.0.8</span>
  <span class="hljs-attr">injectable_generator:</span> <span class="hljs-string">^2.4.0</span>
</code></pre>
<h3 id="heading-folder-structure">Folder Structure</h3>
<p>Organization is key in clean architecture. Here's a recommended folder structure:</p>
<pre><code class="lang-c">lib/
  ├── config/
  │     ├── injection/
  │     ├── router/
  │     └── themes/
  ├── data/
  │     ├── datasources/
  │     │    ├── local/
  │     │    └── remote/
  │     └── repositories/
  ├── domain/
  │     ├── models/
  │     └── repositories/
  ├── presentation/
  │     ├── controllers/
  │     ├── pages/
  │     └── widgets/
  ├── utils/
  │     ├── constants/
  │     ├── extensions/
  │     └── resources/
  └── main.dart
</code></pre>
<p>The <strong>config</strong> folder includes the configuration of the app (<strong>themes</strong>, <strong>router</strong>, ..etc) and anything else related to the app’s configurations.</p>
<p>The <strong>utils</strong> folder, on the other hand, includes (<strong>constants</strong>, <strong>extensions</strong>, <strong>resources</strong>, ..etc) and anything related to that.</p>
<p>The (<strong>data</strong>, <strong>domain</strong> and <strong>presentation</strong>) folders will be explained later in detail.</p>
<h3 id="heading-architecture-and-dependency-rules">Architecture and Dependency Rules</h3>
<p>The clean architecture consists of three primary layers:</p>
<ol>
<li><p><strong>Data Layer:</strong> Responsible for data fetching and caching.</p>
</li>
<li><p><strong>Domain Layer:</strong> Houses the core business logic.</p>
</li>
<li><p><strong>Presentation Layer:</strong> Manages the user interface and user interactions.</p>
</li>
</ol>
<p>Each layer has its unique responsibilities, and dependencies flow inward. The Data Layer is independent, the Domain Layer depends on Data, and the Presentation Layer relies on both Data and Domain.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696499988717/67904f8e-432e-4d19-86d3-491d790d0f1a.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-app-configuration">App Configuration</h2>
<p>Before diving into the layers, let's configure our app. Here's a sneak peek:</p>
<h3 id="heading-routing">Routing</h3>
<p>Routing is a fundamental aspect of any Flutter app. We'll use the <code>go_router</code> package to handle navigation efficiently.</p>
<blockquote>
<p><em>You can absolutely choose whatever the routing package you prefer, and that suits your needs.</em></p>
</blockquote>
<p>Now, after adding the package to your <code>pubspec.yaml</code> file as we talked about it at the beginning of the article, create a folder in this path <strong>lib/config</strong> and call it <strong>router</strong>, then inside the folder create a file and name it <code>app_router.dart</code> as shown below:</p>
<pre><code class="lang-dart"><span class="hljs-meta">@singleton</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppRouter</span> </span>{
  <span class="hljs-keyword">final</span> GoRouter _router = GoRouter(
    debugLogDiagnostics: <span class="hljs-keyword">true</span>,
    initialLocation: <span class="hljs-string">'/'</span>,
    routes: [
      GoRoute(
        path: <span class="hljs-string">'/'</span>,
        builder: (context, state) =&gt; <span class="hljs-keyword">const</span> HomeScreen(),
      ),
      GoRoute(
        path: <span class="hljs-string">'/profile'</span>,
        builder: (context, state) =&gt; <span class="hljs-keyword">const</span> UserDetailsScreen(),
      ),
      ...
      <span class="hljs-comment">// Add more routes as needed</span>
  );

  GoRouter <span class="hljs-keyword">get</span> router =&gt; _router;
}
</code></pre>
<h3 id="heading-theme">Theme</h3>
<p>Defining a global theme ensures consistency in your app's appearance. Let's create a file <code>app_theme.dart</code> inside <strong>lib/config/themes</strong>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:dtdcopedia/config/themes/app_colors.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppTheme</span> </span>{
  <span class="hljs-keyword">static</span> ThemeData <span class="hljs-keyword">get</span> light {
    <span class="hljs-keyword">return</span> ThemeData(
      appBarTheme: <span class="hljs-keyword">const</span> AppBarTheme(
        elevation: <span class="hljs-number">0</span>,
        color: AppColors.primary,
      ),
      scaffoldBackgroundColor: AppColors.background,
      primaryColor: AppColors.primary,
      splashColor: Colors.transparent,
      fontFamily: <span class="hljs-string">'Hind'</span>,
    );
  }

  <span class="hljs-keyword">static</span> ThemeData <span class="hljs-keyword">get</span> dark {
    <span class="hljs-keyword">return</span> ThemeData(
      appBarTheme: <span class="hljs-keyword">const</span> AppBarTheme(
        elevation: <span class="hljs-number">0</span>,
        color: AppColors.primary,
      ),
      scaffoldBackgroundColor: AppColors.text,
      primaryColor: AppColors.primary,
      splashColor: Colors.transparent,
      fontFamily: <span class="hljs-string">'Hind'</span>,
    );
  }
}
</code></pre>
<p>This sets up your app's global theme with the specified colors, fonts, and more. You can customize it the way you like.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Use <strong>ThemeExtension</strong> for creating custom themes: <a target="_blank" href="https://medium.com/geekculture/flutter-3-how-to-extend-themedata-56b8923bf1aa">https://medium.com/geekculture/flutter-3-how-to-extend-themedata-56b8923bf1aa</a></div>
</div>

<h3 id="heading-utils"><strong>Utils</strong></h3>
<p>In the <code>utils</code> folder, you can organize your utility functions, constants, extensions, and resources neatly. Here's an example structure:</p>
<pre><code class="lang-dart">lib/
  ├── utils/
  │     ├── constants/
  │     │     └── app_constants.dart
  │     ├── extensions/
  │     │     ├── string_extensions.dart
  │     │     └── date_extensions.dart
  │     ├── resources/
  │     │     └── data_state.dart
  │     └── ...
  └── ...
</code></pre>
<p>For example, in <code>app_constants.dart</code>:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppConstants</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> appTitle = <span class="hljs-string">'Flutter Clean Architecture'</span>;

 <span class="hljs-comment">// Networking and APIs</span>
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> baseUrl = <span class="hljs-string">'https://appi.example.com/'</span>; 
  <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> defaultApiKey = <span class="hljs-string">'YOUR_API_KEY'</span>;

 <span class="hljs-comment">// Storage and Databases</span>
 <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> appTableName = <span class="hljs-string">'app_table'</span>;
 <span class="hljs-keyword">static</span> <span class="hljs-keyword">const</span> <span class="hljs-built_in">String</span> databaseName = <span class="hljs-string">'app_database.db'</span>;
}
</code></pre>
<p>And in <code>string_extensions.dart</code>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> StringExtensions <span class="hljs-keyword">on</span> <span class="hljs-built_in">String</span> {
  <span class="hljs-built_in">String</span> capitalize() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"<span class="hljs-subst">${<span class="hljs-keyword">this</span>[<span class="hljs-number">0</span>].toUpperCase()}</span><span class="hljs-subst">${<span class="hljs-keyword">this</span>.substring(<span class="hljs-number">1</span>)}</span>"</span>;
  }
}
</code></pre>
<p>In the <strong>lib/utils/resources</strong> create a file and name it <code>data_state.dart</code> which contains the following code:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:dio/dio.dart'</span>;

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataState</span>&lt;<span class="hljs-title">T</span>&gt; </span>{
    <span class="hljs-keyword">final</span> T data;
    <span class="hljs-keyword">final</span> DioError error;
    <span class="hljs-keyword">const</span> DataState({<span class="hljs-keyword">this</span>.data, <span class="hljs-keyword">this</span>.error});
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataSuccess</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-keyword">extends</span> <span class="hljs-title">DataState</span>&lt;<span class="hljs-title">T</span>&gt; </span>{ 
    <span class="hljs-keyword">const</span> DataSuccess(T data): <span class="hljs-keyword">super</span>(data: data);
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataFailed</span>&lt;<span class="hljs-title">T</span>&gt; <span class="hljs-keyword">extends</span> <span class="hljs-title">DataState</span>&lt;<span class="hljs-title">T</span>&gt; </span>{ 
    <span class="hljs-keyword">const</span> DataFailed (DioError error): <span class="hljs-keyword">super</span>(error: error);
}
</code></pre>
<p>This wrapper class <code>DataState</code> can be used to wrap our entire network call in order to determine the state of the request being sent to the server and its response.</p>
<p>As you can see in the code, we’ve two different states, one when we get a successful response (<strong>DataSuccess</strong>), and the other when an error occurs while sending the request or receiving the response (<strong>DataFailed</strong>).</p>
<p>This is very important as later on when we will have too many requests and logic, you will see how minimized the code will become.</p>
<h3 id="heading-dependency-injection">Dependency Injection</h3>
<p>Dependency injection is a crucial part of clean architecture. We use <code>get_it</code> and <code>injectable</code> to manage our dependencies efficiently. Here's a glimpse of how it works:</p>
<p>First, inside <strong>lib/config/injection,</strong> create a file named <code>injection.dart</code>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:get_it/get_it.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:injectable/injectable.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'injection.config.dart'</span>;

<span class="hljs-keyword">final</span> locator = GetIt.instance;

<span class="hljs-meta">@InjectableInit</span>()
Future&lt;<span class="hljs-keyword">void</span>&gt; configureDependencies() {
  <span class="hljs-keyword">return</span> locator.init();
}
</code></pre>
<p>Now, create a file named <code>register_module.dart</code> inside the same folder. Here we can inject third party packages such as <strong>SharedPreferences</strong> &amp; <strong>Dio</strong>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:io'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'package:dio/dio.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:injectable/injectable.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:pretty_dio_logger/pretty_dio_logger.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:shared_preferences/shared_preferences.dart'</span>;

<span class="hljs-meta">@module</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterModule</span> </span>{
  <span class="hljs-comment">// Inject SharedPreferences</span>
  <span class="hljs-meta">@preResolve</span>
  Future&lt;SharedPreferences&gt; <span class="hljs-keyword">get</span> prefs =&gt; SharedPreferences.getInstance();

  <span class="hljs-comment">// Inject Dio</span>
  <span class="hljs-meta">@lazySingleton</span>
  Dio dio(SharedPreferences sharedPreferences) {
    <span class="hljs-keyword">final</span> token = sharedPreferences.getString(<span class="hljs-string">'token'</span>) ?? <span class="hljs-string">''</span>;

    <span class="hljs-keyword">return</span> Dio(
      BaseOptions(
        baseUrl: AppConstants.baseUrl,
        headers: {
          <span class="hljs-keyword">if</span> (token.isNotEmpty) HttpHeaders.authorizationHeader: <span class="hljs-string">"Bearer <span class="hljs-subst">$token</span>"</span>,
        },
      ),
    )..interceptors.add(
        PrettyDioLogger(
          requestHeader: <span class="hljs-keyword">true</span>,
          requestBody: <span class="hljs-keyword">true</span>,
          responseHeader: <span class="hljs-keyword">true</span>,
          maxWidth: <span class="hljs-number">120</span>,
        ),
      );
  }
}
</code></pre>
<p>Now you can import and use these utility functions, constants &amp; injected modules throughout your project for a clean and organized codebase. Finally, the <code>main.dart</code> file will look like this:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> main() <span class="hljs-keyword">async</span> {
  WidgetsFlutterBinding.ensureInitialized();
  <span class="hljs-keyword">await</span> configureDependencies();
  runApp(<span class="hljs-keyword">const</span> MyApp());
}

<span class="hljs-keyword">final</span> _router = locator&lt;AppRouter&gt;().router;

<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({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp.router(
      debugShowCheckedModeBanner: <span class="hljs-keyword">false</span>,
      title: AppConstants.appTitle,
      theme: AppTheme.light,
      darkTheme: AppTheme.dark,
      routerConfig: _router,
    );
  }
}
</code></pre>
<hr />
<h2 id="heading-domain-layer"><strong>Domain Layer</strong></h2>
<p>Now, let's dive into the Domain Layer. The Domain Layer is the core of the application's business logic. It encapsulates the rules, behaviours, and core functionality that define how the application operates. This layer is entirely independent of external factors such as databases, network calls, or the user interface.</p>
<p>In <strong>Clean Architecture</strong>, the <strong>Domain Layer</strong> should be independent of any specific implementation or framework. This means that the code in the Domain Layer should be written in a <strong>technology-agnostic</strong> way, with no dependencies on external systems or libraries.</p>
<h3 id="heading-entities-models"><strong>Entities (Models)</strong></h3>
<p>Entities/Models are plain Dart classes that represent the core business objects of the application. They model the data that the app operates on and typically contain minimal logic. Entities are defined solely based on the business requirements, and they do not contain any database-specific or UI-related code.</p>
<p><strong>Freezed</strong> helps us create immutable data models effortlessly. Here's a sample domain model <code>user.dart</code> inside <strong>lib/domain/models</strong>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">part</span> <span class="hljs-string">'user.freezed.dart'</span>;

<span class="hljs-meta">@freezed</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-title">with</span> <span class="hljs-title">_</span>$<span class="hljs-title">User</span> </span>{
  <span class="hljs-keyword">const</span> <span class="hljs-keyword">factory</span> User({
    <span class="hljs-keyword">required</span> <span class="hljs-built_in">int</span> id,
    <span class="hljs-keyword">required</span> <span class="hljs-built_in">String</span> name,
    <span class="hljs-comment">// Add more fields as needed</span>
  }) = _User;
}
</code></pre>
<h3 id="heading-repositories-abstract-definitions"><strong>Repositories (Abstract Definitions)</strong></h3>
<p>In the Domain Layer, repositories are defined as abstract classes or interfaces. These abstract definitions declare the methods for interacting with data without specifying how data is fetched or stored. The concrete implementations of these repositories are located in the Data Layer.</p>
<p>Repositories are interfaces that define data sources for our domain layer. For example, <code>user_repository.dart</code> inside <strong>lib/domain/repositories</strong>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRepository</span> </span>{
  Future&lt;UserEntity&gt; getUserById(<span class="hljs-built_in">int</span> id);
}
</code></pre>
<h2 id="heading-data-layer"><strong>Data Layer</strong></h2>
<p>The Data Layer is the foundational layer responsible for handling data operations in a Flutter app. Its primary purpose is to abstract and encapsulate data sources, ensuring that the rest of the application doesn't need to know the specifics of data retrieval and storage.</p>
<h3 id="heading-data-sources"><strong>Data Sources</strong></h3>
<p>Data Sources are responsible for interacting with external data providers, such as APIs, databases, or local storage. They define the interfaces for fetching and storing data. This layer is typically implemented using packages like <code>Retrofit</code>, <code>Dio</code>, or other HTTP client libraries for API interactions, as well as database libraries like <code>SQFLite</code> for local storage.</p>
<p>Here's a sample data source service <code>user_data_source.dart</code> inside <strong>lib/data/datasources/remote</strong>:</p>
<pre><code class="lang-dart"><span class="hljs-meta">@RestApi</span>(baseUrl: <span class="hljs-string">'https://api.example.com/'</span>)
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDataSource</span> </span>{
  <span class="hljs-keyword">factory</span> UserDataSource(Dio dio) = _UserDataSource;

  <span class="hljs-meta">@GET</span>(<span class="hljs-string">'/users/{id}'</span>)
  Future&lt;UserEntity&gt; getUserById(<span class="hljs-meta">@Path</span>() <span class="hljs-built_in">int</span> id);
}
</code></pre>
<p>Now, create <code>data_source_injection.dart</code> file inside <strong>lib/config/injection</strong> and inject the <strong>UserDataSource</strong> class as a module:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:dio/dio.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:your_package_name/data/datasources/remote/user_data_source.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:injectable/injectable.dart'</span>;

<span class="hljs-meta">@module</span>
<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DataSourceInjectableModule</span> </span>{
  UserDataSource getUserDataSource(Dio dio) =&gt; UserDataSource(dio);
  <span class="hljs-comment">// Add more data dources as needed</span>
}
</code></pre>
<h3 id="heading-repositories-implementation"><strong>Repositories (Implementation)</strong></h3>
<p>Repositories act as intermediaries between Data Sources and the Domain Layer. They provide a clean and consistent API for accessing data. Repositories are defined as abstract classes in the Domain Layer, listing methods like <code>getUserById()</code> or <code>fetchPosts()</code>. The concrete implementations of these repositories, found in the Data Layer, interact with Data Sources to fetch and manipulate data. Repositories also manage data caching and storage.</p>
<p>Before we implement the <strong>UserRepository</strong> class, we need to create a base class called <strong>BaseApiRepository</strong>, create a folder inside the <strong>data</strong> folder and name it <strong>base</strong>, then create a file inside it and name it <code>base_api_repository.dart</code> which contains the following:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:io'</span> <span class="hljs-keyword">show</span> HttpStatus;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:retrofit/dio.dart'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'package:dio/dio.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:your_project_name/utils/resources/data_state.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BaseApiRepository</span> </span>{
  <span class="hljs-meta">@protected</span>
  Future&lt;DataState&lt;T?&gt;&gt; getStateOf&lt;T&gt;({
    <span class="hljs-keyword">required</span> Future&lt;HttpResponse&lt;T&gt;&gt; <span class="hljs-built_in">Function</span>() request,
  }) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">final</span> httpResponse = <span class="hljs-keyword">await</span> request();
      <span class="hljs-keyword">if</span> (httpResponse.response.statusCode == HttpStatus.created || httpResponse.response.statusCode == HttpStatus.ok) {
        <span class="hljs-keyword">return</span> DataSuccess(httpResponse.data);
      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (httpResponse.response.statusCode == HttpStatus.unauthorized) {
        <span class="hljs-keyword">throw</span> DataFailed(DioException(
          response: httpResponse.response,
          requestOptions: httpResponse.response.requestOptions,
        ));
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">throw</span> DioException(
          response: httpResponse.response,
          requestOptions: httpResponse.response.requestOptions,
        );
      }
    } <span class="hljs-keyword">on</span> DioException <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">return</span> DataFailed(error);
    }
  }
}
</code></pre>
<p>This base class plays an important role here, which wraps our API call that comes from the data source <code>user_data_source.dart</code> and return a <strong>DataState</strong> object instead of <strong>HttpResponse</strong>.</p>
<p>By doing so, we’re reducing the boilerplate code in each method without the need to write “<strong>try-catch”</strong> or “<strong>if”</strong> statements everywhere because you only need to pass the request in the “<strong>getStateOf</strong>” method and this should do the rest and return the result based on the generic “<strong>T</strong>” type.</p>
<p>Now create <code>user_repository_impl.dart</code> inside <strong>lib/data/repositories</strong> &amp; implement the previously defined <strong>UserRepository</strong> class as below:</p>
<pre><code class="lang-dart"><span class="hljs-meta">@Injectable</span>(<span class="hljs-keyword">as</span>: UserRepository)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserRepositoryImpl</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseApiRepository</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserRepository</span> </span>{
  <span class="hljs-keyword">final</span> UserDataSource _userDataSource;
  UserRepositoryImpl(<span class="hljs-keyword">this</span>._userDataSource);

  <span class="hljs-meta">@override</span>
  Future&lt;DataState&lt;User?&gt;&gt; getUserById(<span class="hljs-built_in">int</span> id) {
    <span class="hljs-keyword">return</span> getStateOf&lt;User&gt;(
      request: () =&gt; _userDataSource.getUserById(id),
    );
  }
}
</code></pre>
<h2 id="heading-presentation-layer">Presentation Layer</h2>
<p>Last but not least, we arrive at the Presentation Layer, where we build the user interface, controllers, screens, and common widgets.</p>
<p>The benefit of using <strong>Presentation Layer</strong> is that it makes the codebase more modular and maintainable. By separating the user interface from the business logic and infrastructure, it becomes easier to modify and extend the application over time. Also, it allows for different user interfaces to be developed and used with the same underlying business logic. For example, a <strong>web application</strong>, a <strong>mobile application</strong>, and a <strong>desktop application</strong> could all use the same Domain Layer but have different Presentation Layers that are optimized for their respective platforms.</p>
<h3 id="heading-controllers">Controllers</h3>
<p>Controllers manage the state and business logic of our app. Here's a snippet of a controller <code>user_controller.dart</code> inside <strong>lib/presentation/controllers</strong> using GetX:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">GetxController</span> </span>{
  <span class="hljs-keyword">static</span> UserController <span class="hljs-keyword">get</span> call =&gt; Get.find();

  <span class="hljs-keyword">final</span> UserRepository _userRepository = locator&lt;UserRepository&gt;();
  <span class="hljs-keyword">final</span> Rx&lt;User&gt; user = Rx&lt;User&gt;(User(id: <span class="hljs-number">0</span>, name: <span class="hljs-string">''</span>));

  Future&lt;<span class="hljs-keyword">void</span>&gt; fetchUser(<span class="hljs-built_in">int</span> id) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">final</span> result = <span class="hljs-keyword">await</span> _userRepository.getUserById(id);
    user.value = result;
  }
}
</code></pre>
<h3 id="heading-screens">Screens</h3>
<p>Screens are where the magic happens. Screens correspond to the different views or pages of the app. Each screen is typically represented by a Flutter widget. Screens are responsible for rendering the UI and displaying data to the user.</p>
<p>You can create screen files inside <strong>lib/presentation/screens</strong> folder. For example, here's <code>user_details_screen.dart</code>:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDetailsScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">const</span> UserDetailsScreen({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  State&lt;UserDetailsScreen&gt; createState() =&gt; _UserDetailsScreenState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_UserDetailsScreenState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">UserDetailsScreen</span>&gt; </span>{
  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> initState() {
    <span class="hljs-comment">// Initialize &amp; inject UserController() using Get.put()</span>
    Get.put&lt;UserController&gt;(UserController(), permanent: <span class="hljs-keyword">true</span>);
    <span class="hljs-keyword">super</span>.initState();
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">final</span> controller = UserController.call;
    <span class="hljs-keyword">final</span> userIdController = TextEditingController();

    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: Text(<span class="hljs-string">'User Details'</span>),
      ),
      body: Padding(
        padding: <span class="hljs-keyword">const</span> EdgeInsets.all(<span class="hljs-number">16.0</span>),
        child: Column(
          children: [
            TextField(
              controller: userIdController,
              decoration: InputDecoration(labelText: <span class="hljs-string">'Enter User ID'</span>),
              keyboardType: TextInputType.number,
            ),
            SizedBox(height: <span class="hljs-number">16.0</span>),
            ElevatedButton(
              onPressed: () {
                <span class="hljs-keyword">final</span> userId = <span class="hljs-built_in">int</span>.tryParse(userIdController.text);
                <span class="hljs-keyword">if</span> (userId != <span class="hljs-keyword">null</span>) {
                  controller.fetchUser(userId);
                } <span class="hljs-keyword">else</span> {
                  <span class="hljs-comment">// Handle invalid input</span>
                  Get.snackbar(<span class="hljs-string">'Invalid Input'</span>, <span class="hljs-string">'Please enter a valid User ID'</span>,
                      snackPosition: SnackPosition.BOTTOM);
                }
              },
              child: Text(<span class="hljs-string">'Fetch User'</span>),
            ),
            SizedBox(height: <span class="hljs-number">16.0</span>),
            Obx(() {
              <span class="hljs-keyword">if</span> (controller.isLoading.value) {
                <span class="hljs-keyword">return</span> CircularProgressIndicator();
              } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (controller.user.value.id == <span class="hljs-number">0</span>) {
                <span class="hljs-keyword">return</span> Text(<span class="hljs-string">'User details will appear here'</span>);
              } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(<span class="hljs-string">'User ID: <span class="hljs-subst">${controller.user.value.id}</span>'</span>),
                    Text(<span class="hljs-string">'Name: <span class="hljs-subst">${controller.user.value.name}</span>'</span>),
                    <span class="hljs-comment">// Add more user details as needed</span>
                  ],
                );
              }
            }),
          ],
        ),
      ),
    );
  }
}
</code></pre>
<hr />
<h2 id="heading-run">Run</h2>
<ol>
<li><p><strong>Install Dependencies</strong>: Ensure that you have all the required packages and dependencies installed. Run the following command:</p>
<pre><code class="lang-bash"> flutter pub get
</code></pre>
</li>
<li><p><strong>Generate Code</strong>: Since our app uses code generation tools like <code>freezed</code>, <code>json_serializable</code>, etc., it's important to generate necessary code files. Run the following command:</p>
<pre><code class="lang-bash"> flutter pub run build_runner build --delete-conflicting-outputs
</code></pre>
<p> This command generates code that's needed for serialization, deserialization, and more. The <code>--delete-conflicting-outputs</code> flag helps resolve any conflicts that may arise during code generation.</p>
</li>
<li><p><strong>Run the App</strong>: Finally, you can launch the app using the following command:</p>
<pre><code class="lang-bash"> flutter run
</code></pre>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! 🥳 You've just embarked on a thrilling journey of implementing clean architecture in Flutter using GetX. Clean architecture can be a bit challenging at first, but once you get the hang of it, it makes your code more maintainable and scalable.</p>
<p>So, go forth and create amazing Flutter apps with clean architecture. Happy coding! 🚀📱✨</p>
]]></content:encoded></item><item><title><![CDATA[Dart's Extension Methods: Demystified]]></title><description><![CDATA[Introduction
As a Flutter Developer, you must have used packages/libraries and wanted to add some additional functionality to them based on your use cases. But you cannot just add methods to that class as the original class is in someone else's libra...]]></description><link>https://blog.adityasharma.co/darts-extension-methods-demystified</link><guid isPermaLink="true">https://blog.adityasharma.co/darts-extension-methods-demystified</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[Mobile Development]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Sun, 19 Jun 2022 08:33:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1655627438428/aSqa2GT_L.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>As a Flutter Developer, you must have used packages/libraries and wanted to add some additional functionality to them based on your use cases. But you cannot just add methods to that class as the original class is in someone else's library.</p>
<p>A typical way of extending the functionality would be to create a Utility class providing static methods for your custom use cases:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StringUtil</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-built_in">bool</span> isValidEmail(<span class="hljs-built_in">String</span> email) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&amp;'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"</span>).hasMatch(email);
  }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">void</span> main() {
  <span class="hljs-built_in">print</span>(StringUtil.isValidEmail(<span class="hljs-string">'name@company.com'</span>));  <span class="hljs-comment">// Output: true</span>
}
</code></pre>
<p>This is perfectly fine, but it does not fit well with the Object-Oriented programming paradigms as we are used to performing an operation on the actual instance of an object like:</p>
<pre><code class="lang-dart"><span class="hljs-built_in">String</span> email = <span class="hljs-string">'name@company.com'</span>;
email.toLowerCase();
email.isEmpty;
</code></pre>
<p>We could also create a wrapper class with the original class inside it. But it seems wasteful to wrap an object with another object just because we want to extend the original class with some methods.</p>
<p>So, what can help us here?</p>
<p>Yes, you guessed right, <strong>Extensions</strong>!</p>
<hr />
<h2 id="heading-enable-extension-methods">Enable Extension Methods</h2>
<p>To enable extension methods, you need to go to your <strong>pubspec.yaml</strong> file and ensure the SDK version is set to 2.6.0 or greater:</p>
<pre><code class="lang-dart">environment:
  sdk: <span class="hljs-string">"&gt;=2.6.0 &lt;3.0.0"</span>
</code></pre>
<p>Make sure to run <code>flutter pub get</code> after updating the <strong>pubspec.yaml</strong>.</p>
<hr />
<h2 id="heading-implementing-extension-methods">Implementing Extension Methods</h2>
<p>Extensions can define not just methods, but also other members such as getters, setters, and operators. Also, extensions have names, which can be helpful if an API conflict arises. </p>
<p>You define an extension method by using the following syntax:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> &lt;<span class="hljs-keyword">extension</span> name&gt; <span class="hljs-keyword">on</span> &lt;type&gt; {
  (&lt;member definition&gt;)*
}
</code></pre>
<p>For example, here’s how you might implement an extension on the <code>String</code> class:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> NumParse <span class="hljs-keyword">on</span> <span class="hljs-built_in">String</span> {
  <span class="hljs-built_in">int</span> parseInt() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">int</span>.parse(<span class="hljs-keyword">this</span>);
  }

  <span class="hljs-built_in">double</span> parseDouble() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">double</span>.parse(<span class="hljs-keyword">this</span>);
  }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">void</span> main() {
  <span class="hljs-keyword">var</span> num1 = <span class="hljs-string">'50'</span>.parseInt();
  <span class="hljs-keyword">var</span> num2 = <span class="hljs-string">'101.01'</span>.parseDouble();

  <span class="hljs-built_in">print</span>(num1.runtimeType);  <span class="hljs-comment">// Output: int</span>
  <span class="hljs-built_in">print</span>(num2.runtimeType);  <span class="hljs-comment">// Output: double</span>
}
</code></pre>
<ul>
<li>To extend with getters, you can do something like:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> StringValidation <span class="hljs-keyword">on</span> <span class="hljs-built_in">String</span> {
  <span class="hljs-built_in">bool</span> <span class="hljs-keyword">get</span> isValidEmail {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&amp;'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"</span>).hasMatch(<span class="hljs-keyword">this</span>);
  }
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">void</span> main() {
     <span class="hljs-built_in">print</span>(<span class="hljs-string">'name@company.com'</span>.isValidEmail);  <span class="hljs-comment">// Output: true</span>
}
</code></pre>
<ul>
<li>To extend with operators:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> StringOps <span class="hljs-keyword">on</span> <span class="hljs-built_in">String</span> {
  <span class="hljs-built_in">String</span> <span class="hljs-keyword">operator</span> &amp;(<span class="hljs-built_in">String</span> prefix) =&gt; <span class="hljs-string">"<span class="hljs-subst">$prefix</span> <span class="hljs-subst">$this</span>"</span>;
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">void</span> main() {
     <span class="hljs-built_in">print</span>(<span class="hljs-string">'google.com'</span>&amp;<span class="hljs-string">'https://'</span>);  <span class="hljs-comment">// Output: https://google.com</span>
}
</code></pre>
<h3 id="heading-implementing-generic-extensions">Implementing Generic Extensions</h3>
<p>Extensions can have generic type parameters. For example, here’s some code that extends the built-in <code>List&lt;T&gt;</code> type with a getter, an operator, and a method:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> ListX&lt;T&gt; <span class="hljs-keyword">on</span> <span class="hljs-built_in">List</span>&lt;T&gt; {
  <span class="hljs-built_in">int</span> <span class="hljs-keyword">get</span> doubleLength =&gt; length * <span class="hljs-number">2</span>;
  <span class="hljs-built_in">List</span>&lt;T&gt; <span class="hljs-keyword">operator</span> -() =&gt; reversed.toList();
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">List</span>&lt;T&gt;&gt; split(<span class="hljs-built_in">int</span> at) =&gt; [sublist(<span class="hljs-number">0</span>, at), sublist(at)];
}
</code></pre>
<ul>
<li>You can also extend only lists of some type. For example, This Extension will only show up on lists of integers:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> PowerList&lt;<span class="hljs-built_in">int</span>&gt; <span class="hljs-keyword">on</span> <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">int</span>&gt; {
  <span class="hljs-built_in">int</span> <span class="hljs-keyword">get</span> sum =&gt; fold(<span class="hljs-number">0</span>, (a, b) =&gt; a + b);
}

<span class="hljs-comment">// Usage</span>
<span class="hljs-keyword">void</span> main() {
  <span class="hljs-built_in">print</span>([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>].sum());  <span class="hljs-comment">// Output: 6</span>
}
</code></pre>
<ul>
<li>You can also create an Extension that operates on any type <code>T</code> that extends <code>num</code>:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> IterableNumX&lt;T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">num</span>&gt; <span class="hljs-keyword">on</span> <span class="hljs-built_in">Iterable</span>&lt;T&gt; {
  T sum() {
    <span class="hljs-comment">// 1. initialize sum</span>
    <span class="hljs-keyword">var</span> sum = (T == <span class="hljs-built_in">int</span> ? <span class="hljs-number">0</span> : <span class="hljs-number">0.0</span>) <span class="hljs-keyword">as</span> T;
    <span class="hljs-comment">// 2. calculate sum</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> current <span class="hljs-keyword">in</span> <span class="hljs-keyword">this</span>) {
      <span class="hljs-keyword">if</span> (current != <span class="hljs-keyword">null</span>) { <span class="hljs-comment">// only add non-null values</span>
        sum += current;
      }
    }
    <span class="hljs-keyword">return</span> sum;
  }
}
</code></pre>
<blockquote>
<p>Credit: I borrowed this example from <a target="_blank" href="https://codewithandrea.com/videos/dart-extensions-full-introduction/">this blog post</a>.</p>
</blockquote>
<hr />
<h2 id="heading-how-to-use-extension-methods">How To Use Extension Methods</h2>
<p>Like all Dart code, you usually put extension methods in their independent dart files which can be imported as libraries. To use extension methods in your code, just import the library it’s in, and use it like an ordinary method:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// Import a library that contains an extension on String.</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'string_ext.dart'</span>;
<span class="hljs-comment">// ···</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">'50'</span>.padLeft(<span class="hljs-number">5</span>));  <span class="hljs-comment">// String method</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">'50'</span>.parseInt());  <span class="hljs-comment">// Extension method</span>
</code></pre>
<h3 id="heading-using-with-static-and-dynamic-types">Using With Static and Dynamic types</h3>
<p>You can’t invoke extension methods on variables of type <code>dynamic</code>. For example, the following code results in a runtime exception:</p>
<pre><code class="lang-dart"><span class="hljs-built_in">dynamic</span> <span class="hljs-built_in">num</span> = <span class="hljs-string">'50'</span>;
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">num</span>.parseInt());  <span class="hljs-comment">// Throws Runtime exception: NoSuchMethodError</span>
</code></pre>
<p>On the other hand, extension methods do work with Dart’s type inference. The following code is fine because the variable <code>num</code> is inferred to have type <code>String</code>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">var</span> <span class="hljs-built_in">num</span> = <span class="hljs-string">'50'</span>;
<span class="hljs-built_in">print</span>(<span class="hljs-built_in">num</span>.parseInt());  <span class="hljs-comment">// Output: 50</span>
</code></pre>
<blockquote>
<p>The reason why <code>dynamic</code> doesn’t work is that extension methods are resolved against the static type of the receiver. Because extension methods are resolved statically, they’re as fast as calling a static function.</p>
</blockquote>
<h3 id="heading-resolving-api-conflicts">Resolving API Conflicts</h3>
<p>There are chances that extension methods with the same name are created in different Dart files and you may face API conflicts. For example:</p>
<pre><code class="lang-dart"><span class="hljs-comment">// File: string_validation.dart</span>
<span class="hljs-keyword">extension</span> StringValidation <span class="hljs-keyword">on</span> <span class="hljs-built_in">String</span> {
  <span class="hljs-built_in">bool</span> <span class="hljs-keyword">get</span> isValidEmail {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&amp;'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"</span>).hasMatch(<span class="hljs-keyword">this</span>);
  }
}
--------------------------------------------------------
<span class="hljs-comment">// File: string_ext.dart</span>
<span class="hljs-keyword">extension</span> StringX <span class="hljs-keyword">on</span> <span class="hljs-built_in">String</span> {
  <span class="hljs-built_in">bool</span> <span class="hljs-keyword">get</span> isValidEmail {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&amp;'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+"</span>).hasMatch(<span class="hljs-keyword">this</span>);
  }
}
-------------------------------------------------------
main() {
  <span class="hljs-built_in">print</span>(<span class="hljs-string">'name@company.com'</span>.isValidName);
}
</code></pre>
<p>This will produce a compile-time error and your code will not run.</p>
<p>To resolve this conflict, we have 2 different methods:</p>
<ul>
<li>Use <code>show</code> or <code>hide</code> to limit the exposed API:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// Defines the String extension method isValidEmail().</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'string_validation.dart'</span>;

<span class="hljs-comment">// Also defines isValidEmail(), but hiding StringX</span>
<span class="hljs-comment">// hides that extension method.</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'string_ext.dart'</span> <span class="hljs-keyword">hide</span> StringX;

<span class="hljs-comment">// ···</span>
<span class="hljs-comment">// Uses the isValidEmail() defined in 'string_validation.dart'.</span>
<span class="hljs-built_in">print</span>(<span class="hljs-string">'name@company.com'</span>.isValidName);
</code></pre>
<ul>
<li>Apply the extension explicitly:</li>
</ul>
<pre><code class="lang-dart"><span class="hljs-comment">// Both libraries define extensions on String that contain isValidEmail(),</span>
<span class="hljs-comment">// and the extensions have different names.</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'string_validation.dart'</span>;  <span class="hljs-comment">// Contains StringValidation extension</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'string_ext.dart'</span>;  <span class="hljs-comment">// Contains StringX extension</span>

<span class="hljs-comment">// ···</span>
<span class="hljs-comment">// print('name@company.com'.isEmailValid);  // Doesn't work.</span>
<span class="hljs-built_in">print</span>(StringValidation(<span class="hljs-string">'name@company.com'</span>).isValidEmail);
<span class="hljs-built_in">print</span>(StringX(<span class="hljs-string">'name@company.com'</span>).isValidEmail);
</code></pre>
<hr />
<h2 id="heading-flutter-advantage">Flutter Advantage</h2>
<p>You might be wondering if we can create extension methods on any class, then Flutter Widgets should also support it as they're also classes.</p>
<p>Well, you guessed right.</p>
<p>We can create extensions on existing Flutter Widgets, and reduce boilerplate code for common layout tasks. Suppose you want different alignment of children in the column. Normally you would do something like this:</p>
<pre><code class="lang-dart">Column(
  children: &lt;Widget&gt;[
    Align(
      alignment: AlignmentDirectional.centerStart,
      child: SomeWidget(),
    ),
    Align(
      alignment: AlignmentDirectional.centerEnd,
      child: SomeAnotherWidget(),
    ),
  ],
)
</code></pre>
<p>This can be made more elegant using extensions like this:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">extension</span> AlignUtil <span class="hljs-keyword">on</span> Widget {
  alignAtStart() {
    <span class="hljs-keyword">return</span> Align(
      alignment: AlignmentDirectional.centerStart,
      child: <span class="hljs-keyword">this</span>,
    );
  }

  alignAtEnd() {
    <span class="hljs-keyword">return</span> Align(
      alignment: AlignmentDirectional.centerEnd,
      child: <span class="hljs-keyword">this</span>,
    );
  }
}
------------------------------------------------------------
Column(
  children: &lt;Widget&gt;[
    SomeWidget().alignAtStart(),
    SomeAnotherWidget().alignAtEnd()
  ],
)
</code></pre>
<blockquote>
<p>Credit: I borrowed this example from <a target="_blank" href="https://medium.com/aubergine-solutions/easily-understand-darts-extension-methods-for-flutter-2b3d3d3c698f">this blog post</a>.</p>
</blockquote>
<hr />
<h2 id="heading-more-to-explore">More to Explore</h2>
<p>Do check out these popular packages that provide useful extensions:</p>
<ul>
<li><strong>Dartx</strong> is a package which adds a lot of useful extension methods to types in the Dart Language.<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://pub.dev/packages/dartx">https://pub.dev/packages/dartx</a></div>
</li>
<li><strong>Styled Widgets</strong> is another package that started as an experiment, showing how widget styling APIs could be improved, using a syntax that is similar to the SwiftUI framework by Apple. <div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://pub.dev/packages/styled_widget">https://pub.dev/packages/styled_widget</a></div>
</li>
<li><strong>Time</strong> is yet another package which adds extensions to the Flutter's DateTime library.<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://pub.dev/packages/time">https://pub.dev/packages/time</a></div>
</li>
</ul>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Extensions are a great way to add functionality to existing classes &amp; libraries. It can also help in reducing boilerplate code to a great extent. But Just because we can use extensions, it doesn't mean that we should use them <strong>everywhere</strong>. </p>
<blockquote>
<p>Remember: with power comes great responsibilities.</p>
</blockquote>
<hr />
<h2 id="heading-references">References</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://dart.dev/guides/language/extension-methods#api-conflicts">https://dart.dev/guides/language/extension-methods#api-conflicts</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://medium.com/aubergine-solutions/easily-understand-darts-extension-methods-for-flutter-2b3d3d3c698f">https://medium.com/aubergine-solutions/easily-understand-darts-extension-methods-for-flutter-2b3d3d3c698f</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codewithandrea.com/videos/dart-extensions-full-introduction/">https://codewithandrea.com/videos/dart-extensions-full-introduction/</a></div>
<hr />
<p>That's all folks! Do let me know what you liked and what can be improved in the comments below! Also, feel free to drop me a line if you don't understand something. ✌</p>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[Understanding null safety in Dart]]></title><description><![CDATA[Ever wondered what is all this fuss about null safety? In this article, I'll provide a brief introduction to null safety in Dart and share code examples for a better understanding.

Introduction
Null safety helps you solve one of the most common erro...]]></description><link>https://blog.adityasharma.co/understanding-null-safety-in-dart</link><guid isPermaLink="true">https://blog.adityasharma.co/understanding-null-safety-in-dart</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Dart]]></category><category><![CDATA[programming languages]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Sun, 21 Nov 2021 18:28:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1637519276921/zaivNo6Dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever wondered what is all this fuss about null safety? In this article, I'll provide a brief introduction to null safety in Dart and share code examples for a better understanding.</p>
<hr />
<h2 id="heading-introduction">Introduction</h2>
<p>Null safety helps you solve one of the most common errors in software development: <strong>NullPointerException</strong>.   </p>
<p>The main issue with the <code>NullPointerException</code> is that it can happen in almost any part of the app if not well handled. Checking for nulls every now and then throughout your app isn’t the best solution either. As your app grows, it can become even harder to handle the null values. For these reasons and more, handling nulls at the language level is probably the best way to avoid the infamous <code>NullPointerEception</code>.  </p>
<p>To build on this idea, the Dart team introduced <strong>sound null safety</strong>. This means that variables are considered non-nullable by default. If you don’t give an object null support when you create it, it will never store a <code>null</code>. As a result, you avoid null reference errors in your code.</p>
<hr />
<h2 id="heading-activate-null-safety">Activate Null Safety</h2>
<p>To activate null safety, you need to go to your <strong>pubspec.yaml</strong> file and ensure the SDK version is set to:</p>
<pre><code><span class="hljs-attribute">environment</span>:
  <span class="hljs-attribute">sdk</span>: <span class="hljs-string">"&gt;=2.12.0 &lt;3.0.0"</span>
</code></pre><p>Make sure to run <code>flutter pub get</code> after updating the <strong>pubspec.yaml</strong>.</p>
<hr />
<h2 id="heading-the-dart-type-system">The Dart Type System</h2>
<p>Before we move on to creating null safe apps, let's discuss the type system implemented by Dart.<br />Dart divides types into two groups:</p>
<ul>
<li>Nullable types - can contain either a value or null</li>
<li>Non-Nullable types - can only contain values. Nulls are not permitted</li>
</ul>
<p>Let's have a look at these types in the next section.</p>
<hr />
<h2 id="heading-understanding-sound-null-safety">Understanding Sound Null Safety</h2>
<p>Now that we have null-safety activated, all our types are by default <strong>non-nullable</strong>, which means they all require some value.</p>
<pre><code><span class="hljs-keyword">String</span> name = <span class="hljs-string">'Aditya Sharma'</span>;   <span class="hljs-comment">// This works ✔</span>
<span class="hljs-keyword">String</span> name = <span class="hljs-literal">null</span>;   <span class="hljs-comment">// Will throw error ❌</span>
</code></pre><p>Adding a <code>?</code> makes the Type nullable and allows us to pass a null value to our <code>name</code> field.</p>
<pre><code><span class="hljs-keyword">String</span>? name = <span class="hljs-string">'Aditya Sharma'</span>;   <span class="hljs-comment">// This works ✔</span>
<span class="hljs-keyword">String</span>? name = <span class="hljs-literal">null</span>;   <span class="hljs-comment">// This works too ✔</span>
</code></pre><p>Let's now have a look at some real-world scenarios:</p>
<h3 id="heading-1-null-checks">1. Null Checks</h3>
<p>Null check is a Dart feature that helps you to avoid null related errors.</p>
<p>Let's take an example:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> setName(<span class="hljs-built_in">String</span> name) {  
  name.toUpperCase();
  <span class="hljs-built_in">print</span>(name);
}

<span class="hljs-keyword">void</span> main() {
  setName(<span class="hljs-keyword">null</span>);   <span class="hljs-comment">// Throws error ❌</span>
}
</code></pre>
<p>In this case, type String is not nullable and thus we cannot store a null inside it.</p>
<p>If we want to pass a null value to <code>setName()</code>, we change the parameter type to <code>String?</code>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> setName(<span class="hljs-built_in">String?</span> name) {
  name.toUpperCase();   <span class="hljs-comment">// Warning here ❌</span>
  <span class="hljs-built_in">print</span>(name);
}

<span class="hljs-keyword">void</span> main() {
  setName(<span class="hljs-keyword">null</span>);
}
</code></pre>
<p>Now, the compiler warns us that we cannot call the <code>upperCase()</code> on <code>name</code> as it can also store a null value.<br />We have 2 ways to fix it:</p>
<ol>
<li><p>The null aware accessor <code>?.</code>:  </p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> setName(<span class="hljs-built_in">String?</span> name) {
  name?.toUpperCase();
  <span class="hljs-built_in">print</span>(name);
}
<span class="hljs-comment">//</span>
<span class="hljs-keyword">void</span> main() {
  setName(<span class="hljs-keyword">null</span>);
}
</code></pre>
</li>
<li><p>Check for null before calling any method on <code>name</code>:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> setName(<span class="hljs-built_in">String?</span> name) {
  <span class="hljs-keyword">if</span> (name == <span class="hljs-keyword">null</span>) <span class="hljs-keyword">return</span>;
  name.toUpperCase();
  <span class="hljs-built_in">print</span>(name);
}
<span class="hljs-comment">//</span>
<span class="hljs-keyword">void</span> main() {
  setName(<span class="hljs-keyword">null</span>);
}
</code></pre>
</li>
</ol>
<h3 id="heading-2-non-nullable-type-to-nullable-type-conversion">2. Non-nullable Type to Nullable Type Conversion</h3>
<p>When converting from <code>Type</code> to <code>Type?</code>, there is no problem as <code>Type?</code> accepts both real value and null value.</p>
<pre><code><span class="hljs-keyword">void</span> main() {
  <span class="hljs-keyword">String</span> name = <span class="hljs-string">'Aditya'</span>;
  <span class="hljs-keyword">String</span>? newName = name;   <span class="hljs-comment">// Works fine ✔</span>
}
</code></pre><h3 id="heading-3-nullable-type-to-non-nullable-type-conversion">3. Nullable Type to Non-nullable Type Conversion</h3>
<p>When converting from <code>Type?</code> to <code>Type</code>, the compiler gives us a warning.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">void</span> main() {
  <span class="hljs-built_in">String?</span> name = <span class="hljs-keyword">null</span>;
  <span class="hljs-built_in">String</span> newName = name;   <span class="hljs-comment">// Warning ❌</span>
}
</code></pre>
<p>We have 3 ways to fix it:</p>
<ol>
<li><p>Check for null before conversion:</p>
<pre><code><span class="hljs-type">void</span> main() {
  String? <span class="hljs-type">name</span> = <span class="hljs-keyword">null</span>;

  <span class="hljs-keyword">if</span> (<span class="hljs-type">name</span> != <span class="hljs-keyword">null</span>) {
    String newName = <span class="hljs-type">name</span>;  
  }
}
</code></pre></li>
<li><p>Using the if-null <code>??</code> operator for providing a default value:</p>
<pre><code><span class="hljs-type">void</span> main() {
  String? <span class="hljs-type">name</span> = <span class="hljs-keyword">null</span>;
  String newName = <span class="hljs-type">name</span> ?? <span class="hljs-string">'Aditya'</span>;  
}
</code></pre></li>
<li><p>Using the Bang operator <code>!</code> (also called the null assertion operator):</p>
<pre><code><span class="hljs-type">void</span> main() {
  String? <span class="hljs-type">name</span> = <span class="hljs-keyword">null</span>;
  String newName = <span class="hljs-type">name</span>!;  
}
</code></pre><blockquote>
<p>PS: If you’re sure that an expression with a nullable type isn’t null, you can use a null assertion operator <code>!</code> to make Dart treat it as non-nullable. By adding <code>!</code> just after the expression, you tell Dart that the value won’t be <code>null</code>, and that it’s safe to assign it to a non-nullable variable.<br />⚠️: If you’re wrong, Dart throws an exception at run-time. This makes the <code>!</code> operator unsafe, so don’t use it unless you’re very sure that the expression isn’t null.</p>
</blockquote>
</li>
</ol>
<h3 id="heading-4-late-init">4. Late Init</h3>
<p>Sometimes, you can’t initialize properties in the constructor, but you’ll define them in other methods of your class. In that case, you mark those properties with <code>late</code>.</p>
<p>Another advantage of late is lazy initialization. Dart will not initialize late properties until they’re used for the first time. This can be useful during app initialization when an expression is costly or might not be needed.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">late</span> <span class="hljs-built_in">String</span> name;

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">void</span> initState() {
  <span class="hljs-keyword">super</span>.initState();

  name = <span class="hljs-string">'Aditya Sharma'</span>;
}
</code></pre>
<hr />
<h2 id="heading-sound-null-safety-in-a-nutshell">Sound Null Safety In a Nutshell</h2>
<p>Dart has three main operators to work with null:</p>
<ul>
<li>Null-aware operators: The null aware accessor <code>?.</code>, which accesses properties of its operand, is an example. If the operand is <code>null</code>, then it will <strong>not throw an exception</strong>. Instead, it shows null text.</li>
<li>Bang operator: Use <code>!</code> to cast away nullability. It tries to cast a nullable type to a non-nullable type, <strong>throwing an exception</strong> if the operand is <code>null</code>.</li>
<li>If-null operator: <code>??</code> is shorthand for an if-else condition. If the left side of the <code>??</code> operator is null, then it will use its right side.</li>
<li>Late init: Use <code>late</code> on variables when you’re sure you’ll initialize them before using them. Use <code>late</code> with class properties.</li>
</ul>
<hr />
<h2 id="heading-references">References</h2>
<ul>
<li><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.raywenderlich.com/21955673-non-nullable-dart-understanding-null-safety#toc-anchor-018">https://www.raywenderlich.com/21955673-non-nullable-dart-understanding-null-safety#toc-anchor-018</a></div>
</li>
<li><div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=PnSpQkOKwv0&amp;t=52s">https://www.youtube.com/watch?v=PnSpQkOKwv0&amp;t=52s</a></div>
</li>
</ul>
<hr />
<p>That's all folks! Do let me know what you liked and what can be improved in the comments below! Also, feel free to drop me a line if you don't understand something. ✌</p>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[Next-Gen JavaScript - Level Up]]></title><description><![CDATA[In this article, I'll provide a brief introduction to some core next-gen JavaScript concepts, of course focusing on the ones you'll use the most in your coding joruney. And I'll also include handy code snippets for better understanding just like fore...]]></description><link>https://blog.adityasharma.co/next-gen-javascript-level-up</link><guid isPermaLink="true">https://blog.adityasharma.co/next-gen-javascript-level-up</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[ES6]]></category><category><![CDATA[es7]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[DEVCommunity]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Wed, 01 Sep 2021 16:47:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1630517034947/WxJYYBvTB.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, I'll provide a brief introduction to some core next-gen JavaScript concepts, of course focusing on the ones you'll use the most in your coding joruney. And I'll also include handy code snippets for better understanding just like forever!</p>
<hr />
<h2 id="contents">Contents</h2>
<ul>
<li><a class="post-section-overview" href="#let-and-const">let &amp; const</a></li>
<li><a class="post-section-overview" href="#es6-arrow-functions">ES6 Arrow Functions</a>  </li>
<li><a class="post-section-overview" href="#exports-and-imports">Exports &amp; Imports</a></li>
<li><a class="post-section-overview" href="#classes">Classes</a></li>
<li><a class="post-section-overview" href="#spread-and-rest-operator">Spread &amp; Rest Operator</a></li>
<li><a class="post-section-overview" href="#destructuring">Destructuring</a></li>
</ul>
<hr />
<h2 id="let-and-const">let &amp; const</h2>
<p><code>let</code> and <code>const</code> basically replace <code>var</code>. <code>let</code> is very similar to <code>var</code> with the difference that the <code>let</code> variable has a block-level scope (i.e. the enclosing <code>{ }</code> just like variables in other languages). On the other hand, the scope of a <code>var</code> variable is the entire enclosing function.</p>
<p>Let's have a look at an example:</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">varDemo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> x = <span class="hljs-number">1</span>;
  {
    <span class="hljs-keyword">var</span> x = <span class="hljs-number">2</span>;  <span class="hljs-comment">// same variable!</span>
    <span class="hljs-built_in">console</span>.log(x);  <span class="hljs-comment">// 2</span>
  }
  <span class="hljs-built_in">console</span>.log(x);  <span class="hljs-comment">// 2</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">letDemo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> x = <span class="hljs-number">1</span>;
  {
    <span class="hljs-keyword">let</span> x = <span class="hljs-number">2</span>;  <span class="hljs-comment">// different variable</span>
    <span class="hljs-built_in">console</span>.log(x);  <span class="hljs-comment">// 2</span>
  }
  <span class="hljs-built_in">console</span>.log(x);  <span class="hljs-comment">// 1</span>
}
</code></pre><p>Use <code>const</code> instead of <code>var</code> if you plan on never re-assigning this "variable". It's a good practice to assign arrays and objects as a <code>const</code>.</p>
<pre><code><span class="hljs-keyword">const</span> <span class="hljs-built_in">number</span> = <span class="hljs-number">2</span>;

<span class="hljs-keyword">try</span> {
  <span class="hljs-built_in">number</span> = <span class="hljs-number">99</span>;
} <span class="hljs-keyword">catch</span> (err) {
  <span class="hljs-built_in">console</span>.log(err);
  <span class="hljs-comment">// expected output: TypeError: invalid assignment to const `number'</span>
}

<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">number</span>);
<span class="hljs-comment">// expected output: 2</span>
</code></pre><p>Read more about <code>let</code> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let">here</a>.<br />Read more about <code>const</code> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const">here</a>.</p>
<hr />
<h2 id="es6-arrow-functions">ES6 Arrow Functions</h2>
<p>Arrow functions are an alternate way of creating functions in JavaScript. Besides a shorter syntax, they offer advantages when it comes to keeping the scope of the <code>this</code> keyword.</p>
<pre><code class="lang-JavaScript"><span class="hljs-comment">// Traditional Function</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">callMe</span>(<span class="hljs-params">a</span>) </span>{
  <span class="hljs-built_in">console</span>.log(a);
}

<span class="hljs-comment">// Arrow Function Break Down</span>

<span class="hljs-comment">// 1. The above function can be written as:</span>
<span class="hljs-keyword">const</span> callMe = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">a</span>) </span>{
  <span class="hljs-built_in">console</span>.log(a);
}

<span class="hljs-comment">// 2. Remove the word "function" and place arrow between the argument </span>
<span class="hljs-comment">// and opening body bracket</span>
<span class="hljs-keyword">const</span> callMe = <span class="hljs-function">(<span class="hljs-params">a</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(a);
}
</code></pre>
<h3 id="important">Important:</h3>
<ul>
<li><p>When having no arguments, you have to use empty parentheses in the function declaration:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> callMe = <span class="hljs-function">() =&gt;</span> { 
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Something!'</span>);
}
</code></pre>
</li>
<li><p>When having exactly one argument, you may omit the parentheses:</p>
<pre><code><span class="hljs-keyword">const</span> callMe = <span class="hljs-function"><span class="hljs-params">name</span> =&gt;</span> { 
  <span class="hljs-built_in">console</span>.log(name);
}
</code></pre></li>
<li><p>When just returning a value, you can use the following shortcut:  </p>
<pre><code><span class="hljs-keyword">const</span> returnMe = <span class="hljs-function"><span class="hljs-params">name</span> =&gt;</span> name;
<span class="hljs-comment">// That's equal to:</span>
<span class="hljs-keyword">const</span> returnMe = <span class="hljs-function"><span class="hljs-params">name</span> =&gt;</span> { 
  <span class="hljs-keyword">return</span> name;
}
</code></pre></li>
</ul>
<p>Read more about ES6 Arrow functions <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">here</a>.</p>
<hr />
<h2 id="exports-and-imports">Exports &amp; Imports</h2>
<p>In all modern JavaScript projects, you split your code across multiple JavaScript files - so-called modules. You do this to manage your large code base and make it understandable.</p>
<p>To access functionality in another file, you need <code>export</code> (to make it available) and <code>import</code> (to get access) statements.</p>
<h3 id="export">export</h3>
<p>You got two different types of exports: <strong>default</strong> (unnamed) and <strong>named</strong> exports:</p>
<ul>
<li><p><strong>default</strong> export</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> user = {
<span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
<span class="hljs-attr">name</span>: <span class="hljs-string">'SomeName'</span>
}
<span class="hljs-comment">// Export user</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> user
</code></pre>
</li>
<li><p><strong>named</strong> export</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// export individual features (can export var, let,</span>
<span class="hljs-comment">// const, function, class)</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> initialize = <span class="hljs-function">() =&gt;</span> { ... }
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> BASE_URL = <span class="hljs-string">'https://xyz... '</span>
<span class="hljs-comment">// Or export features declared earlier like this:</span>
<span class="hljs-keyword">export</span> { initialize, BASE_URL };
</code></pre>
</li>
</ul>
<h4 id="important">Important</h4>
<p>A file can only contain one default and an unlimited amount of named exports. You can also mix the one default with any amount of named exports in one and the same file.</p>
<h3 id="import">import</h3>
<ul>
<li><p>You can import <strong>default exports</strong> like this:</p>
<pre><code><span class="hljs-keyword">import</span> someNameOfYourChoice <span class="hljs-keyword">from</span> <span class="hljs-string">'./path/to/file.js'</span>;
</code></pre><p>Surprisingly, <code>someNameOfYourChoice</code> is totally up to you.</p>
</li>
<li><p><strong>Named exports</strong> have to be imported by their name:</p>
<pre><code><span class="hljs-keyword">import</span> { someData } <span class="hljs-keyword">from</span> <span class="hljs-string">'./path/to/file.js'</span>;
</code></pre><p>When importing <strong>named exports</strong>, you can also import all named exports at once with the following syntax:</p>
<pre><code><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> upToYou <span class="hljs-keyword">from</span> <span class="hljs-string">'./path/to/file.js'</span>;
</code></pre><p><code>upToYou</code> is, well, up to you and simply bundles all exported variables/functions in one JavaScript object.<br />For example, if you <code>export const someData = ...</code>, you can access it on <code>upToYou</code> like this: <code>upToYou.someData</code></p>
</li>
</ul>
<p>Read more about <code>export</code> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export">here</a>.<br />Read more about <code>import</code> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">here</a>.</p>
<hr />
<h2 id="classes">Classes</h2>
<p>Classes are a feature that basically replaces constructor functions and prototypes. You can define blueprints for JavaScript objects with them just like other OOP languages.</p>
<p>Like this:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-keyword">constructor</span> () {
        <span class="hljs-built_in">this</span>.name = <span class="hljs-string">'SomeName'</span>;
    }
}

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> User();
<span class="hljs-built_in">console</span>.log(user.name); <span class="hljs-comment">// prints 'SomeName'</span>
</code></pre>
<p>The syntax you see above is the "old" syntax for defining properties. In modern JavaScript projects, you can use the following, more convenient way of defining class properties:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    name = <span class="hljs-string">'SomeName'</span>;
}

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> User();
<span class="hljs-built_in">console</span>.log(user.name); <span class="hljs-comment">// prints 'SomeName'</span>
</code></pre>
<p>You can also define methods. Either like this:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    name = <span class="hljs-string">'SomeName'</span>;
    printName () {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name); <span class="hljs-comment">// this is required to refer to the class!</span>
    }
}

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> User();
user.printName(); <span class="hljs-comment">// prints 'SomeName'</span>
</code></pre>
<p>Or like this:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    name = <span class="hljs-string">'SomeName'</span>;
    printName = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name);
    }
}

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> User();
user.printName(); <span class="hljs-comment">// prints SomeName</span>
</code></pre>
<p>The second approach has the same advantage as all arrow functions have: The <code>this</code> keyword doesn't change its reference.</p>
<p>You can also use inheritance when using classes:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Human</span> </span>{
    gender = <span class="hljs-string">'male'</span>;
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Human</span> </span>{
    name = <span class="hljs-string">'SomeName'</span>;
    printName = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.name);
    }
}

<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">new</span> User();
user.printName(); <span class="hljs-comment">// prints 'SomeName'</span>
<span class="hljs-built_in">console</span>.log(user.gender); <span class="hljs-comment">// prints 'male'</span>
</code></pre>
<p>Read more about <code>class</code> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes">here</a>.</p>
<hr />
<h2 id="spread-and-rest-operator">Spread &amp; Rest Operator</h2>
<p>The <strong>spread</strong> and <strong>rest</strong> operators actually use the same syntax: <code>...</code>
Yes, it's just three dots! Its usage determines whether you're using it as the spread or rest operator.</p>
<h3 id="spread-operator">Spread Operator</h3>
<p>The spread operator allows you to pull elements out of an array (split the array into a list of its elements) or pull the properties out of an object. </p>
<p>Here are two examples:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// spread operator used on array</span>
<span class="hljs-keyword">const</span> oldArray = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
<span class="hljs-keyword">const</span> newArray = [...oldArray, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]; <span class="hljs-comment">// This now is [1, 2, 3, 4, 5];</span>

<span class="hljs-comment">// spread operator used on an object</span>
<span class="hljs-keyword">const</span> oldObject = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'SomeName'</span>
};
<span class="hljs-keyword">const</span> newObject = {
    ...oldObject,
    <span class="hljs-attr">age</span>: <span class="hljs-number">23</span>
};

<span class="hljs-comment">// newObject  would then be</span>
{
    <span class="hljs-attr">name</span>: <span class="hljs-string">'SomeName'</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">23</span>
}
</code></pre>
<h4 id="note">Note</h4>
<p>The spread operator is extremely useful for cloning arrays and objects. Since both are reference types (and not primitives), copying them safely can be tricky. With the spread operator, you have an easy way of creating a clone of the object or array. </p>
<h3 id="rest-operator">Rest Operator</h3>
<p>The rest operator allows a function to accept an indefinite number of arguments as an array.</p>
<p>Here's how you use it:</p>
<pre><code><span class="hljs-keyword">const</span> filter = <span class="hljs-function">(<span class="hljs-params">...args</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> args.filter(<span class="hljs-function"><span class="hljs-params">el</span> =&gt;</span> el === <span class="hljs-number">1</span>)
}

<span class="hljs-built_in">console</span>.log(filter(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>)) <span class="hljs-comment">// prints [1]</span>
</code></pre><p>Read more about spread operator <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">here</a>.<br />Read more about rest operator <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">here</a>.</p>
<hr />
<h2 id="destructuring">Destructuring</h2>
<p>Destructuring allows you to easily access the elements of arrays or objects and assign them to variables.</p>
<p>Here's an example for destructuring an array:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> array = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
<span class="hljs-keyword">const</span> [a, b] = array;
<span class="hljs-built_in">console</span>.log(a); <span class="hljs-comment">// prints 1</span>
<span class="hljs-built_in">console</span>.log(b); <span class="hljs-comment">// prints 2</span>
<span class="hljs-built_in">console</span>.log(array); <span class="hljs-comment">// prints [1, 2, 3]</span>
</code></pre>
<p>And here for destructuring an object:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> user = {
    <span class="hljs-attr">name</span>: <span class="hljs-string">'SomeName'</span>,
    <span class="hljs-attr">age</span>: <span class="hljs-number">23</span>
}
<span class="hljs-keyword">const</span> {name} = user;
<span class="hljs-built_in">console</span>.log(name); <span class="hljs-comment">// prints 'SomeName'</span>
<span class="hljs-built_in">console</span>.log(age); <span class="hljs-comment">// prints undefined</span>
<span class="hljs-built_in">console</span>.log(user); <span class="hljs-comment">// prints {name: 'SomeName', age: 23}</span>
</code></pre>
<p>Destructuring is very useful when working with function arguments. Consider this example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> printName = <span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(user.name);
}
printName({<span class="hljs-attr">name</span>: <span class="hljs-string">'SomeName'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">23</span>}); <span class="hljs-comment">// prints 'SomeName'</span>
</code></pre>
<p>The above code forces us to call <code>user.name</code> inside of our function. We can condense this code with destructuring:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> printName = <span class="hljs-function">(<span class="hljs-params">{name}</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(name);
}
printName({<span class="hljs-attr">name</span>: <span class="hljs-string">'SomeName'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">23</span>}); <span class="hljs-comment">// prints 'SomeName'</span>
</code></pre>
<p>We get the same result as above but we save some code. By destructuring, we simply pull out the <code>name</code> property and store it in a variable/argument named <code>name</code> which we can then use in the function body.</p>
<p>Read more about Destructuring <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">here</a>.</p>
<hr />
<p>That's all folks! Do let me know what you liked and what can be improved in the comments below! Also, feel free to drop me a line if you don't understand something. ✌</p>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[The Ultimate Flutter Layout Guide]]></title><description><![CDATA[Have you ever been stuck on any of these errors while building a Flutter app?
> A RenderFlex overflowed…
> RenderBox was not laid out
> Viewport was given unbounded height
> An InputDecorator…cannot have an unbounded width
> Incorrect use of ParentDa...]]></description><link>https://blog.adityasharma.co/the-ultimate-flutter-layout-guide</link><guid isPermaLink="true">https://blog.adityasharma.co/the-ultimate-flutter-layout-guide</guid><category><![CDATA[Flutter]]></category><category><![CDATA[Flutter Examples]]></category><category><![CDATA[app development]]></category><category><![CDATA[Flutter Widgets]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Mon, 16 Aug 2021 18:16:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1629134143638/0aELDCcuz.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever been stuck on any of these errors while building a Flutter app?</p>
<pre><code><span class="hljs-quote">&gt; A RenderFlex overflowed…</span>
<span class="hljs-quote">&gt; RenderBox was not laid out</span>
<span class="hljs-quote">&gt; Viewport was given unbounded height</span>
<span class="hljs-quote">&gt; An InputDecorator…cannot have an unbounded width</span>
<span class="hljs-quote">&gt; Incorrect use of ParentData widget</span>
</code></pre><p>If yes, then this blog post is for <strong>you</strong>!</p>
<p>In this blog post, I'll discuss and share some common Flutter layout scenarios and best practices. I'll try to focus more on code snippets and less on widget details. For widget details, I'll share the relevant link for the same.</p>
<hr />
<h2 id="contents">Contents</h2>
<ul>
<li><a class="post-section-overview" href="#prerequisites">Prerequisites</a></li>
<li>Single-child layout widgets  <ul>
<li><a class="post-section-overview" href="#align">Align</a></li>
<li><a class="post-section-overview" href="#aspectratio">AspectRatio</a></li>
<li><a class="post-section-overview" href="#center">Center</a></li>
<li><a class="post-section-overview" href="#constrainedBox">ConstrainedBox</a></li>
<li><a class="post-section-overview" href="#container">Container</a></li>
<li><a class="post-section-overview" href="#expanded">Expanded</a></li>
<li><a class="post-section-overview" href="#fittedbox">FittedBox</a></li>
<li><a class="post-section-overview" href="#fractionallysizedbox">FractionallySizedBox</a></li>
<li><a class="post-section-overview" href="#sizedbox">SizedBox</a></li>
</ul>
</li>
<li>Multi-child layout widgets<ul>
<li><a class="post-section-overview" href="#row-and-column">Row and Column</a></li>
<li><a class="post-section-overview" href="#stack">Stack</a></li>
<li><a class="post-section-overview" href="#layoutbuilder">LayoutBuilder</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#references">References</a></li>
</ul>
<hr />
<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>Basic knowledge of Flutter widgets</li>
<li>Desire to learn something new</li>
</ul>
<hr />
<h2 id="single-child-layout-widgets">Single-child layout widgets</h2>
<h3 id="align">Align</h3>
<p>A widget that aligns its <code>child</code> within itself and optionally sizes itself based on the <code>child</code>'s size.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625632361409/Zq9bGq8xA.png" alt="image.png" /></p>
<pre><code><span class="hljs-string">Center(</span>
  <span class="hljs-attr">child:</span> <span class="hljs-string">Container(</span>
    <span class="hljs-attr">height:</span> <span class="hljs-number">120.0</span><span class="hljs-string">,</span>
    <span class="hljs-attr">width:</span> <span class="hljs-number">120.0</span><span class="hljs-string">,</span>
    <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.blue[50],</span>
    <span class="hljs-attr">child:</span> <span class="hljs-string">const</span> <span class="hljs-string">Align(</span>
      <span class="hljs-attr">alignment:</span> <span class="hljs-string">Alignment.topRight,</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">FlutterLogo(</span>
        <span class="hljs-attr">size:</span> <span class="hljs-number">60</span><span class="hljs-string">,</span>
      <span class="hljs-string">),</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">),</span>
<span class="hljs-string">)</span>
</code></pre><p>If you want to align your widget by a ratio from the parent's centre:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625641654669/4WXXU707N.png" alt="image.png" /></p>
<pre><code><span class="hljs-string">Center(</span>
  <span class="hljs-attr">child:</span> <span class="hljs-string">Container(</span>
    <span class="hljs-attr">height:</span> <span class="hljs-number">120.0</span><span class="hljs-string">,</span>
    <span class="hljs-attr">width:</span> <span class="hljs-number">120.0</span><span class="hljs-string">,</span>
    <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.blue[50],</span>
    <span class="hljs-attr">child:</span> <span class="hljs-string">const</span> <span class="hljs-string">Align(</span>
      <span class="hljs-attr">alignment:</span> <span class="hljs-string">Alignment(0.2,</span> <span class="hljs-number">0.6</span><span class="hljs-string">),</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">FlutterLogo(</span>
        <span class="hljs-attr">size:</span> <span class="hljs-number">60</span><span class="hljs-string">,</span>
      <span class="hljs-string">),</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">),</span>
<span class="hljs-string">)</span>
</code></pre><p>Read more about Align <a target="_blank" href="https://api.flutter.dev/flutter/widgets/Align-class.html">here</a>.</p>
<hr />
<h3 id="aspectratio">AspectRatio</h3>
<p>A widget that attempts to size the <code>child</code> to a specific aspect ratio.<br /><strong>Note: aspectRatio = width / height</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625634123445/aE2onzGCV.png" alt="image.png" /></p>
<pre><code><span class="hljs-string">Container(</span>
  <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.blue[100],</span>
  <span class="hljs-attr">alignment:</span> <span class="hljs-string">Alignment.center,</span>
  <span class="hljs-attr">width:</span> <span class="hljs-string">double.infinity,</span>
  <span class="hljs-attr">height:</span> <span class="hljs-number">100.0</span><span class="hljs-string">,</span>
  <span class="hljs-attr">child:</span> <span class="hljs-string">AspectRatio(</span>
    <span class="hljs-attr">aspectRatio:</span> <span class="hljs-number">16</span> <span class="hljs-string">/</span> <span class="hljs-number">9</span><span class="hljs-string">,</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">Container(</span>
        <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.green,</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">),</span>
<span class="hljs-string">)</span>
</code></pre><h4 id="best-practices">Best Practices:</h4>
<ol>
<li>Never put <code>AspectRatio()</code> inside <code>Expanded()</code> or similar widgets that force their child/children to stretch or take up the whole space given by the parent.</li>
<li>If needed, put the <code>AspectRatio()</code> widget inside <code>Align()</code> inside <code>Expanded()</code>.<br />Example:</li>
</ol>
<pre><code><span class="hljs-string">Expanded(</span>
  <span class="hljs-attr">child:</span> <span class="hljs-string">Align(</span>
    <span class="hljs-string">AspectRatio(</span>
      <span class="hljs-attr">aspectRatio:</span> <span class="hljs-number">16</span> <span class="hljs-string">/</span> <span class="hljs-number">9</span><span class="hljs-string">,</span>
        <span class="hljs-attr">child:</span> <span class="hljs-string">Container(),</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">),</span>
<span class="hljs-string">)</span>
</code></pre><p>Read more about AspectRatio <a target="_blank" href="https://api.flutter.dev/flutter/widgets/AspectRatio-class.html">here</a>.</p>
<hr />
<h3 id="center">Center</h3>
<p>A widget that centers its <code>child</code> within itself. By default, the widget will match its <code>child</code>'s size.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625639198984/BIUi19DjT.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Center</span>(
  <span class="hljs-attribute">child</span>: FlutterLogo(
    <span class="hljs-attribute">size</span>: <span class="hljs-number">60</span>,
  ),
)
</code></pre><p>Read more about Center <a target="_blank" href="https://api.flutter.dev/flutter/widgets/Center-class.html">here</a>.</p>
<hr />
<h3 id="constrainedbox">ConstrainedBox</h3>
<p>By default, most of the widgets will use as little space as possible.<br />For Examlpe:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625643876874/sBHWk0Q9y.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Card</span>(
  <span class="hljs-attribute">color</span>: Colors.blue[<span class="hljs-number">200</span>],
  <span class="hljs-attribute">child</span>: Text(
    <span class="hljs-string">'Widget without constraints'</span>,
  ),
)
</code></pre><p><code>ConstrainedBox</code> allows its child widget to use the remaining space as desired.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1625644076727/Exg5DwIjx.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">ConstrainedBox</span>(
  <span class="hljs-attribute">constraints</span>: BoxConstraints.expand(),
  <span class="hljs-attribute">child</span>: Card(
    <span class="hljs-attribute">color</span>: Colors.blue[<span class="hljs-number">200</span>],
    <span class="hljs-attribute">child</span>: Text(
      <span class="hljs-string">'Widget inside ConstrainedBox'</span>,
    ),
  ),
)
</code></pre><p><strong>Note:</strong> The same behavior can be obtained using the <code>SizedBox.expand()</code> widget.</p>
<p>Read more about ConstrainedBox <a target="_blank" href="https://api.flutter.dev/flutter/widgets/ConstrainedBox-class.html">here</a>.</p>
<hr />
<h3 id="container">Container</h3>
<p><strong>Container</strong> is one of the most frequently used Widgets!<br />Container combines a number of other widgets each with their own layout behavior, thus Container's layout behavior is somewhat complicated. </p>
<p>Before we move forward, it's important to understand the layout behavior of the Container.</p>
<h4 id="layout-behavior">Layout Behavior</h4>
<ul>
<li>If the Container has no <code>child</code>, no <code>height</code>, no <code>width</code>, no constraints, and the parent provides unbounded constraints, then Container tries to size as <strong>small</strong> as possible.</li>
<li>If the Container has no <code>child</code> and no <code>alignment</code>, but a <code>height</code>, <code>width</code>, or constraints are provided, then the Container tries to be as <strong>small</strong> as possible given the combination of those constraints and the parent's constraints.</li>
<li>If the Container has no <code>child</code>, no <code>height</code>, no <code>width</code>, no constraints, and no <code>alignment</code>, but the parent provides bounded constraints, then Container <strong>expands</strong> to fit the constraints provided by the parent.</li>
<li>If the Container has an <code>alignment</code>, and the parent provides unbounded constraints, then the Container tries to size itself to <strong>match</strong> the <code>child</code>.</li>
<li>If the Container has an <code>alignment</code>, and the parent provides bounded constraints, then the Container tries to <strong>expand</strong> to fit the parent and then positions the <code>child</code> within itself as per the alignment.</li>
<li>Otherwise, if the Container has a <code>child</code> but no <code>height</code>, no <code>width</code>, no constraints, and no <code>alignment</code>, the Container passes the constraints from the parent to the <code>child</code> and sizes itself to <strong>match</strong> the child.</li>
</ul>
<p>I know that was quite much! But don't worry, you'll get it soon. Let's have a look at some samples below:</p>
<ul>
<li>When you don’t specify the <code>height</code> and the <code>width</code> of the Container, it will match its <code>child</code>’s size.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626520322341/quKxub41I.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">build</span>(BuildContext context) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Scaffold</span>(
    <span class="hljs-attribute">appBar</span>: AppBar(
      <span class="hljs-attribute">title</span>: Text(widget.title),
    ),
    <span class="hljs-attribute">body</span>: Container(
      <span class="hljs-attribute">color</span>: Colors.yellow[<span class="hljs-number">200</span>],
      <span class="hljs-attribute">child</span>: Text(
        <span class="hljs-string">'Widget inside Container'</span>,
      ),
    ),
  );
}
</code></pre><ul>
<li>When you don’t specify the <code>height</code> and the <code>width</code> of the Container, but specify the <code>alignment</code>, it will match its parent’s size and align its <code>child</code> according to the specified <code>alignment</code> property.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626520264818/s9B4ifawr.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">build</span>(BuildContext context) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Scaffold</span>(
    <span class="hljs-attribute">appBar</span>: AppBar(
      <span class="hljs-attribute">title</span>: Text(widget.title),
    ),
    <span class="hljs-attribute">body</span>: Container(
      <span class="hljs-attribute">color</span>: Colors.yellow[<span class="hljs-number">200</span>],
      <span class="hljs-attribute">alignment</span>: Alignment.center,
      <span class="hljs-attribute">child</span>: Text(
        <span class="hljs-string">'Widget inside Container'</span>,
      ),
    ),
  );
}
</code></pre><ul>
<li>When you only specify the <code>height</code> of the Container, it will match its <code>child</code>’s <code>width</code>.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626521994812/CVWsClHmn.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">build</span>(BuildContext context) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Scaffold</span>(
    <span class="hljs-attribute">appBar</span>: AppBar(
      <span class="hljs-attribute">title</span>: Text(widget.title),
    ),
    <span class="hljs-attribute">body</span>: Container(
      <span class="hljs-attribute">color</span>: Colors.yellow[<span class="hljs-number">200</span>],
      <span class="hljs-attribute">height</span>: <span class="hljs-number">100</span>,
      <span class="hljs-attribute">child</span>: Text(
        <span class="hljs-string">'Widget inside Container'</span>,
      ),
    ),
  );
}
</code></pre><ul>
<li>When you only specify the <code>width</code> of the Container, it will match its <code>child</code>’s <code>height</code>.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626522103336/AKl53ZFU6.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">build</span>(BuildContext context) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Scaffold</span>(
    <span class="hljs-attribute">appBar</span>: AppBar(
      <span class="hljs-attribute">title</span>: Text(widget.title),
    ),
    <span class="hljs-attribute">body</span>: Container(
      <span class="hljs-attribute">color</span>: Colors.yellow[<span class="hljs-number">200</span>],
      <span class="hljs-attribute">width</span>: <span class="hljs-number">100</span>,
      <span class="hljs-attribute">child</span>: Text(
        <span class="hljs-string">'Widget inside Container'</span>,
      ),
    ),
  );
}
</code></pre><ul>
<li>When you only specify the <code>height</code> of the Container but also specify the <code>alignment</code>, it will match its parent’s <code>width</code> and align its <code>child</code> according to the specified <code>alignment</code> property.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626522413853/S_WGlAQ6V.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">build</span>(BuildContext context) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Scaffold</span>(
    <span class="hljs-attribute">appBar</span>: AppBar(
      <span class="hljs-attribute">title</span>: Text(widget.title),
    ),
    <span class="hljs-attribute">body</span>: Container(
      <span class="hljs-attribute">color</span>: Colors.yellow[<span class="hljs-number">200</span>],
      <span class="hljs-attribute">height</span>: <span class="hljs-number">100</span>,
      <span class="hljs-attribute">alignment</span>: Alignment.center,
      <span class="hljs-attribute">child</span>: Text(
        <span class="hljs-string">'Widget inside Container'</span>,
      ),
    ),
  );
}
</code></pre><ul>
<li>When you only specify the <code>width</code> of the Container but also specify the <code>alignment</code>, it will match its parent’s <code>height</code> and align its <code>child</code> according to the specified <code>alignment</code> property.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626522527498/7LiNWwHwQ.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">build</span>(BuildContext context) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Scaffold</span>(
    <span class="hljs-attribute">appBar</span>: AppBar(
      <span class="hljs-attribute">title</span>: Text(widget.title),
    ),
    <span class="hljs-attribute">body</span>: Container(
      <span class="hljs-attribute">color</span>: Colors.yellow[<span class="hljs-number">200</span>],
      <span class="hljs-attribute">width</span>: <span class="hljs-number">100</span>,
      <span class="hljs-attribute">alignment</span>: Alignment.center,
      <span class="hljs-attribute">child</span>: Text(
        <span class="hljs-string">'Widget inside Container'</span>,
      ),
    ),
  );
}
</code></pre><p>Read more about Container <a target="_blank" href="https://api.flutter.dev/flutter/widgets/FittedBox-class.html">here</a>.</p>
<hr />
<h3 id="expanded">Expanded</h3>
<p>A widget that expands a child of a <code>Row</code>, <code>Column</code>, or <code>Flex</code> so that the child fills the available space. It's great for distributing space between multiple items.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627322204846/Yu1APGlQN.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Column</span> <span class="hljs-comment">/*or Row*/</span> (
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    Expanded(
      <span class="hljs-attribute">child</span>: Card(
        <span class="hljs-attribute">color</span>: Colors.teal,
        <span class="hljs-attribute">child</span>: Center(<span class="hljs-attribute">child</span>: Text(<span class="hljs-string">'Flex: 1'</span>)),
      ),
      <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>,
    ),
    Expanded(
      <span class="hljs-attribute">child</span>: Card(
        <span class="hljs-attribute">color</span>: Colors.green,
        <span class="hljs-attribute">child</span>: Center(<span class="hljs-attribute">child</span>: Text(<span class="hljs-string">'Flex: 2'</span>)),
      ),
      <span class="hljs-attribute">flex</span>: <span class="hljs-number">2</span>,
    ),
    Expanded(
      <span class="hljs-attribute">child</span>: Card(
        <span class="hljs-attribute">color</span>: Colors.lightGreen,
        <span class="hljs-attribute">child</span>: Center(<span class="hljs-attribute">child</span>: Text(<span class="hljs-string">'Flex: 3'</span>)),
      ),
      <span class="hljs-attribute">flex</span>: <span class="hljs-number">3</span>,
    ),
  ],
),
</code></pre><p>Read more about Expanded <a target="_blank" href="https://api.flutter.dev/flutter/widgets/Expanded-class.html">here</a>.</p>
<hr />
<h3 id="fittedbox">FittedBox</h3>
<p>Scales and positions its child within itself according to <code>fit</code>. It's mainly used to fit images inside itself just like how you fit wallpapers on your desktop!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626524554953/VjXrjhjvd.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Container</span>(
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150</span>,
  <span class="hljs-attribute">width</span>: <span class="hljs-number">300</span>,
  <span class="hljs-attribute">color</span>: Colors.yellow[<span class="hljs-number">200</span>],
  <span class="hljs-attribute">child</span>: FittedBox(
    <span class="hljs-attribute">clipBehavior</span>: Clip.antiAlias,
    <span class="hljs-attribute">fit</span>: BoxFit.cover,
    <span class="hljs-attribute">child</span>: Image.network(
      <span class="hljs-string">'https://xyz.jpg'</span>,
    ),
  ),
),
</code></pre><p>Read more about FittedBox <a target="_blank" href="https://api.flutter.dev/flutter/widgets/Container-class.html">here</a>.</p>
<hr />
<h3 id="fractionallysizedbox">FractionallySizedBox</h3>
<p>A widget that sizes its <code>child</code> to a fraction of the total available space.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626679341097/TQQ_pbmMn.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Center</span>(
  <span class="hljs-attribute">child</span>: FractionallySizedBox(
    <span class="hljs-attribute">widthFactor</span>: <span class="hljs-number">0.6</span>,
    <span class="hljs-attribute">heightFactor</span>: <span class="hljs-number">0.1</span>,
    <span class="hljs-attribute">child</span>: Card(
      <span class="hljs-attribute">color</span>: Colors.orange,
      <span class="hljs-attribute">child</span>: Text(<span class="hljs-string">'Some Widget'</span>),
    ),
  ),
),
</code></pre><h4 id="best-practices">Best Practices:</h4>
<ol>
<li>Use <code>FractionallySizedBox()</code> with no <code>child</code> for fractional sized white space.</li>
<li>Wrap <code>FractionallySizedBox()</code> inside <code>Flexible()</code> widget so it plays well with <code>Row</code>/<code>Column</code>.</li>
</ol>
<p>Read more about FractionallySizedBox <a target="_blank" href="https://api.flutter.dev/flutter/widgets/FractionallySizedBox-class.html">here</a>.</p>
<hr />
<h3 id="sizedbox">SizedBox</h3>
<p>It is one of the simplest yet useful Widgets. It enforces a specific size on its <code>child</code>.</p>
<h4 id="layout-behavior">Layout Behavior</h4>
<ul>
<li>If given a <code>child</code>, this widget forces it to have a specific <code>width</code> and/or <code>height</code>.</li>
<li>These values will be ignored if this widget's parent does not permit them. For example, this happens if the parent is the screen or another SizedBox.</li>
<li>If either the <code>width</code> or <code>height</code> is null, SizedBox will try to size itself to match the <code>child</code>'s size in that dimension.</li>
<li>If <code>height</code> or <code>width</code> is null or unspecified, it will be treated as zero.</li>
<li>Use <code>SizedBox.expand()</code> to make the SizedBox match the size of its parent. It is equivalent to setting <code>width</code> and <code>height</code> to <code>double.infinity</code>.</li>
</ul>
<p>Let's have a look at some samples below:</p>
<ul>
<li>SizedBox as fixed-size padding</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627320693411/vaswzpEdR.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Column</span>(
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    const SizedBox(<span class="hljs-attribute">height</span>: <span class="hljs-number">100</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li>If you want to match the size of the parent, use <code>SizedBox.expand()</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627321041901/rdLYcDYAV.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">SizedBox</span><span class="hljs-selector-class">.expand</span>(
  <span class="hljs-attribute">child</span>: Card(
    <span class="hljs-attribute">color</span>: Colors.orange[<span class="hljs-number">200</span>],
    <span class="hljs-attribute">child</span>: Text(<span class="hljs-string">'Widget inside SizedBox'</span>),
  ),
),
</code></pre><h4 id="best-practices">Best Practices</h4>
<ul>
<li>When placing SizedBox as a <code>child</code> inside a parent Widget which forces its <code>child</code> to be the same size as itself (e.g. another SizedBox), then wrap the child SizedBox in a widget that does permit it to be any size up to the size of the parent, such as <code>Center</code> or <code>Align</code>.<br />Example:</li>
</ul>
<pre><code><span class="hljs-selector-tag">SizedBox</span>(
  <span class="hljs-attribute">height</span>: double.infinity,
  <span class="hljs-attribute">width</span>: double.infinity,
  <span class="hljs-attribute">child</span>: Align(
    <span class="hljs-attribute">child</span>: SizedBox(
      <span class="hljs-attribute">height</span>: <span class="hljs-number">100</span>,
      <span class="hljs-attribute">width</span>: <span class="hljs-number">100</span>,
      <span class="hljs-attribute">child</span>: Card(
        <span class="hljs-attribute">color</span>: Colors.orange[<span class="hljs-number">200</span>],
        <span class="hljs-attribute">child</span>: Text(<span class="hljs-string">'Widget inside SizedBox'</span>),
      ),
    ),
  ),
)
</code></pre><p>Read more about SizedBox <a target="_blank" href="https://api.flutter.dev/flutter/widgets/SizedBox-class.html">here</a>.</p>
<hr />
<h2 id="multi-child-layout-widgets">Multi-child layout widgets</h2>
<h3 id="row-and-column">Row and Column</h3>
<p><strong>Row</strong>: Layout a list of child widgets in the horizontal direction.<br /><strong>Column</strong>: Layout a list of child widgets in the vertical direction.</p>
<p>To align the child widgets inside Row/Column, we use <code>mainAxisAlignment</code> and <code>crossAxisAlignment</code>. Let's have a look at both of these parameters:</p>
<h4 id="mainaxisalignment">MainAxisAlignment</h4>
<ul>
<li><code>MainAxisAlignment.start</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628354826434/wR-hdPz-z6.png" alt="row_col_1.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisAlignment</span>: MainAxisAlignment.start,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>MainAxisAlignment.center</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628355651623/7tNAhPy_sB.png" alt="row_col_2.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisAlignment</span>: MainAxisAlignment.center,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>MainAxisAlignment.end</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628356293795/sxZOpkSWa.png" alt="row_col_3.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisAlignment</span>: MainAxisAlignment.end,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>MainAxisAlignment.spaceBetween</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628356683784/qgeEy3nUh.png" alt="row_col_4.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisAlignment</span>: MainAxisAlignment.spaceBetween,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>MainAxisAlignment.spaceEvenly</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628357043015/dUNBfQ-TV.png" alt="row_col_5.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisAlignment</span>: MainAxisAlignment.spaceEvenly,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>MainAxisAlignment.spaceAround</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628357205623/bOz2Vt0Ee.png" alt="row_col_6.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisAlignment</span>: MainAxisAlignment.spaceAround,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><h4 id="crossaxisalignment">CrossAxisAlignment</h4>
<ul>
<li><code>CrossAxisAlignment.start</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628358455821/in9D8YT0W.png" alt="row_col_7.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">crossAxisAlignment</span>: CrossAxisAlignment.start,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">200</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>CrossAxisAlignment.center</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628358910254/Ms-8JfzKkV.png" alt="row_col_8.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">crossAxisAlignment</span>: CrossAxisAlignment.center,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">200</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>CrossAxisAlignment.end</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628359083911/aA0edoDDv.png" alt="row_col_9.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">crossAxisAlignment</span>: CrossAxisAlignment.end,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">200</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>CrossAxisAlignment.stretch</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628359245765/vUq5kmRDv.png" alt="row_col_10.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">crossAxisAlignment</span>: CrossAxisAlignment.stretch,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">200</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>CrossAxisAlignment.baseline</code><br />Places the children along the cross axis such that their baselines match.
Since baselines are always horizontal, this alignment is intended for <code>Row</code> Widget. If the main axis is vertical, then this value is treated like <code>CrossAxisAlignment.start</code>.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628360289312/WgANZEAJz.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span>(
  <span class="hljs-attribute">crossAxisAlignment</span>: CrossAxisAlignment.baseline,
  <span class="hljs-attribute">textBaseline</span>: TextBaseline.alphabetic,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    Text(
      <span class="hljs-string">'Heading'</span>,
      <span class="hljs-attribute">style</span>: Theme.of(context).textTheme.headline2,
    ),
    Text(
      <span class="hljs-string">'Body'</span>,
      <span class="hljs-attribute">style</span>: Theme.of(context).textTheme.bodyText2,
    ),
  ],
),
</code></pre><p>Use <code>MainAxisSize</code> to size the Row/Column to either match their parent or fit their children.</p>
<h4 id="mainaxissize">MainAxisSize</h4>
<ul>
<li><code>MainAxisSize.max</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628354826434/wR-hdPz-z6.png" alt="row_col_1.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisSize</span>: MainAxisSize.max,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><ul>
<li><code>MainAxisSize.min</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628406305811/0ZtL8ayxI.png" alt="row_col_11.png" /></p>
<pre><code><span class="hljs-selector-tag">Row</span> <span class="hljs-comment">/*or Column*/</span> (
  <span class="hljs-attribute">mainAxisSize</span>: MainAxisSize.min,
  <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
    FlutterLogo(<span class="hljs-attribute">size</span>: <span class="hljs-number">50</span>),
  ],
),
</code></pre><p>Read more about Row <a target="_blank" href="https://api.flutter.dev/flutter/widgets/Row-class.html">here</a>.<br />Read more about Column <a target="_blank" href="https://api.flutter.dev/flutter/widgets/Column-class.html">here</a>.  </p>
<hr />
<h3 id="stack">Stack</h3>
<p>A widget that positions its children on top of each other.<br />Let's have a look at some of its interesting properties:</p>
<ul>
<li>By default, all the children are aligned to the top-left corner of a Stack.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628876988664/_fwm05aDe.png" alt="image.png" /></p>
<pre><code><span class="hljs-string">Stack(</span>
  <span class="hljs-attr">children:</span> <span class="hljs-string">&lt;Widget&gt;[</span>
    <span class="hljs-string">Container(</span>
      <span class="hljs-attr">width:</span> <span class="hljs-number">120</span><span class="hljs-string">,</span>
      <span class="hljs-attr">height:</span> <span class="hljs-number">120</span><span class="hljs-string">,</span>
      <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.green,</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Container(</span>
      <span class="hljs-attr">width:</span> <span class="hljs-number">100</span><span class="hljs-string">,</span>
      <span class="hljs-attr">height:</span> <span class="hljs-number">100</span><span class="hljs-string">,</span>
      <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.red,</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Container(</span>
      <span class="hljs-attr">width:</span> <span class="hljs-number">80</span><span class="hljs-string">,</span>
      <span class="hljs-attr">height:</span> <span class="hljs-number">80</span><span class="hljs-string">,</span>
      <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.blue,</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">],</span>
<span class="hljs-string">),</span>
</code></pre><ul>
<li>To align all the children, we can use the <code>alignment</code> property.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628877226725/S7y6QqQxC.png" alt="image.png" /></p>
<pre><code><span class="hljs-string">Stack(</span>
  <span class="hljs-attr">alignment:</span> <span class="hljs-string">Alignment.center,</span>
  <span class="hljs-attr">children:</span> <span class="hljs-string">&lt;Widget&gt;[</span>
    <span class="hljs-string">Container(</span>
      <span class="hljs-attr">width:</span> <span class="hljs-number">120</span><span class="hljs-string">,</span>
      <span class="hljs-attr">height:</span> <span class="hljs-number">120</span><span class="hljs-string">,</span>
      <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.green,</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Container(</span>
      <span class="hljs-attr">width:</span> <span class="hljs-number">100</span><span class="hljs-string">,</span>
      <span class="hljs-attr">height:</span> <span class="hljs-number">100</span><span class="hljs-string">,</span>
      <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.red,</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Container(</span>
      <span class="hljs-attr">width:</span> <span class="hljs-number">80</span><span class="hljs-string">,</span>
      <span class="hljs-attr">height:</span> <span class="hljs-number">80</span><span class="hljs-string">,</span>
      <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.blue,</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">],</span>
<span class="hljs-string">),</span>
</code></pre><ul>
<li>But what if you want to position all the elements uniquely?
In that case, we can either wrap the individual child widgets with an <code>Align()</code> or <code>Positioned()</code> widget.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628877983649/mwktorG9J.png" alt="image.png" /></p>
<pre><code><span class="hljs-string">Stack(</span>
  <span class="hljs-attr">children:</span> <span class="hljs-string">&lt;Widget&gt;[</span>
    <span class="hljs-string">Align(</span>
      <span class="hljs-attr">alignment:</span> <span class="hljs-string">Alignment.topLeft,</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">Icon(</span>
        <span class="hljs-string">Icons.menu,</span>
      <span class="hljs-string">),</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Align(</span>
      <span class="hljs-attr">alignment:</span> <span class="hljs-string">Alignment.topRight,</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">Icon(</span>
        <span class="hljs-string">Icons.delete,</span>
      <span class="hljs-string">),</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Positioned(</span>
      <span class="hljs-attr">bottom:</span> <span class="hljs-number">0</span><span class="hljs-string">,</span>
      <span class="hljs-attr">right:</span> <span class="hljs-number">0</span><span class="hljs-string">,</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">Icon(</span>
        <span class="hljs-string">Icons.add_circle,</span>
      <span class="hljs-string">),</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Positioned(</span>
      <span class="hljs-attr">bottom:</span> <span class="hljs-number">0</span><span class="hljs-string">,</span>
      <span class="hljs-attr">left:</span> <span class="hljs-number">0</span><span class="hljs-string">,</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">Icon(</span>
        <span class="hljs-string">Icons.home,</span>
      <span class="hljs-string">),</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">],</span>
<span class="hljs-string">),</span>
</code></pre><ul>
<li>Sometimes, a child moves outside of a Stack's bounds. By default, it will be clipped.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628879594246/O44jNPb8hY.png" alt="image.png" /></p>
<p>To prevent clipping, use <code>clipBehavior: Clip.none</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1628879629775/zCkUOpm81Y.png" alt="image.png" /></p>
<pre><code><span class="hljs-string">Stack(</span>
  <span class="hljs-attr">alignment:</span> <span class="hljs-string">Alignment.center,</span>
  <span class="hljs-attr">clipBehavior:</span> <span class="hljs-string">Clip.none,</span>
  <span class="hljs-attr">children:</span> <span class="hljs-string">&lt;Widget&gt;[</span>
    <span class="hljs-string">Container(</span>
      <span class="hljs-attr">width:</span> <span class="hljs-number">120</span><span class="hljs-string">,</span>
      <span class="hljs-attr">height:</span> <span class="hljs-number">120</span><span class="hljs-string">,</span>
      <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.black54,</span>
    <span class="hljs-string">),</span>
    <span class="hljs-string">Positioned(</span>
      <span class="hljs-attr">bottom:</span> <span class="hljs-number">-30</span><span class="hljs-string">,</span>
      <span class="hljs-attr">right:</span> <span class="hljs-number">-30</span><span class="hljs-string">,</span>
      <span class="hljs-attr">child:</span> <span class="hljs-string">Container(</span>
        <span class="hljs-attr">width:</span> <span class="hljs-number">80</span><span class="hljs-string">,</span>
        <span class="hljs-attr">height:</span> <span class="hljs-number">80</span><span class="hljs-string">,</span>
        <span class="hljs-attr">color:</span> <span class="hljs-string">Colors.blue,</span>
      <span class="hljs-string">),</span>
    <span class="hljs-string">),</span>
  <span class="hljs-string">],</span>
<span class="hljs-string">),</span>
</code></pre><p>Read more about Stack here: <a target="_blank" href="https://api.flutter.dev/flutter/widgets/Stack-class.html">here</a>.</p>
<hr />
<h3 id="layoutbuilder">LayoutBuilder</h3>
<p>If you want to layout your widgets based on the parent's size, this is the widget you need. One use-case for <code>LayoutBuilder</code> could be building different layouts for different screen sizes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629136435896/XIot-Tz3p.png" alt="image.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629136317704/YTN8cNrQW.png" alt="image.png" /></p>
<pre><code><span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">build</span>(BuildContext context) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Scaffold</span>(
    <span class="hljs-attribute">appBar</span>: AppBar(<span class="hljs-attribute">title</span>: const Text(<span class="hljs-string">'LayoutBuilder'</span>)),
    <span class="hljs-attribute">body</span>: LayoutBuilder(
      <span class="hljs-attribute">builder</span>: (context, constraints) {
        if (constraints.maxWidth &gt; <span class="hljs-number">600</span>) {
          return _buildWideContainers(constraints.maxWidth);
        } else {
          return _buildNormalContainer();
        }
      },
    ),
  );
}

<span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">_buildNormalContainer</span>() {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Center</span>(
    <span class="hljs-attribute">child</span>: Container(
      <span class="hljs-attribute">height</span>: double.infinity,
      <span class="hljs-attribute">width</span>: double.infinity,
      <span class="hljs-attribute">color</span>: Colors.teal,
    ),
  );
}

<span class="hljs-selector-tag">Widget</span> <span class="hljs-selector-tag">_buildWideContainers</span>(double width) {
  <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">Center</span>(
    <span class="hljs-attribute">child</span>: Row(
      <span class="hljs-attribute">mainAxisAlignment</span>: MainAxisAlignment.spaceEvenly,
      <span class="hljs-attribute">children</span>: &lt;Widget&gt;[
        Container(
          <span class="hljs-attribute">height</span>: double.infinity,
          <span class="hljs-attribute">width</span>: width / <span class="hljs-number">2</span>,
          <span class="hljs-attribute">color</span>: Colors.teal,
        ),
        Container(
          <span class="hljs-attribute">height</span>: double.infinity,
          <span class="hljs-attribute">width</span>: width / <span class="hljs-number">2</span>,
          <span class="hljs-attribute">color</span>: Colors.green,
        ),
      ],
    ),
  );
}
</code></pre><p>Read more about LayoutBuilder here: <a target="_blank" href="https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html">here</a>.</p>
<hr />
<h2 id="references">References</h2>
<ul>
<li><p>Official Flutter layout widgets page:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://flutter.dev/docs/development/ui/widgets/layout#Multi-child%20layout%20widgets">https://flutter.dev/docs/development/ui/widgets/layout#Multi-child%20layout%20widgets</a></div>
</li>
<li><p>A great article on constraints in FLutter, a must-read:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://flutter.dev/docs/development/ui/layout/constraints">https://flutter.dev/docs/development/ui/layout/constraints</a></div>
</li>
<li><p>To understand existing layouts &amp; diagnose layout issues, use Flutter Inspector:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://flutter.dev/docs/development/tools/devtools/inspector">https://flutter.dev/docs/development/tools/devtools/inspector</a></div>
</li>
</ul>
<hr />
<p>That's all for now. This blog is a work in progress. I'll try and add more Widgets and samples in the coming days. Feel free to drop a line if you don't understand something.</p>
<p>Thanks for reading! </p>
]]></content:encoded></item><item><title><![CDATA[8 inspiring UI/UX resources for your next project]]></title><description><![CDATA[Uplabs: UpLabs is a website for designers and developers to find and share resources to build apps and sites.
https://www.uplabs.com/

Pinterest: Just search for UI designs on Pinterest & voila!
https://pinterest.com/

Dribbble: Dribbble has tons of ...]]></description><link>https://blog.adityasharma.co/8-inspiring-uiux-resources-for-your-next-project</link><guid isPermaLink="true">https://blog.adityasharma.co/8-inspiring-uiux-resources-for-your-next-project</guid><category><![CDATA[UI]]></category><category><![CDATA[UX]]></category><category><![CDATA[Inspiration]]></category><category><![CDATA[UI Design]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Tue, 15 Jun 2021 13:51:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1623764514769/qVaKQcaYa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<ol>
<li><p><strong>Uplabs</strong>: UpLabs is a website for designers and developers to find and share resources to build apps and sites.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.uplabs.com/">https://www.uplabs.com/</a></div>
</li>
<li><p><strong>Pinterest</strong>: Just search for UI designs on Pinterest &amp; voila!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://pinterest.com/">https://pinterest.com/</a></div>
</li>
<li><p><strong>Dribbble</strong>: Dribbble has tons of UI/UX app designs posted by some great designers from worldwide.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://dribbble.com/">https://dribbble.com/</a></div>
</li>
<li><p><strong>Behance</strong>: Same goes for Behance. Another awesome community by designers, for designers!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.behance.net/">https://www.behance.net/</a></div>
</li>
<li><p><strong>Uxplanet</strong>: One-stop resource for everything related to user experience.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://uxplanet.org/">https://uxplanet.org/</a></div>
</li>
<li><p><strong>Freefrontend</strong>: Find code for astonishing UI components.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://freefrontend.com/">https://freefrontend.com/</a></div>
</li>
<li><p><strong>Awwwards</strong>: AWWWARDS aims to recognize and promote the best of innovative &amp; inspiring web designs.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.awwwards.com/">https://www.awwwards.com/</a></div>
</li>
<li><p><strong>Freepik</strong>: Just search for UI/UX designs for your next project &amp; get free/paid vectors &amp; PSDs.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.freepik.com/">https://www.freepik.com/</a></div>
</li>
</ol>
<hr />
<p>That's it for now! Feel free to suggest more resources in the comments below! ✌🏻<br />
And don't forget to credit the authors when using their awesome work in your projects! 🙏🏻💯</p>
]]></content:encoded></item><item><title><![CDATA[Yoga Guru - My Final Year Project]]></title><description><![CDATA[About Yoga Guru
Yoga Guru is your personalized yoga trainer app based on Flutter. It uses poseNet, a pre-trained deep learning model, to estimate body poses in real-time and predict yoga asanas.
Link to Code
https://github.com/BetaPundit/Yoga-Guru
 
...]]></description><link>https://blog.adityasharma.co/yoga-guru-my-final-year-project</link><guid isPermaLink="true">https://blog.adityasharma.co/yoga-guru-my-final-year-project</guid><category><![CDATA[side project]]></category><dc:creator><![CDATA[Aditya Sharma]]></dc:creator><pubDate>Wed, 20 May 2020 06:47:50 GMT</pubDate><content:encoded><![CDATA[<h2 id="about-yoga-guru">About Yoga Guru</h2>
<p>Yoga Guru is your personalized yoga trainer app based on Flutter. It uses poseNet, a pre-trained deep learning model, to estimate body poses in real-time and predict yoga asanas.</p>
<h3 id="link-to-code">Link to Code</h3>
<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/BetaPundit/Yoga-Guru">https://github.com/BetaPundit/Yoga-Guru</a></div>
<p> </p>
<h2 id="how-i-built-it-the-story">How I built it (The Story)</h2>
<ul>
<li><p>The idea came to me when I first saw the PoseNet framework which is a computer vision model that estimates the pose of a person in an image or a video by estimating where key body joints are. </p>
</li>
<li><p>I started by wireframing the app and designed different app screens. </p>
</li>
<li><p>I then built different components in Flutter and then used the Flutter Tflite package to run a pre-trained PoseNet model on the image stream (video frame).</p>
</li>
<li><p>Then I trained a custom model on the output of the above PoseNet model to classify Yoga Poses. It certainly took some time to find images on google to create a dataset and fit a classifier on it.</p>
</li>
<li><p>The challenge now was to run the 2 model (PoseNet and the custom Yoga Classifier) in a pipeline in the app. For this, I had to understand how to write platform-specific code in Flutter and run custom Tflite models in Android!</p>
</li>
<li><p>It was a challenging task but in the end, all the hard work paid off and the app was up and running! </p>
</li>
</ul>
<h2 id="additional-thoughts">Additional Thoughts</h2>
<p>The art of practising yoga helps in controlling an individual's mind, body and soul. It brings together physical and mental disciplines to achieve a peaceful body and mind. Thus, by building this app, I wish that everyone can access and learn Yoga and keep their body, soul and mind in tune.</p>
<p>Any contributions to the app are most welcome!</p>
]]></content:encoded></item></channel></rss>