<?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: Leticya Sheyla </title>
    <description>The latest articles on DEV Community by Leticya Sheyla  (@shey).</description>
    <link>https://dev.to/shey</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1264958%2F215cf16b-7439-4bf0-9efa-9d1a1542c012.jpeg</url>
      <title>DEV Community: Leticya Sheyla </title>
      <link>https://dev.to/shey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shey"/>
    <language>en</language>
    <item>
      <title>Fluent 2 UI for Flutter</title>
      <dc:creator>Leticya Sheyla </dc:creator>
      <pubDate>Thu, 31 Oct 2024 19:41:56 +0000</pubDate>
      <link>https://dev.to/shey/fluent-2-ui-for-flutter-2njo</link>
      <guid>https://dev.to/shey/fluent-2-ui-for-flutter-2njo</guid>
      <description>&lt;h2&gt;
  
  
  What is Fluent UI 2
&lt;/h2&gt;

&lt;p&gt;Fluent 2 is the next evolution of Microsoft's design system Fluent UI. With a fluid and intuitive experience you can create beautiful, cohesive Microsoft experiences using &lt;a href="https://fluent2.microsoft.design/" rel="noopener noreferrer"&gt;Fluent 2&lt;/a&gt;.&lt;br&gt;
‎ ‎&lt;br&gt;
‎ &lt;/p&gt;
&lt;h2&gt;
  
  
  Gbt Fluent 2 UI package
&lt;/h2&gt;

&lt;p&gt;The Gbt Fluent 2 UI package is a Fluent2 design system &lt;strong&gt;based on Material&lt;/strong&gt;. It emerged from the necessity to implement the entire Fluent design system within Flutter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Material Design is an open-source design system built and supported by Google designers and developers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This package is a library of customizable components that fit the Fluent 2 UI design standards. With &lt;a href="https://pub.dev/packages/gbt_fluent2_ui/versions/3.3.0" rel="noopener noreferrer"&gt; Gbt Fluent 2 UI package&lt;/a&gt; you can configure your application according to theme tokens, colors, fonts and use design system components.‎ ‎&lt;/p&gt;

&lt;p&gt;Run the following command to install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flutter pub add gbt_fluent2_ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;‎ &lt;/p&gt;

&lt;h2&gt;
  
  
  Consistent Theming
&lt;/h2&gt;

&lt;p&gt;Maintain a consistent theming in your entire app.&lt;br&gt;
First of all, you must wrap your MaterialApp with &lt;code&gt;FluentProvider&lt;/code&gt; to make sure that every component will work well. &lt;/p&gt;

&lt;p&gt;‎&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="n"&gt;FluentProvider&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;MaterialApp&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 pass you brand color, by default it is fluent brand color palette. Use &lt;code&gt;getTheme&lt;/code&gt; function to set the theme in light and dark. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Suggestion: you can use&lt;/em&gt; &lt;a href="https://smart-swatch.netlify.app/#7f22e2" rel="noopener noreferrer"&gt;Smart Swatch Generator&lt;/a&gt; &lt;em&gt;to generate your color palette.&lt;/em&gt;&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="n"&gt;FluentProvider&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;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&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;MaterialColor&lt;/span&gt; &lt;span class="n"&gt;brandColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MaterialColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFF8934e4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFFf5e6ff&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFFd9bafa&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFFbf8df2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFFa461eb&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFF8934e4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFF701bcb&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFF57149f&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFF3e0e73&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFF250747&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;XFF0e011d&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;appLightTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
              &lt;span class="n"&gt;getTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;brandColor:&lt;/span&gt; &lt;span class="n"&gt;brandColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;brightness:&lt;/span&gt; &lt;span class="n"&gt;Brightness&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;light&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;appDarkTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
              &lt;span class="n"&gt;getTheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;brandColor:&lt;/span&gt; &lt;span class="n"&gt;brandColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;brightness:&lt;/span&gt; &lt;span class="n"&gt;Brightness&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dark&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;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;appLightTheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;darkTheme:&lt;/span&gt; &lt;span class="n"&gt;appDarkTheme&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;&lt;br&gt;
‎ ‎&lt;br&gt;
Don't forget to use &lt;strong&gt;FluentScaffold instead Scaffold&lt;/strong&gt; in your views:&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="n"&gt;FluentScaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;FluentNavBar&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
  &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Placeholder&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;br&gt;
 ‎&lt;/p&gt;
