<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>7om Tech</title>
    <description>Crafting top-notch mobile experiences with over 10 years in Android and now in Flutter. Quality and innovation at the heart of every app journey.</description>
    <link>https://7omtech.fr/</link>
    <atom:link href="https://7omtech.fr/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Tue, 30 Dec 2025 16:13:35 +0000</pubDate>
    <lastBuildDate>Tue, 30 Dec 2025 16:13:35 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Newton Evolution</title>
        <description>&lt;p&gt;Recently I received an email from a developer asking me if he could take over
the maintenance of Newton Particles. On one side I was happy cause someone was
interested enough to keep the flame of Newton, on the other hand, I was thinking
“damn” I have so many features I still want to implement to make Newton a
rockstar particle library. If you read
&lt;a href=&quot;https://7omtech.fr/2025/12/mowgli/&quot;&gt;my previous post&lt;/a&gt; I had quite hell for 2
years building a poker app for Betclic. Now I’m moving to another project, I
wanted to enjoy the calm of the end of the year to get back to work on Newton.&lt;/p&gt;

&lt;p&gt;Today I’m happy to announce Newton 0.3.0 is released.&lt;/p&gt;

&lt;h2 id=&quot;particles-interaction-with-widgets&quot;&gt;Particles interaction with Widgets&lt;/h2&gt;

&lt;p&gt;Now particles can interact with your app widgets. For example, if you want your
particles to bounce off your buttons, it’s doable and easy. Just use a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NewtonCollider&lt;/code&gt; and wrap your widget with it and that’s all:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Newton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;effectConfigurations:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RainPreset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;child:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;children:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;NewtonCollider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;borderRadius:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BorderRadius&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;circular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;child:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;height:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;decoration:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BoxDecoration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;borderRadius:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BorderRadius&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;circular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;video width=&quot;600&quot; controls=&quot;&quot; style=&quot;max-width: 100%; height: auto;&quot;&gt;
  &lt;source src=&quot;/videos/2025-12-30-newton-evolution/newton_collider.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  Your browser does not support the video tag.
&lt;/video&gt;

&lt;h2 id=&quot;copy-code-from-configurator&quot;&gt;Copy code from configurator&lt;/h2&gt;

&lt;p&gt;From the beginning you can directly test building an animation with the
configurator. There are still some limitations, you cannot add a post effect
animation but now you can directly copy the code when you are satisfied with an
animation.&lt;/p&gt;

&lt;h2 id=&quot;introduction-of-presets&quot;&gt;Introduction of Presets&lt;/h2&gt;

&lt;p&gt;To be honest my main concern when developing Newton was to have a highly
configurable but also easy to use library. The first objective seems to be met
but not the second one. You needed to tweak 30+ properties to get the perfect
animation. Having presets allows you to have a good starting point to start an
animation. If you have an idea for animations feel free to open a PR.&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Newton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;effectConfigurations:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;RainPreset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;api-coherence&quot;&gt;API coherence&lt;/h2&gt;

&lt;p&gt;The configuration API was a bit messy. You had properties scattered around and
it wasn’t always clear where to find what you needed. I reorganized everything
into logical groups like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PhysicsProperties&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VisualProperties&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmissionProperties&lt;/code&gt;, and so on. It makes the code more type-safe and easier to
navigate.&lt;/p&gt;

&lt;p&gt;I also renamed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RelativisticEffect&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PhysicsEffect&lt;/code&gt; because let’s be honest,
the name was confusing.&lt;/p&gt;

&lt;h1 id=&quot;performance-improvements&quot;&gt;Performance improvements&lt;/h1&gt;

&lt;p&gt;I pushed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Box2D&lt;/code&gt; to reach the limits from 150 to nearly 300 particles with
constant FPS. I won’t be able to go further with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Box2D&lt;/code&gt; but to be honest I’m
not satisfied…&lt;/p&gt;

&lt;p&gt;But I did add viewport culling, which means particles outside the visible area
are automatically removed from calculations. This helps a lot when you have
particles flying off screen. I also optimized the rendering pipeline and
improved how colliders report their positions to reduce unnecessary work.&lt;/p&gt;

&lt;p&gt;There’s also a new particle pool system that reuses particles instead of
constantly creating and destroying them. It’s more memory efficient and should
help with performance on lower-end devices.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;p&gt;To be honest when I started this library I wanted to be able to have 1000+
particles to be able to add really neat and unique animations to your app.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Box2D&lt;/code&gt; seems to have reached a hard cap and
&lt;a href=&quot;https://github.com/tguerin/newton/issues/50&quot;&gt;I’m investigating other engines to
reach this goal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have ideas or want to help with this investigation, feel free to jump in.
I’m also open to suggestions for new presets or features that would make Newton
even better.&lt;/p&gt;

&lt;p&gt;You can check out the full documentation at
&lt;a href=&quot;https://newton.7omtech.fr/&quot;&gt;https://newton.7omtech.fr/&lt;/a&gt; and the source code on
&lt;a href=&quot;https://github.com/tguerin/newton&quot;&gt;GitHub&lt;/a&gt;. As always, feedback and
contributions are welcome!&lt;/p&gt;
</description>
        <pubDate>Tue, 30 Dec 2025 08:00:00 +0000</pubDate>
        <link>https://7omtech.fr/2025/12/newton-evolution/</link>
        <guid isPermaLink="true">https://7omtech.fr/2025/12/newton-evolution/</guid>
        
        <category>Flutter</category>
        
        <category>Flutter lib</category>
        
        <category>Particles</category>
        
        
        <category>Flutter Programming</category>
        
      </item>
    
      <item>
        <title>All-in on Flutter</title>
        <description>&lt;p&gt;One year ago, almost to the day, the new Betclic poker experience was released:
the result of months of hard work, risk-taking, and a whole lot of Flutter
magic.&lt;/p&gt;

&lt;p&gt;And now, on this anniversary, it feels like the perfect moment to share my
personal perspective on that journey. I even considered making a video, before
remembering that I actually have a blog… one that’s been gathering dust for over
a year. Time to bring it back to life.&lt;/p&gt;

&lt;p&gt;So, I sat down, opened a blank page, and began retracing the journey.&lt;/p&gt;

&lt;p&gt;Let me tell you the incredible story of Project Codename: &lt;strong&gt;Mowgli&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;preambule&quot;&gt;Preambule&lt;/h2&gt;

&lt;p&gt;Once upon a time, a young and adventurous Android developer living in Paris
decided to go on a world tour with his girlfriend.&lt;/p&gt;

&lt;p&gt;We took our first flight on &lt;strong&gt;June 2022&lt;/strong&gt;, and &lt;em&gt;flash forward&lt;/em&gt; nine months
later, we were in &lt;strong&gt;Kuala Lumpur, Malaysia&lt;/strong&gt;. That’s when my existential crisis
started:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What do I want to do?&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Where do I want to live?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The second question was easy, we really wanted to move to &lt;strong&gt;Bordeaux&lt;/strong&gt; to escape
the crazy life of Paris.&lt;br /&gt;
But the first one… that was tougher.&lt;/p&gt;

&lt;p&gt;Did I want to become a doctor, raise sheep in the Pyrenees, or become a fucking
awesome blacksmith forging magical swords and hunting deadly monsters?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/2025-08-10-mowgli/choice.png&quot; data-lightbox=&quot;gallery&quot; data-title=&quot;Hard Choice&quot;&gt;
  &lt;img src=&quot;/images/2025-08-10-mowgli/choice.png&quot; alt=&quot;Hard Choice&quot; style=&quot;width: 600px; height: auto; cursor: pointer;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of those felt right. After 15 years of building Android apps, I came to a
surprising realization: &lt;strong&gt;I had never released an app on the App Store.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I really, really (I’d add another &lt;em&gt;really&lt;/em&gt;) didn’t want to learn Swift, and even
less did I want to work with Xcode.&lt;br /&gt;
Then an idea popped up: &lt;em&gt;Hey, it’s been a while since you checked out Flutter.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Within two weeks, I had built and released &lt;a href=&quot;https://factify.7omtech.fr&quot;&gt;Factify&lt;/a&gt;
on both the &lt;strong&gt;Play Store&lt;/strong&gt; and the &lt;strong&gt;App Store&lt;/strong&gt;, complete with ads and premium
subscriptions. Honestly, it took more time to create my developer accounts and
get the app validated than to actually build it.&lt;/p&gt;

