<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cristovão F.</title>
    <description>The latest articles on DEV Community by Cristovão F. (@cristovoxdgm).</description>
    <link>https://dev.to/cristovoxdgm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F205338%2Fef49365c-a760-4e4f-9efe-d8b8108b38ac.jpg</url>
      <title>DEV Community: Cristovão F.</title>
      <link>https://dev.to/cristovoxdgm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cristovoxdgm"/>
    <language>en</language>
    <item>
      <title>Responsive Flutter without a single package — and what building it with AI actually taught me</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Tue, 25 Aug 2026 21:07:34 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/responsive-flutter-without-a-single-package-and-what-building-it-with-ai-actually-taught-me-lch</link>
      <guid>https://dev.to/cristovoxdgm/responsive-flutter-without-a-single-package-and-what-building-it-with-ai-actually-taught-me-lch</guid>
      <description>&lt;p&gt;I built my &lt;a href="https://cristovaofarias.com.br/" rel="noopener noreferrer"&gt;portfolio&lt;/a&gt; in Flutter Web with one hard rule: no responsive package, no &lt;code&gt;responsive_builder&lt;/code&gt;, no &lt;code&gt;sizer&lt;/code&gt;, nothing. Just &lt;code&gt;MediaQuery&lt;/code&gt; and &lt;code&gt;LayoutBuilder&lt;/code&gt;, by hand. I also built most of it pairing with an AI coding agent (Claude Code). Those two choices ended up teaching me something neither would have taught me alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The theory, in two sentences
&lt;/h2&gt;

&lt;p&gt;Responsive and adaptive aren't the same thing. &lt;strong&gt;Responsive&lt;/strong&gt; means the UI adjusts its own positioning to the space it has. &lt;strong&gt;Adaptive&lt;/strong&gt; means the UI picks a different layout or input method for that space — a tablet choosing a side rail over a bottom nav bar, for instance. A hand-rolled system needs to do both, and Flutter gives you exactly two primitives to work with: &lt;code&gt;MediaQuery&lt;/code&gt; and &lt;code&gt;LayoutBuilder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They answer different questions. &lt;code&gt;MediaQuery.sizeOf(context)&lt;/code&gt; tells you the size of the whole app window — global truth, cheap to read if you only need &lt;code&gt;size&lt;/code&gt; (that's why &lt;code&gt;sizeOf&lt;/code&gt; exists instead of the heavier &lt;code&gt;MediaQuery.of&lt;/code&gt;, which subscribes to the entire &lt;code&gt;MediaQueryData&lt;/code&gt; and rebuilds on every field, not just the one you read). &lt;code&gt;LayoutBuilder&lt;/code&gt; tells you the constraints of the &lt;strong&gt;specific parent&lt;/strong&gt; in the tree where you placed it — the true answer when a widget isn't full-window width, which in practice is most widgets past the root scaffold.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually got built
&lt;/h2&gt;

&lt;p&gt;An enum instead of scattered breakpoint numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;ScreenSize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tablet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wide&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;isDesktopUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ScreenSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;desktop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;pick&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;tablet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;wide&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;ScreenSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mobile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ScreenSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tablet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tablet&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ScreenSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;desktop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;desktop&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;tablet&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ScreenSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wide&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;wide&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;desktop&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;tablet&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pick&lt;/code&gt; is the whole trick. Only &lt;code&gt;mobile&lt;/code&gt; is required — everything above inherits from the tier below unless overridden. That single method replaced every &lt;code&gt;if (width &amp;gt; 768) ... else if (width &amp;gt; 1024) ...&lt;/code&gt; chain across the codebase with &lt;code&gt;screen.pick(mobile: 16, desktop: 24)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The breakpoints themselves are just constants — &lt;code&gt;tablet: 720, desktop: 1024, wide: 1440&lt;/code&gt; — and a spacing scale (&lt;code&gt;4, 8, 16, 24, 32, 48, 96&lt;/code&gt;) so no magic number ever gets typed twice.&lt;/p&gt;

&lt;p&gt;The one non-obvious layout problem: a card grid where rows need equal height, but &lt;code&gt;Wrap&lt;/code&gt; doesn't know what a "row" is — it just flows. The fix is building rows explicitly and wrapping each one in &lt;code&gt;IntrinsicHeight&lt;/code&gt; with &lt;code&gt;Row(crossAxisAlignment: stretch)&lt;/code&gt;, then padding the last row with empty &lt;code&gt;SizedBox&lt;/code&gt;es so leftover cards don't stretch to fill space alone. It's a two-pass layout (&lt;code&gt;IntrinsicHeight&lt;/code&gt; measures twice), which is expensive on a huge list — irrelevant here, since the content is static and rendered once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the AI pairing actually helped — and where it didn't
&lt;/h2&gt;

