<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Oussama Aniba]]></title><description><![CDATA[Portfolio & Blog]]></description><link>https://www.oaniba.com/</link><image><url>https://www.oaniba.com/favicon.png</url><title>Oussama Aniba</title><link>https://www.oaniba.com/</link></image><generator>Ghost 5.81</generator><lastBuildDate>Sun, 03 May 2026 12:24:44 GMT</lastBuildDate><atom:link href="https://www.oaniba.com/blog/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Dependency Injection in Kotlin Multiplatform (KMP) with Koin]]></title><description><![CDATA[<p></p><p>As a mobile developer Dependency Injection (DI) is a design pattern in software engineering where an object&apos;s dependencies are provided (or &quot;injected&quot;) by an external entity rather than the object creating the dependencies itself. This is typically achieved through a constructor, setter, or interface injection. The</p>]]></description><link>https://www.oaniba.com/kotlin-kmp-class-injection-with-koin-android-ios/</link><guid isPermaLink="false">66818cd2e6c93e0001983057</guid><category><![CDATA[Kotlin]]></category><category><![CDATA[KMP]]></category><category><![CDATA[Kotlin multiplatform]]></category><category><![CDATA[Android]]></category><category><![CDATA[IOS]]></category><category><![CDATA[Koin dependency injection]]></category><category><![CDATA[DI]]></category><dc:creator><![CDATA[Oussama Aniba]]></dc:creator><pubDate>Mon, 01 Jul 2024 19:12:15 GMT</pubDate><media:content url="https://www.oaniba.com/content/images/2024/07/cover.webp" medium="image"/><content:encoded><![CDATA[<img src="https://www.oaniba.com/content/images/2024/07/cover.webp" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin"><p></p><p>As a mobile developer Dependency Injection (DI) is a design pattern in software engineering where an object&apos;s dependencies are provided (or &quot;injected&quot;) by an external entity rather than the object creating the dependencies itself. This is typically achieved through a constructor, setter, or interface injection. The main idea is to separate the creation of an object&apos;s dependencies from the object&apos;s behavior, promoting a more modular and testable codebase.</p><p>Let&apos;s start with some key fundamentals before digging into this topic. Still, it won&apos;t be long as many of you will be familiar with mobile development and dependency injection.</p><p>So why Koin?</p><p>Besides Koin supporting KMP environment, it provides an easy and efficient way to incorporate dependency injection into any Kotlin application (Multiplatform, Android, backend ...)</p><p>The goals of Koin are:</p><ul><li>Simplify your Dependency Injection infrastructure with smart API</li><li>Kotlin DSL is easy to read, easy to use, to lets you write any kind of application</li><li>Provides different kinds of integration from the Android ecosystem, to more backend needs like Ktor</li><li>Allow to be used with annotations</li></ul><p>AND THAT&apos;S SOME KIND OF INFORMATION THAT YOU COULD FIND EASILY ON THE INTERNET.. I know it&apos;s boring...</p><p>Enough talk and let&apos;s start the exciting part where you can see the magic &#x1F603;</p><p>For this example, I&apos;ll be using Pok&#xE9;API to display a list of Pokemon&apos;s</p><p>First Start by creating your project over </p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://kmp.jetbrains.com/?ref=oaniba.com#newProject"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Kotlin Multiplatform Wizard | JetBrains</div><div class="kg-bookmark-description">Create your first multiplatform project using the Kotlin Multiplatform wizard for Android, iOS, and Desktop, or use one of the pre-made templates.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.jetbrains.com/apple-touch-icon.png?r=1234" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin"><span class="kg-bookmark-author">JetBrains</span></div></div></a></figure><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/06/Screenshot-2024-06-30-at-20.40.05.png" class="kg-image" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" loading="lazy" width="1268" height="1802" srcset="https://www.oaniba.com/content/images/size/w600/2024/06/Screenshot-2024-06-30-at-20.40.05.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/06/Screenshot-2024-06-30-at-20.40.05.png 1000w, https://www.oaniba.com/content/images/2024/06/Screenshot-2024-06-30-at-20.40.05.png 1268w" sizes="(min-width: 720px) 720px"></figure><p>Leave the configuration as it is, only specify your project name and package name (Project ID), and then open it using your Android Studio (Mine is: Android Studio Koala | 2024.1.1)</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/06/Screenshot-2024-06-30-at-22.42.07.png" class="kg-image" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" loading="lazy" width="656" height="876" srcset="https://www.oaniba.com/content/images/size/w600/2024/06/Screenshot-2024-06-30-at-22.42.07.png 600w, https://www.oaniba.com/content/images/2024/06/Screenshot-2024-06-30-at-22.42.07.png 656w"></figure><p>After opening the project I cleaned the boilerplate code</p><p>let&apos;s start by importing packages and dependencies that we need, go to</p><p>gradle/libs.version.toml and add the following </p><p>Under [versions] add :</p><pre><code class="language-Kotlin">ktor-client = &quot;2.3.11&quot;
lifecycleViewModel = &quot;2.8.2&quot;