&lt;p&gt;That release gave me a sense of satisfaction I hadn’t felt in a long time.&lt;/p&gt;

&lt;h2 id=&quot;destiny-is-sometimes-funny&quot;&gt;Destiny is sometimes funny&lt;/h2&gt;

&lt;p&gt;A week after releasing my app, a friend of mine (an ex-colleague and biker),
reached out to catch up. During our chat, he told me he was about to work on a
Flutter app. The subject was confidential, but the real pain point was that the
company wasn’t in Paris but in… (let me build some suspense)… &lt;strong&gt;Bordeaux!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So literally, a project was starting in September, on a technology I liked, in
the exact city where I wanted to live.&lt;/p&gt;

&lt;p&gt;My interview was scheduled for May, and I literally did it in a small hotel room
in &lt;strong&gt;South Korea&lt;/strong&gt;. The only info I could get was that the client, &lt;strong&gt;Betclic&lt;/strong&gt;,
wanted to build an &lt;em&gt;“app-like game.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A week later, I got the news: I’d be starting on the project in September.&lt;/p&gt;

&lt;p&gt;In my spare time, after sightseeing during the day, I decided to dive deeper
into Flutter. I started learning &lt;strong&gt;Flame&lt;/strong&gt; and even created a particle
animations library to better understand how things worked. That’s how
&lt;a href=&quot;https://newton.7omtech.fr&quot;&gt;&lt;strong&gt;Newton&lt;/strong&gt;&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(And as of today, I still have a few features I’d love to add to this
package.)&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-beginning&quot;&gt;The beginning&lt;/h2&gt;

&lt;p&gt;On &lt;strong&gt;June 2023&lt;/strong&gt;, it was time to go back home. I had mixed feelings, something
was ending, but we were happy to see our family and start a new life.&lt;/p&gt;

&lt;p&gt;After spending some time with our close ones, it was time to move to
&lt;strong&gt;Bordeaux&lt;/strong&gt;. We managed to find a flat quite quickly and, on &lt;strong&gt;September 4th&lt;/strong&gt;,
it was my first day. I signed the NDA and finally got to know a bit more about
the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Betclic&lt;/strong&gt; wanted to build a &lt;strong&gt;Poker app from the ground up in one year&lt;/strong&gt;.&lt;br /&gt;
Yes, you read that correctly: &lt;em&gt;one year&lt;/em&gt; to build an app (front and back)
available on &lt;strong&gt;iOS, Android, macOS, and Windows&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In my head, I thought: &lt;em&gt;Crazy… but ok, let’s fucking do it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The project had already begun exploring what technologies we were going to use
and what was doable with Flutter. But in September, we had the &lt;em&gt;real&lt;/em&gt; kickstart.
We were working in a separate building to preserve the NDA, and only a few
people at Betclic even knew what was going on.&lt;/p&gt;

&lt;p&gt;For the front-end team, two guys were already there: &lt;strong&gt;“Flute de Paon”&lt;/strong&gt;
(“Peacock Flute”) and &lt;strong&gt;“Pipo”&lt;/strong&gt; (I’ll use Flute names to preserve the anonymity
of my colleagues).&lt;/p&gt;

&lt;h3 id=&quot;the-first-steps&quot;&gt;The First Steps&lt;/h3&gt;

&lt;p&gt;Our very first feature was… the &lt;strong&gt;login&lt;/strong&gt;.&lt;br /&gt;
We could log into the app and land in the lobby, where, eventually, the poker
offer would be developed.&lt;/p&gt;

&lt;p&gt;Then we started implementing the game itself. We decided not to use &lt;strong&gt;Flame&lt;/strong&gt;
since it wasn’t really a video game, but instead went for a
&lt;a href=&quot;https://flutter.dev/games&quot;&gt;&lt;em&gt;Flutter Casual Game Toolkit&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The communication with the game server relied on a &lt;strong&gt;websocket&lt;/strong&gt;, so everything
was bidirectional: we could receive events but also send commands to the server.&lt;/p&gt;

&lt;p&gt;We started by implementing the first type of game, now called &lt;strong&gt;Spin &amp;amp; Rush&lt;/strong&gt;.&lt;br /&gt;
It’s a short poker format where three players compete for the prize pool.&lt;/p&gt;

&lt;p&gt;In the very first version, there was no prize pool, no lobby, the only action
you could do was &lt;em&gt;check&lt;/em&gt;.&lt;/p&gt;

&lt;div style=&quot;display: flex; gap: 20px; margin: 20px 0;&quot;&gt;
  &lt;video width=&quot;48%&quot; controls=&quot;&quot;&gt;
    &lt;source src=&quot;/images/2025-08-10-mowgli/login.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
  &lt;/video&gt;

&lt;video width=&quot;48%&quot; controls=&quot;&quot;&gt;
    &lt;source src=&quot;/images/2025-08-10-mowgli/check.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
  &lt;/video&gt;
&lt;/div&gt;

&lt;p&gt;Then we added &lt;strong&gt;call&lt;/strong&gt;, &lt;strong&gt;raise&lt;/strong&gt;, &lt;strong&gt;resolution&lt;/strong&gt;, and so on.&lt;/p&gt;

&lt;h2 id=&quot;from-app-to-framework--desktop&quot;&gt;From app to Framework + Desktop&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;October&lt;/strong&gt;, while we were actively working on the core game, a big question
came up:&lt;br /&gt;
&lt;strong&gt;How will the app be released on mobile?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At first, we thought it would be a standalone app.&lt;br /&gt;
But we quickly realized it could actually end up being a &lt;strong&gt;framework embedded in
the iOS and Android native apps&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This had a huge impact. Some features, like &lt;strong&gt;login&lt;/strong&gt; or &lt;strong&gt;account management&lt;/strong&gt;,
aren’t necessary on mobile since they’re already handled by the native apps, but
they are still required on &lt;strong&gt;Desktop&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, in a single day, we went from a &lt;em&gt;single-app project&lt;/em&gt; to a &lt;strong&gt;multi-module
project&lt;/strong&gt; with two apps. The &lt;strong&gt;framework&lt;/strong&gt; and the &lt;strong&gt;Desktop&lt;/strong&gt; app, both
packaging only the features they need.&lt;/p&gt;

&lt;p&gt;We set up &lt;strong&gt;Melos&lt;/strong&gt; and followed this architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/2025-08-10-mowgli/architecture.svg&quot; data-lightbox=&quot;gallery&quot; data-title=&quot;Project Architecture&quot;&gt;
  &lt;img src=&quot;/images/2025-08-10-mowgli/architecture.svg&quot; alt=&quot;Project Architecture&quot; style=&quot;width: 600px; height: auto; cursor: pointer;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal was to &lt;strong&gt;limit interdependencies&lt;/strong&gt; between modules and ensure we ended
up with an &lt;strong&gt;acyclic graph of modules&lt;/strong&gt; when packaging the apps.&lt;/p&gt;

&lt;p&gt;Our main layers were structured as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Utilities&lt;/strong&gt;: All the non–Betclic-specific code. The rule of thumb was
simple: &lt;em&gt;if we could open-source it, it belonged here&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Foundations&lt;/strong&gt;: Core, non-UI components, mainly responsible for interacting
with the Betclic platform&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Features&lt;/strong&gt;: As the name suggests, this layer contained the actual app
features&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;DSM&lt;/strong&gt;: The design system module, holding all the design tokens and assets
shared across features. This is also where we defined reusable UI components&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Composition&lt;/strong&gt;: The layer where we started assembling pieces of the
application, mainly handling routing and theming&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Apps&lt;/strong&gt;: The final layer, adding the last touches to routing and handling
app-level configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After this decision we got back on track. In November &lt;strong&gt;Flutakouliss&lt;/strong&gt; arrived.
In December Santa Claus brought us the &lt;strong&gt;Y&lt;/strong&gt;. The &lt;em&gt;A-team&lt;/em&gt; was complete.&lt;/p&gt;

&lt;h2 id=&quot;one-table-to-rule-them-all&quot;&gt;One table to rule them all&lt;/h2&gt;

