<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Rafael Delos Santos</title>
      <link>https://rafaelds.com</link>
      <description>Software engineer</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://rafaelds.com/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Fri, 05 Apr 2024 00:00:00 +0000</lastBuildDate>
      <item>
          <title>How to use custom theme colours in Flutter without using Material or Cupertino Theme</title>
          <pubDate>Fri, 05 Apr 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/how-to-use-custom-theme-colours-in-flutter/</link>
          <guid>https://rafaelds.com/posts/how-to-use-custom-theme-colours-in-flutter/</guid>
          <description xml:base="https://rafaelds.com/posts/how-to-use-custom-theme-colours-in-flutter/">&lt;p&gt;It is important to think about how to add structured colour theming to your design when building Flutter apps. The most popular way to do so is to use the Material Design&#x27;s &lt;code&gt;ColorScheme&lt;&#x2F;code&gt; class. The better approach is to use a design system that specifically works with your app&#x27;s design system such as the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pub.dev&#x2F;packages&#x2F;color_theme_provider&quot;&gt;color_theme_provider&lt;&#x2F;a&gt; package.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-the-material-design-colour-system&quot;&gt;Using the Material Design colour system&lt;&#x2F;h2&gt;
&lt;p&gt;In many examples, you will always see the following code snippet wherein you can define the Material design colour scheme.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MaterialApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  home&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt; const&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; HomeScreen&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  theme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; ThemeData&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    colorScheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; ColorScheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;fromSeed&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      seedColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;purple&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is not a bad way to start your app with proper colour schemes. Whenever you use widgets that extend the &lt;code&gt;Material&lt;&#x2F;code&gt; widget, then their colour properties will adhere to this theme. However, the downside of this approach is it lacks the customisation that you might need in your application.&lt;&#x2F;p&gt;
&lt;p&gt;A more customisable approach to this is to create your own &lt;code&gt;ColorScheme&lt;&#x2F;code&gt; and define each property with the appropriate colour.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MaterialApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  home&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt; const&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; HomeScreen&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  theme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; ThemeData&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    colorScheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; ColorScheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      brightness&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; brightness&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      onPrimary&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; onPrimary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      secondary&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; secondary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      onSecondary&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; onSecondary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      error&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; error&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      onError&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; onError&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      background&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      onBackground&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; onBackground&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      surface&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; surface&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      onSurface&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; onSurface&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once you defined the colours, you can start using these properties in your widgets by getting the &lt;code&gt;ColorScheme&lt;&#x2F;code&gt; from the context.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;final&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorScheme &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Theme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;of&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(context)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;colorScheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Container&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorScheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;the-downside-of-using-colorscheme&quot;&gt;The downside of using ColorScheme&lt;&#x2F;h2&gt;
&lt;p&gt;The problem with using the Material design colour scheme is that we are restricted to using the following properties defined by this design system. If we are working with a team that has its design system, it might be difficult to match each property to a corresponding token.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s say in my app, I have the following design tokens:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;brandColor&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;backgroundColor&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;errorColor&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;successColor&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;textColor&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I can use the &lt;code&gt;ColorScheme&lt;&#x2F;code&gt; to apply our design tokens to match the &lt;code&gt;brandColor&lt;&#x2F;code&gt; to &lt;code&gt;primaryColor&lt;&#x2F;code&gt;, &lt;code&gt;backgroundColor&lt;&#x2F;code&gt; to &lt;code&gt;background&lt;&#x2F;code&gt;, and so on with the &lt;code&gt;errorColor&lt;&#x2F;code&gt;. But what about &lt;code&gt;successColor&lt;&#x2F;code&gt;? If I want to have a consistent colour theme across the app, then using the &lt;code&gt;ColorScheme&lt;&#x2F;code&gt; falls short. I will have to hard code the &lt;code&gt;successColor&lt;&#x2F;code&gt; somewhere in the app.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-the-color-theme-provider&quot;&gt;Using the color_theme_provider&lt;&#x2F;h2&gt;
&lt;p&gt;One way to solve this issue is to use the &lt;code&gt;color_theme_provider&lt;&#x2F;code&gt; package. This package lets you define your colour scheme according to your requirements using the &lt;code&gt;ColorTheme&lt;&#x2F;code&gt; interface which can be accessed by any widgets in your application as long as these widgets are part of the &lt;code&gt;ColorThemeProvider&lt;&#x2F;code&gt; widget tree.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;color_theme_provider&lt;&#x2F;code&gt; has the following features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Automatically changes the colour theme based on the system&#x27;s mode (light or dark)&lt;&#x2F;li&gt;
&lt;li&gt;Dynamically change the colour theme in runtime&lt;&#x2F;li&gt;
&lt;li&gt;Does not depend on Material or Apple design tokens&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;&#x2F;h3&gt;
&lt;p&gt;You can install this using&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;flutter&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pub add color_theme_provider&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;or adding it directly to &lt;code&gt;pubspec.yaml&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;dependencies&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  color_theme_provider&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1.1.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;defining-the-colortheme-interface&quot;&gt;Defining the ColorTheme interface&lt;&#x2F;h3&gt;
&lt;p&gt;Once the package has been imported into the project, we can start defining the colours that we need in our app. Let&#x27;s use the colours that we defined above and make an interface that extends &lt;code&gt;ColorTheme&lt;&#x2F;code&gt;. Let&#x27;s call it &lt;code&gt;MyTheme&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;package:color_theme_provider&#x2F;color_theme_provider.dart&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;package:flutter&#x2F;material.dart&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;abstract class&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; ColorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; get&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; brandColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; get&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; backgroundColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; get&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; errorColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; get&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; successColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; get&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; textColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We are using an &lt;code&gt;abstract&lt;&#x2F;code&gt; class or an interface so that we can define a colour theme for light mode and another for dark mode. We can also define other colour themes if we want to have multiple colour themes in the app. The only requirement is that these classes should extend &lt;code&gt;MyTheme&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;final class&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; LightMyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; brandColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;blue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; backgroundColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;white&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; errorColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;red&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; successColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;green&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; textColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;black&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can also define another theme for dark mode as such. In this example, we just changed the &lt;code&gt;backgroundColor&lt;&#x2F;code&gt; to a dark colour and its inverse for the &lt;code&gt;textColor&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;final class&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; DarkMyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; brandColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;blue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; backgroundColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;black&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; errorColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;red&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; successColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;green&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  final&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; textColor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;white&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;wrapping-your-app-with-colorthemeprovider&quot;&gt;Wrapping your app with ColorThemeProvider&lt;&#x2F;h3&gt;
&lt;p&gt;Once we have defined the themes, we can wrap our app with the &lt;code&gt;ColorThemeProvider&lt;&#x2F;code&gt;. This is necessary so that all the widgets under this widget tree can access the theme. If you have a top-level widget such as &lt;code&gt;MaterialApp&lt;&#x2F;code&gt;, then we can wrap this widget with &lt;code&gt;ColorThemeProvider&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; StatelessWidget&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MyApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;({super&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;key})&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Widget&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;BuildContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; ColorThemeProvider&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;MyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      theme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; LightMyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      darkTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; DarkMyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      child&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt; const&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MaterialApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        home&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; HomePage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Don&#x27;t forget to define the generic &lt;code&gt;MyTheme&lt;&#x2F;code&gt; when using the &lt;code&gt;ColorThemeProvider&lt;&#x2F;code&gt;. All the widgets under the &lt;code&gt;HomePage&lt;&#x2F;code&gt; can access the &lt;code&gt;MyTheme&lt;&#x2F;code&gt; instance and apply the colours defined in there.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;applying-the-colour-theme&quot;&gt;Applying the colour theme&lt;&#x2F;h3&gt;
&lt;p&gt;Now that we have set up the app, we can start using these colours. We will need access to the widget&#x27;s &lt;code&gt;BuildContext&lt;&#x2F;code&gt; to get the theme from the &lt;code&gt;ColorThemeProvider&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;color_theme_provider&lt;&#x2F;code&gt; has an extension function to get a colour theme instance. To get the colour theme, use the &lt;code&gt;context.colorTheme&amp;lt;MyTheme&amp;gt;()&lt;&#x2F;code&gt; extension function. Make sure to include the generic type of your theme. In our example, it&#x27;s &lt;code&gt;MyTheme&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; HomePage&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; StatelessWidget&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; HomePage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;({super&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;key})&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Widget&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;BuildContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;    final&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorTheme &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;MyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;    &#x2F;&#x2F;Using the colours&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;backgroundColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;brandColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;successColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;    &#x2F;&#x2F; ..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;example-of-using-the-color-theme&quot;&gt;Example of using the color theme&lt;&#x2F;h3&gt;
&lt;p&gt;If we apply all these concepts, we can simply use these colours in our widgets. As an example, let&#x27;s display the different colours from the theme. When using the &lt;code&gt;colorTheme&lt;&#x2F;code&gt;, we just need to define which colour property we want to use. The &lt;code&gt;ColorThemeProvider&lt;&#x2F;code&gt; takes care of applying these colours, whether it is in light or dark mode.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Figure 1. Using ColorThemeProvider for Light and Dark theme.&quot; title=&quot;Figure 1. Using ColorThemeProvider for Light and Dark theme.&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;theme-sample.1f7ec2dadf198b9b.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;theme-sample.43e38b366554ee0b.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;theme-sample.1f7ec2dadf198b9b.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; HomePage&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; StatelessWidget&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; HomePage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;({super&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;key})&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;  @override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;  Widget&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;BuildContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;    final&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorTheme &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;MyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Scaffold&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      backgroundColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;backgroundColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      body&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Center&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        child&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Column&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          mainAxisAlignment&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; MainAxisAlignment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;center&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          children&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;            Container&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 64.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 64.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;brandColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;            Container&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 64.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 64.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;successColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;            Container&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 64.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 64.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;errorColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;            Text&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;              &amp;#39;Sample Text&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;              style&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; TextStyle&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(color&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;textColor)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the example above, we can see that the background and the text colours change according to the device&#x27;s system settings.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dynamically-changing-the-theme&quot;&gt;Dynamically changing the theme&lt;&#x2F;h3&gt;
&lt;p&gt;We can also change the theme whilst the app is running using the &lt;code&gt;ColorThemeManager&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;final&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; colorThemeMananger &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;colorThemeManager&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;MyTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;colorThemeMananger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;setTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;NewLightTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;colorThemeMananger&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;setDarkTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;NewDarkTheme&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is useful if your app offers multiple colour schemes to users.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;color_theme_provider&lt;&#x2F;code&gt; package is an alternative approach to using colour themes. With this package, we are not restricted to using the Material design or Cupertino colour properties. We can easily define the colours that we need according to the app&#x27;s requirements.&lt;&#x2F;p&gt;
&lt;p&gt;First, create an interface that extends &lt;code&gt;ColorTheme&lt;&#x2F;code&gt;. Then, define a light and dark mode extending the created theme. Once the themes have been defined, wrap your application with &lt;code&gt;ColorThemeProvider&lt;&#x2F;code&gt;. To access the theme, use &lt;code&gt;context.themeColor&amp;lt;YourTheme&amp;gt;()&lt;&#x2F;code&gt; and start applying the colours.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, you can change the colour theme in runtime using the &lt;code&gt;ColorThemeManager&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pub.dev&#x2F;packages&#x2F;color_theme_provider&quot;&gt;https:&#x2F;&#x2F;pub.dev&#x2F;packages&#x2F;color_theme_provider&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Trying out Advent of Code 2023</title>
          <pubDate>Sun, 03 Dec 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/trying-out-advent-of-code-2023/</link>
          <guid>https://rafaelds.com/posts/trying-out-advent-of-code-2023/</guid>
          <description xml:base="https://rafaelds.com/posts/trying-out-advent-of-code-2023/">&lt;p&gt;As per tradition, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;was.tl&#x2F;&quot;&gt;Eric Wastl&lt;&#x2F;a&gt; has already started the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;adventofcode.com&#x2F;&quot;&gt;2023 Advent of Code&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;My goal is to solve as much problem as I can before giving up. Let&#x27;s see how far I&#x27;d get with this 😅.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;platform&quot;&gt;Platform&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ll be using &lt;code&gt;Kotlin&lt;&#x2F;code&gt; using &lt;code&gt;Android Studio&lt;&#x2F;code&gt;. This would mean that I would heavily depend on the pre-written Kotlin extension functions and what not to make solving these exercises faster.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;my-solution&quot;&gt;My solution&lt;&#x2F;h2&gt;