&lt;h2&gt;
  
  
  Design tokens
&lt;/h2&gt;

&lt;p&gt;Design tokens are stored values used to assign Fluent styles like color, typography, spacing, or elevation, without hardcoding pixels and hex codes.&lt;/p&gt;

&lt;p&gt;You can use design tokens from theme with &lt;code&gt;FluentThemeDataModel.of(context)&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  CornerRadius
&lt;/h3&gt;

&lt;p&gt;Use the FluentCornerRadius radius tokens to change the corner radius on elements. &lt;br&gt;
You can use the FluentContainer component, which is basically a Material Container with properties that are compatible with Fluent 2 UI design rules.&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="n"&gt;FluentContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nl"&gt;cornerRadius:&lt;/span&gt; &lt;span class="n"&gt;FluentCornerRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;large&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;h3&gt;
  
  
  Color Tokens
&lt;/h3&gt;

&lt;p&gt;Fluent brand colors are defined based on the color palette you placed in the theme:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;color: FluentColors.of(context)?.brandBackground1Rest,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can use neutral colors, that are used on surfaces, text, and layout elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Light Theme:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;FluentColors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;neutralForeground2Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In Dark Theme:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;FluentDarkColors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;neutralForeground2Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Typography
&lt;/h3&gt;

&lt;p&gt;Fluent uses the system's default font to ensure a familiar and accessible experience across platforms. For Android the Roboto font is used and for IOS the San Francisco Pro font is used.&lt;br&gt;
The fluent type ramp defines the weight, size and line height of text elements, you can choose from theme with &lt;code&gt;FluentThemeDataModel&lt;/code&gt;. If you wanna change some text style like color you can use &lt;code&gt;fluentCopyWith&lt;/code&gt; function.&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="n"&gt;FluentText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="s"&gt;"This is a caption 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;FluentThemeDataModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fluentTextTheme&lt;/span&gt;
       &lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;caption1&lt;/span&gt;
       &lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;fluentCopyWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="nl"&gt;fluentColor:&lt;/span&gt; &lt;span class="n"&gt;FluentColors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;neutralForeground1Rest&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;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%2Fh5oixcvkyogkfzf87lsh.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%2Fh5oixcvkyogkfzf87lsh.png" alt="Typography example in light theme" width="688" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&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%2Fljmcbn0z6i76a6cicgfv.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%2Fljmcbn0z6i76a6cicgfv.png" alt="Typography example in dark theme" width="714" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Iconography
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;" This is a set of the Microsoft Fluent system icons used for products across Microsoft. The Fluent icons are friendly - including rounded corners, simplified shapes and come in 3 themes: Regular, Filled &amp;amp; Color."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Import &lt;code&gt;FluentIcons&lt;/code&gt; and use different variations:&lt;/p&gt;

&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%2Fha11c31g991bomwuq5yy.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%2Fha11c31g991bomwuq5yy.png" alt="FluentIcon in dark mode" width="566" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&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%2Fk8lzrpkdwam6rbc3owy9.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%2Fk8lzrpkdwam6rbc3owy9.png" alt="FluentIcon in light mode" width="574" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FluentIcon variants:&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="n"&gt;FluentAvatar&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;FluentIcon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outlineIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="n"&gt;FluentIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;person_20_regular&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;FluentAvatar&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;FluentIcon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accentIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="n"&gt;FluentIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;person_20_regular&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;FluentAvatar&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;FluentIcon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outlinedPrimaryIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="n"&gt;FluentIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;person_20_regular&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;FluentIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FluentIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;person_20_regular&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="n"&gt;FluentAvatar&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;FluentIcon&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;outlineIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="n"&gt;FluentIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;person_20_regular&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;colorScheme:&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;deepOrange&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;h3&gt;
  
  
  Shadow
&lt;/h3&gt;

&lt;p&gt;To use Fluent set of shadows you must use the FluentContainer.&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="n"&gt;FluentContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;shadow:&lt;/span&gt; &lt;span class="n"&gt;FluentThemeDataModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fluentShadowTheme&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;shadow2&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;br&gt;
‎ ‎&lt;/p&gt;

&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%2F7303qex2aas2xvou6m75.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%2F7303qex2aas2xvou6m75.png" alt="Image description" width="688" height="336"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Stroke
&lt;/h3&gt;