&lt;p&gt;One of the main challenges when developing a &lt;strong&gt;mobile/desktop app&lt;/strong&gt; is ensuring
a single design works seamlessly across all devices. This was especially
critical for our &lt;strong&gt;Poker Table experience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To achieve this, we needed a &lt;strong&gt;reference screen&lt;/strong&gt;. For us, it was the &lt;strong&gt;iPhone
14&lt;/strong&gt;.&lt;br /&gt;
Our designer created the full table design, opponents, hero (your avatar and
actions), board, etc. Once we had that, we turned it into a &lt;strong&gt;Table
Specification&lt;/strong&gt;, where every component was placed relative to the table itself.&lt;/p&gt;

&lt;p&gt;When rendering the Poker Table on any mobile screen, we first compute the
maximum available space (removing insets, navigation bar, etc.). From there, we
calculate the &lt;strong&gt;largest box&lt;/strong&gt; that preserves the table’s aspect ratio. Once that
box is defined, it’s simply a matter of scaling.&lt;/p&gt;

&lt;p&gt;At runtime, we determine the table size by multiplying the scale factor with the
&lt;strong&gt;Specification&lt;/strong&gt;, and we apply the same principle for relative positions.&lt;/p&gt;

&lt;p&gt;In the end, we created &lt;strong&gt;three specifications&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Mobile Portrait&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mobile Landscape&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Desktop&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each specification supports &lt;strong&gt;three layouts&lt;/strong&gt;: &lt;em&gt;3-max, 6-max, and 9-max&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Adding other layouts is absolutely possible, we just need to extract the
specifications from Figma, but these nine configurations have been enough for
us.&lt;/p&gt;

&lt;p&gt;As of today, we don’t have a way to fully automate this process, even though
it’s technically doable.&lt;/p&gt;

&lt;div style=&quot;display: flex; gap: 20px; margin: 20px 0;&quot;&gt;
  &lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;a href=&quot;/images/2025-08-10-mowgli/iphone_13mini.png&quot; data-lightbox=&quot;gallery&quot; data-title=&quot;iPhone 13 mini&quot;&gt;
      &lt;img src=&quot;/images/2025-08-10-mowgli/iphone_13mini.png&quot; alt=&quot;iPhone 13 mini&quot; style=&quot;width: 200px; height: auto; cursor: pointer;&quot; /&gt;
    &lt;/a&gt;
    &lt;p style=&quot;margin: 8px 0 0 0; font-size: 14px; color: #666;&quot;&gt;iPhone 13 mini&lt;/p&gt;
  &lt;/div&gt;
  &lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;a href=&quot;/images/2025-08-10-mowgli/iphone_14.png&quot; data-lightbox=&quot;gallery&quot; data-title=&quot;iPhone 14&quot;&gt;
      &lt;img src=&quot;/images/2025-08-10-mowgli/iphone_14.png&quot; alt=&quot;iPhone 14&quot; style=&quot;width: 200px; height: auto; cursor: pointer;&quot; /&gt;
    &lt;/a&gt;
    &lt;p style=&quot;margin: 8px 0 0 0; font-size: 14px; color: #666;&quot;&gt;iPhone 14&lt;/p&gt;
  &lt;/div&gt;
  &lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;a href=&quot;/images/2025-08-10-mowgli/iphone_16promax.png&quot; data-lightbox=&quot;gallery&quot; data-title=&quot;iPhone 16&quot;&gt;
      &lt;img src=&quot;/images/2025-08-10-mowgli/iphone_16promax.png&quot; alt=&quot;iPhone 16&quot; style=&quot;width: 200px; height: auto; cursor: pointer;&quot; /&gt;
    &lt;/a&gt;
    &lt;p style=&quot;margin: 8px 0 0 0; font-size: 14px; color: #666;&quot;&gt;iPhone 16 Pro Max&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;not-ready&quot;&gt;Not ready&lt;/h2&gt;

&lt;p&gt;As the &lt;strong&gt;start-of-August deadline&lt;/strong&gt; was approaching, reality hit us hard: we
weren’t ready. End of story.&lt;/p&gt;

&lt;p&gt;Fortunately, we got some extra time and the deadline was pushed to
&lt;strong&gt;September&lt;/strong&gt;. The final go/no-go decision, however, was set for &lt;strong&gt;December&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By then, the Poker Table had to be &lt;strong&gt;fully animated&lt;/strong&gt;, and we also needed to
support &lt;strong&gt;Omaha&lt;/strong&gt;, a poker variant with four cards in hand and its own specific
rules.&lt;/p&gt;

&lt;p&gt;To be able to meet the deadline the A-Team was completed with &lt;strong&gt;“Picolo”&lt;/strong&gt; in
June and &lt;strong&gt;“Flutella”&lt;/strong&gt; in October.&lt;/p&gt;

&lt;h2 id=&quot;from-flutteranimate-to-rive&quot;&gt;From FlutterAnimate to Rive&lt;/h2&gt;

&lt;p&gt;Animating widgets in Flutter is &lt;strong&gt;really easy&lt;/strong&gt;, but it can also become &lt;strong&gt;really
verbose&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Our first animations were done using &lt;strong&gt;flutter_animate&lt;/strong&gt;. We even had a
dedicated file storing all the animations for table elements (opponent cards,
chips, etc.). That file was… well, let’s just say it was &lt;strong&gt;HUGE&lt;/strong&gt;, thousands of
lines, hard to maintain, and the animations didn’t really have that &lt;em&gt;“wow”&lt;/em&gt;
effect.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;September&lt;/strong&gt;, we made a bold decision: migrate all our animations to
&lt;strong&gt;Rive&lt;/strong&gt;.&lt;br /&gt;
Cards, capsules, chips, most of our table elements became Rive components.&lt;/p&gt;

&lt;p&gt;At the time, Rive was still really new (version &lt;strong&gt;0.12&lt;/strong&gt;), but it showed a lot
of promise. With Rive, motion designers can create the animations they want and
provide a &lt;strong&gt;state machine&lt;/strong&gt; that developers can interact with.&lt;/p&gt;

&lt;p&gt;For example, the capsule containing a player’s name has a state machine that
lets us define its state: &lt;em&gt;waiting&lt;/em&gt;, &lt;em&gt;playing&lt;/em&gt;, or &lt;em&gt;folded&lt;/em&gt;. All we need to do
as developers is set the right state, and Rive takes care of the rest.&lt;/p&gt;

&lt;p&gt;The magic is that we can update not just text at runtime, but also &lt;strong&gt;images&lt;/strong&gt;.
Even our cards became Rive objects, resulting in some really cool animations
(see video below).&lt;/p&gt;

&lt;p&gt;But great animations weren’t the only requirement: they also had to be
&lt;strong&gt;controlled by the game server&lt;/strong&gt;.&lt;br /&gt;
Since we’re building a &lt;strong&gt;real-time game&lt;/strong&gt;, a user with a bad connection might
otherwise end up with less time to play their animation.&lt;/p&gt;

&lt;p&gt;We solved this with a simple approach: the game server tells us &lt;strong&gt;how much
time&lt;/strong&gt; we have to play an animation.&lt;/p&gt;

&lt;p&gt;Take the reveal of the &lt;strong&gt;Flop&lt;/strong&gt; as an example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The reveal normally takes &lt;strong&gt;500ms&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;The game server sends us the &lt;strong&gt;end timestamp&lt;/strong&gt; when the animation should
finish (including extra latency buffer).&lt;/li&gt;
  &lt;li&gt;When the Flutter app receives the event, it computes how much time is left
before the deadline.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the time remaining is &lt;strong&gt;less than 50%&lt;/strong&gt; (250ms), we skip directly to the end.
Otherwise, we simply speed up the animation.&lt;/p&gt;

&lt;p&gt;We ended up implementing a tailored animation system where a widget can receive
&lt;strong&gt;animation events&lt;/strong&gt; for a given &lt;strong&gt;target&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KoCenterWidget&lt;/code&gt;, which displays the big KO animation when eliminating a
player in a PKO tournament, listens for animations on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KoTarget&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;When it receives an animation event, it computes a &lt;strong&gt;ratio&lt;/strong&gt; that defines the
animation speed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pseudo-code is as simple as:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Widget&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Rive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;widget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;speed:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;playAnimation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Animation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KoCenterAnimationType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KoCenterAnimationTarget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_viewModel&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// This a viewmodel from Rive using databinding&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;colorLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bountyLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toDouble&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;triggerStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our animation system is responsible to compute and fire animation events with
the right speed. The speed is applied directly to the rive Animation. As you can
see the result is really cool:&lt;/p&gt;