&lt;p&gt;If you wanna see how awful and brute-forcey my solutions are (if they even run), come check it out &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;themobilecoder&#x2F;Advent-of-Code-2023&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Have fun!&lt;&#x2F;p&gt;
&lt;p&gt;Ta.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>On the importance of abstraction when using third-party libraries</title>
          <pubDate>Fri, 29 Sep 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/on-the-importance-of-abstraction-when-using-third-party-libraries/</link>
          <guid>https://rafaelds.com/posts/on-the-importance-of-abstraction-when-using-third-party-libraries/</guid>
          <description xml:base="https://rafaelds.com/posts/on-the-importance-of-abstraction-when-using-third-party-libraries/">&lt;p&gt;A good rule of thumb when using a third-party library is to use wrapper functions to abstract the implementation instead of calling their APIs directly. Doing so makes your code easily testable and flexible whenever you decide to use a different library.&lt;&#x2F;p&gt;
&lt;p&gt;This applies to third-party libraries that use databases, networking, hardware sensor events, and more.&lt;&#x2F;p&gt;
&lt;p&gt;The code samples here will be written in Kotlin but the idea can be applied to any programming language and framework.&lt;&#x2F;p&gt;
&lt;p&gt;I will share some insights on how abstraction allows us to move faster in developing new features while keeping our code testable. Imagine we are tasked to make a feature-rich Android app for taking card payments. This app will depend on a particular vendor that builds the device and provides us with an SDK (Software Development Kit) along with it.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Initial payment app architecture&quot; title=&quot;Initial payment app architecture&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;initial-payment-app-architecture.d85ec4b56bf94236.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;initial-payment-app-architecture.23e6a189ec6faacd.png 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;h2 id=&quot;directly-using-a-third-party-library-influences-the-app-s-architecture&quot;&gt;Directly using a third-party library influences the app&#x27;s architecture&lt;&#x2F;h2&gt;
&lt;p&gt;The quickest way to use a library is by calling its APIs directly. When building an app, it is straightforward to adapt to what the SDK interface gives you.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose the &lt;code&gt;VendorSdk&lt;&#x2F;code&gt; has an API for payment like this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; VendorSdk&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    enum class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; VendorPaymentStatus&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        SUCCESS,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        FAILED,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        CARD_DENIED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fun&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; makePayment&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, resultCallback: (&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;VendorPaymentStatus&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, the vendor SDK provides a &lt;code&gt;makePayment&lt;&#x2F;code&gt; function that accepts an &lt;code&gt;amount&lt;&#x2F;code&gt; and informs the caller of the payment result through the &lt;code&gt;resultCallback&lt;&#x2F;code&gt; function argument.&lt;&#x2F;p&gt;
&lt;p&gt;If I implement a payment flow within &lt;code&gt;FeatureA&lt;&#x2F;code&gt;, it would look something like this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; FeatureA&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; constructor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    private val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; vendorSdk: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;VendorSdk&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    private val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; analyticsService: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;AnalyticsService&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    fun&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; triggerCardPayment&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, paymentResultCallback: (&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;isSuccessful&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Boolean&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        vendorSdk.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;makePayment&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount) { vendorPaymentStatus: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;VendorSdk&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.VendorPaymentStatus &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            when&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (vendorPaymentStatus) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                VendorSdk.VendorPaymentStatus.SUCCESS &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                    analyticsService.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;reportSuccessfulPayments&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;                    paymentResultCallback&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;                else -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                    analyticsService.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;reportUnsuccessfulPayments&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;                    paymentResultCallback&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This implementation looks fine. The &lt;code&gt;FeatureA&lt;&#x2F;code&gt; module has access to &lt;code&gt;VendorSdk&lt;&#x2F;code&gt;, which in turn has access to the device&#x27;s hardware for making payments. But notice how &lt;code&gt;FeatureA&lt;&#x2F;code&gt; has to adapt &lt;code&gt;VendorSdk&lt;&#x2F;code&gt;&#x27;s interface which in this case is a callback function.&lt;&#x2F;p&gt;
&lt;p&gt;There is nothing wrong with defining the &lt;code&gt;triggerCardPayment()&lt;&#x2F;code&gt; method in &lt;code&gt;FeatureA&lt;&#x2F;code&gt; to accept a callback function. The problem is that we were somehow forced to include &lt;code&gt;paymentListener&lt;&#x2F;code&gt; because the SDK requires one. That is the only way we can handle the payment result of the &lt;code&gt;VendorSdk&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This might pose a problem because our entire app depends on how to use a specific vendor SDK and how it defines a particular way of getting the result. What if we decide to move to another vendor? Changing all the feature blocks to adhere to a new interface is very time-consuming. The ideal approach when migrating to another vendor&#x27;s SDK is only to change a single point in our app.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;create-a-wrapper-class-to-abstract-a-third-party-library-s-api&quot;&gt;Create a wrapper class to abstract a third-party library&#x27;s API&lt;&#x2F;h2&gt;
&lt;p&gt;A wrapper class (or function) in programming is a container whose purpose is to call another function. It might seem redundant, but this approach introduces a few advantages to improve our code.&lt;&#x2F;p&gt;