&lt;p&gt;Claude Code was fast at generating the &lt;code&gt;pick&lt;/code&gt;-based breakpoint calls across a dozen sections once the pattern existed, and good at catching redundant &lt;code&gt;const&lt;/code&gt; after a refactor moved code between &lt;code&gt;const&lt;/code&gt; and non-&lt;code&gt;const&lt;/code&gt; contexts. That's real, useful acceleration.&lt;/p&gt;

&lt;p&gt;What it did &lt;em&gt;not&lt;/em&gt; do reliably: notice that its own generated code was visually broken. At one point, a light-mode pass hardcoded a dark hex value straight into the hero section instead of pulling it from the palette. &lt;code&gt;flutter analyze&lt;/code&gt; was clean. The types checked. The build succeeded. It looked completely fine — as a diff. It was only visibly wrong: dark text painted over a cream background, unreadable, in exactly the mode meant to be the polished "default" of the design system.&lt;/p&gt;

&lt;p&gt;Static analysis has no opinion on contrast. It doesn't know what your background color is at runtime, doesn't render a frame, doesn't know "cream" and "ink" are supposed to be different things. The bug only exists as pixels — and pixels are the one artifact an AI reading a diff never sees unless someone forces the loop to include them.&lt;/p&gt;

&lt;p&gt;The fix wasn't more prompting. It was a screenshot, taken at the actual breakpoint width, in the actual failing mode — a discipline copied straight from CI visual regression testing: cheap headless browser, fixed device metrics, before/after comparison, done automatically instead of trusted by eye. Once that step existed in the workflow, the category of bug stopped shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual takeaway
&lt;/h2&gt;

&lt;p&gt;AI is a legitimate accelerator for writing the &lt;em&gt;mechanism&lt;/em&gt; of responsive layout — the enum, the &lt;code&gt;pick&lt;/code&gt; calls, the constants, the boilerplate that used to be tedious to keep consistent across twelve files by hand. It is not a substitute for looking at the rendered result at the breakpoints that actually matter. &lt;code&gt;flutter analyze&lt;/code&gt; passing means the code is valid Dart. It says nothing about whether the layout works — and neither, it turns out, does an AI's confidence that it does.&lt;/p&gt;

&lt;p&gt;If you're pairing with an AI agent on UI work, the one habit worth keeping non-negotiable: verify with a real screenshot at real widths, every time, regardless of how clean the diff looks. That's not a limitation specific to AI-written code — it was always true of your own code too. AI just makes it easier to forget, because the diff reads so plausibly.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ai</category>
      <category>webdev</category>
      <category>dart</category>
    </item>
    <item>
      <title>Flutter Web is invisible to Google (and nobody warns you)</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Sun, 23 Aug 2026 22:00:51 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/flutter-web-is-invisible-to-google-and-nobody-warns-you-ncm</link>
      <guid>https://dev.to/cristovoxdgm/flutter-web-is-invisible-to-google-and-nobody-warns-you-ncm</guid>
      <description>

&lt;p&gt;I published my portfolio in Flutter Web, sent the link to a few people on LinkedIn, and noticed two strange things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sharing the link on WhatsApp generated no preview card — just the raw link.&lt;/li&gt;
&lt;li&gt;Searching my own name on Google didn't surface a single line of the site's content.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The cause is the same for both, and it's kind of obvious once you understand it: &lt;strong&gt;Flutter Web, on its default renderer (CanvasKit), draws everything on a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;.&lt;/strong&gt; There's no &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, no &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, no text at all in the DOM. For the visitor's browser, nothing changes — they see the app running smoothly, with all the responsiveness and animation you wrote in Dart. But for anything that only reads HTML — Google's crawler, the bot that generates WhatsApp link previews, a screen reader without semantics support — the page is, literally, a blank screen with a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; tag inside it.&lt;/p&gt;

&lt;p&gt;You can confirm this in 10 seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://your-site.netlify.app/ | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"your name"&lt;/span&gt;
&lt;span class="c"&gt;# 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero. It doesn't matter how much text you wrote inside a &lt;code&gt;Text()&lt;/code&gt; widget — none of it becomes a character in the HTML the server actually serves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually fixes this
&lt;/h2&gt;