&lt;video height=&quot;400&quot; controls=&quot;&quot;&gt;
    &lt;source src=&quot;/images/2025-08-10-mowgli/animations.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
  &lt;/video&gt;

&lt;video width=&quot;80%&quot; controls=&quot;&quot;&gt;
    &lt;source src=&quot;/images/2025-08-10-mowgli/ko.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    Your browser does not support the video tag.
  &lt;/video&gt;

&lt;h2 id=&quot;release-hell&quot;&gt;Release Hell&lt;/h2&gt;

&lt;p&gt;The release date was finally set for &lt;strong&gt;December 9th, 2024&lt;/strong&gt;, right in the middle
of my holidays.&lt;br /&gt;
I promise, it wasn’t planned.&lt;/p&gt;

&lt;p&gt;That morning, after a scheduled maintenance, we flipped the switch and &lt;strong&gt;Mowgli
went live&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It didn’t take long before our servers went down.&lt;br /&gt;
After a few days of intense work, the platform was finally stable.&lt;/p&gt;

&lt;p&gt;On the front-end side, we had some bugs, but nothing major. What we really
wanted was &lt;strong&gt;feedback&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The poker community delivered, they were genuinely happy, loved the product, and
were super excited, as you can see in this image:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/2025-08-10-mowgli/feedback.png&quot; data-lightbox=&quot;gallery&quot; data-title=&quot;Gentle Feedback&quot;&gt;
  &lt;img src=&quot;/images/2025-08-10-mowgli/feedback.png&quot; alt=&quot;Gentle Feedback&quot; style=&quot;width: 600px; height: auto; cursor: pointer;&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well… that was in my dreams and not worth to translate.&lt;/p&gt;

&lt;p&gt;In reality, we got a &lt;strong&gt;lot of complaints&lt;/strong&gt;.&lt;br /&gt;
No dark mode, no sounds, the app was &lt;em&gt;crap&lt;/em&gt;. The poker community hit us hard.&lt;/p&gt;

&lt;p&gt;It wasn’t the first time I’d released an app with major design and behavior
changes. At &lt;strong&gt;Zenly&lt;/strong&gt;, we did it twice. Both times people were disappointed and
angry, but both times the number of users exploded right after.&lt;/p&gt;

&lt;p&gt;When reading these kinds of comments, you shouldn’t take them personally.
Instead, you need to understand what’s really causing the anger.&lt;/p&gt;

&lt;p&gt;In our case, people weren’t happy about losing some features, but the feedback
that came up over and over again was:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Dark theme&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sounds&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Buggy animations&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ability to choose the deck color&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In less than &lt;strong&gt;two weeks&lt;/strong&gt;, all of these features/bugs were shipped.&lt;/p&gt;

&lt;p&gt;That’s the power of mastering your code.&lt;/p&gt;

&lt;h2 id=&quot;finally-some-love&quot;&gt;Finally some love&lt;/h2&gt;

&lt;p&gt;After a few weeks, we started to see more and more &lt;strong&gt;positive reviews&lt;/strong&gt; popping
up.&lt;br /&gt;
As expected, our user base grew, and grew a lot!&lt;/p&gt;

&lt;p&gt;Month after month, we kept beating our own records:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;number of users&lt;/li&gt;
  &lt;li&gt;number of games&lt;/li&gt;
  &lt;li&gt;and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We even started to take some market share from our main competitors, who had
been in the poker field much longer than us.&lt;/p&gt;

&lt;p&gt;At &lt;strong&gt;Betclic&lt;/strong&gt;, we really care about what our users think of our products. We
even set up a &lt;strong&gt;Discord&lt;/strong&gt; with our most active players, where they can report
bugs and share feedback.&lt;/p&gt;

&lt;p&gt;As a developer, it’s always fascinating to see what users like, what they don’t,
and what they’d love to have.&lt;/p&gt;

&lt;h2 id=&quot;and-now&quot;&gt;And now?&lt;/h2&gt;

&lt;p&gt;We keep adding really cool features that unfortunately I can’t talk about for
now.&lt;br /&gt;
I have so many topics I could dive into, from our move from &lt;strong&gt;Rive&lt;/strong&gt; to &lt;strong&gt;Rive
Native&lt;/strong&gt;, to multi-window support, performance tricks, weird crashes, or even
how we managed near-monotonic time for animations. I may write dedicated
articles on those subjects.&lt;/p&gt;

&lt;p&gt;In the meantime, I wanted to share my &lt;strong&gt;feedback on working with Flutter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;First, I’d like to thank the &lt;strong&gt;Flutter community&lt;/strong&gt;. It’s rare to find such a
kind and motivated group of people. Everyone I interacted with was eager to
help. The community is also incredibly active: whenever you think &lt;em&gt;“I’d love to
do this, maybe there’s a package for it”&lt;/em&gt;, there almost always is!&lt;/p&gt;

&lt;p&gt;My team was also amazing, deeply dedicated to creating the best poker app and
experience. Flutter itself delivered as well: we managed to maintain a &lt;strong&gt;single
codebase&lt;/strong&gt; for two apps and a framework. There’s still room for improvement, but
honestly, as of today no other framework, not even &lt;strong&gt;KMP&lt;/strong&gt;, delivers at
Flutter’s level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Big up to the Rive team&lt;/strong&gt;. We had the chance to work closely with them, and
their passion really shines through. Rive rocks, and I highly recommend giving
it a try on your projects.&lt;/p&gt;

&lt;p&gt;Of course, there are some frustrations too. The &lt;strong&gt;Flutter build system&lt;/strong&gt; can be
limiting, I miss &lt;strong&gt;Gradle&lt;/strong&gt; from Android, especially for handling module
variants. We worked around it with scripting (e.g. stripping out mobile-only
assets when building desktop and vice-versa), but native support would be great.&lt;/p&gt;

&lt;p&gt;Coming from the Android world, I was used to one big release a year. With
Flutter, multiple releases per year are great, but the &lt;strong&gt;first release of a
cycle often introduces new bugs&lt;/strong&gt;. Usually, you need to wait for one or two
patches for stability. Luckily, we never hit a dead end: rollback was always an
option, and Flutter being &lt;strong&gt;open source&lt;/strong&gt; makes a huge difference. You can even
build your own version of Flutter if necessary, something I could never do with
Android, where some bugs had no fix other than a painful workaround.&lt;/p&gt;

&lt;p&gt;From our perspective, &lt;strong&gt;Windows support&lt;/strong&gt; still lags behind macOS in quality.
Considering Windows is (unfortunately) the most widespread OS, I’d love to see
more effort from the Flutter team or Windows experts to improve this area.&lt;/p&gt;

&lt;p&gt;All in all, after &lt;strong&gt;15 years in tech&lt;/strong&gt;, seeing the rise and fall of countless
technologies, I can tell you this: there is no silver bullet. Every approach has
its pros and cons, the key is making sure the upsides outweigh the downsides.&lt;/p&gt;

&lt;p&gt;In our case, &lt;strong&gt;Flutter absolutely did.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ll dedicate more time to being involved in the Flutter community.&lt;/p&gt;

&lt;p&gt;From the deep blue of my heart, I hope you enjoyed this article as much as I
enjoyed writing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flutterly yours,&lt;/strong&gt;&lt;br /&gt;
&lt;em&gt;Traversiere&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;strawpoll-embed&quot; id=&quot;strawpoll_w4nWWVop3nA&quot; style=&quot;height: 608px; max-width: 640px; width: 100%; margin: 0 auto; display: flex; flex-direction: column;&quot;&gt;&lt;iframe title=&quot;StrawPoll Embed&quot; id=&quot;strawpoll_iframe_w4nWWVop3nA&quot; src=&quot;https://strawpoll.com/embed/w4nWWVop3nA&quot; style=&quot;position: static; visibility: visible; display: block; width: 100%; flex-grow: 1;&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; allowtransparency=&quot;&quot;&gt;Loading...&lt;/iframe&gt;&lt;script async=&quot;&quot; src=&quot;https://cdn.strawpoll.com/dist/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/div&gt;
</description>
        <pubDate>Tue, 09 Dec 2025 01:00:00 +0000</pubDate>
        <link>https://7omtech.fr/2025/12/mowgli/</link>
        <guid isPermaLink="true">https://7omtech.fr/2025/12/mowgli/</guid>
        
        <category>Flutter</category>
        
        <category>Poker</category>
        
        
        <category>Flutter Programming</category>
        
      </item>
    
      <item>
        <title>The hiring bottleneck: why I built TestReviewer.ai</title>
        <description>&lt;p&gt;I did the math recently, and honestly, it was depressing.&lt;/p&gt;