&lt;p&gt;To use Fluent stroke set of styles you must use &lt;code&gt;FluentContainer&lt;/code&gt; or &lt;code&gt;FluentStrokeDivider&lt;/code&gt;.&lt;/p&gt;

&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%2F6w5ejm2b6bxfu2wi4zln.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%2F6w5ejm2b6bxfu2wi4zln.png" alt="Image description" width="684" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Borders:&lt;/strong&gt; 
You can define Fluent stroke tokens in &lt;code&gt;FluentAvatar&lt;/code&gt; and &lt;code&gt;FluentContainer&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;FluentContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;strokeStyle:&lt;/span&gt; &lt;span class="n"&gt;FluentStrokeStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;FluentColors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;neutralStroke1Rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nl"&gt;thickness:&lt;/span&gt; &lt;span class="n"&gt;FluentStrokeThickness&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;strokeWidth20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="mi"&gt;12&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;ul&gt;
&lt;li&gt;
&lt;strong&gt;Divider:&lt;/strong&gt; 
To create stroke lines you can use &lt;code&gt;FluentStrokeDivider&lt;/code&gt;. You can get stroke tokens predefined from fluent from FluentThemeDataModel or you can define color, thickness, dashed properties and padding in FluentStrokeStyle():
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;FluentStrokeDivider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;style:&lt;/span&gt; 
 &lt;span class="n"&gt;FluentThemeDataModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fluentStrokeTheme&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;stroke2&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;h3&gt;
  
  
  Size and spacing
&lt;/h3&gt;

&lt;p&gt;It’s used in every component and layout to create a familiar and &lt;br&gt;
cohesive product experience, regardless of device or environment.&lt;/p&gt;

&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%2Fr3hdah8segof8e934let.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%2Fr3hdah8segof8e934let.png" alt="Size and spacing example" width="404" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To use Fluent spacing tokens and sizes you must use &lt;code&gt;FluentSize&lt;/code&gt; values:&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="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="n"&gt;FluentSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size120&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&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="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="n"&gt;FluentIcons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info_24_regular&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nl"&gt;size:&lt;/span&gt; &lt;span class="n"&gt;FluentSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size240&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&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;br&gt;
‎ &lt;/p&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&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%2Fn278tgsiqy4a5pkhpcf5.gif" alt="Components demonstration in light theme" width="330" height="538"&gt;
&lt;/td&gt;
&lt;td&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%2Frrr7f9tw7ae9blxzggeo.gif" alt="Components demonstration in dark theme" width="330" height="530"&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentProvider&lt;/code&gt;: Don't forget to wrap you application with it.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentScaffold&lt;/code&gt;: It's important to &lt;strong&gt;use FluentScaffold instead Scaffold&lt;/strong&gt; To make sure components will function correctly.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentAvatar&lt;/code&gt;: Shows an image or text to represent a person or group as well as gives additional information like their status and activity.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentNavBar&lt;/code&gt;: Provides information and actions related to the current screen.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentText&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentContainer&lt;/code&gt;: Accepts all fluent values ​​helping and guiding you to use fluent styles.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentIcon&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentActivityIndicator&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentRefreshActivityIndicator&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentBanner&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentButton&lt;/code&gt;: Have customizable backgrounds, and can include a title or an icon. Has three variants &lt;em&gt;outline&lt;/em&gt;, &lt;em&gt;outlineAccent&lt;/em&gt;, &lt;em&gt;accent&lt;/em&gt; and &lt;em&gt;subtle&lt;/em&gt;, the default value is accent.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentCheckbox&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentChip&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentHeadsUpDisplay&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentLeftNav&lt;/code&gt;: Left navigation drawers allow access to destinations and features like switching accounts, and can be controlled by either a navigation menu icon or an avatar.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentList&lt;/code&gt;: FluentList has two variations of list: One-line and Multi-line.&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentListItemOneLine&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentListItemMultiLine&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentPopover&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentProgressBar&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentSearchBar&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentSheet&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentSwitchToggle&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentTabBar&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentTextField&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentToast&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentTooltip&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentCard&lt;/code&gt;: &lt;a href="https://www.figma.com/design/m0350NrOCZaAQpP9Y0rGhT/Microsoft-Fluent-2-iOS-(Community)?node-id=18791-32035" rel="noopener noreferrer"&gt;FluentCard &lt;/a&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentCardContainer&lt;/code&gt;: A flexible container with FluentCard styles that you can use for different components&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentRadioButton&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FluentStrokeDivider&lt;/code&gt;&lt;br&gt;
‎ &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>fluent2</category>
      <category>design</category>
    </item>
    <item>
      <title>Implementando Infinite Scroll Pagination com Riverpod</title>
      <dc:creator>Leticya Sheyla </dc:creator>
      <pubDate>Wed, 14 Feb 2024 20:00:10 +0000</pubDate>
      <link>https://dev.to/shey/implementando-infinite-scroll-pagination-com-riverpod-2h6g</link>
      <guid>https://dev.to/shey/implementando-infinite-scroll-pagination-com-riverpod-2h6g</guid>
      <description>&lt;p&gt;Nesse código usaremos os pacotes flutter_riverpod e infinite_scroll_pagination.&lt;/p&gt;