&lt;p&gt;There's no magic switch that makes Flutter render to the DOM instead (there was an HTML renderer, but it's been deprecated and had its own visual-fidelity problems). The realistic path is accepting that the app runs on canvas and &lt;strong&gt;complementing &lt;code&gt;index.html&lt;/code&gt;&lt;/strong&gt; with what a crawler needs, without depending on Dart to generate it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A block of real text, hidden visually — not with &lt;code&gt;display: none&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This part matters: &lt;code&gt;display: none&lt;/code&gt; and &lt;code&gt;visibility: hidden&lt;/code&gt; have historically been associated with keyword stuffing, and search engines tend to discount or ignore that content. The correct technique is the same one used for years for accessibility — the &lt;code&gt;sr-only&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#seo-fallback&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;white-space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;nowrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The content stays in the DOM, takes up zero space on screen, and isn't treated as cloaking — as long as it's &lt;strong&gt;the same content&lt;/strong&gt; the page actually has, just in plain text. In my case, it's literally the same text that Flutter's &lt;code&gt;Semantics&lt;/code&gt; tree already exposes to screen readers: name, role, summary, experience, skills. It's a genuine win-win — the same block improves both accessibility and indexability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Complete Open Graph and Twitter Card tags&lt;/strong&gt;, including a fixed-size &lt;code&gt;og:image&lt;/code&gt; (1200×630). Without this, every link you send falls flat with no preview — and that's the kind of thing that decides whether someone clicks or scrolls past.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. JSON-LD with &lt;code&gt;schema.org/Person&lt;/code&gt;.&lt;/strong&gt; It's not text for a human to read — it's a structured block that tells Google "this is a person, their role is X, their site is Y":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jobTitle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mobile Software Engineer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yoursite.com/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sameAs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://linkedin.com/in/...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. &lt;code&gt;robots.txt&lt;/code&gt; and &lt;code&gt;sitemap.xml&lt;/code&gt;.&lt;/strong&gt; Sounds obvious, but on a fresh project scaffolded with &lt;code&gt;flutter create&lt;/code&gt;, neither comes by default — and without them you have no way to tell Google to crawl the page for the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical result
&lt;/h2&gt;

&lt;p&gt;After these changes, the same &lt;code&gt;curl&lt;/code&gt; that used to return zero lines now shows the full content — because it's there, in plain HTML, before any JavaScript runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://your-site.netlify.app/ | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"your name"&lt;/span&gt;
&lt;span class="c"&gt;# 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the link, when pasted into any app, now comes with an image, title, and description.&lt;/p&gt;

&lt;p&gt;None of these four things require touching a single line of Dart. It's all in &lt;code&gt;web/index.html&lt;/code&gt; and the static files next to it — which makes sense, because the problem was never the app. It was what exists (or doesn't) before the app even loads.&lt;/p&gt;

&lt;p&gt;If you've got a portfolio or product running on Flutter Web, it's worth running that &lt;code&gt;curl&lt;/code&gt; right now. There's a good chance the result is zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cristovaofarias.com.br/" rel="noopener noreferrer"&gt;Cristovao Farias&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>webdev</category>
      <category>seo</category>
      <category>dart</category>
    </item>
    <item>
      <title>Flutter vs React Native — what changes once you've shipped both</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Sun, 23 Aug 2026 21:58:45 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/flutter-vs-react-native-what-changes-once-youve-shipped-both-2047</link>
      <guid>https://dev.to/cristovoxdgm/flutter-vs-react-native-what-changes-once-youve-shipped-both-2047</guid>
      <description>

&lt;p&gt;"Flutter or React Native?" is the question every mobile dev eventually gets asked. After more than 6 years shipping production apps — including real projects in both, not just tutorials — I've landed on an answer that isn't about which framework is "better" in the abstract. It's about what each one costs you day to day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The difference that matters most: who draws the screen
&lt;/h2&gt;

&lt;p&gt;Both follow declarative UI, but they get there through very different paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React Native&lt;/strong&gt; uses JSX and resolves the interface by bridging over to native components — the same mental model as someone coming from web front-end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flutter&lt;/strong&gt; has no bridge: it draws its own widget tree directly, with Dart compiling to native code. That shows up in practice — no bridge latency, no "this library doesn't have a native binding for this RN version."&lt;/p&gt;

&lt;p&gt;The classic "hello world" already makes this visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// React Native&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StyleSheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Text&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/View&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StyleSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#fff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Flutter&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;'Hello, world!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;textDirection:&lt;/span&gt; &lt;span class="n"&gt;TextDirection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ltr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's not just fewer lines — it's fewer moving parts in transit. In React Native, styling, layout, and the native component behind it live in three different places that need to agree with each other. In Flutter, it's all the same tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where each one gave me the most trouble
&lt;/h2&gt;

&lt;p&gt;I worked with React Native on products ranging from a smart home app (sensor control, 3D visualization) to virtual reality projects. The recurring friction wasn't writing the logic itself — it was every time the app needed something RN didn't cover natively: that's when it turns into a native module, into debugging Swift/Kotlin underneath a JS abstraction, into Fast Refresh — which is supposed to be fast — turning into a noticeably slower rebuild cycle than Flutter's Hot Reload.&lt;/p&gt;

