<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/luka-knezic/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Fri, 17 Apr 2026 13:59:15 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>42938https://infinum.com/uploads/2023/09/Blogpost-hero-img-Building-apps-with-ChatGPT-02-min-1.webp</url>
				</image>
				<title>How We Got ChatGPT to Build a Flutter App</title>
				<link>https://infinum.com/blog/chatgpt-flutter-app/</link>
				<pubDate>Thu, 28 Sep 2023 13:36:02 +0000</pubDate>
				<dc:creator>Luka Knezić</dc:creator>
				<guid isPermaLink="false">https://infinum.com/?p=42938</guid>
				<description>
					<![CDATA[<p>Testing out the abilities of new LLM and AI tools, we examined whether Chat GPT's model can build a Flutter app from scratch.</p>
<p>The post <a href="https://infinum.com/blog/chatgpt-flutter-app/">How We Got ChatGPT to Build a Flutter App</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-144"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-93">
	<p	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-94'
	>
	We tested out the abilities of new LLM and AI tools and examined whether Chat GPT&#8217;s GPT-3.5 Turbo model can build a Flutter app from scratch – and learned something about using AI in development on the way.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-97'
	>
	With new LLM and AI tools like ChatGPT and Github Copilot proving themselves helpful in more and more use cases, <a href="https://infinum.com/blog/ai-coding-assistants/" target="_blank" rel="noreferrer noopener">using AI assistants in development</a> is gaining ground. Generated code can be pretty helpful…most of the time. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-100'
	>
	This situation got me wondering – if AI tools can generate useful code snippets, could they generate a whole file? Or a project? Some development-focused agents like <a href="https://github.com/smol-ai/developer" target="_blank" rel="noreferrer noopener">smol-developer</a> can build a web application. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-102">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-103'
	>
	Wanting to find out just how far these new LLM tools can take us, I decided to examine if they can build a Flutter application from scratch.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-105">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-106'
	>
	Building an AI Developer for Flutter in Flutter</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-108">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-109'
	>
	As a Flutter developer, naturally, I decided to try and create a Flutter application that can build and run other Flutter applications. The idea was to come up with a workflow that simple agents could follow and eventually build an application. Using the agents, we’ll have to parse the responses we get and then utilize them further. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-111">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-112'
	>
	The workflow would go like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-117"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-114">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-115'
	>
	1</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-116'
	>
	Generate project documentation</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-122"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-118">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-119'
	>
	2</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-120'
	>
	Use the generated results with other agents</p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-121'
	>
	When the <em>Write code agent</em> finishes its task, we just take the whole response and save it as <code>some_name.dart</code>, depending on the file name of course. Repeat this for every file.</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-127"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--number bullet__color--infinum block-bullet__bullet" data-id="es-123">
	<p	class='typography typography--size-14-text js-typography bullet__dot'
	data-id='es-124'
	>
	3</p>	<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-125'
	>
	When all the files are complete, run <code>flutter analyze</code> and <code>flutter build</code> on the project</p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-126'
	>
	If any errors occur, we use agents that get the current project documentation, along with the error message. This type of agent will decide what needs to be fixed. </p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-130"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-128">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-129'
	>
	Fixing code works almost the same as writing code with an agent. The only difference is that in this case, we also provide the old code for reference, together with the error messages and the messages from the <em>Analyze agent</em>. I should note that in some parts of this process, I simply relied on AI to work and do the right thing. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-133"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-131">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-132'
	>
	<em>Disclaimer: this experiment was done prior to OpenAI introducing function calling to their API. While functions would certainly work better here, my implementation was still good enough that refactoring to functions wouldn’t bring much extra value. I used OpenAI’s cheapest model, GPT-3.5 Turbo. Note that this comes with a limit of just 4k tokens, which becomes really limiting when you need to describe the whole application and its architecture to create the file.</em></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-136"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-134">
	<h3	class='typography typography--size-36-text js-typography block-typography__typography'
	data-id='es-135'
	>
	Let’s get some agents on the task</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-139"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-137">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-138'
	>
	They may sound fancy, but agents are basically just hard-coded prompts you can feed into an LLM, and then expect and assume that it will generate the desired response. Since agents perform best on simple tasks, we will need to really break down the application-writing workflow and help the agents however we can.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-142"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-140">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-141'
	>
	In this case, the desired result is a Flutter application that can build another Flutter application from a short description. There’s no need to write the whole requirements file; it can do that by itself. The requirements should come down to one simple prompt, based on which it should be able to build the application. For that to work, we will need a few agents that we can chain.</p></div>	</div>
</div>
</div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-147"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-145"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-146">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2023/10/Chat-gpt-in-article_02-min-1400x3409.webp				media='(max-width: 699px)'
				type=image/webp								height="3409"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2023/10/Chat-gpt-in-article_02-min.webp"
					class="image__img block-media__image-img"
					alt=""
										height="3653"
															width="1500"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>		</div>
	</div>

<div
	class="wrapper"
	data-id="es-267"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-148">
	

</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-152"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-149">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-150'
	>
	<strong>Generate features agent</strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-151'
	>
	Generates the separation of concerns, decides on state management, generates the file tree</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-156"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-153">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-154'
	>
	<strong><strong>Generate readme agent</strong></strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-155'
	>
	Generates the readme file with the app’s specification<br>Generates the hierarchy for each file</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-160"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-157">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-158'
	>
	<strong>Write code agent</strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-159'
	>
	Goes over each file, writes code for it</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-164"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-161">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-162'
	>
	<strong><strong>Fix code agent</strong></strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-163'
	>
	Fixes errors in the existing code, if any </p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-168"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-165">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-166'
	>
	<strong>Analyze project files agent</strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-167'
	>
	If we get an error from <code>flutter analyze</code>, it assesses which files need to be fixed</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-172"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="bullet bullet--left bullet__type--dot bullet__color--infinum block-bullet__bullet" data-id="es-169">
			<div class="bullet__dot"></div>
		<div class="bullet__content">
		<p	class='typography typography--size-20-text js-typography bullet__heading'
	data-id='es-170'
	>
	<strong>Analyze runtime error agent</strong></p><p	class='typography typography--size-20-text-roman js-typography bullet__paragraph'
	data-id='es-171'
	>
	In case of a runtime error, it assess it and tells us what files need to be fixed</p>	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-173">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-174'
	>
	As you can see, these are quite a few agents. We use three separate ones only for writing code in one way or another. However, we need all three of them since any change in the prompt requires a new agent. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-178"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-176">
	<h4	class='typography typography--size-30-text js-typography block-typography__typography'
	data-id='es-177'
	>
	Generate features and readme agents</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-181"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-179">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-180'
	>
	This workflow makes sure that the first features agent keeps track of our files and the architecture that we will use. From that, we will generate a more detailed readme file with the desired class hierarchy.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-184"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-182">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-183'
	>
	These two files are the most important ones because other agents will use them in their prompts in some way. We do this to keep our files consistent. This way, an agent knows what other files are supposed to look like without us actually providing it with the whole code files, which would use up our 4k token limit very fast.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-187"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-185">
	<h4	class='typography typography--size-30-text js-typography block-typography__typography'
	data-id='es-186'
	>
	Write code agent</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-190"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-188">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-189'
	>
	When the documentation is complete, we can start with the code. We call the <em>Write code agent</em> for each file separately and have it write the code for that specific file. When we have the code for each file, we check if there is a <code>build_runner</code> dependency. If there is one, we run the <code>build_runner</code> command to generate any files that we need. After that, we use the <code>flutter analyze</code> command. If we get any errors with it, another agent is started so it can tell us what we need to fix or if any files need to be added.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-193"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-191">
	<h4	class='typography typography--size-30-text js-typography block-typography__typography'
	data-id='es-192'
	>
	Fix code</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-196"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-194">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-195'
	>
	If we encounter any errors, we employ agents that can fix the code. The <em>Analyze project files</em> and <em>Analyze runtime error</em> agents can mark the files that need to be fixed. They also add small messages about the error and what needs to be fixed in the file.&nbsp;</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-199"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-197">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-198'
	>
	In our example, we provided the whole code file as well. This makes sure that the agent does not forget to include a part of the code that we need.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-202"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-200">
	<h4	class='typography typography--size-30-text js-typography block-typography__typography'
	data-id='es-201'
	>
	Run the application</h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-205"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-203">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-204'
	>
	If <code>flutter analyze</code> didn’t find any issues, we can try and start the app. By running the <code>flutter run</code> command, we start the app and listen to its output. If there are any errors, the <em>Analyze runtime error</em> agent is run to try and fix the issue with the app running.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-208"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-206">
	<h4	class='typography typography--size-30-text js-typography block-typography__typography'
	data-id='es-207'
	>
	The final result – success! </h4></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-211"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-209">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-210'
	>
	Finally, ChatGPT managed to build the application based on my short prompt. However, the process wasn’t trivial, and sometimes it would get stuck in a “fixing loop”, desperately wanting to fix the wrong file, which resulted in the application crashing.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-214"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-212">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-213'
	>
	It took a few tries, but in the end, I did get the app that I wanted. To make it as simple as possible, I had to significantly reduce the app’s scope and just give up on some of the things I planned. The app had a lot of issues with navigation between different screens, as well as parsing models from the API, since they usually require consistency between the files.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-221"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<a	class="card-simple js-card-simple card-simple--is-ad block-card__card-simple card-simple--has-link js-card-simple-link card-simple__content-align--left"
	data-id="es-215"
	 href='https://infinum.com/artificial-intelligence/agent-development/'>

	
	
	<div class="card-simple__content">
		<div class="card-simple__heading-wrap">
			<h2	class='typography typography--size-24-text js-typography card-simple__heading'
	data-id='es-216'
	>
	As the pressure to implement AI grows, many businesses don&#8217;t know where to start. Our 14-day sprint helps you cut through the noise—turning early ideas into validated prototypes with clear logic, smart design, and real momentum. Learn how it works.</h2>		</div>

		<button	class="btn btn--color-infinum btn--size-small btn--width-default btn__icon-position--right card-simple__btn js-block-card-btn js-card-simple-link"
	data-id="es-218"
	 tabindex='-1'>
		<div class="btn__inner">
					<div	class='typography typography--size-none js-typography btn__label'
	data-id='es-219'
	>
	Learn more </div>		
		<i
	class="icon btn__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='arrow-right-16' data-id='es-220'>
	<svg fill='none' height='16' viewBox='0 0 17 16' width='17' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><g stroke='currentColor' stroke-width='2'><path d='m.5 7.99999 14 .00001'/><path d='m9.23352 2.7251 5.97848 5.97852'/><path d='m9.23352 13.2744 5.97848-5.9785'/></g></svg></i>	</div>
	</button>	</div>
</a>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-224"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-222">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-223'
	>
	Can ChatGPT really build Flutter apps? Limitations apply</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-227"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-225">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-226'
	>
	As this experiment proves, agents seem to work on smaller applications and can even fix the code they generated earlier. However, handling larger and more complex applications could prove problematic. The contextual knowledge needed to build such apps may be too expansive to fit in the token limit.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-230"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-228">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-229'
	>
	The AI tool should also take into account all the utilities and existing files and implementations. Otherwise, we can easily end up with multiple implementations of the same feature in multiple places, or changes done in one file breaking other files. Also, sometimes we work on more complex features that need to use multiple files in very specific ways, and AI could easily make mistakes here.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-233"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-231">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-232'
	>
	Another important thing to note is that these types of AI tools are not constantly trained on new updates, so they will inevitably use old or even depreciated code. This is especially true for Flutter since both Flutter and Dart have seen substantial changes in the last few years.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-236"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-234">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-235'
	>
	<strong>AI – Terrible lead engineer, great assistant</strong></h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-239"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-237">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-238'
	>
	AI in development certainly has a case. Actually, many potential use cases. However, for now, they are probably best kept within the confines of the assistant role. That way, when they give outdated suggestions or just plain weird ones, the human eye can still easily dismiss them, and just stick to the useful parts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-242"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-240">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-241'
	>
	A good example would be a partial automation of the code review process, where AI could start the review as soon as the code is pushed. That way, pieces of code would get flagged and marked as high priority for human reviewers. Ideally, this would require some contextual understanding, but should still work since AI wouldn’t actually be writing or modifying the code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-245"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-243">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-244'
	>
	Further, every application requires performing some repetitive and not particularly challenging tasks. Normally, these are hard to automate because there are always newer versions that do something slightly differently. With AI, we can streamline this process.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-247"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-highlighted-text">
	<p	class='typography typography--size-36-text js-typography block-highlighted-text__typography'
	data-id='es-246'
	>
	<strong>By feeding AI tools all the information we have and giving it the latest documentation, we can easily automate repetitive tasks.</strong></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-250"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-248">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-249'
	>
	What’s more, local models are also becoming more capable and some can even be run on phones. While they are still behind GPT-3.5, they are not that far behind – wIth further updates and development, they will be able to achieve GPT-3.5 results. This will allow us to implement a local model to ensure privacy of any sensitive data. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-253"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-251">
	<h2	class='typography typography--size-52-default js-typography block-typography__typography'
	data-id='es-252'
	>
	ChatGPT still has a long way to go to start building Flutter apps</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-256"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-254">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-255'
	>
	As we’ve seen in this experiment, AI becoming the sole developer of an application is still a long way off. It struggles with building more complex apps, which is practically any app that includes more than one feature at this point. It is also doomed to always use outdated libraries and code. </p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-259"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-257">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-258'
	>
	However, while it may not be able to write code independently, it is already proving to be a very useful assistant. It can speed up development when used to implement some simple features, write boilerplate code, or perform repetitive tasks.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-262"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-260">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-261'
	>
	We should also be aware that these tools are improving their performance by the minute, and there is no doubt they will hold an important place in the future of development.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-265"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-typography" data-id="es-263">
	<p	class='typography typography--size-16-text-roman js-typography block-typography__typography'
	data-id='es-264'
	>
	<em>If you are interested in utilizing AI in your digital product, see <a href="https://infinum.com/artificial-intelligence/" target="_blank" rel="noreferrer noopener">how we can help you on the way</a>.</em></p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/chatgpt-flutter-app/">How We Got ChatGPT to Build a Flutter App</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>19093https://infinum.com/uploads/2022/01/charts-in-flutter-0.webp</url>
				</image>
				<title>How to Create Custom Flutter Charts</title>
				<link>https://infinum.com/blog/charts-in-flutter/</link>
				<pubDate>Fri, 17 Dec 2021 13:55:00 +0000</pubDate>
				<dc:creator>Luka Knezić</dc:creator>
				<guid isPermaLink="false">https://infinum.com/blog/charts-in-flutter/</guid>
				<description>
					<![CDATA[<p>Presenting information in graphs and charts can be tricky in Flutter due to poor template availability, but a possible solution is to create custom charts. </p>
<p>The post <a href="https://infinum.com/blog/charts-in-flutter/">How to Create Custom Flutter Charts</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-390"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-268">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-271"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-269">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-270'
	>
	<strong>Flutter charts</strong> are a challenge to implement in mobile apps. Learn how to do it easier with this handy guide on creating charts that are ready for production. This article will help you navigate the abundance of <strong>charting libraries</strong>, showing you tricks for customization and smooth integration to bring your designer&#8217;s vision to life. Make your data pop in a fun and professional way for your <a href="https://infinum.com/mobile-web-apps/">mobile app</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-274"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-272">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-273'
	>
	It’s not a secret that apps collect user data. Insight into some of that data is also available for app users. An efficient way to present the information is using visuals, specifically graphs and charts.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-277"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-275">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-276'
	>
	They are easy to implement when it comes to Android or iOS, but for designers and engineers working with <a href="https://infinum.com/mobile-web-apps/flutter/">Flutter</a>, it’s easier said than done due to a scarcity of chart templates at their disposal.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-280"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-278">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-279'
	>
	A possible solution is to create <strong>custom charts</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-283"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-281">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-282'
	>
	Creating custom Flutter charts</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-286"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-284">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-285'
	>
	Unlike chart templates, <strong>charting libraries</strong> available at our disposal are abundant. For example, I stumbled upon more than 128 packages for the keyword “charts” when writing. They aren’t perfect, though – most are lacking in customization or require adding some UI elements, making it almost impossible to replicate designers’ ideas.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-289"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-287">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-288'
	>
	I’ve tested several available chart libraries, desperately trying to mold our data to fit in the chart and repeatedly failing because the developers had either missed or forgotten something. Don’t get me wrong, none of those libraries are bad per se, nor do developers like to reinvent charts that much.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-292"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-290">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-291'
	>
	Charts are challenging to make, especially when presenting an enormous amount of data in a neat visual that should be fully customizable and accurate. And that’s just half of what a chart is supposed to do. The next part would be displaying a legend for more straightforward data interpretation.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-295"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-293">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-294'
	>
	The grammar of graphics</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-298"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-296">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-297'
	>
	Leland Wilkinson has an excellent book about data representation called <strong>The Grammar of Graphics</strong>. It dissects in simple terms the repression of graphics and their rules into seven layers, from data to themes:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-301"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-299"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-300">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2022/01/charts-in-flutter-1-1400x751.webp				media='(max-width: 699px)'
				type=image/webp								height="751"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2022/01/charts-in-flutter-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="805"
															width="1500"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-304"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-302">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-303'
	>
	We can see that layers have their functions, namely they enable us to build new layers on top quickly. The book describes how to present any data in any way imaginable. Our library will be used mainly on mobile devices, so we will focus on drawing in rectangular coordinate space to save time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-307"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-305">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-306'
	>
	We can also delegate some layers. For example, we have limited space on mobile where multiple charts in grid view might be overkill. That being said, we can delegate the facets layer to the developer. If necessary, it can be done using <code>GridView</code> and by adding multiple <code>Chart</code> widgets as children.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-310"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-308">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-309'
	>
	Working on a custom solution for Flutter charts</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-313"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-311">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-312'
	>
	We wanted a simple Flutter chart that allows for a lot more UI customization. Making a scatter diagram or pie chart is technically possible using this lib, but it would require a lot of work.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-316"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-314">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-315'
	>
	Back to <strong>The Grammar of Graphics</strong>, how could we use those layers, and what layers do we need to create simple charts? Following this will allow us to implement missing layers later if required.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-319"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-317"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-318">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2022/01/charts-in-flutter-2-1400x751.webp				media='(max-width: 699px)'
				type=image/webp								height="751"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2022/01/charts-in-flutter-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="805"
															width="1500"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-322"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-320">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-321'
	>
	Now that we know what layers we need to handle immediately, it no longer looks so intimidating. With just four layers, we will be able to see our data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-325"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-323">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-324'
	>
	Data</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-328"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-326">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-327'
	>
	Now that we know how to make our Flutter chart, we can start handling the data layer. <code>ChartData</code> will map data to chart items. There is also <code>ChartData.randomBarValues</code> that helps with testing when adding charts. Chart data is handling aesthetics as well for now – it will try to display all of the data in the list and scale the chart accordingly. You can change that with exact value by specifying the axisMin and axisMax, or you can change the valueAxisMaxOver. That will add ‘invisible’ data on the max value, acting as ‘padding’ on current data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-331"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-329">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-330'
	>
	Geometries</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-334"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-332">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-333'
	>
	Geometry is a layer that takes the item and decides how and where to draw it in the chart. By using <code>ItemPainter</code>, we can draw different items while passing the same data. We could also expand our <code>ChartItem&lt;T&gt;</code> to show additional or other data.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-337"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-335">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-336'
	>
	Having geometry separated is useful since that way we can show the data we want without reinventing the whole chart. For example, if you need to show a custom chart item with five values, it can be done by extending <code>ChartItem&lt;T&gt;</code> and <code>GeometryPainter&lt;T&gt;</code> to draw and show any item you want. You can even add your own item options by extending <code>ItemOptions</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-340"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-338">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-339'
	>
	Statistics</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-343"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-341">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-342'
	>
	<code>DataStrategy</code> is used to manipulate the data. Current strategies are <code>DefaultDataStrategy</code> and <code>StackDataStrategy</code>. For now, since we won’t be adding an <em>Aesthetics</em> layer at this time, <code>ChartData</code> will also handle the scale the data will use. Horizontal axis for the charts is by default linear.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-346"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-344">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-345'
	>
	Themes</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-349"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-347">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-348'
	>
	Themes are just things that decorate the<strong> Flutter chart</strong>. In our case, we added “2” layers of decoration, front-ground and back-ground decorations. That way, we can also control the decorations shown on the front and back of the items. The neat thing is that we can use the decoration we make in multiple different use cases while also allowing complete customizability by extending <code>DecorationPainter</code> new Decorations can easily be added.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-352"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-350">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-351'
	>
	Animating the Flutter charts </h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-355"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-353">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-354'
	>
	It’s not enough for charts to be customizable and flexible to satisfy the design and blend with the app. Usually, analytics screens will have filters or something similar that will change the chart. That chart should animate to a new state to keep the app looking fluid and smooth.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-358"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-356">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-357'
	>
	Making this was a bit of a challenge, but since we already had layers nicely set up, it was just a matter of getting layers to animate between states.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-361"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-359">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-360'
	>
	We added <code>lerp</code> functions to each layer. Making a new <code>ImplicitlyAnimatedWidget</code> would ensure users can add <code>AnimatedChart</code>, and it will automatically update when a change in chart state is detected.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-364"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-362">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-363'
	>
	Using Flutter charts in production</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-367"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-365">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-366'
	>
	We have significant experience <a href="https://infinum.com/work/?industries=healthcare">building healthcare apps</a>, and they always want to show data in some way. That gave us a chance to try our Flutter charts immediately in the app we were developing for the US market. It was a perfect test since the charts were complex, and each screen had a slightly different chart to show.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-370"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-368"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-369">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2022/01/charts-in-flutter-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="616"
															width="1369"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-373"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-371"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-372">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2022/01/charts-in-flutter-4.webp"
					class="image__img block-media__image-img"
					alt=""
										height="575"
															width="1369"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-376"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-374">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-375'
	>
	The library didn’t limit us in any way. We could easily create a custom extension and add it to the chart if something was missing. So, by using the library more and more, we added a variety of decorations that would later prove suitable for the charts we were yet to create.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-379"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-377">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-378'
	>
	Finally, to make sure we don’t break any of the existing decorations or item painters when adding new features, we added over 80 golden tests. Safety first!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-382"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-380">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-381'
	>
	Pixel perfect charts every time</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-385"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-383">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-384'
	>
	Using charts in production can be tricky, but <a href="https://github.com/infinum/flutter-charts">Flutter charts can help</a>. Try it out and help us make it better with feedback!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-388"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-386">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-387'
	>
	Infinum is proud to be enlisted in <a href="https://flutter.dev/consultants">Google’s Flutter Consultants Repository</a>. If you need a Flutter app that will elevate your business, <a href="https://infinum.com/contact/">get in touch</a> with us for top-notch development services.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/charts-in-flutter/">How to Create Custom Flutter Charts</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>7858https://infinum.com/uploads/2021/06/logging-in-flutter-0.webp</url>
				</image>
				<title>Better Logging in Flutter with Loggy Library</title>
				<link>https://infinum.com/blog/logging-in-flutter/</link>
				<pubDate>Wed, 16 Jun 2021 16:15:00 +0000</pubDate>
				<dc:creator>Luka Knezić</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/logging-in-flutter/</guid>
				<description>
					<![CDATA[<p>Never again overlook critical messages.</p>
<p>The post <a href="https://infinum.com/blog/logging-in-flutter/">Better Logging in Flutter with Loggy Library</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-495"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-391">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-394"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-392">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-393'
	>
	<strong>Flutter logging</strong> proved inadequate for all our requirements as we started using <a href="https://infinum.com/mobile-web-apps/flutter/">Flutter more extensively in larger projects</a> at Infinum.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-397"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-395">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-396'
	>
	<a href="https://infinum.com/blog/flutter-vs-native/">Flutter</a> had a great year in 2020 with over half a million developers using it daily. It has surpassed react-native, linux, and vscode by the number of stars on github.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-400"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-398">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-399'
	>
	Is a logger really necessary?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-403"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-401">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-402'
	>
	Logging is a really important tool for any developer and any application. It can make debugging time significantly shorter and help developers figure out sooner what’s going on in the app.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-406"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-404">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-405'
	>
	Using the <strong>Flutter logger</strong> properly can be highly valuable when an app is in the production environment. It allows developers to analyze user actions and understand the cause of a problem.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-409"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-407">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-408'
	>
	Problems with Flutter logging</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-412"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-410">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-411'
	>
	As logging in Flutter is very bland by default, developers mostly rely on print. The main problem with print is that all messages are treated the same way. There is no distinction between info and critical log messages. <strong>Critical messages are easily overlooked</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-415"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-413">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-414'
	>
	There is also no ability to turn logging off when building a production version. That can be a big security concern since all prints would be visible and easily accessible.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-418"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-416">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-417'
	>
	Possible solutions to Flutter logging</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-421"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-419">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-420'
	>
	We noticed this problem when we were developing an app with complex navigation with socket communication. Often, <strong>socket messages would overflood our console</strong>, and then removing them would take a while, and debugging if something went wrong in communication would take even longer.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-424"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-422">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-423'
	>
	We wanted a way to toggle logs depending on the feature we were working on, so we set up the following criteria for the logger. Firstly, we wanted to have multiple logger levels and types, because filtering just by levels is not sufficient. In addition to that, we would need filtering and the ability to easily toggle logging.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-427"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-425">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-426'
	>
	We would also try to <strong>find a logger that has as little setup as possible</strong> in order to get as much data as possible.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-430"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-428">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-429'
	>
	The hunt for libraries</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-433"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-431">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-432'
	>
	<strong>We tried almost every logging library that existed at the time</strong>. Even though all of them had implemented our criteria on multiple levels, none of them fitted all the criteria.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-436"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-434"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-435">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2021/06/logging-in-flutter-1-1400x995.webp				media='(max-width: 699px)'
				type=image/webp								height="995"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2021/06/logging-in-flutter-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1137"
															width="1600"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-439"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-437">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-438'
	>
	<strong>Filter by type was the hardest requirement to fulfil</strong> and it was either impossible or very difficult to implement. But we persisted on fulfilling that criteria as it would allow us to turn loggers on and off for a single feature, without affecting other loggers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-442"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-440">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-441'
	>
	Filtering only by level would again lead us to the same path, and further down in app development more and more messages would become error or warning levels in order to become visible.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-445"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-443">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-444'
	>
	Some of the libraries had nice extra features which we wanted to include, but since none of them met all of our requirements, the only reasonable decision was to make our own Flutter logging library. Cue <a href="https://github.com/infinum/floggy">Flutter Loggy</a>!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-448"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-446">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-447'
	>
	Mixins to the rescue</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-451"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-449">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-450'
	>
	We decided to use mixins from dart to achieve quick setup, while keeping different types separated. Using mixins has a lot of practical usages, so we wanted to see if they could help us with our logging problems.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-454"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-452">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-453'
	>
	Since mixins can get calling class name, we used that to generate tags for logs, and we could make more types by making different mixins for different layers. Having multiple types would allow us to separate loggers for different layers of the application, which can be easily filtered.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-457"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-455">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-456'
	>
	We built the logger with mixins, and filtering them worked as expected – making new types was simple, and Loggy would come with 2 types – <code>UiLoggy</code> and <code>NetworkLoggy</code>. They are a great starting point and good examples for creating custom types later.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-460"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-458">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-459'
	>
	To use Loggy, simply add <code>Loggy.initLoggy()</code> before <code>runApp()</code>, and add <code>with UiLoggy</code> in any class where you need Loggy. That being done, it’s now time to log the messages <code>loggy.debug</code>, <code>loggy.info</code>, <code>loggy.warning</code> or <code>loggy.error</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-463"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-461"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-462">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2021/06/logging-in-flutter-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="961"
															width="1212"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-466"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-464">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-465'
	>
	The library can be configured with <code>initLoggy</code>, from where it’s possible to add filters, levels and printer for logger.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-469"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-467">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-468'
	>
	With different types of logging and a habit of using networking in pretty much every app, we made an interceptor for the most popular networking library Dio. Dio interceptor can attach to Dio instance and log requests and responses.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-472"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-470"
	 data-media-type='video'>

	<div class="video__wrapper" data-id="es-471">
		<video
		class="video block-media__video js-video js-block-media-video video--cursor-takeover-use"
		 loop autoplay playsinline muted preload='metadata'>
		<source  src='https://infinum.com/uploads/2021/06/loggy_dio_gif.mp4' type='video/mp4' />	</video>
	</div></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-475"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-473">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-474'
	>
	This interceptor is useful because of ║, ╔ and ╚. Using these symbols, it is possible to set up the console to collapse all lines that contain them. This way, we will see the request and the response code, but the request body will be collapsed and can be expanded to show more details.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-478"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-476">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-477'
	>
	Problems solved with Flutter Loggy</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-481"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-479">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-480'
	>
	With Loggy, all of the problems we had before were gone. Now we can <strong>easily set up different printers</strong>, eg. instead of sending events to console the printer can send events to crashlytics for production builds or just disable logging completely.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-484"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-482">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-483'
	>
	When it comes to types, <strong>it’s simple to set up different ones</strong>, allowing for easy filtering by type in order to decide which to include in production builds.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-487"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-485">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-486'
	>
	Finally, <strong>using Loggy inside the app is convenient</strong> – simply by adding <code>with UiLoggy</code> and logging something a lot more info becomes available, and it’s possible to control priority or easily disable it without actually removing it.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-490"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-488">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-489'
	>
	We also managed to clear out our console while actually logging more stuff about the request, since they show up collapsed they take just 1 line of space, but they can be expanded to show whole request details.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-493"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-491">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-492'
	>
	All in all, we are pleased with the results, so <a href="https://github.com/infinum/floggy">give Loggy a try</a> and let us know whether it made your Flutter logging easier!</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/logging-in-flutter/">Better Logging in Flutter with Loggy Library</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>