&lt;p&gt;Recentemente, comecei a usar riverpod  como meu gerenciador de estado.&lt;/p&gt;

&lt;p&gt;No meu projeto eu utilizei o pacote &lt;a href="https://pub.dev/packages/infinite_scroll_pagination"&gt;infinite_scroll_pagination&lt;/a&gt; pra trabalhar com listas paginadas, e, para implementar cache na minha lista, eu precisava adicionar &lt;a href="https://pub.dev/packages/flutter_riverpod"&gt;flutter_riverpod&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Antes de tudo começaremos agrupando todo o aplicativo em um ProviderScope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyApp extends StatelessWidget {
  final Widget child;


  MyApp({super.key, required this.child});

  @override
  Widget build(BuildContext context) {

    return ProviderScope(
      child: FluentProvider(
        child: MaterialApp(
          title: 'Flutter Demo',
          theme: theme,
          home: child,
        ),
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;‎ &lt;/p&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;Criaremos a classe repositório e criaremos um Provider pra ela:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final usersRepositoryProvider = Provider((ref) =&amp;gt; UsersRepository());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UsersRepository {
  final http.Client client = http.Client();
  final apiBaseUri = Uri.parse("https://api.slingacademy.com/");

  Future&amp;lt;Result&amp;lt;UsersPagedList&amp;lt;UserModel&amp;gt;&amp;gt;&amp;gt; fetchUsers(
    int pageNumber,
  ) async {
    try {
      const int limit = 10;
      final String offset = (pageNumber * limit).toString();
      final response = await client.get(
        apiBaseUri.replace(
          path: "v1/sample-data/users",
          queryParameters: {
            "offset": offset,
          },
        ),
      );

      if (response.statusCode != 200) {
        switch (response.statusCode) {
          case 404:
            return Result.error(
              'Recurso não encontrado. Verifique a URL ou tente novamente mais tarde',
            );
          case 500:
            return Result.error('Erro Interno do Servidor.');
          default:
            return Result.error('Erro Http');
        }
      }

      final jsonListResponse =
          jsonDecode(response.body) as Map&amp;lt;String, Object?&amp;gt;;

      final modelPagedList = UsersPagedList.fromJson(
        jsonListResponse,
        UserModel.fromJson,
      );

      return Result.value(modelPagedList);
    } on ClientException {
      return Result.error("Erro de conexão");
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
‎ &lt;br&gt;
‎ &lt;/p&gt;
&lt;h2&gt;
  
  
  Pagination Controller
&lt;/h2&gt;

&lt;p&gt;Vamos criar a classe &lt;strong&gt;RiverpodPaginationController&lt;/strong&gt;. Começamos criando nosso pagingController assim como mostra na implementação da infinite scroll pagination. Usamos a função addPageRequestListener e chamamos nossa função de request no construtor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class RiverpodPaginationController&amp;lt;T&amp;gt; {
  final PagingController&amp;lt;int, T&amp;gt; pagingController =
  PagingController(firstPageKey: 0);

  RiverpodPaginationController(){
    pagingController.addPageRequestListener(onPageRequest);
  }

  void onPageRequest(pageKey){
    // request data here
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para que não esqueçamos de usar dispose no nosso controller, criaremos a classe abstrata &lt;strong&gt;ViewController&lt;/strong&gt; e vamos fazer nossa pagination controller extender dela.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import 'package:flutter/material.dart';

abstract class ViewController&amp;lt;TState extends State&amp;gt; implements SimpleController {
  final TState state;

  ViewController(this.state);
}

abstract interface class SimpleController{
  void dispose();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora implementamos a função dispose e damos dispose em nossa &lt;code&gt;pagingController&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@override
  void dispose() {
    pagingController.dispose();
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Precisaremos passar dois parâmetros para nossa classe: o &lt;code&gt;ref&lt;/code&gt; (esse objeto nos ajuda a interagir com providers), e o nosso provider que busca os dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class RiverpodPaginationController extends ViewController {
  final WidgetRef ref;

    ProviderListenable&amp;lt;AsyncValue&amp;lt;UsersPagedList&amp;lt;UserModel&amp;gt;&amp;gt;&amp;gt; Function(
    int pageKey,
  ) provider;

final PagingController&amp;lt;int, UserModel&amp;gt; pagingController =
      PagingController(firstPageKey: 0);

  RiverpodPaginationController(super.state, {
    required this.ref,
    required this.provider,
  }) {
    pagingController.addPageRequestListener(onPageRequest);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos criar uma lista de &lt;code&gt;ProviderListenable&lt;/code&gt; e a cada chamada de página adicionamos um novo ProviderListenable, usando a função &lt;code&gt;onPageRequest&lt;/code&gt; que é chamada na nossa &lt;code&gt;addPageRequestListener&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
final List&amp;lt;ProviderSubscription&amp;lt;AsyncValue&amp;lt;UsersPagedList&amp;lt;UserModel&amp;gt;&amp;gt;&amp;gt;&amp;gt;
      subs = [];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usaremos o &lt;code&gt;ref.listenManual&lt;/code&gt; onde passaremos o provider e uma função que vai ser executada toda vez que o valor do provider mudar, chamaremos essa função de handleState. Não esquecendo de passar &lt;code&gt;fireImmediately&lt;/code&gt; como true.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void onPageRequest(int pageKey) {
    subs.add(
      ref.listenManual(
        provider(pageKey),
            (previous, next) {
          handleState(
            pageInfo: next,
            pageKey: pageKey,
            previousState: previous,
          );
        },
        fireImmediately: true,
      ),
    );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na nossa &lt;code&gt;handleState&lt;/code&gt; usaremos a função .when para lidar com o valor AsyncValue e seguimos a lógica de paginação do infiniteScrollPagination:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void handleState({
    required AsyncValue&amp;lt;UsersPagedList&amp;lt;UserModel&amp;gt;&amp;gt;? previousState,
    required AsyncValue&amp;lt;UsersPagedList&amp;lt;UserModel&amp;gt;&amp;gt; pageList,
    required int pageKey,
  }) async {
    await pageList.when(
      skipLoadingOnRefresh: true,
      data: (pagedListData) async {
        final List&amp;lt;UserModel&amp;gt; usersList = pagedListData.users;

        final isLastPage = usersList.length &amp;lt; pagedListData.limit;

        usersList.forEach((element) async {
          final coverImageUrl = element.profile_picture;

          await DefaultCacheManager().downloadFile(coverImageUrl);
        });

        if (isLastPage) {
          pagingController.appendLastPage(usersList);
        } else {
          final nextPageKey = pageKey + 1;
          pagingController.appendPage(usersList, nextPageKey);
        }
      },
      error: (error, stack) {
        pagingController.error = error;
      },
      loading: () {
        print("Loading...");
      },
    );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;‎ &lt;br&gt;
‎ &lt;/p&gt;
&lt;h2&gt;
  
  
  View
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknaslw7n5oww4spo9i52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknaslw7n5oww4spo9i52.png" alt="My paginated list with riverpod" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos criar nosso provider que busca os dados. Será um &lt;code&gt;FutureProvider&lt;/code&gt;com os modificadores &lt;code&gt;.familly&lt;/code&gt; (obtém um único provider com base em um parâmetro externo) e &lt;code&gt;autoDispose&lt;/code&gt;(para destruir o estado de um provider quando ele não está mais sendo utilizado).&lt;/p&gt;

&lt;p&gt;Vamos usar &lt;code&gt;ref.keepAlive&lt;/code&gt; na primeira página pra que esses dados sejam guardados.&lt;/p&gt;

&lt;p&gt;Assim como a &lt;a href="https://riverpod.dev/docs/essentials/auto_dispose#example-keeping-state-alive-for-a-specific-amount-of-time"&gt;documentação do riverpod&lt;/a&gt; nos mostra, podemos implementar um método de extensão para manter o estado ativo durante um periodo de tempo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension CacheForExtension on AutoDisposeRef&amp;lt;Object?&amp;gt; {
  /// Keeps the provider alive for [duration].
  void cacheFor(Duration duration) {
    // Immediately prevent the state from getting destroyed.
    final link = keepAlive();
    // After duration has elapsed, we re-enable automatic disposal.
    final timer = Timer(duration, link.close);

    // Optional: when the provider is recomputed (such as with ref.watch),
    // we cancel the pending timer.
    onDispose(timer.cancel);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então nosso provider fica assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final usersProvider = FutureProvider.autoDispose
    .family&amp;lt;UsersPagedList&amp;lt;UserModel&amp;gt;, int&amp;gt;((ref, pageNumber) async {
  /// Keeps the state alive for 10 seconds

  final users = await ref.read(usersRepositoryProvider).fetchUsers(pageNumber);

  if (pageNumber == 0) {
    ref.keepAlive();
  } else {
    ref.cacheFor(const Duration(seconds: 10));

    ref.onDispose(() {
      print('Dispose');
    });
  }

  return users.asFuture;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na view usaremos o &lt;code&gt;ConsumerStatefulWidget&lt;/code&gt; (que é equivalente ao StateFullWidget, com a diferença que no State temos acesso ao objeto &lt;code&gt;ref&lt;/code&gt;) do riverpod, e a classe RiverpodPaginationController vai ser instanciada no initState:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UsersView extends ConsumerStatefulWidget {
  const UsersView({super.key});

  @override
  ConsumerState&amp;lt;UsersView&amp;gt; createState() =&amp;gt; _UsersViewState();
}

class _UsersViewState extends ConsumerState&amp;lt;UsersView&amp;gt; {
  late final RiverpodPaginationController paginationController;

  @override
  void initState() {
    super.initState();
    paginationController = RiverpodPaginationController(
      this,
      ref: ref,
      provider: (pageKey) =&amp;gt; usersProvider(pageKey),
    );
  }

  @override
  Widget build(BuildContext context) {
    return FluentScaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        title: const Text(
          "Users List",
          style: TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.w500,
          ),
        ),
        actions: const [
          Padding(
            padding: EdgeInsets.only(right: 16),
            child: Icon(Icons.info),
          ),
          Padding(
            padding: EdgeInsets.only(right: 16),
            child: Icon(Icons.add_circle),
          ),
        ],
        foregroundColor: Colors.white70,
        backgroundColor: Colors.transparent,
      ),
      body: Container(
        padding: const EdgeInsets.only(top: 18),
        decoration: const BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Color(0XFF273754),
              Color(0XFF4b6696),
            ],
          ),
        ),
        child: SafeArea(
          child: Column(
            children: [
              SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: Padding(
                  padding: const EdgeInsets.only(bottom: 30, top: 16),
                  child: Row(
                    children: [
                      const SizedBox(width: 16),
                      Container(
                        decoration: BoxDecoration(
                            color: Colors.cyan,
                            borderRadius: BorderRadius.circular(8)),
                        padding: const EdgeInsets.all(10),
                        child: const Text(
                          "Lorem Ipsum",
                          style: TextStyle(
                            fontSize: 18,
                          ),
                        ),
                      ),
                      const SizedBox(width: 16),
                      Container(
                        decoration: BoxDecoration(
                          color: Colors.cyan,
                          borderRadius: BorderRadius.circular(8),
                        ),
                        padding: const EdgeInsets.all(10),
                        child: const Text(
                          "Lorem Ipsum",
                          style: TextStyle(
                            fontSize: 18,
                          ),
                        ),
                      ),
                      const SizedBox(width: 16),
                      Container(
                        decoration: BoxDecoration(
                          color: Colors.cyan,
                          borderRadius: BorderRadius.circular(8),
                        ),
                        padding: const EdgeInsets.all(10),
                        child: const Text(
                          "Lorem Ipsum",
                          style: TextStyle(
                            fontSize: 18,
                          ),
                        ),
                      )
                    ],
                  ),
                ),
              ),
              Expanded(
                child: PagedListView(
                  pagingController: paginationController.pagingController,
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  builderDelegate: PagedChildBuilderDelegate&amp;lt;UserModel&amp;gt;(
                    animateTransitions: false,
                    itemBuilder: (context, item, index) {
                      return Container(
                        decoration: BoxDecoration(
                          border: Border(
                            bottom: BorderSide(
                              color: const Color(0XFF57859b).withOpacity(0.7),
                              width: 0.5,
                            ),
                          ),
                        ),
                        padding: const EdgeInsets.symmetric(vertical: 18),
                        child: Row(
                          children: [
                            FluentContainer(
                              cornerRadius: FluentCornerRadius.circle,
                              shadow: FluentThemeDataModel.of(context)
                                  .fluentShadowTheme
                                  ?.shadow8,
                              width: 60,
                              height: 60,
                              child: Image.network(
                                item.profile_picture,
                                fit: BoxFit.cover,
                              ),
                            ),
                            const SizedBox(width: 20),
                            Expanded(
                              child: Container(
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      item.first_name + item.last_name,
                                      textAlign: TextAlign.start,
                                      style: const TextStyle(
                                        fontWeight: FontWeight.w600,
                                        color: Colors.white,
                                        fontSize: 18,
                                      ),
                                    ),
                                    const SizedBox(
                                      height: 4,
                                    ),
                                    Text(
                                      item.email,
                                      textAlign: TextAlign.center,
                                      style: const TextStyle(
                                        fontSize: 13,
                                        color: Colors.white,
                                      ),
                                    ),
                                    Row(
                                      children: [
                                        Icon(
                                          FluentIcons.location_12_filled,
                                          size: FluentSize.size120.value,
                                          color: Colors.white60,
                                        ),
                                        const SizedBox(
                                          width: 4,
                                        ),
                                        Text(
                                          item.city,
                                          style: const TextStyle(
                                            fontSize: 13,
                                            color: Colors.white60,
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ],
                        ),
                      );
                    },
                    firstPageErrorIndicatorBuilder: (context) =&amp;gt; Center(
                      child: FilledButton(
                        onPressed: () {
                          print("Should be refreshing");
                          paginationController.pagingController.refresh();
                        },
                        child: const Text(
                          "Tente Novamente",
                        ),
                      ),
                    ),
                    newPageErrorIndicatorBuilder: (context) =&amp;gt; Center(
                      child: FilledButton(
                        onPressed: () {
                          print("Should be refreshing");
                          paginationController.pagingController.refresh();
                        },
                        child: const Text(
                          "Tente Novamente",
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Model
&lt;/h2&gt;

&lt;p&gt;Essas são minhas Models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;‎ UserModel:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UserModel {
  final int id;
  final String city;
  final String email;
  final String last_name;
  final String first_name;
  final String profile_picture;

  UserModel({
    required this.id,
    required this.city,
    required this.email,
    required this.last_name,
    required this.first_name,
    required this.profile_picture,
  });

  factory UserModel.fromJson(Map&amp;lt;String, dynamic&amp;gt; json) {
    return UserModel(
      id: json["id"] as int,
      city: json["city"].toString(),
      email: json["email"].toString(),
      last_name: json["last_name"].toString(),
      first_name: json["first_name"].toString(),
      profile_picture: json["profile_picture"].toString(),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;UsersPagedList:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class UsersPagedList&amp;lt;T&amp;gt; {
  final bool success;
  final String message;
  final int total_users;
  final int offset;
  final int limit;
  final List&amp;lt;T&amp;gt; users;

  UsersPagedList.raw({
    required this.success,
    required this.total_users,
    required this.message,
    required this.offset,
    required this.limit,
    required this.users,
  });

  factory UsersPagedList.fromJson(
    Map&amp;lt;String, Object?&amp;gt; jsonObject,
    FromJsonObjectConstructor&amp;lt;T&amp;gt; constructor,
  ) {
    return UsersPagedList.raw(
      success: jsonObject["success"]! as bool,
      total_users: jsonObject["total_users"]! as int,
      message: jsonObject["message"].toString(),
      offset: jsonObject["offset"]! as int,
      limit: jsonObject["limit"]! as int,
      users: (jsonObject["users"]! as List&amp;lt;dynamic&amp;gt;)
          .cast&amp;lt;Map&amp;lt;String, Object?&amp;gt;&amp;gt;()
          .map((jsonObject) {
        return constructor(jsonObject);
      }).toList(),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>flutter</category>
      <category>dart</category>
      <category>riverpod</category>
      <category>pagination</category>
    </item>
  </channel>
</rss>