&lt;p&gt;With Flutter, the friction moves elsewhere: less "this library doesn't support that," more "I need to write this native integration myself via a platform channel" — which takes more upfront setup, but fewer surprises later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Differences that matter in practice
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Flutter&lt;/th&gt;
&lt;th&gt;React Native&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compilation&lt;/td&gt;
&lt;td&gt;To native code&lt;/td&gt;
&lt;td&gt;Bridge/JSI to native components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;Dart&lt;/td&gt;
&lt;td&gt;JavaScript/TypeScript + JSX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI customization&lt;/td&gt;
&lt;td&gt;Full control, own widget library&lt;/td&gt;
&lt;td&gt;Depends on the native component behind it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev-time reload&lt;/td&gt;
&lt;td&gt;Hot Reload&lt;/td&gt;
&lt;td&gt;Fast Refresh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native integration&lt;/td&gt;
&lt;td&gt;Platform channels, more upfront setup&lt;/td&gt;
&lt;td&gt;Native modules, more third-party dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I'd actually recommend
&lt;/h2&gt;

&lt;p&gt;Starting a new project today: I go with Flutter, no hesitation. The predictability of owning the entire rendering tree pays off the Dart learning curve — especially as the app grows and maintenance starts to matter more than initial setup.&lt;/p&gt;

&lt;p&gt;That's not saying React Native is a bad choice — entire teams (Meta, Airbnb for a while, Discord) prove it scales. It's saying that, in my track record, the maintenance cost paid off more on the Flutter side than the learning cost paid off on the RN side.&lt;/p&gt;

&lt;p&gt;The right question isn't "which framework is better." It's "which friction would I rather pay: learning Dart now, or depending on someone else's native module later?"&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>reactnative</category>
      <category>mobile</category>
      <category>dart</category>
    </item>
    <item>
      <title>How to Implement Video Casting in Flutter</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Thu, 24 Jul 2025 02:31:43 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/how-to-implement-video-casting-in-flutter-2j28</link>
      <guid>https://dev.to/cristovoxdgm/how-to-implement-video-casting-in-flutter-2j28</guid>
      <description>&lt;p&gt;Hey folks! Today I’ll show you how to implement a casting feature in your Flutter app —&lt;br&gt;
especially useful for video apps, courses, streaming platforms, or even fitness apps, like&lt;br&gt;
Netflix or YouTube.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Cast?
&lt;/h2&gt;

&lt;p&gt;"Cast" is the ability to send media (like video or audio) from your app to another device,&lt;br&gt;
such as a Chromecast-enabled TV or an AirPlay-compatible receiver. The content plays&lt;br&gt;
on the external screen, while your app becomes a remote control.&lt;/p&gt;
&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;Casting protocols work mainly in two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chromecast (Google Cast)&lt;/strong&gt;: The receiver device (usually a smart TV or dongle) runs
a player and receives control commands over the network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AirPlay (Apple)&lt;/strong&gt;: Native on Apple TVs and compatible smart TVs. iOS can also
mirror the screen when casting isn't supported directly.
## Documentation and Useful Links&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cast package on pub.dev: &lt;a href="https://pub.dev/packages/cast" rel="noopener noreferrer"&gt;https://pub.dev/packages/cast&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Google Cast SDK Developer Docs: &lt;a href="https://developers.google.com/cast/docs/developers" rel="noopener noreferrer"&gt;https://developers.google.com/cast/docs/developers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apple AirPlay Overview: &lt;a href="https://developer.apple.com/airplay/" rel="noopener noreferrer"&gt;https://developer.apple.com/airplay/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;flutter_to_airplay package: &lt;a href="https://pub.dev/packages/flutter_to_airplay" rel="noopener noreferrer"&gt;https://pub.dev/packages/flutter_to_airplay&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to implement it?
&lt;/h2&gt;

&lt;p&gt;First, add the necessary dependencies to your &lt;code&gt;pubspec.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;cast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.1.0&lt;/span&gt;
 &lt;span class="na"&gt;flutter_to_airplay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.0.5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠&lt;br&gt;
 Important: Read the documentation for the &lt;code&gt;cast&lt;/code&gt; package carefully — you must&lt;br&gt;
configure AndroidManifest.xml, permissions, and iOS protocols as required.&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating the Cast Service
&lt;/h3&gt;