koin = &quot;3.6.0-alpha3&quot;
koinCompose = &quot;3.6.0-alpha3&quot;
koinComposeMultiplatform = &quot;1.2.0-alpha3&quot;
navigationCompose = &quot;2.7.0-alpha03&quot;</code></pre><p>Under [libraries] add :</p><pre><code class="language-kotlin">navigation-compose = { module = &quot;org.jetbrains.androidx.navigation:navigation-compose&quot;, version.ref = &quot;navigationCompose&quot; }

ktor-client-core = { module = &quot;io.ktor:ktor-client-core&quot;, version.ref = &quot;ktor-client&quot; }
ktor-client-encoding = { module = &quot;io.ktor:ktor-client-encoding&quot;, version.ref = &quot;ktor-client&quot; }
ktor-client-logging = { module = &quot;io.ktor:ktor-client-logging&quot;, version.ref = &quot;ktor-client&quot; }
ktor-client-darwin = { module = &quot;io.ktor:ktor-client-darwin&quot;, version.ref = &quot;ktor-client&quot; }
ktor-client-okhttp = { module = &quot;io.ktor:ktor-client-okhttp&quot;, version.ref = &quot;ktor-client&quot; }
ktor-client-content-negotiation = { module = &quot;io.ktor:ktor-client-content-negotiation&quot;, version.ref = &quot;ktor-client&quot; }
ktor-serialization-kotlinx-json = { module = &quot;io.ktor:ktor-serialization-kotlinx-json&quot;, version.ref = &quot;ktor-client&quot; }

koin-android = { module = &quot;io.insert-koin:koin-android&quot;, version.ref = &quot;koin&quot; }
koin-androidx-compose = { module = &quot;io.insert-koin:koin-androidx-compose&quot;, version.ref = &quot;koinCompose&quot; }
koin-core = { module = &quot;io.insert-koin:koin-core&quot;, version.ref = &quot;koin&quot; }
koin-compose = { module = &quot;io.insert-koin:koin-compose&quot;, version.ref = &quot;koinComposeMultiplatform&quot; }

lifecycle-viewmodel = { module = &quot;androidx.lifecycle:lifecycle-viewmodel&quot;, version.ref = &quot;lifecycleViewModel&quot;}
  </code></pre><p>Under [plugins] add :</p><pre><code class="language-kotlin">kotlin-serialization = { id = &quot;org.jetbrains.kotlin.plugin.serialization&quot;, version.ref = &quot;kotlin&quot; }</code></pre><p>Go to the APP level gradle file and add the following</p><p>First of all add under plugins</p><pre><code class="language-kotlin">alias(libs.plugins.kotlin.serialization)</code></pre><p>Under <em>sourceSets &gt;</em> <em>androidMain</em>.<em>dependencies : </em></p><pre><code class="language-kotlin">implementation(libs.ktor.client.okhttp)