&lt;p&gt;If you are a Tech Lead, you know the struggle: your calendar looks like a game
of Tetris where you are losing. Instead of building apps, I found myself
constantly reviewing them.&lt;/p&gt;

&lt;p&gt;The workflow is a killer. You stop your actual work, pull a repo, and pray that
running the candidate’s code doesn’t hijack your local environment (a genuine
security risk these days).&lt;/p&gt;

&lt;p&gt;My colleagues and I tried using LLM prompts to speed things up, but that only
solved the &lt;em&gt;reading&lt;/em&gt; part, not the &lt;em&gt;process&lt;/em&gt;. HR was still chasing us on Slack,
the Tech team was swamped, and candidates were left in the dark.&lt;/p&gt;

&lt;p&gt;I realized we didn’t just need a code analyzer; we needed a tool to bridge the
gap between the &lt;strong&gt;Recruiter&lt;/strong&gt;, the &lt;strong&gt;Candidate&lt;/strong&gt;, and the &lt;strong&gt;Technical
Evaluator&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;enter-testreviewerai&quot;&gt;Enter TestReviewer.ai&lt;/h2&gt;

&lt;p&gt;Today, I am launching &lt;strong&gt;&lt;a href=&quot;https://testreviewer.ai&quot;&gt;TestReviewer.ai&lt;/a&gt;&lt;/strong&gt; in Early
Access.&lt;/p&gt;

&lt;p&gt;The goal is simple: &lt;strong&gt;HR shouldn’t waste time chasing feedback, and Tech
shouldn’t waste time on setup and basic code review.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built a flow that respects everyone’s time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: The Setup -&lt;/strong&gt; The recruiter creates a test (e.g., “Senior Android
Developer”), creates a candidate profile, and sends the test link. No friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: The Submission -&lt;/strong&gt; The candidate opens the link, completes the task,
and uploads a Zip file or a Git link.&lt;/p&gt;

&lt;p&gt;But here is the “magical” part: We also allow candidates to &lt;strong&gt;upload a video
walkthrough&lt;/strong&gt;. If you’ve ever reviewed a UI/Frontend test, you know that code
doesn’t tell the whole story. Seeing the dev explain their choices in a video?
That’s a game changer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: The Analysis -&lt;/strong&gt; Before a human ever looks at the code, our tool
analyzes the project for &lt;strong&gt;security concerns, anti-cheat, and project quality.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: The Feedback -&lt;/strong&gt; The tech team receives a detailed report. They don’t
need to run the code locally to know if it’s secure or functional. They get a
deep analysis, add their final feedback, and the recruiter gets the green light
to hire (or pass).&lt;/p&gt;

&lt;h2 id=&quot;why-different&quot;&gt;Why different?&lt;/h2&gt;

&lt;p&gt;The project is in the early stages, but the vision is to save you money and time
immediately.&lt;/p&gt;

&lt;p&gt;Most ATS platforms charge you a fortune in monthly subscriptions for seats you
don’t use. I hate that model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TestReviewer.ai is pay-per-completed-review.&lt;/strong&gt; You don’t pay for idle seats;
you only pay when you are actually interviewing.&lt;/p&gt;

&lt;h2 id=&quot;i-need-your-eyes-on-this&quot;&gt;I need your eyes on this&lt;/h2&gt;

&lt;p&gt;I’m launching this today, slightly under the radar, because I want &lt;strong&gt;honest
feedback&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you are a Recruiter tired of bottlenecks, or a Dev tired of reviewing messy
code, give it a spin.&lt;/p&gt;

&lt;p&gt;Check it out here: &lt;strong&gt;&lt;a href=&quot;https://testreviewer.ai&quot;&gt;https://testreviewer.ai&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you find a bug, or if you think a feature is missing, join our &lt;a href=&quot;https://discord.gg/S4WAZsNTPt&quot;&gt;Discord&lt;/a&gt; or shoot me a mail at
&lt;strong&gt;hi@testreviewer.ai&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy reviewing,&lt;/strong&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 06 Dec 2025 01:00:00 +0000</pubDate>
        <link>https://7omtech.fr/2025/12/testreviewer/</link>
        <guid isPermaLink="true">https://7omtech.fr/2025/12/testreviewer/</guid>
        
        <category>Startups</category>
        
        <category>Engineering</category>
        
        
        <category>Startups</category>
        
        <category>Engineering</category>
        
      </item>
    
      <item>
        <title>CSS-like Gradient in Flutter</title>
        <description>&lt;p&gt;In one of my recent projects, we encountered the challenge of integrating gradients, but not the usual linear or radial types—this time, 
it was elliptical gradients. An elliptical gradient is essentially a radial gradient altered with a matrix transformation.
However, accurately translating these from Figma into Flutter proved challenging;
while the CSS code rendered perfectly, Flutter’s code generation didn’t quite hit the mark. 
Here’s a glimpse of what the CSS version looked like:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.radial-gradient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radial-gradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;60%&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;45%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50%&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;246&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;187&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;246&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;187&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;400px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;200px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;

&lt;style&gt;
.radial-gradient {
    background: radial-gradient(60% 45% at 50% 50%, rgba(1, 246, 187, 0.80) 0%, rgba(1, 246, 187, 0.00) 100%);
    height: 400px;
    width: 200px;
}
&lt;/style&gt;

&lt;div class=&quot;radial-gradient&quot;&gt;&lt;/div&gt;

&lt;p&gt;Given the complexities, we decided to develop an API that would allow us to easily implement the gradient using the same parameters.&lt;/p&gt;

&lt;p&gt;To tackle this, we first dissected the CSS command:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;radial-gradient(60% 45% at 50% 50%, rgba(1, 246, 187, 0.80) 0%, rgba(1, 246, 187, 0.00) 100%);&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Breaking it down, it’s pretty straightforward:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;60% 45% defines the ellipse dimensions relative to the container’s width and height.&lt;/li&gt;
  &lt;li&gt;50% 50% positions the center of the ellipse in the middle of the container.&lt;/li&gt;
  &lt;li&gt;The color stops transition from a semi-transparent green to fully transparent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s translate this into Flutter code:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;EllipticalGradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;backgroundColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;ellipseRelativeCenter:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;ellipseScale:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Scale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;widthFactor:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;heightFactor:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.45&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;colors:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xFF01F6BB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;withOpacity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xFF01F6BB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;withOpacity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;stops:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the implementation, rather than creating a custom shader—which would be overkill—we utilized Flutter’s RadialGradient and applied a GradientTransform. 
This method modifies only the gradient’s appearance without altering the entire canvas.&lt;/p&gt;

&lt;p&gt;Here’s the core of our EllipticalGradient class:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EllipticalGradient&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Gradient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backgroundColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;/// This offset is relative to top left of the widget, [0,0] means top left and [1,1] bottom right.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;///&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;/// The range is not limited to [0,1] for both x and y axis.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Scale&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EllipticalGradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;colors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;backgroundColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ellipseScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;stops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Shader&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;createShader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RadialGradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;center:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Alignment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;colors:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colors&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;alphaBlend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backgroundColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;radius:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;stops:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;transform:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_EllipseTransform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;ellipseRelativeCenter:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;ellipseScale:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseScale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createShader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;textDirection:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;EllipticalGradient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EllipticalGradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;backgroundColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backgroundColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;colors:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colors&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;ellipseRelativeCenter:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;ellipseScale:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseScale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are 3 important things to note in the previous code:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;This operation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ellipseRelativeCenter.dx * 2 - 1&lt;/code&gt; is just to ensure our align value will be between -1 and 1. -1 meaning start and 1 end of the view.&lt;/li&gt;
  &lt;li&gt;The radius property is 1, this property is quite tricky cause the radius is percentage of the shortest side. Let’s imagine we have a box of width 300px and height 200px