&lt;p&gt;To follow Clean Architecture, let’s encapsulate the cast logic in a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VideoCastService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;mediaSessionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CastDevice&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;searchDevices&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;devices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;CastDiscoveryService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;on&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;CastSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;forward10seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;seekMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"SEEK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"mediaSessionId"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mediaSessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"currentTime"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"resumeState"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"PLAY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seekMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;backwards10seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;seekMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"SEEK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"mediaSessionId"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mediaSessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"currentTime"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"resumeState"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"PLAY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seekMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;stopSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"STOP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"mediaSessionId"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mediaSessionId&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;playMedia&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s"&gt;'type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"PLAY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;'mediaSessionId'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mediaSessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;setVolume&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isMuted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceReceiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"SET_VOLUME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'volume'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"muted"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;isMuted&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;pauseMedia&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'PAUSE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'mediaSessionId'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mediaSessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;CastDevice&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;CastSessionManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;minutes:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;launchDefaultMediaApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CastSessionState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;listenToStateStream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;stateStream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;listenToMessageStream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;messageStream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;launchDefaultMediaApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceReceiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'LAUNCH'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'appId'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'CC1AD845'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default media device&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;getMediaStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"GET_STATUS"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;getReceiverStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"GET_STATUS"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;openMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;VideoCastParams&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;'contentId'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'contentType'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'video/dash'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'streamType'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'BUFFERED'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;'metadata'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'metadataType'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;'images'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;'url'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thumb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSession&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;seconds:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;currentSession&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CastSession&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kNamespaceMedia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="s"&gt;'type'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'LOAD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;'autoPlay'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;'currentTime'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;'media'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can inject this service using GetIt, Riverpod, or any other DI solution and Create a Cubit or a bloc to consume it, also using a enum to simplify the flow of use for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  AirPlay support (iOS)
&lt;/h2&gt;

&lt;p&gt;As a fallback for iOS, when Google Cast is not supported, we can use&lt;/p&gt;

&lt;p&gt;&lt;code&gt;flutter_to_airplay&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Displaying the AirPlay button:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;AirPlayRoutePickerView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nl"&gt;tintColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nl"&gt;activeTintColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nl"&gt;backgroundColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This widget displays the native system button, opening the AirPlay or screen mirroring&lt;br&gt;
interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fallback: Native screen mirroring (iOS)
&lt;/h3&gt;

&lt;p&gt;If the device doesn’t support AirPlay directly, the &lt;code&gt;AirPlayRoutePickerView&lt;/code&gt; lets users&lt;br&gt;
enable screen mirroring instead — ensuring your video is still shown.&lt;br&gt;
✅ Tip: You can listen to the &lt;code&gt;CastService&lt;/code&gt; stream to detect when casting starts or stops,&lt;br&gt;
and adapt your UI accordingly (e.g., hiding local controls or changing the player view).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the &lt;code&gt;cast&lt;/code&gt; and &lt;code&gt;flutter_to_airplay&lt;/code&gt; packages, you can implement a complete&lt;br&gt;
casting experience on Flutter — supporting both Google Cast and AirPlay on iOS. Even&lt;br&gt;
though Flutter doesn't natively handle all media controls, this solution gives you great&lt;br&gt;
flexibility.&lt;br&gt;
To make your app more robust, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Showing visual feedback when connected.&lt;/li&gt;
&lt;li&gt;Centralizing media controls (play, pause, seek).&lt;/li&gt;
&lt;li&gt;Displaying a casting icon in your app bar.
If you want the full example or have questions, feel free to reach out on Instagram
@kiustudios or comment below!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>learning</category>
      <category>code</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Thu, 10 Apr 2025 00:41:32 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/-62p</link>
      <guid>https://dev.to/cristovoxdgm/-62p</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/cristovoxdgm/some-of-my-projects-46pb" class="crayons-story__hidden-navigation-link"&gt;Some of my projects&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/cristovoxdgm" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F205338%2Fef49365c-a760-4e4f-9efe-d8b8108b38ac.jpg" alt="cristovoxdgm profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/cristovoxdgm" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Cristovão F.
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Cristovão F.
                
                
              
              &lt;div id="story-author-preview-content-2395095" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/cristovoxdgm" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F205338%2Fef49365c-a760-4e4f-9efe-d8b8108b38ac.jpg" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Cristovão F.&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/cristovoxdgm/some-of-my-projects-46pb" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 10 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/cristovoxdgm/some-of-my-projects-46pb" id="article-link-2395095"&gt;
          Some of my projects
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/flutter"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;flutter&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/portfolio"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;portfolio&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mobile"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mobile&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/cristovoxdgm/some-of-my-projects-46pb#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            1 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>flutter</category>
      <category>portfolio</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Some of my projects</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Thu, 10 Apr 2025 00:38:54 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/some-of-my-projects-46pb</link>
      <guid>https://dev.to/cristovoxdgm/some-of-my-projects-46pb</guid>
      <description>&lt;p&gt;Hey everyone! 👋&lt;/p&gt;