implementation(libs.koin.android)
implementation(libs.koin.androidx.compose)</code></pre><p>Under <em>sourceSets &gt;</em> <em>commonMain</em>.<em>dependencies</em> <em>: </em></p><pre><code class="language-kotlin">implementation(libs.ktor.client.core)
implementation(libs.ktor.client.logging)            implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.content.negotiation)            implementation(libs.ktor.client.encoding)
api(libs.koin.core)
implementation(libs.koin.compose)            implementation(libs.navigation.compose)
implementation(libs.lifecycle.viewmodel)</code></pre><p>and then add the IOS part as follows:</p><pre><code class="language-kotlin">iosMain.dependencies {
     implementation(libs.ktor.client.darwin) // added
}</code></pre><p>Hit sync now and wait, once finished without errors, let&apos;s make sure we keep in mind some key conditions in mind</p><p>Upon creating modules we first need to know about the expect/actual implementation</p><h2 id="rules-for-expected-and-actual-declarations">Rules for expected and actual declarations&#xFEFF;<a href="https://kotlinlang.org/docs/multiplatform-expect-actual.html?ref=oaniba.com#rules-for-expected-and-actual-declarations"></a></h2><p>To define expected and actual declarations, follow these rules:</p><ol><li>In the common source set, declare a standard Kotlin construct. This can be a function, property, class, interface, enumeration, or annotation.</li><li>Mark this construct with the&#xA0;<code>expect</code>&#xA0;keyword. This is your&#xA0;<em>expected declaration</em>. These declarations can be used in the common code, but shouldn&apos;t include any implementation. Instead, the platform-specific code provides this implementation.</li><li>In each platform-specific source set, declare the same construct in the same package and mark it with the&#xA0;<code>actual</code>&#xA0;keyword. This is your&#xA0;<em>actual declaration</em>, which typically contains an implementation using platform-specific libraries.</li></ol><p>Now let&apos;s set what we need for HTTP calls, ViewModels, and Koin initialization</p><p>Under common main add the following files, preferably following the same architecture unless you know how to adapt the code based on your needs, the same structure must be added under androidMain and iosMain, and file nomination and path must be identical on all parts</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.19.44-1.png" class="kg-image" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" loading="lazy" width="640" height="724" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.19.44-1.png 600w, https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.19.44-1.png 640w"></figure><p></p><p>[module] package folder contains the following:</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.24.28.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.24.28.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.24.28.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.24.28.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.24.28.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.24.34.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.24.34.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.24.34.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.24.34.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.24.34.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.24.38.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.24.38.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.24.38.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.24.38.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.24.38.png 2400w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption><p><span style="white-space: pre-wrap;">Expects</span></p></figcaption></figure><p>[repository] package folder contains the following:</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.26.14.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.26.14.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.26.14.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.26.14.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.26.14.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.26.17.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.26.17.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.26.17.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.26.17.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.26.17.png 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>[source] package folder contains the following:</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.26.20.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.26.20.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.26.20.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.26.20.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.26.20.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.26.22.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.26.22.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.26.22.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.26.22.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.26.22.png 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>[models] package folder contains the following:</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-20.05.52.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-20.05.52.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-20.05.52.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-20.05.52.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-20.05.52.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-20.05.49.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-20.05.49.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-20.05.49.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-20.05.49.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-20.05.49.png 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>this data class has been generated using JSON to Kotlin class plugin in Android Studio, you can see the actual data that we will be using <a href="https://pokeapi.co/api/v2/pokemon?ref=oaniba.com" rel="noreferrer">Pok&#xE9;mon API</a></p><p>Now let&apos;s see what&apos;s under the hood for <strong>androidMain</strong> and <strong>iosMain</strong> folder</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.36.07.png" width="622" height="438" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.36.07.png 600w, https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.36.07.png 622w"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.37.56.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.37.56.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.37.56.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.37.56.png 1600w, https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.37.56.png 2000w" sizes="(min-width: 720px) 720px"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.37.53-1.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.37.53-1.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.37.53-1.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.37.53-1.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.37.53-1.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.39.36.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.39.36.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.39.36.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.39.36.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.39.36.png 2400w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption><p><b><strong style="white-space: pre-wrap;">androidMain</strong></b></p></figcaption></figure><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.42.41.png" width="628" height="264" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.42.41.png 600w, https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.42.41.png 628w"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.41.30.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.41.30.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.41.30.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.41.30.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.41.30.png 2400w" sizes="(min-width: 720px) 720px"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.41.33.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.41.33.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.41.33.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.41.33.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.41.33.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-01.41.36.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-01.41.36.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-01.41.36.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-01.41.36.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-01.41.36.png 2400w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption><p><b><strong style="white-space: pre-wrap;">iosMain</strong></b></p></figcaption></figure><p>Extra configuration (Android only)</p><p>Let&apos;s define our Application entry and initialize Koin first</p><p>under androidMain &gt; kotlin &gt; com.your.package-name &gt; create a file/class PokeApplication and set-up the following</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-19.19.36.png" class="kg-image" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" loading="lazy" width="2000" height="1594" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-19.19.36.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-19.19.36.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-19.19.36.png 1600w, https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-19.19.36.png 2000w" sizes="(min-width: 720px) 720px"></figure><p>Add Internet permission and name attribute into AndroidManifest.xml</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-19.20.03.png" class="kg-image" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" loading="lazy" width="2000" height="1594" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-19.20.03.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-19.20.03.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-19.20.03.png 1600w, https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-19.20.03.png 2000w" sizes="(min-width: 720px) 720px"></figure><p>Hurraaaaaaah!! you made it, start your project, and hopefully, you won&apos;t face any issues. if so let&apos;s take a look inside our viewModel and display some quick information, nothing much just a list that shows what we got through the Pok&#xE9; API</p><p>PS: I didn&apos;t mind much about the design or the design pattern or even the architecture the sole reason for this article is to show you how things are done with KMP</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-20.03.59-1.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-20.03.59-1.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-20.03.59-1.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-20.03.59-1.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-20.03.59-1.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-20.03.51-1.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-20.03.51-1.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-20.03.51-1.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-20.03.51-1.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-20.03.51-1.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://www.oaniba.com/content/images/2024/07/Screenshot-2024-07-01-at-20.03.43-1.png" width="2000" height="1594" loading="lazy" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin" srcset="https://www.oaniba.com/content/images/size/w600/2024/07/Screenshot-2024-07-01-at-20.03.43-1.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/07/Screenshot-2024-07-01-at-20.03.43-1.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/07/Screenshot-2024-07-01-at-20.03.43-1.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/07/Screenshot-2024-07-01-at-20.03.43-1.png 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>I won&apos;t be explaining much about the UI or the business logic as I presume that if you are reading this article you know enough about Jetpack Compose principle and Kotlin </p><p>You can find the full source code through my <a href="https://github.com/oussamaniba/pokedeck-koin-di?ref=oaniba.com" rel="noreferrer">GitHub Repository</a></p><p>Hope this can help you through your learning journey as I am still learning</p><p>Enjoy!</p><p>References:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://kotlinlang.org/docs/multiplatform-expect-actual.html?ref=oaniba.com#different-approaches-for-using-expected-and-actual-declarations"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Expected and actual declarations | Kotlin</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://kotlinlang.org/assets/images/apple-touch-icon-144x144.png?v2" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin"><span class="kg-bookmark-author">Kotlin Help</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://kotlinlang.org/assets/images/open-graph/docs.png" alt="Dependency Injection in Kotlin Multiplatform (KMP) with Koin"></div></a></figure><figure class="kg-card kg-embed-card kg-card-hascaption"><iframe width="200" height="113" src="https://www.youtube.com/embed/TAKZy3uQTdE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="Full Guide to Dependency Injection With Koin for Compose Multiplatform - KMP for Beginners"></iframe><figcaption><p><span style="white-space: pre-wrap;">THIS DUDE IS AWESOOOOOOOME !</span></p></figcaption></figure>]]></content:encoded></item><item><title><![CDATA[Retrofit ft. Dio API calls using JSON class converters for Flutter]]></title><description><![CDATA[A flutter example of Android Native Retrofit API calls]]></description><link>https://www.oaniba.com/retrofit-ft-dio-api-calls-using-json-class-converters-service-for-flutter/</link><guid isPermaLink="false">660c7f0de6c93e0001983018</guid><dc:creator><![CDATA[Oussamaniba]]></dc:creator><pubDate>Sat, 17 Sep 2022 18:42:14 GMT</pubDate><media:content url="https://www.oaniba.com/content/images/2024/04/VhPa06xt2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.oaniba.com/content/images/2024/04/VhPa06xt2.jpg" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter"><p>A flutter example of Android Native Retrofit API calls</p><p>In this article, we will discuss Retrofit and Dio API calls and the usage of custom interceptors in a singleton class</p><blockquote><strong>Table of content</strong></blockquote><ol><li>What are APIs?</li><li>What&#x2019;s Retrofit</li><li>What are flutter data classes?</li><li>Full use case of Retrofit</li></ol><blockquote><strong>Important tools</strong></blockquote><ol><li>Flutter SDK 3.3.0</li><li>Visual Code or Android Studio</li><li>A little bit of patience and knowledge :)</li></ol><h3 id="what-are-apis">What are APIs?</h3><p>API stands for <strong>Application Programming Interface</strong>. In the context of APIs, the word Application refers to any software with a distinct function. An interface can be thought of as a contract of service between two applications. This contract defines how the two communicate using requests and responses.</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-1dkpvogen084nx8qco2vcg.png" class="kg-image" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter" loading="lazy" width="640" height="300" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-1dkpvogen084nx8qco2vcg.png 600w, https://www.oaniba.com/content/images/2024/04/1-1dkpvogen084nx8qco2vcg.png 640w"></figure><h3 id="what-is-retrofit">What is Retrofit?</h3><p>Retrofit is a library that your API into JAVA, Kotlin, and in our case Dart Interfaces</p><p>This tool uses code generation for all platforms in our case we will need to import it alongside Retrofit generator and build runner</p><p>You can use this as the actual date of this article.</p><pre><code>dependencies: 
  retrofit:</code></pre><pre><code>dev_dependencies:</code></pre><h3 id="what-are-flutter-data-classes"><strong>What are </strong>flutter data classes<strong>?</strong></h3><p>A data class refers to <strong>a class that contains only fields, values, and CRUD methods for accessing them (getters and setters</strong>)</p><p>In Dart data classes can be presented such as the example below:</p><pre><code>class OrderItem { 
  final num id; 
  final List&lt;num&gt; pid; 
 
  OrderItem( 
    this.id, 
    this.pid, 
  ); 
 
  OrderItem copyWith({ 
    num? id, 
    List&lt;num&gt;? pid, 
  }) { 
    return OrderItem( 
      id ?? this.id, 
      pid ?? this.pid, 
    ); 
  } 
 
  Map&lt;String, dynamic&gt; toMap() { 
    return &lt;String, dynamic&gt;{ 
      &apos;id&apos;: id, 
      &apos;pid&apos;: pid, 
    }; 
  } 
 
  factory OrderItem.fromMap(Map&lt;String, dynamic&gt; map) { 
    return OrderItem( 
      map[&apos;id&apos;] as num, 
      List&lt;num&gt;.from( 
        (map[&apos;pid&apos;] as List&lt;num&gt;), 
      ), 
    ); 
  } 
 
  String toJson() =&gt; json.encode(toMap()); 
 
  factory OrderItem.fromJson(String source) =&gt; 
      OrderItem.fromMap(json.decode(source) as Map&lt;String,dynamic&gt;); 
 
  @override 
  String toString() =&gt; &apos;OrderItem(id: $id, pid: $pid)&apos;; 
 
  @override 
  bool operator ==(covariant OrderItem other) { 
    if (identical(this, other)) return true; 
 
    return other.id == id &amp;&amp; listEquals(other.pid, pid); 
  } 
 
  @override 
  int get hashCode =&gt; id.hashCode ^ pid.hashCode; 
}</code></pre><blockquote>Note: this is just an example that we won&#x2019;t be using during this article</blockquote><h3 id="full-use-case-of-retrofit">Full use case of Retrofit</h3><p>First of all, we will need our test API or something that will help us simulate what we call a Request and Response, and for that, we will be using the <a href="https://jsonplaceholder.typicode.com/?ref=oaniba.com" rel="nofollow noopener">https://jsonplaceholder.typicode.com/</a></p><p>This website will help us test our use case without the need to build or mock data as it accepts multiple Request Methods such as POST, GET, and PUT</p><p>If you visit the link <a href="https://jsonplaceholder.typicode.com/posts?ref=oaniba.com" rel="nofollow noopener">https://jsonplaceholder.typicode.com/posts</a> you&#x2019;ll see what an API response looks like.</p><p>Now let&#x2019;s start by creating our data class for POSTS to facilitate that I&#x2019;ll be using <a href="https://www.dripcoding.com/json-to-dart/?ref=oaniba.com" rel="nofollow noopener">https://www.dripcoding.com/json-to-dart/</a>. Basically, it&#x2019;s just pasting a JSON response from one side and copying the data class from the other</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-ntgdhrkauf-m2asijy_e7w.png" class="kg-image" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter" loading="lazy" width="800" height="464" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-ntgdhrkauf-m2asijy_e7w.png 600w, https://www.oaniba.com/content/images/2024/04/1-ntgdhrkauf-m2asijy_e7w.png 800w" sizes="(min-width: 720px) 720px"></figure><p>Create a Dart class name it as you like and past the right part of your screen inside of it use &#x201C;COPY DART&#x201D;.</p><hr><p>Now let&#x2019;s start by creating too different .dart files</p><ul><li><strong>endpoints.dart:</strong></li></ul><p>This one will hold all of our endpoints for example posts/, users/, comments/ &#x2026; and so on</p><blockquote>So far our case will be based on posts/ end point</blockquote><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-en6wnqbfh6-tj1rhc6iwfq.png" class="kg-image" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter" loading="lazy" width="800" height="621" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-en6wnqbfh6-tj1rhc6iwfq.png 600w, https://www.oaniba.com/content/images/2024/04/1-en6wnqbfh6-tj1rhc6iwfq.png 800w" sizes="(min-width: 720px) 720px"></figure><p>Create another file called in my case <strong>api_service.dart, </strong>this one will hold all the logic of our API calls as you can see in the screenshot below.</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-ubl6zdl88-oivsqspvtd8a.png" class="kg-image" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter" loading="lazy" width="800" height="621" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-ubl6zdl88-oivsqspvtd8a.png 600w, https://www.oaniba.com/content/images/2024/04/1-ubl6zdl88-oivsqspvtd8a.png 800w" sizes="(min-width: 720px) 720px"></figure><p>The most important part of this screen is the RestClientApi abstract class it contains all the API calls GET, PUT, and POST and each one of them has a different type of annotation and passed parameter. So far our code has multiple errors but that&#x2019;s okay it will be fixed by going to your IDE terminal and typing the following command:</p><p>Note: add the line <strong>part &#x201C;api_service.g.dart&#x201D;</strong> even if does not exist</p><p><strong>flutter pub run build_runner build&#x200A;&#x2014;&#x200A;delete-conflicting-outputs</strong></p><p>Wait for some time... and voila, a file named api_service.g.dart will be automatically generated containing the elements below but please don&#x2019;t add or delete anything if you submit any modification rerun the later command.</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-z895abfcplqrzulmuhax3w.png" class="kg-image" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter" loading="lazy" width="800" height="621" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-z895abfcplqrzulmuhax3w.png 600w, https://www.oaniba.com/content/images/2024/04/1-z895abfcplqrzulmuhax3w.png 800w" sizes="(min-width: 720px) 720px"></figure><p>Now ladies and gentlemen let us try our API calls and see the results</p><blockquote>Note: I&#x2019;ll be creating a basic UI that you can use from the repo at the end of this article</blockquote><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.oaniba.com/content/images/2024/04/1-vjd4umtlf74lckvb3fk6nq.png" class="kg-image" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter" loading="lazy" width="800" height="666" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-vjd4umtlf74lckvb3fk6nq.png 600w, https://www.oaniba.com/content/images/2024/04/1-vjd4umtlf74lckvb3fk6nq.png 800w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Result 1</span></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.oaniba.com/content/images/2024/04/1-nkbwz-3imso2sz5lx2rp2q.png" class="kg-image" alt="Retrofit ft. Dio API calls using JSON class converters for Flutter" loading="lazy" width="800" height="666" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-nkbwz-3imso2sz5lx2rp2q.png 600w, https://www.oaniba.com/content/images/2024/04/1-nkbwz-3imso2sz5lx2rp2q.png 800w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Result 2</span></figcaption></figure><blockquote>You can find the whole example on my GitHub link below</blockquote><p>This will be the end of our little example and I hope it wasn&#x2019;t too much to handle, this is basic stuff that will help with bigger projects, and to assure you this is what I use for my day-by-day, 9-to-5 job as a Mobile Software Engineer</p><p>Enjoy the reading, see you soon, and if you have any suggestions for other subjects JAVA, Kotlin, or dart, use the comment section to let me know.</p><p>GitHub Repo: <a href="https://github.com/oussamaniba/retrofit_medium_example?ref=oaniba.com" rel="nofollow noopener">https://github.com/oussamaniba/retrofit_medium_example</a></p>]]></content:encoded></item><item><title><![CDATA[Dynamic Bottom sheets content using Sliding Panel and Streams use-case]]></title><description><![CDATA[A quick way of exploiting your pages to the fullest.]]></description><link>https://www.oaniba.com/dynamic-bottom-sheets-content-using-sliding-panel-and-streams-use-case/</link><guid isPermaLink="false">660c7f0de6c93e000198301a</guid><dc:creator><![CDATA[Oussamaniba]]></dc:creator><pubDate>Sun, 24 Jul 2022 01:05:50 GMT</pubDate><media:content url="https://www.oaniba.com/content/images/2024/04/1-amrwkglg1bxhufahfa5qwg-jpeg.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.oaniba.com/content/images/2024/04/1-amrwkglg1bxhufahfa5qwg-jpeg.jpg" alt="Dynamic Bottom sheets content using Sliding Panel and Streams use-case"><p>A quick way of exploiting your pages to the fullest.</p><p>Managing users routes and pages can be tedious when you have a lot of features in some parts of your app. Today we will discover an easy way to manage your screens and widgets using a sign-in and sign-up page as an example.</p><p><strong><em>Table of contents.</em></strong></p><p>1- What is Bottom Sheet?<br>2- What are Dart streams?<br>3- real use-case with Sign-in, Sign-up and Recover account pages</p><hr><p>Demo:</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-gozgx54x3kc70jvdptuq7g.gif" class="kg-image" alt="Dynamic Bottom sheets content using Sliding Panel and Streams use-case" loading="lazy" width="600" height="1087" srcset="https://www.oaniba.com/content/images/2024/04/1-gozgx54x3kc70jvdptuq7g.gif 600w"></figure><blockquote><strong>Bottom sheet quick definition</strong></blockquote><p>Modal bottom sheets in Flutter display additional content while restricting the user from interacting with the app&#x2019;s main content. As the name suggests, a bottom sheet is positioned at the bottom of the screen.</p><p>Let&#x2019;s say, for example, you have a photo saved in Google Photos that you want to share with a friend. When you tap the photo and click <strong>SHARE</strong>, some additional information shows up at the bottom of the screen:</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-flsxk_wxgsdmtxj7fz9etw-jpeg.jpg" class="kg-image" alt="Dynamic Bottom sheets content using Sliding Panel and Streams use-case" loading="lazy" width="500" height="1111"></figure><hr><blockquote><strong>Dart streams quick definition</strong></blockquote><p>A <strong>Stream</strong> is a sequence of <strong>asynchronous events</strong>. It is like an asynchronous Iterable&#x200A;&#x2014;&#x200A;where, instead of getting the next event when you ask for it, the stream tells you that there is an event when it is ready.</p><p>In other words, streams are a source of asynchronous events delivered sequentially. There are data events, which are sometimes referred to as elements of the stream due to a stream&#x2019;s similarity to a list, and there are error events, which are notifications of failure. Once all data elements have been emitted, a special event signaling the stream is done will notify any listeners that there is no more.</p><hr><blockquote><strong>Use-case of streams alongside Bottom sheets</strong></blockquote><p>Let&#x2019;s start by creating an empty Flutter project using Terminal:</p><ul><li><em>flutter create example_project</em></li></ul><p>Let&#x2019;s import a few packages from <a href="http://pub.dev/?ref=oaniba.com" rel="noopener">Pub.dev</a>, we will be using one package named <a href="https://pub.dev/packages/sliding_up_panel?ref=oaniba.com" rel="noopener">sliding_up_panel</a></p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-immcawfxszlot1i5h_oovw.png" class="kg-image" alt="Dynamic Bottom sheets content using Sliding Panel and Streams use-case" loading="lazy" width="1640" height="938" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-immcawfxszlot1i5h_oovw.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/04/1-immcawfxszlot1i5h_oovw.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/04/1-immcawfxszlot1i5h_oovw.png 1600w, https://www.oaniba.com/content/images/2024/04/1-immcawfxszlot1i5h_oovw.png 1640w" sizes="(min-width: 720px) 720px"></figure><p>Once done importing go to the main Dart file and clear everything then create these files inside the lib folder even if it&#x2019;s not necessary, just to separate things:</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-sasc22wvgeemozjnmb1ujq.png" class="kg-image" alt="Dynamic Bottom sheets content using Sliding Panel and Streams use-case" loading="lazy" width="430" height="526"></figure><p>Inside the controller file, we will set up a few things that will help us achieve the purpose of this post. First, we will add a <strong>PanelController</strong> as it&#x2019;s included with<em> the sliding_up_panel</em> package that we imported earlier, we will also need a stream controller as it will help us send data to our <strong>StreamBuilder.</strong>PanelController panelController = PanelController();StreamController&lt;Widget?&gt; pageController = StreamController&lt;Widget?&gt;.broadcast();</p><p>Then let&#x2019;s add a function that will help us reduce the amount of code used for switching, showing, and hiding dynamic content.Future&lt;void&gt; slidePanelOn(Widget <em>screen</em>) async {<br>pageController.sink.add(<em>screen</em>);<br>await panelController.open();<br>}</p><p>Now let&#x2019;s set up our Root widget that will be responsible for holding and managing the content of the Sign-in, Sign-up, and Recover account pages</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-izps2d3i2p0teawwqiweeg.png" class="kg-image" alt="Dynamic Bottom sheets content using Sliding Panel and Streams use-case" loading="lazy" width="2000" height="1272" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-izps2d3i2p0teawwqiweeg.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/04/1-izps2d3i2p0teawwqiweeg.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/04/1-izps2d3i2p0teawwqiweeg.png 1600w, https://www.oaniba.com/content/images/size/w2400/2024/04/1-izps2d3i2p0teawwqiweeg.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>They will all have the same logic, as there&#x2019;s no need to create UI this post is just for educational purposes</p><p>Now inside our main Dart file let&#x2019;s add a StatefulWidget named RootWidget and the content will be as follow</p><figure class="kg-card kg-image-card"><img src="https://www.oaniba.com/content/images/2024/04/1-tdujein9c1q5g_cx9dg7jq.png" class="kg-image" alt="Dynamic Bottom sheets content using Sliding Panel and Streams use-case" loading="lazy" width="2000" height="1669" srcset="https://www.oaniba.com/content/images/size/w600/2024/04/1-tdujein9c1q5g_cx9dg7jq.png 600w, https://www.oaniba.com/content/images/size/w1000/2024/04/1-tdujein9c1q5g_cx9dg7jq.png 1000w, https://www.oaniba.com/content/images/size/w1600/2024/04/1-tdujein9c1q5g_cx9dg7jq.png 1600w, https://www.oaniba.com/content/images/2024/04/1-tdujein9c1q5g_cx9dg7jq.png 2366w" sizes="(min-width: 720px) 720px"></figure><ul><li>We need to define a bool <em>isPageOpen </em>to check whether the panel is open or not, so if we tap on the back button the app won&#x2019;t close rather it&#x2019;ll only close the bottom sheet with the help of dart&#x2019;s <em>WillPopScope</em> package</li><li>We need our panel set to min-height 0, max-height to <em>MediaQuery</em> full-size and we don&#x2019;t need it to be draggable</li><li>Our main screen will be the Sign-in page in the body parameter of RootWidget with two buttons controlling the opening of the panel projecting different screens Sign-up and Recover Account pages</li><li>As for the panel, it&#x2019;ll contain a <em>StreamBuilder </em>casting <em>&lt;Widget?&gt;</em> as a return type because when we close the panel we don&#x2019;t need anything to be saved at the bottom of our app for more performance and that&#x2019;s why we send null value through our <em>StreamController</em></li></ul><p>You can find the project on my Github page <a href="https://github.com/oussamaniba?ref=oaniba.com" rel="noopener">here</a>.</p><p>Or directly on <a href="https://github.com/oussamaniba/dynamic-bottom-sheet?ref=oaniba.com" rel="noopener">here</a>.</p><p>Hope you enjoy it.</p>]]></content:encoded></item></channel></rss>