&lt;img alt=&quot;App architecture with PaymentWrapper included&quot; title=&quot;App architecture with PaymentWrapper included&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;architecture-with-payment-wrapper.1aeeb26e86391ebb.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;architecture-with-payment-wrapper.9e1ff4def24f1d74.png 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;With this approach, we can decide how we pass and receive data between the app and the &lt;code&gt;VendorSdk&lt;&#x2F;code&gt;. This extra layer will transform data and define the interface the app expects from third-party libraries.&lt;&#x2F;p&gt;
&lt;p&gt;In rare instances when a particular third-party library has been deprecated, moving to another library will only involve changing the &lt;code&gt;Wrapper&lt;&#x2F;code&gt; container whilst keeping the features of our app the same. This is in line with the principle of &lt;em&gt;coding against interfaces, not implementations&lt;&#x2F;em&gt; where the &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt; is such an interface to one or more different third-party libraries.&lt;&#x2F;p&gt;
&lt;p&gt;Returning to our example, we might implement a &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt; that looks like this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; PaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    suspend fun&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; pay&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) : &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentResult&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    enum class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; PaymentResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        SUCCESS,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        FAILED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; VendorSdkPaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; constructor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    private val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; vendorSdk: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;VendorSdk&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;) : &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    override suspend fun&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; pay&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;): &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;PaymentResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        try&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; completableDeferred &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; CompletableDeferred&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; withTimeout&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;5_000&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                vendorSdk.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;makePayment&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount) { result &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                    when&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (result) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                        VendorSdk.VendorPaymentStatus.SUCCESS &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                            completableDeferred.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(PaymentWrapper.PaymentResult.SUCCESS)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;                        else -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                            completableDeferred.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;complete&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(PaymentWrapper.PaymentResult.FAILED)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                completableDeferred.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        } &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;catch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (e: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; PaymentWrapper.PaymentResult.FAILED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As a team decision, we may have agreed to have our payment interface return the payment result from the function call instead of through a callback function. We can transform this approach in the &lt;code&gt;VendorSdkPaymentWrapper&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;FeatureA&lt;&#x2F;code&gt; module can adapt to this interface without knowing how the vendor implements their payment flow. We could potentially write the &lt;code&gt;FeatureA&lt;&#x2F;code&gt; as follows where the &lt;code&gt;triggerCardPayment()&lt;&#x2F;code&gt; can be run on a separate coroutine (asynchronously):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; FeatureA&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; constructor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    private val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; paymentWrapper: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    private val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; analyticsService: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;AnalyticsService&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    private val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; coroutineContext: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;CoroutineContext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    suspend fun&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; triggerCardPayment&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) : &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Boolean&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        val&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; result &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; paymentWrapper.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pay&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return when&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(result) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            PaymentWrapper.PaymentResult.SUCCESS &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                analyticsService.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;reportSuccessfulPayment&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;                true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;            else -&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                analyticsService.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;reportUnsuccessfulPayment&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;                false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this particular example, this is a better approach than using a callback function because there is a chance that the callback function may never be called, rendering your app to be stuck if there are no safeguards for timeouts.&lt;&#x2F;p&gt;
&lt;p&gt;The important thing here is that the &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt; interface is dependent on your (or your team&#x27;s) decision and not decided by the third-party library that you&#x27;re using.&lt;&#x2F;p&gt;
&lt;p&gt;Now that there&#x27;s an abstraction on how we make payments, our code will be easier to change if the vendor SDK changes its implementation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;running-automated-tests-with-third-party-libraries&quot;&gt;Running automated tests with third-party libraries&lt;&#x2F;h2&gt;
&lt;p&gt;For the most part, running automated tests on an app that includes third-party libraries on emulators or simulators works fine as long as these libraries depend on common platform APIs such as Android or iOS frameworks. But what happens if a library is hardware-dependent?&lt;&#x2F;p&gt;




&lt;img alt=&quot;Running UI tests on an emulator breaks when a third-party library depends on specific hardware&quot; title=&quot;Running UI tests on an emulator breaks when a third-party library depends on specific hardware&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;ui-tests-break-on-emulator.72cdd5b7934fdf82.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;ui-tests-break-on-emulator.374b52ca5e7574d8.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;ui-tests-break-on-emulator.72cdd5b7934fdf82.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;If we want to run automation tests on an emulated device when a particular SDK only works on real devices, then using the third-party library directly will not work. In our payment app, these automation tests would fail as emulators do not have the necessary hardware for payment.&lt;&#x2F;p&gt;
&lt;p&gt;The good thing is that with the &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt; we wrote, it is easier to make testing possible by changing a few bits in our implementation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-interfaces-or-abstract-classes-when-writing-wrapper-classes&quot;&gt;Use interfaces or abstract classes when writing wrapper classes&lt;&#x2F;h3&gt;
&lt;p&gt;Use the abstract or interface construct when writing your wrapper functions or classes (as long as your framework supports it). This approach makes it easier to swap implementation whenever needed. Since we have already written &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt; as an &lt;code&gt;interface&lt;&#x2F;code&gt;, we can simply write up new implementations according to the services we need.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Different implementation of PaymentWrapper through extension&quot; title=&quot;Different implementation of PaymentWrapper through extension&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;payment-wrapper-implementations.1ea877cc6bc8732d.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;payment-wrapper-implementations.32a75c16b841b501.png 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Our app will have two instances of &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt;, one for running the real app for production and the other for running UI tests on emulators.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; UiTestPaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; : &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-keyword&quot;&gt;    override suspend fun&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; pay&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(amount: &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;): &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;PaymentWrapper&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;PaymentResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; PaymentWrapper.PaymentResult.SUCCESS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The implementation of &lt;code&gt;UiTestPaymentWrapper&lt;&#x2F;code&gt; does not depend on the &lt;code&gt;VendorSdk&lt;&#x2F;code&gt;, so we are sure that this will run on UI tests. In this example, calling the &lt;code&gt;pay()&lt;&#x2F;code&gt; method always returns a successful result. To change this result, you can introduce a &lt;code&gt;setter()&lt;&#x2F;code&gt; function and change the return value according to different test cases.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;inject-the-correct-instance-of-paymentwrapper-according-to-use-case&quot;&gt;Inject the correct instance of PaymentWrapper according to use-case&lt;&#x2F;h3&gt;




&lt;img alt=&quot;Inject the correct instance of PaymentWrapper according to use-case&quot; title=&quot;Inject the correct instance of PaymentWrapper according to use-case&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;inject-payment-wrapper.7f9fde7dba27d298.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;inject-payment-wrapper.8ed95f8623928876.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;inject-payment-wrapper.7f9fde7dba27d298.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Swapping implementations of &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt; when building the app depends on how you implement dependency management, and how these dependencies are injected into your wrappers. (For Android, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;training&#x2F;dependency-injection&#x2F;hilt-android&quot;&gt;Hilt&lt;&#x2F;a&gt; is a popular dependency injection library).&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned before, this approach also solves the problem of migrating from one vendor to another. Instead of rewriting everything, we only need to add another implementation of &lt;code&gt;PaymentWrapper&lt;&#x2F;code&gt; that adheres to the interface of the new vendor SDK. Each feature&#x27;s existing implementation and tests will be untouched because the interface never changes.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Migrate to a new library by creating a new instance of PaymentWrapper while the rest of the app remains unchanged&quot; title=&quot;Migrate to a new library by creating a new instance of PaymentWrapper while the rest of the app remains unchanged&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;migrate-to-new-library.3b484719d0d87006.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;migrate-to-new-library.3cf45a9e1282aecb.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;migrate-to-new-library.3b484719d0d87006.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Abstraction of third-party libraries can make your app more scalable, testable, and flexible when it comes to changes. Using wrapper classes as an abstraction can keep your features unchanged regardless of how a third-party library is implemented under the hood. This extra layer may seem like additional work, but the benefits of being resilient to dependency changes and testable code far outweigh the time cost.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Should I learn Flutter in 2023 - An App Developer&#x27;s edge</title>
          <pubDate>Thu, 13 Jul 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/should-i-learn-flutter-in-2023/</link>
          <guid>https://rafaelds.com/posts/should-i-learn-flutter-in-2023/</guid>
          <description xml:base="https://rafaelds.com/posts/should-i-learn-flutter-in-2023/">&lt;p&gt;&lt;strong&gt;Yes&lt;&#x2F;strong&gt;, it is worth learning Flutter app development in 2023. You get the satisfaction of creating something valuable, get paid for it, and all the other good stuff!&lt;&#x2F;p&gt;
&lt;p&gt;I want to share the benefits and advantages that you will get if you decide to learn it, or even start a career as an app developer.&lt;&#x2F;p&gt;
&lt;p&gt;This article is not only for current software engineers who want to learn a new framework but also for people without a programming background who are considering making a career shift to the world of app development.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;starting-a-career-in-software-engineering&quot;&gt;Starting a career in software engineering&lt;&#x2F;h1&gt;
&lt;p&gt;I personally did not start in the app development space. I was not even a programmer when I finished university. But after spending time learning on my own and doing side projects, I was able to build a career that is still going on for 10 years.&lt;&#x2F;p&gt;
&lt;p&gt;Some people might tell themselves they do not have what it takes to start a career writing code. I disagree. Anyone can become a software developer as long as they have these two key assets: Determination and Time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-determination&quot;&gt;1. Determination&lt;&#x2F;h2&gt;
&lt;p&gt;You need to be determined to learn new skills. You just have to want it. All information that you need to be successful is freely available on the internet, this website included! It is only yourself that&#x27;s preventing you to gain more knowledge.&lt;&#x2F;p&gt;
&lt;p&gt;You don&#x27;t need a high level of mathematics knowledge to start. Considering the requirements and gruelling interview processes posted by companies looking for software engineering candidates, I understand that it is a very bold statement. You still need to learn the fundamentals to start moving.&lt;&#x2F;p&gt;
&lt;p&gt;Knowing the fundamentals of logic theory and mathematics is essential, and is something that you will learn eventually as you start your learning journey in software development.&lt;&#x2F;p&gt;
&lt;p&gt;The catch is that you need to have the determination to start. You need to start soon.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-time&quot;&gt;2. Time&lt;&#x2F;h2&gt;
&lt;p&gt;The other requirement is time. Author Malcolm Gladwell proposed that mastery of a skill happens after spending 10,000 hours of dedicated work. This roughly translates to working on your skills for around 3 hours a day, every day, for 10 years.&lt;&#x2F;p&gt;
&lt;p&gt;While your first goal is not to be a master at first, it is important to designate a reasonable amount of time to learn how to write code, understand programming concepts, and learn the framework that we want to use.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;why-flutter&quot;&gt;Why Flutter?&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;posts&#x2F;should-i-learn-flutter-in-2023&#x2F;flutter-google.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Flutter x Google&lt;&#x2F;p&gt;
&lt;p&gt;Flutter is an open-source framework made by Google used to build apps across different platforms.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-it-s-easy&quot;&gt;1. It&#x27;s easy*&lt;&#x2F;h2&gt;
&lt;p&gt;The primary language used in Flutter is &lt;code&gt;Dart&lt;&#x2F;code&gt;. Based on my experience, &lt;code&gt;Dart&lt;&#x2F;code&gt; is a relatively easy programming language to learn, especially for developers who have worked with Java, Python, or other object-oriented languages.&lt;&#x2F;p&gt;
&lt;p&gt;Building a user interface in Flutter is straightforward. Flutter code can be described as hierarchical in nature, built from trees of basic units called Widgets. You create these widgets and combine them with each other to form beautiful screens.&lt;&#x2F;p&gt;
&lt;p&gt;The truth is, learning your first programming language may require certain changes in your perspective to understand (e.g. loops, condition statements, etc.). Flutter&#x27;s thorough examples and documentation will definitely help to get you started.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;☝🏾&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Flutter is easy given the assumption that you have been writing code before.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;2-it-runs-on-all-platforms&quot;&gt;2. It runs on all platforms&lt;&#x2F;h2&gt;
&lt;p&gt;This is the best time to write Flutter apps because of how Flutter supports development not just on mobile platforms but also on desktop and web.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;posts&#x2F;should-i-learn-flutter-in-2023&#x2F;flutter-on-different-platforms.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Flutter apps running on different platforms &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;flutter.dev&#x2F;?ref=rafaelds&quot;&gt;https:&#x2F;&#x2F;flutter.dev&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Learning just &lt;code&gt;Dart&lt;&#x2F;code&gt; and &lt;code&gt;Flutter&lt;&#x2F;code&gt; keeps your mind focused on developing features instead of learning all the bits and pieces of each platform that you want to build the app for. As they say, one code to rule them all.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-it-provides-a-smooth-development-experience&quot;&gt;3. It provides a smooth development experience&lt;&#x2F;h2&gt;
&lt;p&gt;Imagine working together with a designer while both of you are going through a prototype. Flutter makes it possible to do this seamlessly because it was built to make the development process fast as it reduces unnecessary waiting times for feedback.&lt;&#x2F;p&gt;
&lt;p&gt;Hot reload is one of the features that I like where you see your new changes in code being applied on your test device instantaneously. There is no need to wait to compile and deploy your app to see the changes which saves you a lot of time.&lt;&#x2F;p&gt;
&lt;p&gt;The framework itself is also open-source, which means a whole bunch of contributors are improving Flutter and developing useful libraries for your apps.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-edge-of-an-app-developer&quot;&gt;The Edge of an App Developer&lt;&#x2F;h1&gt;
&lt;h3 id=&quot;the-perks-you-get-as-a-flutter-developer&quot;&gt;The perks you get as a Flutter developer&lt;&#x2F;h3&gt;
&lt;h2 id=&quot;1-be-a-creator&quot;&gt;1 - Be a creator&lt;&#x2F;h2&gt;
&lt;p&gt;Humans have always been driven to create solutions. A &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;pii&#x2F;S1053811920302445?ref=rafaelds&quot;&gt;study from Drexel University&lt;&#x2F;a&gt; has shown that creating something and solving a problem invokes a certain reward response from the brain. This response produces pleasurable experiences similar to food intake, positive social experiences, addictive drugs, and orgasms. You can say that our brain rewards us for being creative.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;posts&#x2F;should-i-learn-flutter-in-2023&#x2F;thisisengineering-raeng-aL2rxQhEfAM-unsplash.jpg&quot; alt=&quot;img&quot; &#x2F;&gt;Make your idea a reality - Source: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;unsplash.com&#x2F;photos&#x2F;aL2rxQhEfAM?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Being a Flutter engineer makes you a creator. You can create solutions for other people&#x27;s problems. If you discover a problem and think of a solution, you can immediately test a solution by yourself.&lt;&#x2F;p&gt;
&lt;p&gt;Having the ability to quickly write up an app gives you the opportunity to provide instant value especially if it involves a technical approach. If you come up with an interesting business idea or even join a [hackathon](https:&#x2F;&#x2F;www.techtarget.com&#x2F;searchcio&#x2F;definition&#x2F;hackathon?ref=rafaelds#:~:text=A hackathon%2C also known as,build a new software program.), you can easily spin up a product on a browser or desktop and have something to show for it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-financial-stability&quot;&gt;2 - Financial stability&lt;&#x2F;h2&gt;
&lt;p&gt;The technology space is one of the most lucrative fields to have a career in 2024. A quick lookup at the current market in Sydney shows an &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.glassdoor.com.au&#x2F;Salaries&#x2F;software-engineer-salary-SRCH_IM962_KO0,17.htm?ref=rafaelds&quot;&gt;average salary of $130,000 AUD&lt;&#x2F;a&gt; for entry to mid-level software engineering roles. This may widely vary from where you live or your experience but it&#x27;s hard to deny the monetary opportunity it can provide.&lt;&#x2F;p&gt;
&lt;p&gt;As for Flutter-specific developer roles, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;flexiple.com&#x2F;flutter&#x2F;salary&#x2F;?ref=rafaelds&quot;&gt;Flexiple&lt;&#x2F;a&gt; has provided data from different sources that show a similar average salary in the US market.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;posts&#x2F;should-i-learn-flutter-in-2023&#x2F;flexiple-2024-salary.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Flexiple&#x27;s 2024 Flutter salary data&lt;&#x2F;p&gt;
&lt;p&gt;The game has changed now in terms of software engineering opportunities. Many tech start-ups and companies are still on the lookout for developers. Even non-technical businesses are starting to have their own digital transformation, which in turn creates high demands for engineers.&lt;&#x2F;p&gt;
&lt;p&gt;Getting a job from these companies still depends on your skills, but knowing how many tech roles there are indicates the strong demand for software engineers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-freelancing-opportunities&quot;&gt;3 - Freelancing opportunities&lt;&#x2F;h2&gt;
&lt;p&gt;Working full-time for a company might not be the best fit for you. You may have dependents or might be in a certain condition where you cannot work on a full-time schedule.&lt;&#x2F;p&gt;
&lt;p&gt;Being a Flutter developer gives you the opportunity to work on a freelance basis. Online portals such as Fiverr and UpWork have businesses looking for developers to build their apps from scratch.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;posts&#x2F;should-i-learn-flutter-in-2023&#x2F;kristin-wilson-z3htkdHUh5w-unsplash.jpg&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Maybe work in Iceland - Source: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;unsplash.com&#x2F;photos&#x2F;z3htkdHUh5w?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I had a colleague who used to move constantly from one place to another while working according to her local time zone at the time. As long as you have your computer, an internet connection, and skills, you can do your projects wherever you are.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-entrepreneurial-endeavours&quot;&gt;4 - Entrepreneurial endeavours&lt;&#x2F;h2&gt;
&lt;p&gt;Building a business is one of the many paths you can take when you start learning Flutter.&lt;&#x2F;p&gt;
&lt;p&gt;As a Flutter developer, you already have what it takes to build something that generates revenue. Whether you build an app and sell it on different app stores or have subscription-based services, your skills will give you a push to start building.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;posts&#x2F;should-i-learn-flutter-in-2023&#x2F;austin-distel-RX_0vwSPiWs-unsplash.jpg&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Deliver product fast for early feedback - Source: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;unsplash.com&#x2F;s&#x2F;photos&#x2F;startup?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can also build a start-up based on your ideas which you would pitch with an actual proof-of-concept you just built. Showing an actual app on a device is a much more effective pitch than pure speech.&lt;&#x2F;p&gt;
&lt;p&gt;Another great by-product of running a business is creating jobs for other people. While you&#x27;re earning money, you also help your team achieve financial stability. It&#x27;s a win-win situation for everyone.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;&#x2F;h1&gt;
&lt;p&gt;Many of the things I shared are based on my experiences as an app developer. I have first-hand experience with many of the points I mentioned and am still working to achieve the rest.&lt;&#x2F;p&gt;
&lt;p&gt;I hope that I have inspired you to try out app development. Whether you have a tech background or not, &lt;strong&gt;you will succeed&lt;&#x2F;strong&gt; if you dedicate your time to working on it.&lt;&#x2F;p&gt;
&lt;p&gt;Start learning Flutter and start giving value to yourself and others. Happy coding!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h1 id=&quot;references&quot;&gt;References&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;flutter.dev&#x2F;?ref=rafaelds&quot;&gt;https:&#x2F;&#x2F;flutter.dev&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;pii&#x2F;S1053811920302445?ref=rafaelds&quot;&gt;https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;pii&#x2F;S1053811920302445&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;au.talent.com&#x2F;salary?job=software+engineer&amp;amp;ref=rafaelds&quot;&gt;https:&#x2F;&#x2F;au.talent.com&#x2F;salary?job=software+engineer&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;flexiple.com&#x2F;flutter&#x2F;salary&#x2F;?ref=rafaelds&quot;&gt;https:&#x2F;&#x2F;flexiple.com&#x2F;flutter&#x2F;salary&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>What does a Flutter code structure look like to a beginner? - An Introduction</title>
          <pubDate>Wed, 28 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/what-does-a-flutter-code-structure-look-like-to-a-beginner/</link>
          <guid>https://rafaelds.com/posts/what-does-a-flutter-code-structure-look-like-to-a-beginner/</guid>
          <description xml:base="https://rafaelds.com/posts/what-does-a-flutter-code-structure-look-like-to-a-beginner/">&lt;p&gt;Back when I started learning Flutter app development many years ago, I was surprised at how the code structure of Flutter was presented. When I learned that you only need &lt;code&gt;Dart&lt;&#x2F;code&gt; code to make Flutter apps, this concept of a single language to encompass both &lt;em&gt;View logic&lt;&#x2F;em&gt; and &lt;em&gt;Business logic&lt;&#x2F;em&gt; was foreign to me.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Messy, brackets, nesting hell. It&amp;#x27;s a mess!&quot; title=&quot;Messy, brackets, nesting hell. It&amp;#x27;s a mess!&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;hello-world-example-flutter.8903255f478e413b.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;hello-world-example-flutter.3344dbf334de25fd.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;hello-world-example-flutter.8903255f478e413b.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;The first time I looked at the &lt;code&gt;Hello World&lt;&#x2F;code&gt; Flutter code example, I shrugged my head and said to myself how absurd this is. Because I was a more naive developer back then, looking at the hello world app in &lt;em&gt;one file&lt;&#x2F;em&gt;, and in &lt;em&gt;one language&lt;&#x2F;em&gt; made me think how bad this design was.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, I was wrong. Not only can you separate these logic blocks cleanly, but this design decision also made Flutter one of the easiest app-development frameworks to learn these days.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;this-nested-flutter-code&quot;&gt;This nested Flutter code&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s great to look at a source code that clearly tells you exactly what it does. Let&#x27;s look at an example of a UI element I wrote using Flutter.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Job Advertisement Card&quot; title=&quot;Job Advertisement Card&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-widget-flutter.8dc4b0606739cd2b.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-widget-flutter.3c4070b6175afb31.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-widget-flutter.8dc4b0606739cd2b.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Now, without knowing how to read or write &lt;code&gt;Dart&lt;&#x2F;code&gt; code or not knowing what a &lt;code&gt;Widget&lt;&#x2F;code&gt; is, let&#x27;s see if you can understand this nested code and what it represents.&lt;&#x2F;p&gt;




&lt;img alt=&quot;The Job Advertisement Card written in Dart&quot; title=&quot;The Job Advertisement Card written in Dart&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-card-simple-code.e98fa21e092b20f4.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-card-simple-code.45f8da91bb75ab14.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-card-simple-code.e98fa21e092b20f4.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;To me, this code is straightforward when it comes to telling me how this job advertisement card is implemented. It is a nest of objects where each object can have a &lt;code&gt;child&lt;&#x2F;code&gt; or &lt;code&gt;children&lt;&#x2F;code&gt; if it is more than one. A &lt;code&gt;Row&lt;&#x2F;code&gt; arranges its children horizontally, a &lt;code&gt;Column&lt;&#x2F;code&gt; vertically, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;You might already have a clue, but the &lt;code&gt;StarRating&lt;&#x2F;code&gt; object there is made of a few nested objects as well.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: Paddings and spacings are implemented within the objects in the sample code for simplification and demonstration purposes.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Thinking back on my first look at the &lt;code&gt;Hello World&lt;&#x2F;code&gt; example from the Flutter team made me realise that any code can be refactored and improved to be more readable and reusable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;widgets-everywhere&quot;&gt;Widgets everywhere&lt;&#x2F;h2&gt;
&lt;p&gt;Another popular saying in the Flutter community is &lt;em&gt;&quot;Everything in Flutter is a Widget&quot;&lt;&#x2F;em&gt;. While it is not technically 100% true, there is still some truth to that.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Everything in Flutter is a Widget, sort of.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;A Flutter &lt;code&gt;Widget&lt;&#x2F;code&gt; is the basic unit of the user interface in Flutter. It can be described as a &lt;em&gt;unit of composition&lt;&#x2F;em&gt; and &lt;em&gt;the building block of a Flutter app&lt;&#x2F;em&gt;. Almost everything that you see in a Flutter app is a &lt;code&gt;Widget&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Using the example above, the &lt;code&gt;Row&lt;&#x2F;code&gt;, &lt;code&gt;Column&lt;&#x2F;code&gt;, and so on are &lt;code&gt;Widgets&lt;&#x2F;code&gt;. The way they are arranged together, the nesting of parent and child &lt;code&gt;Widgets&lt;&#x2F;code&gt;, is called a &lt;code&gt;Widget Tree&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Job ad widget tree&quot; title=&quot;Job ad widget tree&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-widget-tree.dceb34c6b7ac3752.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-widget-tree.8de4784c61db7c4a.png 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;It is important for us developers to know this tree structure because we will need to pass data from one &lt;code&gt;Widget&lt;&#x2F;code&gt; to another, and knowing how our app is structured helps us plan how to do so.&lt;&#x2F;p&gt;
&lt;p&gt;This widget tree also plays a significant role when it comes to speed and memory optimisation. This involves two more sets of trees called &lt;code&gt;Element Tree&lt;&#x2F;code&gt; and &lt;code&gt;RenderObject Tree&lt;&#x2F;code&gt;, but is out of scope and will be discussed in another article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;flutter-s-composability&quot;&gt;Flutter&#x27;s composability&lt;&#x2F;h2&gt;
&lt;p&gt;Take a look again at our job card code and widget tree. It is very much simplified and is composed of a few widgets. The Flutter framework was designed with the composition and reusability of &lt;code&gt;Widgets&lt;&#x2F;code&gt; in mind. Of course, there are proper ways to nest &lt;code&gt;Widgets&lt;&#x2F;code&gt; but for now, it is best to understand that you can.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Job ad widgets&amp;#x27; composition of basic widgets&quot; title=&quot;Job ad widgets&amp;#x27; composition of basic widgets&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-widget-composition.d293a1210bb5c45b.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-widget-composition.3ff1a7753b95f47c.png 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Some of the widgets that you see in the job card widget tree were built from other widgets. The &lt;code&gt;StarRating&lt;&#x2F;code&gt; widget for example is implemented using a &lt;code&gt;Row&lt;&#x2F;code&gt; with children composed of &lt;code&gt;Image&lt;&#x2F;code&gt; widgets.&lt;&#x2F;p&gt;
&lt;p&gt;While this is a common pattern that you&#x27;ll see in general software design, Flutter under the hood has its own optimisations in which changing a widget&#x27;s state may or may not rebuild the other widgets in the tree. (See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;flutter-community&#x2F;the-layer-cake-widgets-elements-renderobjects-7644c3142401&quot;&gt;Frederik&#x27;s layer cake explanation&lt;&#x2F;a&gt; for a deep-dive explanation).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;user-input&quot;&gt;User input&lt;&#x2F;h2&gt;
&lt;p&gt;The last thing I want to talk about is how Flutter handles user inputs such as button clicks, scrolls, drag, and so on. &lt;code&gt;Widgets&lt;&#x2F;code&gt; such as &lt;code&gt;Button&lt;&#x2F;code&gt; can accept input through an &lt;code&gt;onAction()&lt;&#x2F;code&gt; function callback which varies depending on which input &lt;code&gt;Widget&lt;&#x2F;code&gt; you use.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Any widget can accept user inputs&quot; title=&quot;Any widget can accept user inputs&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-card-user-input.799e1472940bf918.png&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-card-user-input.88bd61808597fe7c.png 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;job-ad-card-user-input.799e1472940bf918.png 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;For widgets that don&#x27;t have user inputs, one can just wrap this widget around with something like a &lt;code&gt;GestureDetector&lt;&#x2F;code&gt; widget, and decide which inputs you want your widget to receive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-remarks&quot;&gt;Closing remarks&lt;&#x2F;h2&gt;
&lt;p&gt;There is so much ground to cover in Flutter, like changing a &lt;code&gt;Widget&lt;&#x2F;code&gt; properties such as changing colour, size, and text (hint: Flutter state management) and we will discuss that eventually. I hope you learned something from this short introductory article about what a Flutter code structure looks like.&lt;&#x2F;p&gt;
&lt;p&gt;If you are new to Flutter or someone who is interested to jump into Flutter development, I guarantee that you will have a pleasant experience learning and building apps that are ready to be deployed on mobile devices, desktop devices, and even the web.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;api.flutter.dev&#x2F;flutter&#x2F;widgets&#x2F;Widget-class.html&quot;&gt;https:&#x2F;&#x2F;api.flutter.dev&#x2F;flutter&#x2F;widgets&#x2F;Widget-class.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;flutter-community&#x2F;the-layer-cake-widgets-elements-renderobjects-7644c3142401&quot;&gt;https:&#x2F;&#x2F;medium.com&#x2F;flutter-community&#x2F;the-layer-cake-widgets-elements-renderobjects-7644c3142401&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.flutter.dev&#x2F;resources&#x2F;architectural-overview&quot;&gt;https:&#x2F;&#x2F;docs.flutter.dev&#x2F;resources&#x2F;architectural-overview&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Transforming themobilecoder to rafaelds, and the other way around</title>
          <pubDate>Thu, 08 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/transforming-themobilecoder-to-rafaelds-and-the-other-way-around/</link>
          <guid>https://rafaelds.com/posts/transforming-themobilecoder-to-rafaelds-and-the-other-way-around/</guid>
          <description xml:base="https://rafaelds.com/posts/transforming-themobilecoder-to-rafaelds-and-the-other-way-around/">&lt;p&gt;Here&#x27;s an update for those looking 👀 into my page.&lt;&#x2F;p&gt;
&lt;p&gt;I got a notification in my email that my domain rafaelds dot com is expring.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what&quot;&gt;What?&lt;&#x2F;h3&gt;
&lt;p&gt;I did not know that I &lt;em&gt;HAVE&lt;&#x2F;em&gt; this domain! It&#x27;s short and sweet.&lt;&#x2F;p&gt;
&lt;p&gt;So for now, I will make my personal one use &lt;code&gt;rafaelds.com&lt;&#x2F;code&gt;, whilst my &lt;code&gt;themobilecoder.com&lt;&#x2F;code&gt; domain will be used for my Flutter-centric blog.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The new mobilecoder website</title>
          <pubDate>Tue, 07 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/the-new-mobilecoder-website/</link>
          <guid>https://rafaelds.com/posts/the-new-mobilecoder-website/</guid>
          <description xml:base="https://rafaelds.com/posts/the-new-mobilecoder-website/">&lt;p&gt;I made a decision to migrate my website &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;rafaelds.com&quot;&gt;rafaelds.com&lt;&#x2F;a&gt; from Bluehost&#x2F;Wordpress into a static site generator.&lt;&#x2F;p&gt;
&lt;p&gt;I am now using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.11ty.dev&#x2F;&quot;&gt;eleventy&lt;&#x2F;a&gt; as my tool to build my website. Since it is a static site generator, I have to update my source code and redeploy to my server every time I want my changes to be public. This includes new posts such as this one.&lt;&#x2F;p&gt;
&lt;p&gt;This change gives me more flexibility in what I want to do with my content.&lt;&#x2F;p&gt;
&lt;p&gt;Special thanks to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.lenesaile.com&#x2F;en&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.lenesaile.com&#x2F;en&#x2F;&lt;&#x2F;a&gt; for sharing a beautiful Eleventy template!&lt;&#x2F;p&gt;
&lt;p&gt;Ta!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Flutter hackathon #hack20 journey</title>
          <pubDate>Mon, 06 Jul 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/flutter-hackathon-hack20-journey/</link>
          <guid>https://rafaelds.com/posts/flutter-hackathon-hack20-journey/</guid>
          <description xml:base="https://rafaelds.com/posts/flutter-hackathon-hack20-journey/">&lt;p&gt;I will share in this post how our Flutter hackathon #hack20 journey was. This is an anecdote on how the whole experience was for me and my team.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hack20-background&quot;&gt;#hack20 background&lt;&#x2F;h2&gt;
&lt;p&gt;#hack20 is the second of the annual Flutter hackathon hosted by the Flutter community that happened from 27-29th of June 2020. While it is not an official Google event, it is backed and sponsored by Google and other big companies in the field.&lt;&#x2F;p&gt;
&lt;p&gt;Basically, you think of a project that you can create using Flutter. You then form a team or work on your own for 48 hours before you submit your project. Top 20 winners get prizes, with the first place getting a $4000 worth of electronic setup.&lt;&#x2F;p&gt;
&lt;p&gt;The theme of your project can be &lt;strong&gt;Saving the Planet or Retro&#x2F;Cyberpunk&lt;&#x2F;strong&gt;. There were around ~2600 participants, 650 teams and ~250 submitted projects&lt;&#x2F;p&gt;
&lt;h2 id=&quot;did-you-win&quot;&gt;Did you win?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;No, we did not&lt;&#x2F;strong&gt; 😂. There were two rounds of voting, and all participating teams get to vote on other teams&#x27; projects. We luckily managed to reach the final round (one of the 90 teams), but that was it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-project&quot;&gt;The project&lt;&#x2F;h2&gt;
&lt;p&gt;You can checkout our code in this &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;InkRibbonApp&#x2F;inkribbonflutter&quot;&gt;github repository&lt;&#x2F;a&gt;. You can also try it on web &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;inkribbon-cd2f7.web.app&#x2F;&quot;&gt;from here&lt;&#x2F;a&gt;, though some of the features are not really optimised for browsers. Make sure to use landscape! Also, exporting PDF on web sometimes work!&lt;&#x2F;p&gt;
&lt;p&gt;On top of that, here is the video that we almost did not submit due to iMovie crashing 30 minutes before the deadline.&lt;&#x2F;p&gt;
&lt;div class=&quot;yt&quot;&gt;&lt;iframe src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;KS8G8Mi8MFA&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;&lt;&#x2F;div&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;the-team&quot;&gt;The team&lt;&#x2F;h2&gt;
&lt;p&gt;Our team of three is called &lt;strong&gt;GMT+10&lt;&#x2F;strong&gt;. We chose that name because we all work together here in Sydney, AU. The three of us are all Android developers who believed that we should use Flutter in our company app!&lt;&#x2F;p&gt;
&lt;p&gt;We believe that we are at a slight disadvantage because of timezones. The official time started at Saturday, 10:00 PM Sydney local time and will end at Monday 10:00 pm. So following the rules, we only have around 24 hours with sleep because we have a day job on a Monday.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;day-1-ideation&quot;&gt;Day 1 - Ideation&lt;&#x2F;h2&gt;
&lt;p&gt;This is the fun part in my opinion. This is where we tried to think of ideas that can either be fun to use or just plain helpful to others. We used Invision to draw out and gather different ideas and suggestions, because all of us were working together remotely.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Our sketch before we started writing code&quot; title=&quot;Our sketch before we started writing code&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;invisonscreenshot.3a97a7ecf17ed4e2.jpg&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;invisonscreenshot.d3f3ea57ce0a38e7.jpg 512w, https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;invisonscreenshot.3a97a7ecf17ed4e2.jpg 1024w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;At the same time, this is the hardest part of the hackathon. There are so many considerations while we were thinking of possible projects.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Is it doable in 48 hours?&lt;&#x2F;li&gt;
&lt;li&gt;Will people use it?&lt;&#x2F;li&gt;
&lt;li&gt;Has anyone already made one?&lt;&#x2F;li&gt;
&lt;li&gt;Will someone possibly have the same project?&lt;&#x2F;li&gt;
&lt;li&gt;Will it look presentable on the demo?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Each of these points are valid considerations. At the time, we did not know how voting will work, but I realized after that the video of the demo is the most important part of it.&lt;&#x2F;p&gt;
&lt;p&gt;On top of that, we avoided projects that other people will most likely make e.g. Recycling App, Retro Games, COVID tracing, etc.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;P.S. The winner of the hackathon was actually a retro game (Game and Watch)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;day-2-making-the-app&quot;&gt;Day 2 - Making the app&lt;&#x2F;h2&gt;
&lt;p&gt;This day is how we spent our time making the app. We were using Zoom to be constantly together. While everyone worked on every part of the code base, each one of us has a specific focus.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;app-design&quot;&gt;App design&lt;&#x2F;h3&gt;
&lt;p&gt;As a disclaimer, I am in no means a designer. None of us in the team claimed to be. Therefore, our approach is to make the best design we can do with our skills. In order to do this, we have to go for the simplest thing we could do.&lt;&#x2F;p&gt;
&lt;p&gt;If you had a look at our ideation page above, the typewriter app would look something like this.&lt;&#x2F;p&gt;




&lt;img alt=&quot;The keyboard is not even centered!&quot; title=&quot;The keyboard is not even centered!&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;raw-typewriter.b0db50fb6f8ec9cf.jpg&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;raw-typewriter.cf691623e513188e.jpg 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Because I have prior experience in using Sketch for images in my blog, I volunteered to make the designs and export them as assets.&lt;&#x2F;p&gt;
&lt;p&gt;One of the main source of assets that I used was &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;undraw.co&#x2F;&quot;&gt;unDraw&lt;&#x2F;a&gt;. They are open source and don&#x27;t even require to cite them as sources. And if you haven&#x27;t already, don&#x27;t forget to give them a shoutout through twitter. I am sure that most of you have used one or two of their images.&lt;&#x2F;p&gt;
&lt;p&gt;I get these images, and modify them as I go. Even our app logo was derived from it. This is how my Sketch board looks like during the hackathon.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Messy messy sketchboard&quot; title=&quot;Messy messy sketchboard&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;sketch-design.a4b2fadbe9637489.jpg&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;sketch-design.6325df3fa7bddb3d.jpg 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;h3 id=&quot;keyboard-design&quot;&gt;Keyboard design&lt;&#x2F;h3&gt;
&lt;p&gt;I designed the keyboard using Sketch. The idea is not an original one from me, as I have to look at how a typewriter keyboard would look in a mobile app. We used the top typewriter app in Play Store as a guide. Looking at our InVision screenshot again, here is what we used as a reference.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Existing typewriter app in Android&quot; title=&quot;Existing typewriter app in Android&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;android-typewriter.a9502851ff9068e4.jpg&quot; srcset=&quot;&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Now, the dreaded part is to design our own keyboard. I didn&#x27;t have much time and experience in doing this efficiently, so I had to quickly look for tutorials on how to do this properly.&lt;&#x2F;p&gt;
&lt;p&gt;In Sketch, there is a thing called &lt;strong&gt;Symbol&lt;&#x2F;strong&gt;, where it is like a master copy of a design. It means that if I change this master copy, all the designs that use this will also update. Here is what I had in Sketch.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Far from perfect but I&amp;#x27;m proud of it :)&quot; title=&quot;Far from perfect but I&amp;#x27;m proud of it :)&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;master-key.54db9e1254830ab3.jpg&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;master-key.57fd0a4a532ab9bf.jpg 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Using that symbol, I had to make each key that will be present in the keyboard. The letters in the keyboard has to change their cases too, so I have to account for that as well. Never forget all those numbers and symbols!&lt;&#x2F;p&gt;




&lt;img alt=&quot;I already feel tired looking at it&quot; title=&quot;I already feel tired looking at it&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;keys.4224d633c7de903a.jpg&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;keys.18ce2a467cf7c25a.jpg 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;h3 id=&quot;writing-the-code&quot;&gt;Writing the code&lt;&#x2F;h3&gt;
&lt;p&gt;For the most part, I wrote the code for the typewriter keyboard. It was far from perfect, and not really using any patterns such as BLoC.&lt;&#x2F;p&gt;
&lt;p&gt;What I did however is to make it reusable. The typewriter keyboard widget is just a normal Flutter widget that allows you to listen to keystroke events.&lt;&#x2F;p&gt;
&lt;p&gt;It means that user of this keyboard just needs to pass a TypewriterKeyboardController, listen to keys being pressed and process it elsewhere in the code. Here is an actual snippet of our main screen using the typewriter keyboard and controller.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;dart&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;@override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; initState&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  super&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;initState&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  _typewriterKeyboardController &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; TypewriterKeyboardController&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  _typewriterKeyboardController&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;textStream&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;listen&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(_onTextReceived)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-annotation&quot;&gt;@override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-class&quot;&gt;Widget&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; build&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;BuildContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; Scaffold&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    appBar&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; AppBar&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      leading&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; BackButton&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    bottomSheet&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt; TypewriterKeyboard&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      typewriterKeyboardController&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _typewriterKeyboardController&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; _onTextReceived&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; text) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;   final&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; textValue &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;toLowerCase&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;   switch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (textValue) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;      &#x2F;&#x2F;Update EditText&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;&#x2F; © themobilecoder&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Again, this could be further refactored, such that the logic to handle keys would be on a BLoC or a different service class. Given the time and pressure, we just wrote what would work at the time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;code-collaboration&quot;&gt;Code collaboration&lt;&#x2F;h3&gt;
&lt;p&gt;This can a bit inconvenient sometimes. Each of us have our own style of writing code. While there is really no right or wrong with style, it is important to have a consistent way of structuring and formatting code within a codebase.&lt;&#x2F;p&gt;
&lt;p&gt;One example is line formatting. I personally prefer putting commas at the end of a Flutter tree code so it would look like a tree when auto format happens. Some of us however prefer to make it single line if it&#x27;s short enough.&lt;&#x2F;p&gt;
&lt;p&gt;Due to these inconsistencies, a small commit &lt;strong&gt;might end up having a large changeset due to spaces and formatting&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we write code in Android, we will definitely have consistent style of writing code as we have been pair programming at work, and everyone just syncs with each other.&lt;&#x2F;p&gt;
&lt;p&gt;The good thing with what we did is that we barely stepped on each others&#x27; toes. We split our work by features, such that one is working with Firebase authentication and the other is on exporting and viewing PDFs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;day-3-ish-submitting-the-project&quot;&gt;Day 3-ish - Submitting the project&lt;&#x2F;h2&gt;
&lt;p&gt;The team was able to barely finish the app on Sunday evening. The problem is that the deadline will be at 10:00 pm Monday. We have our daily job on a weekday, so we only have the Monday afternoon to finish the video.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;making-the-video&quot;&gt;Making the video&lt;&#x2F;h3&gt;
&lt;p&gt;We had an idea of just showing in the video how the app works, but it is &lt;strong&gt;so damn boring to present a note taking app with a typewriter design.&lt;&#x2F;strong&gt; I mean yeah, there&#x27;s Firebase integration so you can save your notes online, but every other note app does the same thing!&lt;&#x2F;p&gt;
&lt;p&gt;We already know that we are not going to win &lt;em&gt;(not with that attitude)&lt;&#x2F;em&gt;. Our last saving grace is to just make a good video, and that&#x27;s what we tried to achieve.&lt;&#x2F;p&gt;
&lt;p&gt;Our solution is to select a really dramatic music that still sits well with the app, with a great message written in the note. Since we already knew we will never going to win, we decided to just write a message that wishes everyone good luck.&lt;&#x2F;p&gt;
&lt;p&gt;We were sure that other teams will be writing apps that will help save the planet, so that&#x27;s where we focused on. We spent a fair amount of time looking for a good music and thinking about a message.&lt;&#x2F;p&gt;
&lt;p&gt;If you have not watched the video above, here is the message in our video.&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;video src=&quot;typewriter-message.mp4&quot; controls preload=&quot;metadata&quot; style=&quot;max-width: 100%&quot;&gt;&lt;&#x2F;video&gt;
  &lt;figcaption&gt;Our message to the hackathon participants&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;exporting-the-video&quot;&gt;Exporting the video&lt;&#x2F;h3&gt;
&lt;p&gt;Exporting the whole video gave us all a mild heart attack. It was &lt;strong&gt;30 minutes&lt;&#x2F;strong&gt; before the deadline, and we just started exporting this movie project to a video file.&lt;&#x2F;p&gt;
&lt;p&gt;As someone who has not exported a 1-minute long video on a 6 year old laptop, this was a new experience for me. Our saving grace to our simple app is going down the drain as we saw this image. Oh, I could have benefited from the new Macbook prize 😂&lt;&#x2F;p&gt;
&lt;p&gt;We are in a dilemma because if I just force shutdown iMovie, it might take another 30 minutes to export. We are also not quite sure if we have saved the movie project, because &lt;strong&gt;iMovie does not have a manual Save function!!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, the project was auto saved. One of my teammate was using a newer Macbook, so we thought of just copying the iMovie project (which was hard to locate btw), send it to him with our amazing Australian internet speed, and let him do the file export.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-miracle&quot;&gt;The miracle&lt;&#x2F;h3&gt;
&lt;p&gt;While we are waiting for a miracle, my other team mate started to export the video in his laptop. I was browsing the Slack channel for this Flutter hackathon and saw a message that kept our hopes up.&lt;&#x2F;p&gt;




&lt;img alt=&quot;Just in time!&quot; title=&quot;Just in time!&quot; src=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;deadline-extension.d442c8417d2f9aad.jpg&quot; srcset=&quot;https:&#x2F;&#x2F;rafaelds.com&#x2F;processed_images&#x2F;deadline-extension.7f1011631a3fd814.jpg 512w&quot; class=&quot;&quot; &#x2F;&gt;

&lt;p&gt;Now that we have an additional hour to submit our video, we knew that we will be able to sleep well that night.&lt;&#x2F;p&gt;
&lt;p&gt;Even before my teammates video export, iMovie successfully exported the video. However, iMovie didn&#x27;t recover so I just shut it down. If you have a dinosaur laptop like I do, stay away from iMovie.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;&#x2F;h2&gt;
&lt;p&gt;It was a fun hackathon experience. I was coughing the whole time during the hackathon, so it was fun but not entirely a pleasant experience.&lt;&#x2F;p&gt;
&lt;p&gt;My teammates and I just proved that Flutter is a great tool to develop apps reliably on most platforms, including web. It will be a long stretch to convince our teammates in the office how much Flutter can do, but it does not matter.&lt;&#x2F;p&gt;
&lt;p&gt;I honestly learned a lot more in doing designs in Sketch. This is a skill that I really want to improve.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, I am really impressed with the app ideas of the other participants, especially the ones with the &lt;strong&gt;Save the Environment&lt;&#x2F;strong&gt; theme.&lt;&#x2F;p&gt;
&lt;p&gt;Congratulations to everyone that won, and see you next hackathon!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;links&quot;&gt;Links&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=KS8G8Mi8MFA&quot;&gt;Promotional video&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;InkRibbonApp&#x2F;inkribbonflutter&quot;&gt;Github project repo&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;inkribbon-cd2f7.web.app&quot;&gt;Demo web app&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>I started building a radio app</title>
          <pubDate>Sat, 04 Apr 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://rafaelds.com/posts/i-started-building-a-radio-app/</link>
          <guid>https://rafaelds.com/posts/i-started-building-a-radio-app/</guid>
          <description xml:base="https://rafaelds.com/posts/i-started-building-a-radio-app/">&lt;p&gt;I started writing a radio app following the tutorial on making a radio app in Flutter that I recently published. I was inspired to make one as I wanted to publish a radio app for iOS and Android devices.&lt;&#x2F;p&gt;
&lt;p&gt;Although still in its early stages, I am planning to release this soon to both App Store and Google Play stores.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;current-features&quot;&gt;Current features&lt;&#x2F;h3&gt;
&lt;p&gt;At the time of writing (4th April, 2020), the radio app is at least able to play an online radio station. You can also choose which country to get stations from and bookmark them.&lt;&#x2F;p&gt;
&lt;p&gt;I have used the most basic and vanilla design I can think just so I can push more features early on. No fancy animations yet!&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;video src=&quot;playthrough.mov&quot; controls preload=&quot;metadata&quot; style=&quot;max-width: 240px&quot;&gt;&lt;&#x2F;video&gt;
  &lt;figcaption&gt;Radio playthrough&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Here are some of the features that are already in the app worth mentioning:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Works on both iOS and Android&lt;&#x2F;li&gt;
&lt;li&gt;Can play radio station on the background (even when the phone is locked)&lt;&#x2F;li&gt;
&lt;li&gt;Can play &#x2F; pause radio from the lock screen&lt;&#x2F;li&gt;
&lt;li&gt;Bookmark a radio station&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;challenges&quot;&gt;Challenges&lt;&#x2F;h3&gt;
&lt;p&gt;I found out that the simple things are the ones difficult to implement. It took me a while to fix simple issues just to make the experience of using the app better, even if they seem very easy to do.&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;video src=&quot;add-favourite.mov&quot; controls preload=&quot;metadata&quot; style=&quot;max-width: 240px&quot;&gt;&lt;&#x2F;video&gt;
  &lt;figcaption&gt;Features&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;Things like consistency between parts of the screens in the app for example. Pressing the heart button in the media player should update the favourites screen. At the same time, if I remove the station in the favourites screen, the heart button in the media player should be updated too.&lt;&#x2F;p&gt;
&lt;p&gt;Another example is showing screens in between stages of the app. The app should show important information such as telling the user that there are no stations saved (instead of just showing a blank canvas). Or letting the user know that the app is still getting the list of radio stations by showing a loading spinner.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;features-to-be-added-soon&quot;&gt;Features to be added soon&lt;&#x2F;h3&gt;
&lt;p&gt;The app still needs a lot of polishing and updates before I publish it. These are some of the features I might add before I release the app to the public&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Make the UI more beautiful&lt;&#x2F;li&gt;
&lt;li&gt;Add simple animations&lt;&#x2F;li&gt;
&lt;li&gt;Add a screen to show the radio information&lt;&#x2F;li&gt;
&lt;li&gt;Get stations by genre (news, rock, country, etc.)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h3&gt;
&lt;p&gt;That is it for the update! Writing this app has been both a joy and a pain in the butt, but (double pun) I will still continue and finish this up for everyone to use.&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