&lt;p&gt;I wanted to share a quick post to give you all a better idea of what I’ve been building lately! 🚀 Here’s a list of some of my projects from the past few years — whether personal projects, client work, or apps I’ve contributed to. Check out the links and, if possible, I’ll drop some screenshots too! 😁&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.kiustudios.link_generator_app&amp;amp;hl=pt_BR" rel="noopener noreferrer"&gt;Link Generator App (Android)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://link-gen-kiu-studios.netlify.app/" rel="noopener noreferrer"&gt;Link Generator App (Web)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apps.apple.com/br/app/fitdance-plus/id6444678335" rel="noopener noreferrer"&gt;FitDance Plus (iOS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=br.com.magnumbank" rel="noopener noreferrer"&gt;Magnum Bank (Android)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://play.google.com/store/search?q=prote%C3%A7%C3%A3o%20pix&amp;amp;c=apps&amp;amp;hl=pt_BR" rel="noopener noreferrer"&gt;Proteção Pix (Android)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cristovaoresume.netlify.app/" rel="noopener noreferrer"&gt;My Resume (Web)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kiustudios.netlify.app/" rel="noopener noreferrer"&gt;Kiu Studios Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://weather-kiustudios-app.netlify.app/" rel="noopener noreferrer"&gt;Weather App (Web)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cristovao-react-gallery.netlify.app/" rel="noopener noreferrer"&gt;React Gallery (Web)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there’s a lot more over on my GitHub! They might not be live apps, but they’re open-source if you want to take a look:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/CristovoXDGM" rel="noopener noreferrer"&gt;https://github.com/CristovoXDGM&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you're into tech, mobile development, or just curious about my journey, feel free to connect! I’m always down to share experiences, ideas, or even collaborate on cool projects. 🚀✨&lt;/p&gt;

&lt;p&gt;You can also follow me here on dev.to, and on my other platforms for more updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧩 &lt;a href="https://github.com/CristovoXDGM" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📸 &lt;a href="https://instagram.com/kiustudios" rel="noopener noreferrer"&gt;Instagram @kiustudios&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s build cool stuff together! 💡&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>portfolio</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Discover the Secrets of Effective Learning</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Thu, 29 Aug 2024 01:23:02 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/discover-the-secrets-of-effective-learning-4d16</link>
      <guid>https://dev.to/cristovoxdgm/discover-the-secrets-of-effective-learning-4d16</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;I’m bringing you a topic that I believe is crucial, especially for those who are just starting out in the field. Having worked in the technology industry for several years now, I can say this to anyone who is just beginning or planning to enter this field: always study and stay updated. It may sound obvious, but it’s absolutely essential in our line of work.&lt;/p&gt;

&lt;p&gt;When I talk about "learning to learn," I don't just mean studying for the sake of it. It’s about studying with purpose, truly understanding what you’ve studied, and discovering your own learning style. Each person will develop or adopt a study method, whether it’s through writing, making videos, reading and repeating the content, or sharing the knowledge you’ve gained.&lt;/p&gt;

&lt;p&gt;"Your most dissatisfied customers are your best source of learning." – Bill Gates&lt;/p&gt;

&lt;p&gt;As odd as it may sound, this quote makes a lot of sense, especially because it’s from our mistakes that we learn the most. We understand our learning process, identify areas to improve, learn how to seek out content, and figure out what to study. All of this comes with time. Of course, learning efficiently is key, so here are some tips that I follow whenever I need to master something new.&lt;/p&gt;

&lt;p&gt;Tips for Effective Learning&lt;br&gt;
I won’t go into too much detail, so I’ll keep these tips concise:&lt;/p&gt;

&lt;p&gt;Choose a Study Technique: Find a method that works for you. Personally, I prefer sharing knowledge and creating practical projects to reinforce what I want to learn.&lt;br&gt;
Read Books: Never underestimate the power of reading. It broadens our horizons and deepens our knowledge.&lt;br&gt;
Create Your Own Roadmap: Have a clear vision of where you want to go in your career, how you want to evolve, and what you want to achieve in the future.&lt;br&gt;
Watch Videos from Industry Professionals: Influences matter. Learn from those who are actively working in the field. Even juniors can offer valuable insights.&lt;br&gt;
Accept Different Perspectives: There’s no absolute truth for everything. Be open to understanding other opinions and approaches to the problems or content you’re studying.&lt;br&gt;
Avoid Comparisons: Comparing yourself to others, especially to someone with over 11 years of experience, is a quick way to stall your progress. Focus on your own journey.&lt;br&gt;
Teach and Share: Sharing knowledge is the best way to identify your mistakes and improve, as it forces you to understand the subject deeply enough to explain it to others.&lt;br&gt;
Focus on One Thing at a Time: Don’t rush to learn everything at once. Take your time, as there will be phases where studying becomes repetitive.&lt;br&gt;
Build Projects: In the tech field, having a portfolio and personal projects is vital. Use these projects as opportunities to gain experience.&lt;br&gt;
Finish What You Start: Completing a project, even if it’s not perfect, is essential for designing better ones in the future. Learn from your mistakes and keep improving.&lt;br&gt;
Know When to Rest: Resting is crucial for consolidating what you’ve learned. It’s not about playing games or watching movies, but taking a shower, going for a walk, or even taking a nap.&lt;/p&gt;