the size of the radial gradient will be 200px. (This behavior will have an impact on how we compute the width and height factor)&lt;/li&gt;
  &lt;li&gt;Last but not least we blend the background color with gradients color so the final result looks like there is a ColoredBox behind our gradient
without the need of a Stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now comes the “Mathematical” part. The signature of the transform method is:&lt;/p&gt;
&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Matrix4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TextDirection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textDirection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The initial step involves determining the correct dimensions for width and height, guided by the widthFactor and heightFactor. 
Given that the radius is set to 1, the radius of the radial gradient will equal the length of the shortest side of the container. Consequently, we must accurately adjust these size factors to maintain the desired proportions of the elliptical gradient:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;widthFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;heightFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;heightFactor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseScale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;heightFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;widthFactor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseScale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;widthFactor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;heightFactor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseScale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;heightFactor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;widthFactor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseScale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;widthFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformMatrix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Matrix4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;widthFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;heightFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once the size factors and the transformation matrix are initialized, the next challenge is to accurately position the ellipse. 
This is the most intricate part of the process. Initially, we determine the ellipse’s position as though no transformation has been applied. 
Subsequently, we calculate the center’s position using the scaled matrix. The discrepancy between these values indicates the necessary translation of the matrix. 
It’s crucial to note, however, that this offset is influenced by scaling, so you must adjust the translation by dividing the scaled offset by the respective size factors. With these adjustments, the ellipse will be perfectly positioned.&lt;/p&gt;
&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalCenterOffset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;top&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bounds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ellipseRelativeCenter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offsetLocation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformMatrix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;applyToVector3Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;originalCenterOffset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalCenterOffset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalCenterOffset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offsetLocation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;originalCenterOffset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offsetLocation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transformMatrix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;widthFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;heightFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can play with this dartpad to see how it behaves.&lt;/p&gt;

&lt;iframe width=&quot;800&quot; height=&quot;800&quot; src=&quot;https://dartpad.dev/?id=b4c4290b9356eba7a76e2827d270c10e?theme=light&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;I won’t create a dart package just for this class, so if you feel it could fit your needs, feel free to copy/paste
this code, but don’t forget to like the article if you do so ;).&lt;/p&gt;

&lt;p&gt;Last but not least, while implementing this behavior I opened my first &lt;a href=&quot;https://github.com/flutter/flutter/issues/145481&quot;&gt;bug&lt;/a&gt; on Impeller, which was since fixed by the Flutter team.
Thanks guys, keep the good work!&lt;/p&gt;

&lt;p&gt;Cheers&lt;/p&gt;
</description>
        <pubDate>Sun, 21 Jul 2024 08:00:00 +0000</pubDate>
        <link>https://7omtech.fr/2024/07/elliptic-gradient/</link>
        <guid isPermaLink="true">https://7omtech.fr/2024/07/elliptic-gradient/</guid>
        
        <category>Flutter</category>
        
        <category>Gradient</category>
        
        <category>Ellipse</category>
        
        
        <category>Flutter Programming</category>
        
      </item>
    
      <item>
        <title>Newton: Captivating Flutter Particle Effects</title>
        <description>&lt;p&gt;I was playing around with the Flutter casual game toolkit and the &lt;a href=&quot;https://github.com/flutter/samples/blob/main/game_template/lib/src/style/confetti.dart&quot;&gt;confetti animation&lt;/a&gt; caught my eye.
Wouldn’t be cool to easily achieve this kind of effect in a flutter app? Today, i’m eager
to introduce:
&lt;img src=&quot;/images/2023-08-06-introducing-newton-particles/newton-light.png&quot; alt=&quot;Newton&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Newton is a highly configurable particle emitter package for Flutter that allows you to create
captivating animations such as rain, smoke, explosions, and more. With Newton, you can easily add
visually stunning effects to your Flutter applications.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Rain&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Smoke&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Pulse&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Explode&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Fountain&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://raw.github.com/tguerin/newton/main/graphics/rain.gif&quot; alt=&quot;Rain&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://raw.github.com/tguerin/newton/main/graphics/smoke.gif&quot; alt=&quot;Smoke&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://raw.github.com/tguerin/newton/main/graphics/pulse.gif&quot; alt=&quot;Pulse&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://raw.github.com/tguerin/newton/main/graphics/explode.gif&quot; alt=&quot;Explode&quot; /&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://raw.github.com/tguerin/newton/main/graphics/fountain.gif&quot; alt=&quot;Fountain&quot; /&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;To use Newton, simply add it as a dependency in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pubspec.yaml&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;newton_particles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;use the latest version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flutter pub get&lt;/code&gt; to fetch the package.&lt;/p&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;p&gt;Import the Newton package:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;package:newton_particles/newton_particles.dart&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Newton&lt;/code&gt; widget and add it to your Flutter UI with the desired effects:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Newton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Add any kind of effects to your UI&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// For example:&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;activeEffects:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;RainEffect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;particleConfiguration:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ParticleConfiguration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;shape:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CircleShape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;color:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SingleParticleColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;color:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;black&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;enjoy-the-doc&quot;&gt;Enjoy the doc&lt;/h2&gt;

&lt;p&gt;A complete documentation is available &lt;a href=&quot;https://newton.7omtech.fr/&quot;&gt;here&lt;/a&gt;, you’ll find out how to create custom effects
and all the configuration properties.&lt;/p&gt;

&lt;p&gt;What’s come next is even better!&lt;/p&gt;

&lt;h2 id=&quot;configure-your-effect&quot;&gt;Configure your effect&lt;/h2&gt;

&lt;p&gt;Newton provides an effect configurator to help you tweak the effects and achieved the desired result:&lt;/p&gt;

&lt;iframe width=&quot;650&quot; height=&quot;800&quot; src=&quot;https://newton.7omtech.fr/configure/#/&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;feedback&quot;&gt;Feedback&lt;/h2&gt;

&lt;p&gt;The lib is still wip, don’t hesitate to give your feedback directly on &lt;a href=&quot;https://github.com/tguerin/newton/&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Really hope you’ll enjoy adding cool effects to your app. If you would like specific effects let me know!&lt;/p&gt;
</description>
        <pubDate>Sun, 06 Aug 2023 08:00:00 +0000</pubDate>
        <link>https://7omtech.fr/2023/08/introducing-newton-particles/</link>
        <guid isPermaLink="true">https://7omtech.fr/2023/08/introducing-newton-particles/</guid>
        
        <category>Flutter</category>
        
        <category>Flutter lib</category>
        
        <category>Particles</category>
        
        
        <category>Flutter Programming</category>
        
      </item>
    
      <item>
        <title>Flutter: Translucent Navigation</title>
        <description>&lt;p&gt;While working on &lt;a href=&quot;https://factify.7omtech.fr&quot;&gt;Factify Facts&lt;/a&gt;, I wanted to have a translucent navigation (status and navigation) for an immersive design in light and dark mode.
Flutter provides everything you need to achieve this goal. However having a smooth experience on Android requires some
adjustments. Let’s dive in!&lt;/p&gt;

&lt;h2 id=&quot;quick-takeout&quot;&gt;Quick Takeout&lt;/h2&gt;

&lt;p&gt;If you are just interested by the solution, everything is available &lt;a href=&quot;https://github.com/tguerin/flutter_playground/tree/article-translucent-navigation&quot;&gt;here&lt;/a&gt;. 
All commits are organized so you can understand the progression.&lt;/p&gt;

&lt;h2 id=&quot;setup-the-sample&quot;&gt;Setup the Sample&lt;/h2&gt;

&lt;p&gt;First we will need to define a simple light and dark theme:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;package:flutter/material.dart&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AppTheme&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ColorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;fromSeed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;seedColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;appBarTheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppBarTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;backgroundColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inversePrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;colorScheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;useMaterial3:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ColorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;fromSeed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;seedColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;appBarTheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppBarTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;backgroundColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inversePrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;colorScheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;useMaterial3:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see nothing fancy, we will also need a theme provider to notify when the theme is switching from light to dark:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;package:flutter/widgets.dart&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ThemeProvider&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ChangeNotifier&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_darkMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;darkMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;_darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;notifyListeners&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invertCurrentThemeMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;darkMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To finish, the app will just have an AppBar, a text with the current theme, and a floating action button to invert the theme:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Widget&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BuildContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThemeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;builder:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SystemChrome&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setEnabledSystemUIMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SystemUiMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;edgeToEdge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Scaffold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;appBar:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppBar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;title:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;widget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;body:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Center&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;child:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MainAxisAlignment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;center&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;children:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Widget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;s&quot;&gt;&quot;The current theme is :&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Dark&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Light&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;floatingActionButton:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FloatingActionButton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;onPressed:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;invertCurrentThemeMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;tooltip:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Invert current theme mode&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;child:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Icons&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;change_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge)&lt;/code&gt; means that the navigation bar and status bar
will be drawn on top of the application.&lt;/p&gt;

