<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Norbert on Medium]]></title>
        <description><![CDATA[Stories by Norbert on Medium]]></description>
        <link>https://medium.com/@norbertkozsir?source=rss-aca5101434f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/2*0btsmXnn_tCN4lxxly0Mlw.jpeg</url>
            <title>Stories by Norbert on Medium</title>
            <link>https://medium.com/@norbertkozsir?source=rss-aca5101434f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 03:31:27 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@norbertkozsir/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Detective, how to dramatically speed up debugging.]]></title>
            <link>https://medium.com/flutter-community/detective-how-to-dramatically-speed-up-debugging-d06bccb43f8a?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/d06bccb43f8a</guid>
            <category><![CDATA[dart]]></category>
            <category><![CDATA[debugging]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[debugging-tools]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Tue, 15 Dec 2020 19:19:26 GMT</pubDate>
            <atom:updated>2020-12-15T19:19:51.868Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*IVbiYY1gp5oCgc0dCJLB3Q.gif" /></figure><p><strong><em>TL;DR: I built a tool that lets you inspect app-state in real-time and allows you to do even more in the future. Visit </em></strong><a href="http://www.detective.dev/"><strong><em>www.detective.dev</em></strong></a><strong><em> for instructions on how to use it.</em></strong></p><h3>On debugging</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/0*UJaugBWJ12bm4i5q" /><figcaption>Source: every meme site on the internet.</figcaption></figure><p>Debugging can be fun at times, but most of the time, it just sucks. The feature is done, the workday is over but and you are ready to do anything but sit in front of the computer for the rest of the day. But just as you close your IDE you notice something, something that is bound to keep you awake at night: <strong>a bug</strong>.</p><p>You were ready to move on onto your next coding adventure (others call them “feature”) but you can’t.</p><p>I hope I’m not the only one feeling like this from time to time.</p><p>I did a Twitter poll and it turns out, debugging is a rather big part of developing an app, and scenarios like this aren’t the exception.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/609/0*EkC9tb7fH0Gsr4gc" /><figcaption>64 votes but it should contain some truth</figcaption></figure><p>Debugging mostly consists of guessing where the problem might be and then setting up assumptions and checking those.</p><blockquote>It’s like looking through a magnifying glass</blockquote><p>Sometimes you just don’t see the wood for the trees. When debugging, you only see a very small portion of your application. It may be the variables you printed out for debugging purposes or the current frame where the debugger hit a breakpoint. So you keep looking for the issue with a very small slice of the whole world and this works surprisingly well. People find bugs and subsequently fix them — but now imagine what happens when you have the power to see more? To levitate above the forest instead of standing in the middle of it.</p><h3>Detective to the rescue</h3><p>Detective allows you to inspect all the interesting application states at once. For information on how to install, head over to <a href="http://www.detective.dev/"><em>www.detective.dev</em></a><em>.</em></p><h4>How to use it</h4><p>First, you have to select a class you are interested in. This typically is some sort of class holding some mutable (<em>changeable</em>) state.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/645/0*1wQskJssTY4gKjt3" /><figcaption>In this case MyTestBloc</figcaption></figure><p>Next, select the specific instance to use. Most often, the class you are interested in only exists once, if that’s the case just select it. Sometimes you may not find an instance at all, there are a couple of reasons for that but one to watch out for is that <strong>Providers are lazy </strong>by default, meaning the instance will not be created until its first use.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/591/0*2VRbDVfXofxj_gK4" /></figure><p>And you are ready to go! Start by looking at the state of this specific instance of your class. Notice how changes, that you do by using the app, happen in real-time — no need for any reloading.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/502/0*GNpsu81GDGiM7h32" /></figure><h3>Seeing the big picture is great — but can we do even more?</h3><p>Good question! And the answer is a definite yes. State inspection is just the very beginning of all the possibilities with an app that is able to access meta information in combination with runtime information of a process. Here are my top three features on the roadmap:</p><h4>Debug function invocation</h4><p>Sometimes, while debugging, you just want to invoke a function, emit an event or change the state in a specific way. Usually, this happens through some sort of UI, but there can potentially be a couple of problems with that.</p><p><strong>The UI is not built yet</strong></p><p>Starting with logic first and then building the UI is generally a widespread approach. But testing said logic becomes hard without an interface, so usually, some kind of placeholder is implemented — this again takes time and can be avoided.</p><p><strong>UI cumbersome to use</strong></p><p>Some features just require lots of setup to move into the desired state. This could be tapping through long forms, changing system settings, or any other setup.</p><p><strong>Faster due to the use of presets &amp; shortcuts</strong></p><p>A lot of programmers prefer command lines and other text-based inputs due to having mastered the keyboard quite well. So why go the slow route of using a point and click UI?</p><h4>Visualizing class-dependency graphs</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/566/0*cRQMnn7KM2rzAGQm" /></figure><p>Everybody knows the term ‘spaghetti’ code. What that means is code that is very interconnected. Everything is referencing a lot of classes, maintaining such code becomes increasingly difficult as it is very hard to reason about a specific section without having the whole picture in one&#39;s mind.</p><p>Therefore is important to separate code into chunks that are very isolated, and thus making it easy to read and modify. A reference is when one class [‘<strong>Foo</strong>’ uses another class ‘<strong>Bar</strong>’], meaning [‘<strong>Foo</strong>’ depends on ‘<strong>Bar</strong>’] or [‘<strong>Foo</strong>’ references ‘<strong>Bar</strong>’]. If you look at all classes in your project and you notice a lot of cycles ([‘<strong>Foo</strong>’ uses ‘<strong>Bar</strong>’] and [‘<strong>Bar</strong>’ uses ‘<strong>Foo</strong>’]), it probably is a good indicator to refactor.</p><p>Getting a sense of the project structure can be hard at times because you can only look at one class at once. Visualizing this into a graph structure lets you reason more efficiently about the architecture you chose.</p><h4>State time travel</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/0*1Xo3ToTtN2h4M0Nw" /></figure><p><em>This one is potentially the coolest.</em></p><p>When debugging applications, a very interesting fact to learn about is state changes, and what causes them. Right now, when the state is changed, there is no going back. This means if you want to find out what leads to said state change, you are forced to redo the actions that led to right before the interesting state change.</p><p>Make this process of redoing time-consuming, and requiring multiple tries and you successfully spent more time than you wanted on solving the issue instead of creating something new.</p><p><strong>Detective </strong>has the potential to record interesting states as you interact with the app and replay it to you without having to do anything in the app anymore.</p><p>Think of this as time-travel in Redux web but for Flutter. I think it is pretty self-evident how this can potentially save a lot of time.</p><h4>Embedding it into IntelliJ and VSCode</h4><p>This one is pretty self-explanatory. Using the power of Flutter web, <strong>Detective </strong>can be built right into IntelliJ and VSCode, using a plugin, resulting in fewer windows on your desktop and even more productivity.</p><h3>Closing remarks</h3><p>If this sounds as execting to you as it does to me, be sure to give it a try at <a href="http://www.detective.dev/"><em>www.detective.dev</em></a><em>. </em>It only takes 3 commands to install.</p><p>If you want to stay up to date with the newest development information be sure to join the newsletter at the bottom of the site.</p><p>Last but not least, let me know what you think!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AuT0GXEd7j21RI6uXlxYTQ.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d06bccb43f8a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/detective-how-to-dramatically-speed-up-debugging-d06bccb43f8a">Detective, how to dramatically speed up debugging.</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing: Flutter Widget-Maker, a Flutter App-Builder written in Flutter]]></title>
            <link>https://medium.com/flutter-community/introducing-flutter-widget-maker-a-flutter-app-builder-written-in-flutter-231e8d959348?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/231e8d959348</guid>
            <category><![CDATA[code]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[ide]]></category>
            <category><![CDATA[software]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Sun, 03 Feb 2019 22:37:50 GMT</pubDate>
            <atom:updated>2019-02-03T22:37:50.099Z</atom:updated>
            <content:encoded><![CDATA[<h4>Much more than just a layout builder</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*bZoLu2GwC2seNXdAJ0i7Ow.gif" /></figure><p><em>This is a widget builder for Flutter. At first, it might look like just another layout builder, but this is going to be so much more.</em></p><p><em>Check out the landing page I made for this: </em><a href="https://norbert515.github.io/widget_maker/website/"><em>https://norbert515.github.io/widget_maker/website/</em></a></p><h3>Core features</h3><p>These are the features I feel are the core of the whole project.</p><p><em>Keep in mind, most of these features are not implemented yet.</em></p><h4>Code — Visual seamless transition</h4><p>There is not going to be any copy paste. You can work with the drag and drop interface while simultaneously modifying the code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*9CAO5kdRqpZ3KKyQtjY4UA.gif" /><figcaption>Adjust with minimal effort</figcaption></figure><h4>Stateful editing</h4><p>Interacting with widgets while also editing its source code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*H3F9CwctvzaFkfcSDiXKHQ.gif" /><figcaption>The App being edited is fully running</figcaption></figure><h4>Editing complex properties easily</h4><p>Editing BoxDecorations, CustomPaints, and CustomMultiChildLayouts with ease.</p><h3>The core philosophy of this project</h3><p><strong>Improve rather than replace</strong></p><p>Unlike some HTML editors — which try to hide the actual HTML and CSS code as good as possible (I get why - CSS is horrible), this editor embraces the power of the underlying code.</p><p>Instead of hiding the code under some GUI it generates clear, readable and correct code which happens to be visualized and editable through a GUI.</p><p><strong>No platform restricting</strong></p><p>The widget maker will run on all desktop platforms. In addition to that, it will be able to run on the web thanks to project Hummingbird.</p><p>Besides being able to run the editor on mobile, I’ll be looking into actually compiling apps on the phone, I’ve done some research and I’m pretty sure it is possible.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*tZoNGhSjm0GUk-vmTGQI0Q.gif" /><figcaption>App running on a tablet</figcaption></figure><p><strong>Does not require any fancy setup</strong></p><p>When opening a dart file containing a widget, widget maker will analyze and automatically pick up on that and suggest showing the visual editor.</p><p><strong>Made for everyone</strong></p><p>Doesn’t matter if you are new to Flutter or have been coding since the alpha. Widget maker will bring value to everyone.</p><h3>Fast feedback-loop</h3><p>A fast feedback loop is, in my opinion, the biggest productivity boosts you can get. And Flutter does a hell of a good job with its hot-reloads. But there are scenarios which can be improved.</p><p>I want to talk about one example: Developing a responsive layout.</p><p>What you would do is write the code and check how it looks on a small device, then you’d get your tablet and take a look at how it looks there.</p><p>You might also be fortunate enough to have an emulator/ embedder which supports resizes. This is already a huge improvement compared to having multiple physical devices/ emulators open at the same time. But you’d still have to change code — resize the window to a bunch of different sizes and repeat.</p><p>The workflow with Widget-Maker might look like the following:</p><p>Have differently sized flutter apps open in one GUI which update in real time as you slide a slider which, for example, controls the flex value of one of the Expanded’s.</p><h3>A few teasers for future possibilities</h3><p>I don’t want to talk about every single idea I have right now, simply because I first want to make it solid before expanding (and I have way too many ideas), but here are some ideas I thought about, which might make it into the application someday:</p><h4>Animations through keyframes</h4><p>Possible workflow:</p><p>Select a property and set a keyframe, press a button or trigger any other action, select the same property and add another keyframe.</p><p>The animation code is generated and used on the fly.</p><h4>Writing tests on the fly (without actually writing tests)</h4><p>Widget tests: automatically generated golden files (images of the widget to compare to) and basics assertions (the color you set is actually used etc.)</p><p>Integration tests: Click through your App and assert things (like Robolectric for Android) and then generate widget tests (which can be run headless) and actual on-device tests.</p><h4>Share and download widgets</h4><p>Similar to pub (the Dart package manager) but focused on widgets.</p><p>Key differences being:</p><ol><li>No need to add anything to pubspec.yaml</li><li>Browse widgets with preview and source code</li><li>Drag&amp;Drop in widgets from the web</li><li>Share and browse widgets</li></ol><h3>Downloading the program</h3><p>Head over to <a href="https://github.com/Norbert515/flutter_ide/releases/tag/v0.1-alpha">https://github.com/Norbert515/flutter_ide/releases/tag/v0.1-alpha</a></p><p>Just unzip the folder and run “run.bat”.</p><p>If it’s not working try installing the C++ runtime files (<a href="https://aka.ms/vs/15/release/vc_redist.x64.exe">https://aka.ms/vs/15/release/vc_redist.x64.exe</a>)</p><h3>What can you do to make this happen?</h3><p>I believe this could be a huge thing — but I need feedback.</p><p>Before diving in heads deep into this project (what some argue I already have) I need to find out whether people are actually interested in this.</p><p>For that purpose, I made the current demo available to download and play around with. But please keep in my, it’s just a demo. There are a few bugs in it and it’s nowhere near finished.</p><p>If you do like this project or have feedback please let me know on Twitter, through an e-mail or other communication channels. The more feedback I get the better I can make an informed decision about the future of this project.</p><p><em>PS. Thanks to </em><a href="https://twitter.com/devangelslondon?lang=en"><em>Simon Lightfoot</em></a><em> for the last minute panic help :)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=231e8d959348" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/introducing-flutter-widget-maker-a-flutter-app-builder-written-in-flutter-231e8d959348">Introducing: Flutter Widget-Maker, a Flutter App-Builder written in Flutter</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Coding Flutter Apps on your Phone with Flutter, an Experiment]]></title>
            <link>https://medium.com/flutter-community/coding-flutter-apps-on-your-phone-with-flutter-an-experiment-3b4e8a50dde?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/3b4e8a50dde</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[cross-platform]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[dart]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Sun, 30 Dec 2018 19:02:12 GMT</pubDate>
            <atom:updated>2018-12-30T20:59:24.746Z</atom:updated>
            <content:encoded><![CDATA[<h4>With code to try out at home</h4><p>Have you ever thought about how cool it would be if you could just make this quick change in your app without opening your laptop? Or you simply thought about the idea of writing Flutter apps on your phone.</p><p>I did some experimenting and I might have something for you!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*pDHo-DOjZPQ3RBA7_4Oeag.gif" /><figcaption>Writing Flutter Apps on the Phone</figcaption></figure><p>If you want to try it out, head over to this <a href="https://github.com/Norbert515/flutter_experiment_phone_ide">Github repository</a> which has a detailed setup guide.</p><p>This article will take a look at the hows and whys.</p><h3>How does it work?</h3><blockquote>It’s probably simpler than you thought.</blockquote><p>The compilation is still being done by a PC.</p><p>What is happening is that there is a server (written in Dart) running on the computer. It manages the files, handles building and reloading.</p><p>The app you are developing needs to include the IDE itself. This works by wrapping the topmost widget in an IdeApp.</p><pre><strong>class </strong>MyApp <strong>extends </strong>StatelessWidget {<br>  @override<br>  Widget build(BuildContext context) {<br>    <strong>return new </strong>MaterialApp(<br>      title: &#39;Flutter Demo&#39;,<br>      theme: <strong>new </strong>ThemeData(<br>        primarySwatch: Colors.<em>red</em>,<br>     ),<br>      home: IdeApp(child: <strong>new </strong>MyHomePage()),<br>    );<br>  }<br>}</pre><p>The IdeApp manages listing editable files, writing those back to the computer and invoking hot reloads.</p><p><em>Fun fact: because the IDE itself is inside the project, you can modify the phone-IDE through itself.</em></p><p>When pressing the hot-reload button in the app, a request is sent to the server to reload the app. It then performs a Flutter hot-reload and pushes the changes to the device (if it is Android, this goes through ADB).</p><h4>In the gif there is no cable, how’s that possible?</h4><p>The answer is simple: <a href="https://futurestud.io/tutorials/how-to-debug-your-android-app-over-wifi-without-root">ADB over WiFi</a>.</p><h4>So I’ll have to be in the same private network? What if I want to develop on the go?</h4><p>You still need to be in a private network with the build server but here is where VPNs (Virtual private networks) come to the rescue.</p><p>Using a VPN you can be in a private network anywhere on the earth <em>over the internet.</em></p><p>With a configured build server and a VPN, you can develop apps anywhere.</p><p>Be it on the train, while walking through the city or secretly in a lecture. All you need is an internet connection.</p><h3>Improvements</h3><p>Well, there are obviously a lot of possible improvements to this. Bear in mind, this was only an experiment I have written in about one day.</p><p><strong>A good text editor</strong></p><p>Having a good text editor that supports features every IDE needs would, in my opinion, makes this a somewhat viable way to develop in some cases.</p><p><strong>Compiling on the device instead of relying on a build server</strong></p><p>I think it might be possible, but I haven&#39;t looked into that too much.</p><p><strong>Not having to include the ide code in the actual app</strong></p><p>This should be possible. There are a few ways to achieve this. For example, the server could copy the project on start and inject the necessary classes on start.</p><h3>Is this actually useful?</h3><p><em>Probably not. </em>At least not yet.</p><h4>Could this be useful?</h4><p>In my opinion, yes.</p><p>Imagine being in a meeting with a client and he wants to see how the app looks like with a tiny change. Let’s be honest, is there any cooler way than taking out the phone and editing that small change right on the spot?</p><p>Also, writing code inside a running app and then hot reloading it, is quite satisfying.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/271/1*yC4sl6j6h34CMo_NvIHcgA.gif" /><figcaption>Hot-reloads on the phone ❤</figcaption></figure><h3>Conclusion</h3><p>I’ve been involved in building a <a href="https://medium.com/flutter-community/flutter-on-desktop-a-real-competitor-to-electron-4f049ea6b061">desktop embedder</a> and I’m currently exploring ideas in that area.</p><p>I’m actually working on something even crazier right now :)</p><p>Be sure to follow me on <a href="https://twitter.com/norbertkozsir?lang=en">Twitter</a>, to stay up to date.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3b4e8a50dde" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/coding-flutter-apps-on-your-phone-with-flutter-an-experiment-3b4e8a50dde">Coding Flutter Apps on your Phone with Flutter, an Experiment</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter on desktop, a real competitor to Electron]]></title>
            <link>https://medium.com/flutter-community/flutter-on-desktop-a-real-competitor-to-electron-4f049ea6b061?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/4f049ea6b061</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[desktop]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[dart]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Sat, 01 Dec 2018 19:01:35 GMT</pubDate>
            <atom:updated>2024-01-25T21:37:03.273Z</atom:updated>
            <content:encoded><![CDATA[<h4>Flutter desktop for real-world applications and to accelerate mobile development. A project made by <a href="https://twitter.com/devangelslondon">Simon Lightfoot</a> and <a href="https://twitter.com/norbertkozsir">Norbert Kozsir</a>.</h4><p>At its core, Flutter is a standalone, binary executable; making it a game-changer not only on mobile, but on desktop as well.</p><p>Writing once and deploying <strong>natively </strong>on Android, iOS, Windows, Mac and Linux and additionally sharing all the business logic to the web (using AngularDart) is a big deal.</p><p>Let’s explore this idea!</p><h3>Native Desktop client to accelerate mobile development</h3><p>But before taking a look at actual native desktop apps, let’s see what running Flutter on desktop can do for people developing for mobile.</p><h4>Startup time</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/413/0*FQY3dOdSngP7Yny_" /><figcaption><a href="http://i.imgur.com/cwg333d.png">http://i.imgur.com/cwg333d.png</a>, original: <a href="https://xkcd.com/303/">https://xkcd.com/303/</a></figcaption></figure><p>The first thing that happens before anything productive can be done is starting the android emulator and running Gradle.</p><p>In the following Gif I recorded myself cold booting the emulator and running the default Flutter app. I took me a whopping 2 minutes and 40 seconds. Just image how much productive things could have happened during that time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*_RPnddTV2sKT22eTS-Ck1w.gif" /><figcaption>Android booting &amp; Gradle running (speed up 10x)</figcaption></figure><p>What if I told you, you could be up and running in less than 10 seconds?</p><p>Running the app natively skips the whole overhead of running Android on your system and going through Gradle.</p><p><em>Just check this out:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*1Ugg3hSO084gQY4cqATi_g.gif" /><figcaption>Flutter Simulator starting in real time</figcaption></figure><p><strong>Notice how you don’t have to leave IntelliJ. We’ve written the tooling needed to run Flutter as a native application. Works in all Flutter IDEs.</strong></p><h4>Resizable during runtime</h4><p>As with any app, you’ll want to test your layout for different sizes. What do you do?</p><p>You ask all your friends with different phones and/or create a bunch of emulators to make sure your layout looks as intended on each and every device.</p><p>This feels pretty cumbersome to me. Can we do it better?</p><p><em>Yes, we can!</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*Z7gmjdcuw9O26mM9Zaqnmg.gif" /><figcaption>I think this is pretty self-explanatory</figcaption></figure><h4>Work with assets on your PC</h4><p>When developing and testing apps which need to interact with assets on the phone, it can be quite annoying to first move all the testing files to the emulator or device.</p><p>Wouldn’t it be nicer to just pick the file you want with your native file picker?</p><p>If you are screaming <em>YES</em>, then I got the right thing for you!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*NN7TjlD3pL9E8HkQYDNGBA.gif" /><figcaption>File picker for desktop</figcaption></figure><p>The best part about this: the desktop implementation uses the same method channel as the mobile implementation, <strong>therefore no code needs to be changed at all.</strong></p><h4>Hot reloads and debugging</h4><p>This is all nice and fun. But hot-reloading and debugging capabilities are a must for every productive engineer.</p><p>So we made that work for desktop too!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*3qXffowFIsQUrBTzmu2paw.gif" /><figcaption>Hot reloading and debugging the native app</figcaption></figure><h4>RAM</h4><p>Last but not least: RAM. This is a pretty big deal for people working on notebooks and/or somewhat less beefy machines.</p><p>The Android emulator eats up roughly 1GB of RAM. Now, imagine running two of those (testing a chat application or similar), IntelliJ, and the ever-RAM-hungry Chrome.</p><p>That’s pretty heavy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/621/1*2VQW2JrshBpF6td2p29Daw.png" /><figcaption>1 GB of RAM for the Android Emulator</figcaption></figure><p>Because the embedder is running natively, there is no need for Android. Which makes it <strong>much </strong>smaller.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/620/1*3jkLDYGHWaLz8yqnAcE1KA.png" /><figcaption>100 MB of Ram for the native app</figcaption></figure><h3>Native Desktop Apps</h3><p>Simply running a Flutter app on desktop isn’t enough for a fully fledged, production-ready desktop app. Doing so feels (and it essentially is) like running a mobile app on desktop.</p><p>What’s missing? A lot!</p><p>Hovering, Cursor Changes, Scroll Wheel Interaction, etc.</p><p><em>So we built that too!</em></p><p>We managed to implement those features without changing any platform code — so, it’s a standalone package that can be included within any ordinary Flutter app. However, when used together with our desktop embedder, magic happens!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*1Bh45ip4kwTwp8j7opdKoA.gif" /><figcaption>Generic chat app in Flutter, on desktop :)</figcaption></figure><p>This is the exact same code running on the Android emulator.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PuNJARAJ9SSx6wesSuIbjA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*OhvLLYA2nqlzq02eqFEPVg.gif" /><figcaption>Developing for Android and Desktop at the same time.</figcaption></figure><p><em>Notice how it behaves like a normal app on the emulator, but changes the cursor and adds the hover effect on desktop.</em></p><h3>A little showcase of the simplicity of these desktop widgets</h3><h4>Hovering:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/447/1*W5boF-3Ol7ZXKJLUSZktcg.gif" /></figure><h4>Cursor:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/187/1*FcvGW2XEXBXu6zMj9AnNeg.gif" /></figure><h3>Writing a truly cross-platform app — including desktop</h3><h4>Widgets</h4><p>Most of the widgets you create are universally usable. Think button, loading indicators, etc.</p><p>Those which need a different look depending on the platform can be encapsulated pretty easily by checking the TargetPlatform property.</p><p>Widgets like the CursorWidget can also be included in the Android version without a problem. They are simply ignored there.</p><h4>Pages</h4><p>Pages differ quite a bit depending on the platform and the screen size. However they mostly only differ in layout and not in actual functionality.</p><p>Using a PageLayoutWidget makes creating accurate layouts for each platform super easy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/732/1*AaKyTkpA3sCBAnvK_sfBcQ.png" /></figure><p><em>Bonus: You also have nice tablet support by default :)</em></p><h4>Plugins</h4><p>No changes to your Flutter code have to be done when using a plugin which also supports the desktop embedder.</p><h3>When will the code be released?</h3><p>It’s here! Check it out at:</p><p><a href="https://github.com/devangels/desktop_simulator">https://github.com/devangels/desktop_simulator</a></p><ul><li><a href="https://github.com/devangels/flutter_simulator">GitHub - devangels/flutter_simulator: flutter_simulator Dart Extension written in C++</a></li><li><a href="https://github.com/devangels/flutter_desktop_widgets">GitHub - devangels/flutter_desktop_widgets: Desktop Widgets (hover and such) [for Flutter Desktop apps]</a></li><li><a href="https://twitter.com/FlutterComm">JavaScript is not available.</a></li><li><a href="https://twitter.com/devangelslondon">Simon Lightfoot 🥇💙 (@devangelslondon) | Twitter</a></li><li><a href="https://twitter.com/norbertkozsir">Norbert Kozsir (@norbertkozsir) | Twitter</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4f049ea6b061" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/flutter-on-desktop-a-real-competitor-to-electron-4f049ea6b061">Flutter on desktop, a real competitor to Electron</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Devlog #1, building the most awesome music player (in Flutter).]]></title>
            <link>https://medium.com/@norbertkozsir/devlog-1-building-the-most-awesome-music-player-in-flutter-a1ca0cdd4dce?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/a1ca0cdd4dce</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[design]]></category>
            <category><![CDATA[apps]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[flutter]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Mon, 17 Sep 2018 09:14:54 GMT</pubDate>
            <atom:updated>2018-09-23T19:05:55.642Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gY5w48aFRWB-ulDeyEJlhw.png" /><figcaption>The Figma project for this app. Scroll down for more gifs.</figcaption></figure><h3>First off.</h3><p>It has been a long time since I last posted here on medium. Interestingly my follower count kept growing — so thanks for that! :)</p><p>When I started posting on Medium back in February. I didn’t really know what I was doing (I still don’t).</p><p>My first post <a href="https://proandroiddev.com/flutter-how-i-built-a-simple-app-in-under-an-hour-from-scratch-and-how-you-can-do-it-too-6d8e7fe6c91b"><em>“Flutter: How I built a simple app in under an hour from scratch. And how you can do it too.”</em></a> got featured on AndroidProDev and got pretty big.</p><p>I wrote it because I saw a YouTube video about Flutter and tried it out. I was so amazed, that I thought “Why not write a post about that?”. So I did.</p><p>But the app I was working on didn’t have that much potential and eventually, I lost motivation.</p><p>People always say “The idea is worth nothing, it’s all about execution”, while I certainly don’t disagree. I think there is more to it. If the idea you have isn’t exciting (for yourself) then you [probably] won’t be able to execute it well.</p><p><em>Enough rambling</em></p><p>As you might have guessed from the title, I’ve been working on a <strong>music player.</strong></p><h3>Why a music player?</h3><h4>The Design</h4><p><em>I love well-designed stuff.</em></p><p>Sometimes I just go to sites like <a href="https://dribbble.com/">dribbble.com</a> or <a href="http://www.uplabs.com/">uplabs.com</a> and admire the beauty people create.</p><p>I wanted to challenge myself and music players seemed like a great opportunity to do so.</p><h4>The market</h4><p>If you search for “music player” on the app store, you will be flooded with apps. Seriously you wouldn’t be able to count them.</p><blockquote>So why on earth should there exist <em>another one</em>?</blockquote><p><strong>A lot of them have a huge amount of downloads.</strong> I’m pretty sure I won’t reach those counts, but it’s nice to know that the market exists :D</p><p><strong>Most of them are “good”. But I haven’t seen too many amazing ones yet.</strong></p><p>Don’t get me wrong. They all do their job. And I’m also pretty sure there are a few outstanding ones, but most do their job and that’s it.</p><blockquote>In my eyes apps are more than just a tool to accomplish a task. Music is art. So are apps.</blockquote><h3>What I’ve done until now</h3><h4>Design</h4><p>The design took me a long time and still is one of those parts where I’m not exactly sure what I am doing. But every iteration it looks a little bit nicer, so that’s good!</p><p><em>Keep in mind, nothing is final yet.</em></p><p>Here are some cool snippets of the app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*TqE8whOg-BJwBTz9sSUNEQ.gif" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*DNfzniHEHqV55OTxccjeag.gif" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*eQYkbfA3mlpCiy7zcn5wEA.gif" /><figcaption>Interactions</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*i3_hkD0i5dbjdpsggyUE2A.gif" /><figcaption>Spinning the disk</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/270/1*WuOQJaTy2kxKWS-JwBRB1A.png" /><figcaption>The categories pages.</figcaption></figure><h3>What already works</h3><ul><li>List all songs/ all albums/ all artist/ all genres / all folder</li><li>Homepage displays recently played albums</li><li>Editing metadata + cover art fetcher</li><li>Artist Page downloads artist images</li><li>Searching for individual songs</li><li>Background service/ Notification with controls/ Lock screen image</li></ul><h3>Whats still left to do</h3><ul><li>Designing and implementing the Home-Page</li><li>Rewriting the Queue Logic to run in the background service</li><li>A lot of small UI tweaks</li><li>Fixing bugs</li><li>A lot of cool features</li></ul><h3>The future of this series</h3><p>As a disclaimer, this app is not going to be open source (at least for now). I will, however, post snippets which might be useful for other people and explain them.</p><p>Also, I will release packages which have their origin in this project. For example, <a href="https://github.com/Norbert515/pimp_my_button">https://github.com/Norbert515/pimp_my_button</a> was made for this app.</p><p>I hope you can understand!</p><p>If you want to get the latest new about the development, be sure to follow me on Twitter! <a href="https://twitter.com/norbertkozsir?lang=en">https://twitter.com/norbertkozsir?lang=en</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a1ca0cdd4dce" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter Heroes and Villains — bringing balance to the Flutterverse.]]></title>
            <link>https://medium.com/flutter-community/flutter-heroes-and-villains-bringing-balance-to-the-flutterverse-2e900222de41?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/2e900222de41</guid>
            <category><![CDATA[android]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[dart]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Mon, 09 Jul 2018 09:29:54 GMT</pubDate>
            <atom:updated>2018-07-09T14:11:56.125Z</atom:updated>
            <content:encoded><![CDATA[<h4>A story about how heroes and villains work.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*AHypbXYdBWnNfLoeseJ3lw.gif" /><figcaption>Villains combined with a hero.</figcaption></figure><p><em>Villains allow you to add page transition like the one above with just a few lines of code.</em></p><p>The package is available <a href="https://github.com/Norbert515/flutter_villains">here</a>. You can find how to use villains in the projects <a href="https://github.com/Norbert515/flutter_villains/blob/master/README.md">README</a>. This post is more focused on explaining heroes and villains and the thought process behind all of it.</p><p>One of the most awesome parts of flutter is having such a nice and clean API for everything. I just <strong>love </strong>the way you can use Heroes. Two simple lines of code, and it just works. You just drop in Heroes at two places, assign according tags and the rest is taken care of.</p><h3>Before you understand the villain, you must first understand the hero.</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*QbbLnNEKCz02skDo2QRuOg.gif" /><figcaption>Simple Hero transition.</figcaption></figure><p>We’ll take a quick look at how the heroes are implemented.</p><h4>Overview</h4><p>There are three major steps involved in the hero animation.</p><ol><li><strong>Finding and matching the heroes</strong></li></ol><p>The first step is to determine which heroes exist and which have the same tag.</p><p><strong>2. Determining the hero positions</strong></p><p>Then, the position of both heroes are captured and the flight is ready to happen.</p><p><strong>3. Initiating the flight</strong></p><p>The flight always happens on the new screen, but not with the actual widget. The widget on the opening page is replaced with an empty placeholder widget (SizedBox) during the flight. Instead the Overlay is used (the Overlay can display widgets on top of everything).</p><blockquote>The whole hero animation happens on the page being opened. The widgets don’t share any state between pages and are completely separate.</blockquote><h4>The NavigationObserver</h4><p>It is possible to observe the events of routes being pushed and popped with a NavigationObserver .</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/68eddb143cdf3b13d6eae545f448ca6c/href">https://medium.com/media/68eddb143cdf3b13d6eae545f448ca6c/href</a></iframe><p>The hero uses this class to start the flight. Besides being able to add NavigationObservers yourself, the MaterialApp adds the HeroController by default. <a href="https://github.com/flutter/flutter/blob/v0.5.5/packages/flutter/lib/src/material/app.dart#L598"><em>Take a look.</em></a></p><h4>The Hero Widget</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0e4440e269b23223f3efef48020d37bf/href">https://medium.com/media/0e4440e269b23223f3efef48020d37bf/href</a></iframe><p>The hero widget doesn’t actually do much. It holds the child and the tag. In addition to that, the createRectTween argument determines what route the Hero takes while flying to its destination. The default implementation is the MaterialRectArcTween. As the name suggests it moves the hero along an arc to its final position.</p><p>The state of the hero also is responsible for capturing sizes and replacing itself with the placeholder.</p><h4>_allHeroesFor</h4><p>Elements (concrete widgets) are placed in a tree. Using a visitor, you can walk down the tree and gather information.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/736648ba2713274481ac831c9490f140/href">https://medium.com/media/736648ba2713274481ac831c9490f140/href</a></iframe><p>An inline function called visitor is declared inside the method. The context.visitChildElements(visitor) method and element.visitChildren(vistor)call the function until all elements below the context are visited. On each visit it checks whether that child is a Hero and if it is, it saves it into a map.</p><h4>The start of the flight</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8a66fc1b450213f49f5a8f9cccc71abc/href">https://medium.com/media/8a66fc1b450213f49f5a8f9cccc71abc/href</a></iframe><p>This gets called in response to the route push/pop event. On line 14 and 15 you can see the _allHeroesFor call which finds all heroes on both pages. Starting on line 21 a _HeroFlightManifest is constructed and the flight is initiated. From here on there is a bunch of code setting up the animation and handling edge cases. I encourage you to take a look at the <a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/heroes.dart">whole class</a>, it’s pretty interesting and there’s a lot to learn from it. Also you can take a look at <a href="https://flutter.io/animations/hero-animations/">this</a>.</p><h3>How do villains work</h3><p>Villains are simpler creatures than Heroes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*DyLbjknJBTxiDOWhcZf0bg.gif" /><figcaption>Hero with 3 villains playing (AppBar, Text, FAB).</figcaption></figure><p>They use the same mechanic of finding all villains for a given context and they also use a NavigationObserver to automatically react on page transitions. But instead of animating from one screen to another they only animate on their respective screen.</p><h4>SequenceAnimation and custom TickerProvider</h4><p>When dealing with animations, you usually use the SingleTickerProviderStateMixin or the TickerProviderStateMixin. In this case the animation doesn’t start in a StatefulWidget and we therefore need another way to access a TickerProvider.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6b8ed70632759651a5ee6a18f64dfe4b/href">https://medium.com/media/6b8ed70632759651a5ee6a18f64dfe4b/href</a></iframe><p>Defining a custom ticker is pretty easy. All there is to it is implementing the TickerProvider interface and returning a new Ticker.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/98669ce80befe6817746415bc4cc5ff2/href">https://medium.com/media/98669ce80befe6817746415bc4cc5ff2/href</a></iframe><p>First all villains which should not be playing (those who set animateExit/animateEntrance to false) are filtered out. Then an AnimationController with the custom TickerProvider is created. Using the <a href="https://pub.dartlang.org/packages/flutter_sequence_animation">SequenceAnimation </a>library each Villain is assigned an animation running from 0.0–1.0 in their respective time slot (the from and to duration). At the end, animations are all started. When all of them finish, the controller is disposed.</p><h4>The Villain build()</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/37c2a890290650c313749c455f57f94f/href">https://medium.com/media/37c2a890290650c313749c455f57f94f/href</a></iframe><p>This might look scary, but bear with me. Let’s just look at line 3 and 4. The widget.villainAnimation.animatedWidgetBuilder is a custom typedef:</p><pre><strong>typedef </strong>Widget AnimatedWidgetBuilder<em>(</em>Animation animation, Widget child<em>)</em>;</pre><p>Its job is to return a widget which animates according to the animation (most of the times the returned widget is an AnimatedWidget).</p><p>It gets handed the child of the villain and this animation:</p><pre>widget.villainAnimation.animatable.chain<em>(</em>CurveTween<em>(</em>curve: widget.villainAnimation.curve<em>))</em>.animate<em>(</em>_animation<em>)<br></em></pre><p>The chain method first evaluates the CurveTween. It then uses that value to evaluate the animatable on which it is called. This simply adds the desired curve to the animation.</p><p><strong><em>That was a rough overview on how the villains work, be sure to also look at the </em></strong><a href="https://github.com/Norbert515/flutter_villains/blob/master/lib/villains/villains.dart"><strong><em>source code</em></strong></a><strong><em> and feel free to ask questions.</em></strong></p><h3>Mutable static variables are bad, let me explain..</h3><p>I was sitting at my desk in the late evening, writing tests. After a few hours every single test was passing and it seemed there were no bugs. Right before heading to bed I ran all the tests together to make sure it’s alright. Then this happend:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/374/1*l2ugqc801sM0pm6FVa8KsQ.png" /><figcaption>Each test passes on its own but not together</figcaption></figure><p>I was pretty confused. Every test succeed before. Sure enough, when I ran those two tests by themselves, they worked as expected. But when running all tests together the last two failed. WTF.</p><p>The first reaction was obviously: “My code must be working, it has to do something with the way tests are executed! Maybe tests are playing in parallel and thus interfering with each other? Maybe it is because I used the same keys?”.</p><p>Brian Egan point out to me that deleting one particular test fixed the bug and moving it to the top made all other tests fail too. If that doesn’t scream “SHARED DATA” then I don’t know what does.</p><p>When I found out what the problem was I just couldn’t stop laughing. It was exactly the reason why using static variables are considered bad in certain situations.</p><p>Basically, the predefined animations were all static. I was too lazy to write a method for each animation taking all the parameters that a VillainAnimation needs. So I made the VillainAnimation <em>mutable (bad idea). </em>This way I didn’t have to explicitly write all the necessary parameters into the method. This looked like this when using it:</p><pre>Villain<em>(<br>  </em>villainAnimation: VillainAnimation.<em>fromBottom(</em>0.4<em>)<br>    </em>..to = Duration<em>(</em>milliseconds: 150<em>)</em>,<br>  child: Text(&quot;HI&quot;),<br>)</pre><p>The test which broke everything was supposed to test villain transitions starting after the page transition finished. It set the starting point of the animation to 1 second. Because it was setting it on a static reference, the test after that used that as the default. The tests failed because an animation can’t run from 1 second to 750 milliseconds.</p><p>The fix was pretty easy (making everything immutable and passing the arguments in the method) but I still found this little bug quite entertaining.</p><h3>Wrapping up</h3><p>Thanks to the Villains the balance between good and evil is now restored.</p><p>Opinions and discussions about the #fluttervillains are welcome. If you create cool animations with the villains, I’d love to see it.</p><p><a href="https://twitter.com/norbertkozsir?lang=en">My Twitter: @norbertkozsir</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2e900222de41" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/flutter-heroes-and-villains-bringing-balance-to-the-flutterverse-2e900222de41">Flutter Heroes and Villains — bringing balance to the Flutterverse.</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter, what are Widgets, RenderObjects and Elements?]]></title>
            <link>https://medium.com/flutter-community/flutter-what-are-widgets-renderobjects-and-elements-630a57d05208?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/630a57d05208</guid>
            <category><![CDATA[cross-platform]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[code]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Sat, 30 Jun 2018 09:16:30 GMT</pubDate>
            <atom:updated>2020-06-18T20:06:45.950Z</atom:updated>
            <content:encoded><![CDATA[<h4>Ever wondered how Flutter takes those widgets and actually converts them to pixels on the screen?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*j5RI_BysyCqCg-aQ" /><figcaption>Photo by <a href="https://unsplash.com/@pluyar?utm_source=medium&amp;utm_medium=referral">Shane Aldendorff</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Ever wondered how Flutter takes those widgets and actually converts them to pixels on the screen? No?</p><p>You should!</p><p>Understanding how an underlying technology works makes the difference between a good developer and a great one.</p><p>You can create custom layouts and special effects more easily when you know what works and what doesn’t; and knowing this will save you a few long nights at the keyboard.</p><p>The goal of this post is to introduce you to the world beyond the surface of flutter. We will take a look at different aspects of flutter and understand how it <em>actually </em>works.</p><h3>Let’s get started</h3><p>You probably already know how to use the StatelessWidget &amp; StatefulWidget. But those widgets only compose the other widgets. Laying out the widgets and rendering them happens elsewhere.</p><p><strong>I highly recommend opening your favorite IDE and following along, seeing the structures in the actual code often creates those “aha” moments. In Intellij you can double tap shift and enter a class name to find it.</strong></p><h4>The Opacity</h4><p>To get familiar with the basic concepts of how flutter works we will take a look at the <a href="https://github.com/flutter/flutter/blob/f38743593d00f13b21f49d8d8ee2d2206bf820d3/packages/flutter/lib/src/widgets/basic.dart#L150">Opacity</a> widget and examine that. Because it’s a pretty basic widget, it makes a good example to follow along.</p><p>It only accepts one child. Therefore you can wrap any widget in an Opacity and change the way it’s displayed. Besides the child, there is only one parameter called opacity which is a value between 0.0 and 1.0. It controls the opacity (duh).</p><h3>The Widget</h3><p>The Opacity is a SingleChildRenderObjectWidget.</p><p><strong>The hierarchy of extension class extensions goes like this:</strong></p><p><em>Opacity → SingleChildRenderObjectWidget → RenderObjectWidget → Widget</em></p><p><strong>In contrast, the StatelessWidget and StatefulWidget goes as follows:</strong></p><p><em>StatelessWidget/StatefulWidget → Widget</em></p><p>The difference lies in the fact that the Stateless/StatefulWidget only <em>compose </em>widgets while the Opacity widget actually changes how the widget is drawn.</p><p>But if you look at any of those classes you won’t find any code related to actually painting the opacity.</p><p>That’s because a widget only holds the configuration information.<strong> </strong>In this case, the opacity widget is only holding the opacity value.</p><blockquote>This is the reason why you can create new widget every time the build function is called. Because the widgets are not expensive to construct. They are merely containers for information.</blockquote><h3>The Rendering</h3><p>But where <strong>does </strong>the rendering happen?</p><p><strong>It’s inside the RenderObjects</strong></p><p>As you might have guessed from the name, the RenderObject is responsible for a few things, including rendering.</p><p>The Opacity widget creates and updates a RenderObject with these methods.</p><pre>@override<br>RenderOpacity createRenderObject<em>(</em>BuildContext context<em>) </em>=&gt; <strong>new </strong>RenderOpacity<em>(</em>opacity: opacity<em>)</em>;<br><br>@override<br><strong>void </strong>updateRenderObject<em>(</em>BuildContext context, RenderOpacity renderObject<em>) {<br>  </em>renderObject.opacity = opacity;<br><em>}</em></pre><p><a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/basic.dart#L188"><em>source</em></a></p><h4>RenderOpacity</h4><p>The Opacity widget sizes itself to be exactly the same size as its child. It basically mimics every aspect of the child <strong>but </strong>the painting. Before painting its child it is adding an opacity to it.</p><p>In this case, the RenderOpacity needs to implement all the methods (for example performing layout/ hit testing/ computing sizes) and ask its child to do the actual work.</p><p>The RenderOpacity extends the RenderProxyBox (which mixes in a few other classes). Those are exactly implementing those methods and deferring the actual calculation to the only child.</p><pre>double <strong>get </strong>opacity =&gt; _opacity;<br>double _opacity;<br><strong>set </strong>opacity<em>(</em>double value<em>) {<br>  </em>_opacity = value;<br>  markNeedsPaint<em>()</em>;<br><em>}</em></pre><p><em>I removed a lot of assertions/ optimizations in this code. Take a look at the original for the full method. </em><a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/rendering/proxy_box.dart#L736"><em>source</em></a></p><p>Fields usually expose a getter to the private variable. And a setter, which in addition to setting the field, also calls markNeedsPaint() or markNeedsLayout()<em>. </em>As the name suggests, it tells the system “Hey I have changed, please repaint/relayout me”.</p><p>Inside the RenderOpacity we find this method:</p><pre>@override<br><strong>void </strong>paint<em>(</em>PaintingContext context, Offset offset<em>) {</em><br>    context.pushOpacity<em>(</em>offset, _alpha, <strong>super</strong>.paint<em>)</em>;<em><br>}</em></pre><p><em>Again, removed optimization and assertions. </em><a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/rendering/proxy_box.dart#L757"><em>source</em></a></p><p>The PaintingContext is basically a fancy canvas. And on this fancy canvas there is a method called pushOpacity. <em>BINGO</em>.</p><p>This one line is the <em>actual </em>opacity implementation.</p><h4>To recap</h4><ul><li>The Opacity is not a StatelessWidget or a StatefulWidget but instead a SingleChildRenderObjectWidget.</li><li>The Widget only holds information which the renderer can use.</li><li>In this case the Opacity is holding a double representing the opacity.</li><li>The RenderOpacity, which extends the RenderProxyBox does the actual layouting/ rendering etc.</li><li>Because the opacity behaves pretty much exactly as its child it delegates every method call to the child.</li><li>It overrides the paint method and calls <em>pushOpacity </em>which adds the desired opacity to the widget.</li></ul><h3>That’s it? Kind of.</h3><p>Remember, the widget is only a configuration and the RenderObject only manages layout/rendering etc.</p><p>In Flutter you recreate widgets basically all the time. When your build() methods gets called you create a bunch of widgets. This build method is called every time something changes. When an animation happens for example, the build method gets called very often. This means you can’t rebuild the whole sub tree every time. Instead you want to update it.</p><blockquote>You can’t get the size or location on the screen of a widget, because a widget is like a blueprint, it’s not actually on the screen. It’s only a description of what variables the underlying render object should use.</blockquote><p><strong>Introducing the Element</strong></p><p>The element is a concrete widget in the big tree.</p><p><strong>Basically what happens is:</strong></p><p>The first time when a widget is created, it is inflated to an Element. The element then gets inserted it into the tree. If the widget later changes, it is compared to the old widget and the element updates accordingly. The important thing is, the element doesn’t get rebuilt, it only gets updated.</p><p>Elements are a central part of the core framework and there is obviously more to them, but for now this is enough information.</p><h4>Where is the element created in the opacity example?</h4><p><em>Just a little paragraph for those who are curios.</em></p><p>The SingleChildRenderObjectWidget creates it.</p><pre>@override<br>SingleChildRenderObjectElement createElement<em>() </em>=&gt; <strong>new </strong>SingleChildRenderObjectElement<em>(</em><strong>this</strong><em>)</em>;</pre><p><a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart#L1631"><em>source</em></a></p><p>And the SingleChildRenderObjectElement is just an Element which has single child.</p><h4>The element creates the RenderObject, but in our case the Opacity widget creates its own RenderObject?</h4><p>This is just for a smooth API. Because more often then not, the widget needs a RenderObject but no custom Element. The RenderObject is actually created by the Element, let’s take a look:</p><pre>SingleChildRenderObjectElement<em>(</em>SingleChildRenderObjectWidget widget<em>) </em>: <strong>super</strong><em>(</em>widget<em>)</em>;</pre><p><a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart#L4643"><em>source</em></a></p><p>The SingleChildRenderObjectElement gets a reference to the RenderObjectWidget (which has the methods to create a RenderObject).</p><p>The mount method is the place where the element gets inserted into the element tree, and here the magic happens (RenderObjectElement class):</p><pre>@override<br><strong>void </strong>mount<em>(</em>Element parent, <strong>dynamic </strong>newSlot<em>) {<br>  </em><strong>super</strong>.mount<em>(</em>parent, newSlot<em>)</em>;<br>  _renderObject = widget.createRenderObject<em>(</em><strong>this</strong><em>)</em>;<br>  attachRenderObject<em>(</em>newSlot<em>)</em>;<br>  _dirty = <strong>false</strong>;<br><em>}</em></pre><p><em>(Right after super.mount(parent,newSlot); </em><a href="https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart#L4287"><em>source</em></a></p><p>Only once (when it get’s mounted) it asks the widget “Please give me the renderobject you’d like to use so I can save it”.</p><h3>The End</h3><p>And that’s it. This is how the opacity widget works internally.</p><p>My goal with this post was to introduce you to the world beyond widgets. There are still a lot of topics to cover, but I hope I could give you a nice introduction to the inner workings.</p><p>Big thanks to <a href="https://twitter.com/devangelslondon?lang=en">Simon Lightfoot</a> for helping me out researching this!</p><p>Edit: If you want to learn more, check out the talk I did on this subject on Youtube!<br><a href="https://www.youtube.com/watch?v=PnWxW21vDak&amp;t=2300s">https://www.youtube.com/watch?v=PnWxW21vDak</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=630a57d05208" width="1" height="1" alt=""><hr><p><a href="https://medium.com/flutter-community/flutter-what-are-widgets-renderobjects-and-elements-630a57d05208">Flutter, what are Widgets, RenderObjects and Elements?</a> was originally published in <a href="https://medium.com/flutter-community">Flutter Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to dynamically change the theme in Flutter]]></title>
            <link>https://proandroiddev.com/how-to-dynamically-change-the-theme-in-flutter-698bd022d0f0?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/698bd022d0f0</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[cross-platform]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[android-app-development]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Tue, 05 Jun 2018 13:04:07 GMT</pubDate>
            <atom:updated>2018-06-05T21:38:19.780Z</atom:updated>
            <content:encoded><![CDATA[<h4>Changing the theme at runtime and persisting those changes across restarts? No problem!</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/620/1*3bJPBzNscZ5T5TB1tfxhlA.png" /></figure><h4>TLDR: I made a <a href="https://github.com/Norbert515/dynamic_theme">package</a> which takes care of all of this, if you are interested on how it’s done keep reading.</h4><h3>How to do it.</h3><p>Usually your entry point to the app looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/84f17d4a3174589e8e049123861150e9/href">https://medium.com/media/84f17d4a3174589e8e049123861150e9/href</a></iframe><p>If you want to change the theme of your app at compile time you can modify ThemeData. There is an attribute called Brightness which changes a bunch of colors from light to dark if set to Brightness.dark .</p><p>We want it to dynamically change that variable during runtime. We therefore introduce state to the top level widget.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4c32d3388225da4122a23f4a95b6dccc/href">https://medium.com/media/4c32d3388225da4122a23f4a95b6dccc/href</a></iframe><p>Now, we have to access this state. Either by passing down a callback, writing a custom InheritedWidget or using the BuildContext to walk up the tree.</p><p>Passing down a callback is the most straight forward thing to do. But it also is the most annoying one. If the tree gets deep a lot of classes just pass the callback to its children. The logic is pretty simple though all that happens is:</p><ul><li>Top widget implements a method which changes the brightness and calls setState()</li><li>Any child who has a reference to that method can invoke it.</li></ul><p>An InheritedWidget would solve this problem by giving all the children access to the callback. You would still have to manage a callback, but this time there is no need to pass it all the way down.</p><p>The last viable option is searching the tree for the state. This one is pretty straight forward. We need a context to start the search, all we do is walk up the tree a search for a State which is of our type.</p><pre>context.ancestorStateOfType<em>(</em><strong>const </strong>TypeMatcher<em>&lt;</em>YourState<em>&gt;())</em>;</pre><p>Holding a static reference or global variable is a big no go, I won’t cover why in this post though.</p><p>Now we are be able to access and modify the Brightness on the go. The last thing is to persist the Brightness across app restarts.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7f3159b653ef7c35c3c886e271d6f7f0/href">https://medium.com/media/7f3159b653ef7c35c3c886e271d6f7f0/href</a></iframe><p>Using shared preferences we can fetch the brightness before we run the app. When the brightness changes we will also have to save it there.</p><p>Because the shared preferences are asynchronous we need to await the result. The call is very fast and therefore this is not a big deal.</p><p>And we’re done! Now we can change the Theme of the app anywhere in our code.</p><h3>The package</h3><p>Because we as developers shouldn’t waste time re-implementing features, I made this a package!</p><p>Basically it’s exactly doing all the things I talked about above but encapsulated in one handy class.</p><p>Here is how it works:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/edfee40f844f62f88db9abb34e8ef507/href">https://medium.com/media/edfee40f844f62f88db9abb34e8ef507/href</a></iframe><p>You wrap your MaterialApp in the DynamicTheme widget. There you can specify a default brightness.</p><p>Because the brightness value is changing the colors when constructing the ThemeData you’re able to either just pass the brightness on to the ThemeData constructor and let it take care of it, or you can customize it by passing your own colors depending on the Brightness.</p><p>Last but not least, the ThemedWidgetBuilder. This is the place you usually just return the MaterialApp and pass it the theme.</p><p>And that’s it.</p><p>Now you can modify your Theme from anywhere in your code with:</p><pre>DynamicTheme.<em>of(</em>context<em>)</em>.setBrightness<em>(</em>Brightness.dark<em>)</em>;</pre><p>It will take care of saving it to the shared preferences and updating the app.</p><h3>Bonus</h3><p>Because I had way to much fun coding this, here is a dialog you can use for the theme switching:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/514/1*OGQz-urfJrz4xUIc0Aes6Q.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=698bd022d0f0" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/how-to-dynamically-change-the-theme-in-flutter-698bd022d0f0">How to dynamically change the theme in Flutter</a> was originally published in <a href="https://proandroiddev.com/">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter Book App part 4: From demo to real app.]]></title>
            <link>https://proandroiddev.com/flutter-book-app-part-4-from-demo-to-real-app-ec9026b3c303?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/ec9026b3c303</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[cross-platform]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Wed, 25 Apr 2018 09:12:30 GMT</pubDate>
            <atom:updated>2018-04-25T09:12:30.601Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*4VZzjFXlLnRNip4lpqIZ8A.gif" /></figure><p>T<em>aking the bookshelf app from demo to a real app.</em></p><h3>The Idea</h3><p><strong>“Collecting books as you read them, virtually”</strong></p><p>It isn’t rare that people don’t own the physical book but instead read them on an e-reader, listen to them as an audio books or simply lend them a from friend. The books have been read but the shelf stays empty. There is no sense of accomplishment and more importantly no collection of books to show your grandchildren.</p><p>There are two aspects to the app: <em>collecting books </em>and <em>discovering </em>new books.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*ckzCHRx7fFfe1TXLmMzynw.gif" /></figure><p>The app consist of different collections.</p><p>First there is your own collection (all the books you have read).</p><p>Then there are collections about certain topics, for example a “Fantasy” or a “Biography” collection, these contain books which the author of the collection found to be similar to each other. You will later be able to browse collections people made and add them to your list.</p><h3>The future of this series</h3><p>The future posts will be more directed towards updates and exciting features I made. I won’t go into detail on every change but I will always include code and a walk through about topics I think many people could benefit from.</p><p>As always, the code can be found <a href="https://github.com/Norbert515/BookSearch">here</a>.</p><h3>Creating the stamps</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/270/1*DhTJZoSr7rA4Z76JJ8PjnQ.png" /><figcaption>A “stamp” collection</figcaption></figure><p>The stamp is basically just an image in a stack with the locked icon. But there are still some interesting things going on.</p><h4>The elevation</h4><p>This one’s pretty simple but effective. Wrap your widget in a transparent material which has the attribute elevation . That’s it, this way you can add elevation to any widget.</p><pre>child: <strong>new </strong>Material(<br>  elevation: 8.0,<br>  color: Colors.<em>transparent</em>,<br>  child: <strong>new </strong>Center(<br>    child: _clippedNetwork(context, width, height, holeRadius),<br>  ),<br>),</pre><h4>The stamp shape</h4><p>There are two ways one could accomplish this. Either by using an image or crating it programmatically. The image solution has two downsides.</p><ul><li>Scaling can result in a resolution drop</li><li>It is fix, meaning you can’t change the looks of it at runtime</li></ul><p>On the other hand there are Clippers, these clip the area a widget can draw on.</p><p>I used the ClipPath with a CustomClipper . This way you can define a mesh to cut out of the canvas of a widget.</p><pre><strong>return new </strong>ClipPath(<br>  clipper: <strong>new </strong>StampClipper(holeRadius: holeRadius),<br>  child: <strong>myWidget<br>);</strong></pre><h4>Drawing the path</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0c7406b144cf4ff4868d7c453c4ba5a8/href">https://medium.com/media/0c7406b144cf4ff4868d7c453c4ba5a8/href</a></iframe><p>The CustomClipper has the getClip method which you need to override and return the Path that you want to cut out.</p><p>I won’t go into detail how this algorithm works. But basically it calculates a new radius which is as close as possible to the original one and “looks good”. Meaning edges are handled well. It then goes through all the sides and cuts out the circles.</p><p>Here are some variations using different circle radii:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/470/1*S82kRRMuylqqUWH8lPzqLA.png" /><figcaption>Stamp variations of different holeRadii</figcaption></figure><p>You might notice the shadow is a bit off. That’s because the shadow is not affected by the ClipPath . This could probably be fixed pretty easily (masking the shadow too). But in my case (the left example) this works out just fine.</p><h3>The fade in animation</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*ftr7UIbvFe5KB5k7ba_Lfw.gif" /></figure><p>The page containing the animation (<a href="https://github.com/Norbert515/BookSearch/blob/v4/lib/pages/home_page.dart">home_page.dart</a>) has an animation which runs once the page is opened.</p><pre>AnimationController cardsFirstOpenController;</pre><pre>@override<br><strong>void </strong>initState() {<br>  <strong>super</strong>.initState();<br>  cardsFirstOpenController = <strong>new </strong>AnimationController(vsync: <strong>this</strong>, duration: <strong>const </strong>Duration(milliseconds: 1300));<br>  cardsFirstOpenController.forward(from: 0.2);<br>}</pre><p>This AnimationController runs a 1.3 seconds long animation starting from the value 0.2 to 1.0. As this is in the initState() method this will run when the page is opened.</p><p>Next I made a method which wraps the widgets in an animated widget for convenience.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/86cd77a50d814a97ec79f33f15e4e5a5/href">https://medium.com/media/86cd77a50d814a97ec79f33f15e4e5a5/href</a></iframe><p>Normally you’d have to listen to the animation and on each tick update the widget based on that value with a setState() call. But theSlideTranstion and the FadeTransition are both AnimatedWidgets. These handle all the setState() calls, all they require is an animation.</p><h4>The CurvedAnimation</h4><p>If you’d pass the animation we created before, all widgets would move identically. We need a <strong>curve </strong>to change that behavior.</p><p>The animation runs from the value 0.2 to 1.0 in 1300ms. But we can modify the actual value the widget receives at a given time with a curve.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2bf01238a67d872ddcdc9b5a5be1dadd/href">https://medium.com/media/2bf01238a67d872ddcdc9b5a5be1dadd/href</a></iframe><p>This little class transforms the time value based on an index. This index is the position of that widget in the list. If you look at the formula you will see that widgets with a low index will move slower than widgets with a larger index.</p><p>All the movements start at the same time and end at the same time, but move at different speeds.</p><p>I also wrapped that animations in a curved animation using a Curve.ease to make them smoother.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4cc7942c9c3c0c923e2c66bdfa2b5124/href">https://medium.com/media/4cc7942c9c3c0c923e2c66bdfa2b5124/href</a></iframe><p>Here everything comes together and the list is done.</p><p>Be sure to check out the whole <a href="https://github.com/Norbert515/BookSearch/blob/v4/lib/pages/home_page.dart">home_page.dart</a> if you want to learn more.</p><p>If you want to learn more about animations take a look at the official documentation: <a href="https://flutter.io/tutorials/animation/">https://flutter.io/tutorials/animation/</a></p><h3>The next medium post</h3><p>If you look at the <a href="https://github.com/Norbert515/BookSearch">source code</a> every time the home page is opened the database is queried for essentially the same information. This is not a big problem because such a small database query is very fast but once the database becomes very big this might change. Also there is a prettier solution.</p><p>Next post will be about architecture, we’ll be looking at different possibilities and implement a suitable one.</p><h3>Call to action</h3><p>If you are a designer or somebody who has an idea how to make this app look better don’t hesitate to contact me. All suggestions are welcome.</p><p>Also if you have an idea about the name or an idea in general feel free to leave a comment.</p><p>As always, if you enjoyed this post, please leave a few claps.</p><p>You can also follow me on <a href="https://twitter.com/norbertkozsir?lang=en">Twitter</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ec9026b3c303" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/flutter-book-app-part-4-from-demo-to-real-app-ec9026b3c303">Flutter Book App part 4: From demo to real app.</a> was originally published in <a href="https://proandroiddev.com/">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Flutter Bookshelf App Part 3: Managing data the right way.]]></title>
            <link>https://proandroiddev.com/flutter-bookshelf-app-part-3-managing-data-the-right-way-30569abf9487?source=rss-aca5101434f------2</link>
            <guid isPermaLink="false">https://medium.com/p/30569abf9487</guid>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Norbert]]></dc:creator>
            <pubDate>Tue, 06 Mar 2018 19:29:52 GMT</pubDate>
            <atom:updated>2018-05-05T18:38:05.229Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ip3o28ytPgPiYmWL." /><figcaption>“Binders and boxes on shelves in a large archive” by <a href="https://unsplash.com/@samuelzeller?utm_source=medium&amp;utm_medium=referral">Samuel Zeller</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>In this post I’m am going to discuss a good way to store/ cache/ and load data. Most of today’s apps rely on a server to display information. In combination with a cache, a database and error handling, this can become pretty messy. Luckily there is a design pattern which makes accessing data very convenient and easy.</p><h4>Without a pattern:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/543/1*Zt-1nHJcBmXP8v-of2Jslw.png" /><figcaption>Before v3</figcaption></figure><p>Each screen needs data, and therefore requests the network to load it. Let’s say you also want to have a cache, now every screen first needs to check the cache and then the network. Everything added to the data layer is reflected inside UI code.</p><p>The code is tightly coupled and not well organized, the question arises why the screen manages the data.</p><h4>Introducing the repository:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/543/1*ntLiZJxTnNx2sQ9qmzjUWw.png" /><figcaption>After v3</figcaption></figure><p>A repository is a datasource. To be more specific, to the rest of the app, it’s the only datasource. Screens requesting data don’t necessarily need to know where it is coming from. This allows all data related operations to be in one place. Refactoring and modifying becomes easy and accessing the data even easier.</p><h4>Strucuture</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/228/1*yrzB-KoCUMbOEIoB0wnWfA.png" /></figure><ul><li>The data folder contains all data related classes</li><li>I split pages (which are actual screens) and widgets (reusable screen elements) into their respective folders.</li></ul><p>As always, the code can be found at: <a href="https://github.com/Norbert515/BookSearch/tree/v3">https://github.com/Norbert515/BookSearch/tree/v3</a></p><h4>The repository</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/55304b5ae727f5e59f6bf2cd06119b80/href">https://medium.com/media/55304b5ae727f5e59f6bf2cd06119b80/href</a></iframe><p>Same as the BookDatabase, the repository is a singleton.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0e5313a303efbad147017c1fe41fd4c7/href">https://medium.com/media/0e5313a303efbad147017c1fe41fd4c7/href</a></iframe><p>These calls do not need any additional logic and are therefore simply delegated to the database.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0198643781c55b1a61400cac48c48c00/href">https://medium.com/media/0198643781c55b1a61400cac48c48c00/href</a></iframe><p>This method returns all the books based on a search query. The result is composed of the books coming from the internet and the ones coming from the database (books which hold additional information such as the star and notes).</p><p>In v2 a database request was issued for every book. This is very inefficient for huge databases. This however involves only one SQL query:</p><ul><li>First all books coming from the network are stored in a map (using the ID as its key)</li><li>Then all keys a queried together returning a list of books</li><li>These books hold more information, therefore we can simply replace the according network-book with the database-book</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/60b6ca6a3610bf7228bff8f7595070f1/href">https://medium.com/media/60b6ca6a3610bf7228bff8f7595070f1/href</a></iframe><p>The list gets convert to “(“id1”, “id2”, …, “idn”)” and inserted into the SQLite query.</p><h4>Error handling</h4><p>You might have noticed the ParsedResponse class which is the return type of the method wrapped in a future.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/630755f121ae9ab14a888200925539f2/href">https://medium.com/media/630755f121ae9ab14a888200925539f2/href</a></iframe><p>This neat little generic class holds the already parsed response and the status code. This enables us to return a ready to use dart object alongside additional information such as the servers status code.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a9fd40382653e81d63822ad17e820e3e/href">https://medium.com/media/a9fd40382653e81d63822ad17e820e3e/href</a></iframe><p>Now the search_book looks much cleaner. The data-flow is as follows:</p><ul><li>Request the data</li><li>When it arrives check the status code and decide whether to show the result or an error message.</li></ul><p>As an alternative to this, it is also possible to use a FutureBuilder which I will go into in one of my next posts.</p><h4>Making as many widgets as dumb as possible</h4><p>In v2 the BookCard managed it’s own clicks, meaning when pressed, it went right to the database and updated the appropriate entry. But there’s a better way.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/47b4dd6c6018ec6466bc61f7c44130b9/href">https://medium.com/media/47b4dd6c6018ec6466bc61f7c44130b9/href</a></iframe><p>Now, the BookCard exposes two on click listeners, one for the clickable star and one for the rest of the card surface. The card doesn’t know anything about a database or what so ever. It is now reusable in any part of the app.</p><p>Furthermore the logic is now at a more appropriate place, a simple card shouldn’t know about a database, its only purpose is to display data and notice clicks.</p><h4>The Collection Screen</h4><p>We have a centralized data access and made the BookCard reusable, let’s build a page which displays all starred books.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*sGYsgZJrlIhJFkRMFCIlMQ.gif" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4c130442af954f6f9face439153ab46b/href">https://medium.com/media/4c130442af954f6f9face439153ab46b/href</a></iframe><p>The repository exposes a method called getFavoriteBooks(), this method gets delegated to the database which then performs a rawQuery:</p><pre><strong>var </strong>result = <strong>await </strong>db.rawQuery(&#39;SELECT * FROM $tableName WHERE ${Book.<em>db_star</em>} = &quot;1&quot;&#39;);</pre><p>I kept the loading indicator because at some point in time the books will also come from a remote database.</p><p>And that’s it, the collections page is done.</p><p>The build method is pretty much the same as the search screen one. The class can be found <a href="https://github.com/Norbert515/BookSearch/blob/v3/lib/pages/collection_page.dart">here</a>.</p><h4>Wrapping up</h4><p>We learned:</p><ul><li>how data abstraction can make the overall code more readable, and easier to manage.</li><li>how making widgets “dumb”, makes them easier to reuse and easier to debug.</li></ul><p>If you liked the post be sure to hold that clap button down for a few second.</p><p>Also if you want the latest development updates you can follow me on <a href="https://twitter.com/norbertkozsir?lang=en">Twitter</a>.</p><h4>Edit: Part 4 is now up!</h4><p><a href="https://proandroiddev.com/flutter-book-app-part-4-from-demo-to-real-app-ec9026b3c303">Flutter Book App part 4: From demo to real app.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=30569abf9487" width="1" height="1" alt=""><hr><p><a href="https://proandroiddev.com/flutter-bookshelf-app-part-3-managing-data-the-right-way-30569abf9487">Flutter Bookshelf App Part 3: Managing data the right way.</a> was originally published in <a href="https://proandroiddev.com/">ProAndroidDev</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>