&lt;p&gt;I’m not here to be a coach; I just want to share this knowledge because I believe it’s essential for everyone. If you've made it this far, don't forget to follow me here and on my other social networks.&lt;/p&gt;

&lt;p&gt;@kiustudios - Instagram, YouTube, and Twitter&lt;/p&gt;

</description>
      <category>learning</category>
      <category>programming</category>
      <category>code</category>
      <category>newbie</category>
    </item>
    <item>
      <title>Make flutter builds easier</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Thu, 06 Jun 2024 13:45:30 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/make-flutter-builds-easier-17ab</link>
      <guid>https://dev.to/cristovoxdgm/make-flutter-builds-easier-17ab</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fil7sjwlowmz6olc92q8x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fil7sjwlowmz6olc92q8x.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>developer</category>
      <category>newbie</category>
    </item>
    <item>
      <title>The joy of the Service pattern and Dependency inversion</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Sat, 04 May 2024 02:41:21 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/the-joy-of-the-service-pattern-and-dependency-inversion-5a7n</link>
      <guid>https://dev.to/cristovoxdgm/the-joy-of-the-service-pattern-and-dependency-inversion-5a7n</guid>
      <description>&lt;p&gt;I believe that every Dev has come across the situation of needing to do something and having to look for something ready to solve their problem, such as libs and database packages, external services that seek to facilitate our day-to-day lives as developers.&lt;br&gt;
Eventually the Dev will come across an update that breaks the current code to use a new implementation or etc. For small projects, this doesn't have such an impact, but for large projects, it can cost you your job or hours of time updating and hoping that something doesn't break in the process.&lt;/p&gt;

&lt;p&gt;For this we have a Project Pattern and a rule that helps a lot, they are the Service pattern and the Depency inversion of solid, together they help us to make a structure that allows us to scale the system and not depend on packages or external changes, only ours.&lt;/p&gt;

&lt;p&gt;I don't intend to put the whole pattern here to encourage you to study it, but believe me, it's very worthwhile. My recommendation is always Uncle Bob's book and the refactoring guru's website. Finally, studying solid will help you understand more about it.&lt;/p&gt;

&lt;p&gt;Site mentioned:&lt;br&gt;
&lt;a href="https://refactoring.guru/" rel="noopener noreferrer"&gt;https://refactoring.guru/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>developer</category>
      <category>mid</category>
      <category>flutter</category>
      <category>dart</category>
    </item>
    <item>
      <title>How to create a similar to Google maps pan an a zoom movement in Flutter flame</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Sun, 11 Feb 2024 01:42:03 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/how-to-create-a-similar-pan-an-a-zoom-movement-in-flutter-flame-1ccj</link>
      <guid>https://dev.to/cristovoxdgm/how-to-create-a-similar-pan-an-a-zoom-movement-in-flutter-flame-1ccj</guid>
      <description>&lt;p&gt;Hello everyone, how are you? Here I am with another mini-tutorial that I learned in my day-to-day work. Recently, we needed a camera movement in our app similar to what Google does in Google Maps, and since we are using Flutter and, in conjunction, Flame, there wasn't much material available on this. So, with this challenge in mind, I researched extensively and tested various possibilities until one day I decided to try ScaleDetector and Pandetect from Flame. I discovered that ScaleDetector was nothing more than a superset of PanDetector.&lt;/p&gt;

&lt;p&gt;In summary, we were able to create the solution, and here I am to document this code for you.&lt;/p&gt;

&lt;p&gt;Note: Remember to check the Flutter Flame documentation to implement everything correctly, using the ScaleDetector mixin.&lt;/p&gt;