&lt;p&gt;When playing on the emulator we could imagine that everything is working fine:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;/images/2023-06-05-translucent-navigation-bar/working-sdk-29-plus.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;
&lt;em&gt;Gesture navigation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However some devices do not use the gesture navigation, and if you change the settings to display 
the navigation bar:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;/images/2023-06-05-translucent-navigation-bar/sdk-29-plus-not-working-navigation-bar.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;
&lt;em&gt;System navigation bar not translucent&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The result is quite ok but not what we really expect.&lt;/p&gt;

&lt;h1 id=&quot;going-translucent&quot;&gt;Going Translucent&lt;/h1&gt;

&lt;p&gt;The easiest way we can find on Internet to go translucent is to call this method:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;SystemChrome&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setSystemUIOverlayStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SystemUiOverlayStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;systemNavigationBarContrastEnforced:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;systemNavigationBarDividerColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;systemNavigationBarIconBrightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;systemNavigationBarColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can see different parameters we need to adjust:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemNavigationBarContrastEnforced&lt;/code&gt; -&amp;gt; this one means that the system “may” add a contrast color in order
to ensure the navigation bar is visible. We want to be fully transparent so better to deactivate it.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemNavigationBarDividerColor&lt;/code&gt; -&amp;gt; let define the color of the divider located a the top of the system navigation bar.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemNavigationBarIconBrightness&lt;/code&gt; -&amp;gt; as you decided to override the contrast property, you need to apply the right brightness
for the system bar navigation icons. Light brightness for dark mode and dark for light mode.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemNavigationBarColor&lt;/code&gt; -&amp;gt; this one is pretty obvious.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go back to the emulator:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;/images/2023-06-05-translucent-navigation-bar/issue-brightness-updated.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;
&lt;em&gt;Navigation bar icons brightness issue&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see the system navigation bar is transparent BUT the icon brightness is not updating properly.&lt;/p&gt;

&lt;h2 id=&quot;introducing-annotatedregion&quot;&gt;Introducing AnnotatedRegion&lt;/h2&gt;

&lt;p&gt;To solve this issue you need to use an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnnotatedRegion&lt;/code&gt;, this will ensure the layer tree will use the updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SystemUiOverlayStyle&lt;/code&gt;.
I will write a dedicated post to explain in details why you need to do this.&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Widget&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BuildContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThemeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;builder:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AnnotatedRegion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SystemUiOverlayStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;systemNavigationBarContrastEnforced:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;systemNavigationBarDividerColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;systemNavigationBarIconBrightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;systemNavigationBarColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;child:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Scaffold&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;/images/2023-06-05-translucent-navigation-bar/working-sdk-29-plus-navigation-bar.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;
&lt;em&gt;System navigation bar is translucent on Android 29+&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Job is done, I finished my day! Hold on, hold on, does it work for all API levels? Let’s test on 
api level 28.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;/images/2023-06-05-translucent-navigation-bar/not-working-sdk-28-navigation-bar.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;
&lt;em&gt;System navigation bar not working on Android 28 and less&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hmm not working as expected. The reason behind this issue is quite simple and can be found in the documentation of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SystemUiMode.edgeToEdge&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Available starting at SDK 29 or Android 10. Earlier versions of Android 
 * will not be affected by this setting.
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This means that the app will not be drawn below the system navigation bar if API level &amp;lt; 29.&lt;/p&gt;

&lt;h2 id=&quot;faking-translucence&quot;&gt;Faking Translucence&lt;/h2&gt;

&lt;p&gt;To be able to have a similar design for all API levels there is a simple trick. We are going to have
the system navigation bar the same color as the background only for API levels &amp;lt; 29. As i don’t like to have reference to 
sdk levels in my code, i will have a DeviceFeature wrapper class that will let me know if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edgeToEdge&lt;/code&gt; feature is available.&lt;/p&gt;

&lt;p&gt;For this i’ll need to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;device_info_plus&lt;/code&gt; plugin:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;dart:io&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;package:device_info_plus/device_info_plus.dart&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DeviceFeature&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;DeviceFeature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeviceFeature&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_singleton&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeviceFeature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;factory&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeviceFeature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_singleton&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_deviceInfoPlugin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeviceInfoPlugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;AndroidDeviceInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_androidDeviceInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_androidDeviceInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_deviceInfoPlugin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;androidInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isEdgeToEdgeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Platform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isAndroid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_androidDeviceInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_androidDeviceInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sdkInt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The final code for our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AnnotatedRegion&lt;/code&gt; becomes:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Widget&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BuildContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThemeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;builder:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeviceFeature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isEdgeToEdgeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;navigationBarColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Theme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AnnotatedRegion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SystemUiOverlayStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarContrastEnforced:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarDividerColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarIconBrightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;navigationBarColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Tadaa everything works fine for all API levels!&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;/images/2023-06-05-translucent-navigation-bar/working-sdk-28-navigation-bar.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;
&lt;em&gt;System navigation bar working on Android 28 and less&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;theme-is-everything&quot;&gt;Theme is Everything&lt;/h2&gt;

&lt;p&gt;Even if everything is working well, there is something i can’t get rid off my head. I don’t like to have 
theme attributes hard coded in my UI. Isn’t there a better way to handle this issue?&lt;/p&gt;

&lt;p&gt;There is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemOverlayStyle&lt;/code&gt; attribute in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AppBarTheme&lt;/code&gt;. We can leverage this and define everything at the theme level.&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;package:flutter/material.dart&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;package:flutter/services.dart&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AppTheme&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ColorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;fromSeed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;seedColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;appBarTheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppBarTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;backgroundColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inversePrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;systemOverlayStyle:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SystemUiOverlayStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;statusBarIconBrightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;statusBarColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemStatusBarContrastEnforced:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarContrastEnforced:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarDividerColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarIconBrightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarColor:&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;colorScheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;useMaterial3:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ColorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;fromSeed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;seedColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ThemeData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;brightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;appBarTheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppBarTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;backgroundColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inversePrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;systemOverlayStyle:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SystemUiOverlayStyle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;statusBarIconBrightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;statusBarColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemStatusBarContrastEnforced:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarContrastEnforced:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarDividerColor:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarIconBrightness:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;systemNavigationBarColor:&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;transparent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;colorScheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorScheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;useMaterial3:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see we also have to define the status bar color and contrast enforcement to have a smooth integration
for status and navigation bar. Now our main build is as simple as:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@override&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Widget&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BuildContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ThemeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;builder:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DeviceFeature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isEdgeToEdgeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;themeProvider&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;darkMode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ThemeMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ThemeMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;appTheme&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AppTheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SystemChrome&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setEnabledSystemUIMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SystemUiMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;edgeToEdge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MaterialApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;title:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Translucent Navigation&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;themeMode:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;themeMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;theme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;appTheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;darkTheme:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;appTheme&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edgeToEdgeAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;home:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyHomePage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;title:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;Translucent Navigation&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I hope you enjoyed this article. Don’t hesitate to leave a comment or ask questions!&lt;/p&gt;

&lt;p&gt;If you could give your feedback about &lt;a href=&quot;https://factify.7omtech.fr&quot;&gt;Factify Facts&lt;/a&gt; either on &lt;a href=&quot;https://www.producthunt.com/products/factify-facts&quot;&gt;Product Hunt&lt;/a&gt; or by direct message it would be awesome!&lt;/p&gt;