&lt;p&gt;Flame doc -&amp;gt; &lt;a href="https://docs.flame-engine.org/" rel="noopener noreferrer"&gt;https://docs.flame-engine.org/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void clampZoom() {
    camera.viewfinder.zoom = camera.viewfinder.zoom.clamp(0.8, 5);
  }

  static const zoomPerScrollUnit = 0.01;
  late double startZoom;
  @override
  void onScaleStart(info) {
    startZoom = camera.viewfinder.zoom;
  }

  @override
  void onScaleUpdate(ScaleUpdateInfo info) {
    final currentScale = info.scale.global;
    if (!currentScale.isIdentity()) {
      camera.viewfinder.zoom = startZoom * currentScale.y;
      camera.moveBy(info.delta.global);
      clampZoom();
    } else {
      final delta = -info.delta.global;
      camera.moveBy(delta);
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would also like to thank Lukas (&lt;a class="mentioned-user" href="https://dev.to/spydon"&gt;@spydon&lt;/a&gt; ), who has been doing an excellent job in the development of Flame and its community.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What is use for work as a developer - Basic Flutter setup</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Sat, 27 Jan 2024 17:09:50 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/what-is-use-for-work-as-a-developer-basic-flutter-setup-3e7n</link>
      <guid>https://dev.to/cristovoxdgm/what-is-use-for-work-as-a-developer-basic-flutter-setup-3e7n</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/PiJzxikGxQQ"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>setup</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Mobile Dev Roadmap</title>
      <dc:creator>Cristovão F.</dc:creator>
      <pubDate>Thu, 07 Sep 2023 13:49:12 +0000</pubDate>
      <link>https://dev.to/cristovoxdgm/mobile-dev-roadmap-hoh</link>
      <guid>https://dev.to/cristovoxdgm/mobile-dev-roadmap-hoh</guid>
      <description>&lt;h1&gt;
  
  
  Programming Foundation
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Get a clear idea of what an algorithm is.&lt;/li&gt;
&lt;li&gt;Learn the difference between data, information, knowledge, and intelligence.&lt;/li&gt;
&lt;li&gt;Understand the basics of programming logic.&lt;/li&gt;
&lt;li&gt;Explore common data structures.&lt;/li&gt;
&lt;li&gt;Get familiar with databases (both relational and non-relational) at a basic level.&lt;/li&gt;
&lt;li&gt;Learn how RESTful APIs work (GraphQL is a nice extra if you want).&lt;/li&gt;
&lt;li&gt;Dive into Object-Oriented Programming (OOP), especially if your language focuses on it.&lt;/li&gt;
&lt;li&gt;Study some design patterns.&lt;/li&gt;
&lt;li&gt;Understand the SOLID principles (like Single Responsibility, Open/Closed, and the others).&lt;/li&gt;
&lt;li&gt;Get to know the idea of Clean Code and why it matters for writing maintainable code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Choose Your Development Stack
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Pick your mobile programming language (like Swift for iOS or Kotlin for Android).&lt;/li&gt;
&lt;li&gt;Learn the language well — its syntax and core concepts.&lt;/li&gt;
&lt;li&gt;Choose a framework for mobile development (like SwiftUI for iOS or Flutter for cross-platform).&lt;/li&gt;
&lt;li&gt;Understand how the app lifecycle works on your chosen platform.&lt;/li&gt;
&lt;li&gt;Learn how to style components and build user interfaces.&lt;/li&gt;
&lt;li&gt;Practice breaking your code into components and modules.&lt;/li&gt;
&lt;li&gt;Check out the design guidelines for your platform (like Material Design for Android or Human Interface Guidelines for iOS).&lt;/li&gt;
&lt;li&gt;Get the basics of state management (like Flutter's State Management or Android's ViewModels).&lt;/li&gt;
&lt;li&gt;Explore reactive programming with things like Streams and Observables (depending on your platform).&lt;/li&gt;
&lt;li&gt;Spend time reading the official docs for your language and framework.&lt;/li&gt;
&lt;li&gt;Build small projects to practice and solidify what you’ve learned.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Architecture and Beyond
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Start digging into mobile architecture patterns (like MVVM, MVP, MVC, and Clean Architecture).&lt;/li&gt;
&lt;li&gt;Go deeper into Clean Architecture and how to use it in real projects.&lt;/li&gt;
&lt;li&gt;Keep improving your Clean Code skills — naming things right, refactoring, following best practices.&lt;/li&gt;
&lt;li&gt;Learn more design patterns (like Singleton, Observer, and Factory).&lt;/li&gt;
&lt;li&gt;Get a good sense of UX/UI principles to make your apps feel intuitive and smooth.&lt;/li&gt;
&lt;li&gt;Master layouts on your platform (like ConstraintLayout on Android or SwiftUI layouts on iOS).&lt;/li&gt;
&lt;li&gt;Make sure your app works well on different devices and screen sizes (responsiveness and adaptability).&lt;/li&gt;
&lt;li&gt;Learn about accessibility so your app is usable for everyone.&lt;/li&gt;
&lt;li&gt;Level up your state management skills with advanced tools (like Redux, MobX, or Provider).&lt;/li&gt;
&lt;li&gt;Stay up to date with what's happening in mobile development — join communities, attend events, and take courses.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  And remember:
&lt;/h3&gt;

&lt;p&gt;Mobile development is always changing. Stay curious, keep learning, and tweak your roadmap as new tech and tools come out. That’s how you stay ahead!&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>codenewbie</category>
      <category>coding</category>
      <category>flutter</category>
    </item>
  </channel>
</rss>