&lt;p&gt;May Flutter be with you!&lt;/p&gt;
</description>
        <pubDate>Sun, 04 Jun 2023 15:04:23 +0000</pubDate>
        <link>https://7omtech.fr/2023/06/translucent-navigation-bar/</link>
        <guid isPermaLink="true">https://7omtech.fr/2023/06/translucent-navigation-bar/</guid>
        
        <category>Flutter</category>
        
        <category>Flutter Development</category>
        
        
        <category>Flutter</category>
        
      </item>
    
      <item>
        <title>Becoming Apple Developer: The Hard Way</title>
        <description>&lt;p&gt;I‘ve been an Android Developer for almost 10 years now, recently I was playing around with Flutter
and was struck by a personal fact: “I’ve never published a personal mobile application on the stores”.&lt;/p&gt;

&lt;p&gt;Well… in my previous jobs I was responsible for publishing releases, but I had never built and released
a personal project on stores. This year, I decided things were going to change and built an app about fun/interesting facts.
Factify Facts was born and it was time to release it on the stores (&lt;a href=&quot;https://apps.apple.com/us/app/factify-facts/id6448727476&quot;&gt;iOS&lt;/a&gt; and &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.factify.app&quot;&gt;Android&lt;/a&gt;).
I already own a PlayStore developer account but no Apple Developer Account. Spoiler alert: becoming an Apple Developer
was not a ”Piece of Cake“.&lt;/p&gt;

&lt;h2 id=&quot;updating-my-apple-id&quot;&gt;Updating my Apple Id&lt;/h2&gt;

&lt;p&gt;I got the first macbook during my studies thanks to the Apple student program and it was looking like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2023-05-22-becoming-apple-developer/mcbook.jpg&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At that time I used a &lt;em&gt;hotmail.com&lt;/em&gt; mail address to register. For the youngest one it was the ancestor of outlook (damn I feel old). 
This hotmail mail address became by default my Apple Id. For my developer account, I wanted to update this Apple Id to use my &lt;em&gt;gmail&lt;/em&gt; account instead.
Once updated on &lt;a href=&quot;https://appleid.apple.com/&quot;&gt;appleid.apple.com&lt;/a&gt;, I logged in again on my mac and everything was working well.&lt;/p&gt;

&lt;p&gt;So far so good, I downloaded the Developer app from AppStore to start enrollment. Upon logging in, the app was requested the password 
for my &lt;em&gt;hotmail&lt;/em&gt; account and not my &lt;em&gt;gmail&lt;/em&gt; account. Long story short I ended in state where I could enter my new Apple Id and password but a dialog was popping later requesting my password for my old account.
None of the password was working, so I was totally stuck.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2023-05-22-becoming-apple-developer/begins.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I reverted my change on &lt;a href=&quot;https://appleid.apple.com/&quot;&gt;appleid.apple.com&lt;/a&gt; back to my &lt;em&gt;hotmail&lt;/em&gt; account and everything went back to normal.&lt;/p&gt;

&lt;p&gt;Ok Apple, I will use my &lt;em&gt;hotmail&lt;/em&gt; account!&lt;/p&gt;

&lt;h2 id=&quot;enrolling-with-developer-app-on-mac&quot;&gt;Enrolling with Developer App on Mac&lt;/h2&gt;

&lt;p&gt;I started the enrollment within the Developer app. The first step was to take a picture of an Id card with the front 
camera of the mac. I used my driving licence, took a sharp picture and my first name ended up being Amomas and not Thomas.
For some reason you can’t edit the fields to correct them and you can’t go back…&lt;/p&gt;

&lt;p&gt;I contacted Apple Support, two days later the support had reset my personal information. In the mail, support confirmed 
that It was not possible to continue the enrollment in the Developer app. I had to finish it on the web.&lt;/p&gt;

&lt;h2 id=&quot;dead-ending&quot;&gt;Dead ending&lt;/h2&gt;

&lt;p&gt;I started over the enrollment on the web, completed all the step. On the last page, I was excited to click on the submit button
and become an Apple Developer. The excitement became incomprehension as soon as I got this error message:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Your enrollment in the Apple Developer Program could not be completed at this time.&lt;/code&gt;
I love this kind of error message cause I have no idea at all what to do: should I try again? is it a temporary error? a server issue?&lt;/p&gt;

&lt;p&gt;After having read some Apple community threads, I realized I was not the only one. I checked everything: my credit card, my birthdate, apple agreements, everything…&lt;/p&gt;

&lt;p&gt;I ended sending an mail to Apple Support again and 2 days later I got the most epic mail:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Thank you for contacting Apple Developer Program Support.

My name is xxxxx and I am delighted to assist you today.

From your message, I understand that you are still unable to register for the Apple Developer program.

We cannot verify your identity through the Apple Developer app or provide additional support regarding this Apple ID for Apple developer programs.

You can still enjoy great content by using your Apple ID in Xcode to develop and test apps on your own device.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This was the most polite way I had ever seen to tell me: “Your Apple Id is fucked up, we can’t do anything but go play around”&lt;/p&gt;

&lt;p&gt;“I WANT TO SUBMIT AN APP” I repeat “I WANT TO SUBMIT AN APP”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2023-05-22-becoming-apple-developer/everybodystaycalm-staycalm.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;new-apple-id&quot;&gt;New Apple Id&lt;/h2&gt;

&lt;p&gt;As I was not using iCloud services, I was ok to create a new Apple Id. Finally, I could use my &lt;em&gt;gmail&lt;/em&gt; account!
This time I took time to ensure that:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;All my personal information was filled on Apple Id website with a valid birthdate (18+)&lt;/li&gt;
  &lt;li&gt;2FA was enabled and working properly&lt;/li&gt;
  &lt;li&gt;My credit card information was setup in Apple Id and AppStore app&lt;/li&gt;
  &lt;li&gt;iCloud services were enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once everything was double (triple) checked, I started over on the web this time. I filled all the information
paid 99$ and 2 hours later I got this mail:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Hello Thomas,
Thank you for joining the Apple Developer Program. We’re thrilled to support your work as you bring your ideas to life! As a developer program member, you have access to a comprehensive set of resources to build, test, and distribute innovative apps for Apple platforms.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You would think that the story is over, but noooo…&lt;/p&gt;

&lt;h2 id=&quot;from-personal-to-company-account&quot;&gt;From Personal to Company Account&lt;/h2&gt;

&lt;p&gt;Few days later, I was finishing the in-app purchase implementation for my app when I started to wonder: “Wait a minute, how am I going to declare this revenue?”
As I became a freelancer earlier this year, there is a rule in France that is:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;If you own a company in a specific field, you need to declare all revenue from that field&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In fact, I must declare my revenue on my freelance company. I contacted Apple Support to request a migration to company account.&lt;/p&gt;

&lt;p&gt;Few days later, I got the answer and had to provide following information:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Your organization’s legal entity name in Roman characters&lt;/li&gt;
  &lt;li&gt;Your organization’s &lt;a href=&quot;https://developer.apple.com/support/D-U-N-S&quot;&gt;D-U-N-S Number&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;A valid organization website is required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to Apple you can enjoy this new website cause at the time of the request it didn’t exist. Regarding
DUNS Number, Apple provide a tool to search your company. Don’t pay for your DUNS number!&lt;/p&gt;

&lt;p&gt;After everything was setup by mail, I got a call to ensure that I was actually me. Once confirmed that me was me,
the migration process started. Two days later I finally got my company developer account.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2023-05-22-becoming-apple-developer/champagne.gif&quot; alt=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;As this article started to be a bit longish, I decided to elude the French specific part where I had to fill
the W8ben then W8ben-e form for U.S. tax.&lt;/p&gt;

&lt;p&gt;It took more time to have my developer account up and ready
than developing Factify Facts. The main point to keep in mind when creating your developer account is to check
that everything (birthdate, credit card, etc…) is correct. Don’t hesitate to contact support, they honestly did a good job and helped me a lot. Expect a 2 days delay for your answer though.&lt;/p&gt;

&lt;p&gt;Finally, for anyone wishing to be an Apple Developer, I wish you good luck!&lt;/p&gt;
</description>
        <pubDate>Mon, 22 May 2023 15:04:23 +0000</pubDate>
        <link>https://7omtech.fr/2023/05/becoming-apple-developer/</link>
        <guid isPermaLink="true">https://7omtech.fr/2023/05/becoming-apple-developer/</guid>
        
        <category>Apple Development</category>
        
        <category>App Store Process</category>
        
        <category>Release</category>
        
        
        <category>Release Process</category>
        
      </item>
    
  </channel>
</rss>
