<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Souvik Biswas</title>
    <description>The latest articles on DEV Community by Souvik Biswas (@sbis04).</description>
    <link>https://dev.to/sbis04</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F268620%2Fed36fc8f-c46b-42bd-a76d-6cc2ff8ac4d0.png</url>
      <title>DEV Community: Souvik Biswas</title>
      <link>https://dev.to/sbis04</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sbis04"/>
    <language>en</language>
    <item>
      <title>Ghost Maintainer — An AI Junior Partner for Open Source</title>
      <dc:creator>Souvik Biswas</dc:creator>
      <pubDate>Fri, 27 Mar 2026 04:13:12 +0000</pubDate>
      <link>https://dev.to/sbis04/ghost-maintainer-an-ai-junior-partner-for-open-source-11l0</link>
      <guid>https://dev.to/sbis04/ghost-maintainer-an-ai-junior-partner-for-open-source-11l0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I maintain a couple of open source projects on my own, and the worst part has never been writing code — it's the stuff around it. Going through new issues, deciding if something's a bug or a feature request, digging into the codebase to figure out what's actually wrong, and then sitting down to fix it. Half the issues end up sitting untouched for weeks because I just don't get to them.&lt;/p&gt;

&lt;p&gt;So I built Ghost Maintainer. It turns Notion into an operations center for a GitHub repo, and handles most of the grunt work with AI. Here's what happens when someone opens an issue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It shows up in a &lt;strong&gt;Triage Queue&lt;/strong&gt; in Notion&lt;/li&gt;
&lt;li&gt;Gemini reads the issue and classifies it — bug or feature, priority level, confidence score&lt;/li&gt;
&lt;li&gt;Bugs go to the &lt;strong&gt;Maintenance Backlog&lt;/strong&gt;, features go to the &lt;strong&gt;Feature Backlog&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;If auto-fix is on, it reads through the codebase, figures out a fix, and opens a PR&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All I have to do is review the PR and merge.&lt;/p&gt;

&lt;p&gt;If you've turned off auto-fix (or want to handle features), there's a CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ghost_maintainer fix 3
ghost_maintainer implement 9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Same pipeline — reads the code, writes a fix, opens a PR.&lt;/p&gt;

&lt;p&gt;Setting it up is one command from inside your repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://raw.githubusercontent.com/sbis04/ghost_maintainer/main/install.sh &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; install.sh &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  bash install.sh &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;rm &lt;/span&gt;install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You plug in your Notion, GitHub, and Gemini tokens, and it handles the rest — creates the databases, sets up GitHub secrets, pushes the workflows.&lt;/p&gt;

&lt;p&gt;There's also a Dart MCP server that pairs with Notion MCP (&lt;code&gt;@notionhq/notion-mcp-server&lt;/code&gt;). Hook both up to Gemini CLI or Claude, and you can interact with your backlog in plain English — triage stuff, investigate bugs, ship fixes. 5 tools, 2 resources, 2 prompts.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Notion workspace
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzerg7f7g10lhzg1jim14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzerg7f7g10lhzg1jim14.png" alt="Ghost Maintainer Notion Page" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Triage Queue&lt;/strong&gt; — everything starts here, AI sorts it out&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance Backlog&lt;/strong&gt; — bugs, with AI summaries and PR links&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature Backlog&lt;/strong&gt; — feature requests, ready when you are&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Archive&lt;/strong&gt; — done items land here with timestamps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project Vision Statement&lt;/strong&gt; — tells the AI what matters to your project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdtoibmewxlk8svhxti3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdtoibmewxlk8svhxti3.png" alt="Feature Request Notion Page" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/AwVQcZSCFgM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/hBSJtesPpmM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;
&lt;h2&gt;
  
  
  Link to Code on GitHub
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sbis04" rel="noopener noreferrer"&gt;
        sbis04
      &lt;/a&gt; / &lt;a href="https://github.com/sbis04/ghost_maintainer" rel="noopener noreferrer"&gt;
        ghost_maintainer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AI-powered junior partner for solo open-source maintainers
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Ghost Maintainer&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/43280874/570174214-979938f8-370b-4185-a662-531630d50e7c.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzQ3NjMyMjksIm5iZiI6MTc3NDc2MjkyOSwicGF0aCI6Ii80MzI4MDg3NC81NzAxNzQyMTQtOTc5OTM4ZjgtMzcwYi00MTg1LWE2NjItNTMxNjMwZDUwZTdjLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjAzMjklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwMzI5VDA1NDIwOVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWFlMGJiY2U5ZGNlNjYxM2UzZDgxY2YwOTZhMTJjZjkwNjA1MmE0NDhkOWFiMzU2OGM2MDc0NTFhNjU0NWQzOTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.i9t_aXaEi-6cJXr20MpWhZR-E1bF8Y4cel7EVkkQJ98"&gt;&lt;img width="1280" height="640" alt="ghost maintainer cover" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F43280874%2F570174214-979938f8-370b-4185-a662-531630d50e7c.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzQ3NjMyMjksIm5iZiI6MTc3NDc2MjkyOSwicGF0aCI6Ii80MzI4MDg3NC81NzAxNzQyMTQtOTc5OTM4ZjgtMzcwYi00MTg1LWE2NjItNTMxNjMwZDUwZTdjLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjAzMjklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwMzI5VDA1NDIwOVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWFlMGJiY2U5ZGNlNjYxM2UzZDgxY2YwOTZhMTJjZjkwNjA1MmE0NDhkOWFiMzU2OGM2MDc0NTFhNjU0NWQzOTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.i9t_aXaEi-6cJXr20MpWhZR-E1bF8Y4cel7EVkkQJ98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Solo maintainers wear too many hats. Ghost Maintainer takes over the repetitive parts — triaging issues, reading code, writing fixes, and opening PRs — so you can focus on the work that actually needs a human.&lt;/p&gt;

&lt;p&gt;It uses Notion as an operations center. Bugs get triaged and fixed automatically. Features queue up until you're ready. Everything stays visible in Notion so you never lose track.&lt;/p&gt;

&lt;p&gt;Built with Dart, MCP, Google Gemini, and the Notion API.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;You'll need &lt;a href="https://dart.dev/get-dart" rel="nofollow noopener noreferrer"&gt;Dart&lt;/a&gt; (&amp;gt;= 3.7.0) and &lt;a href="https://cli.github.com/" rel="noopener noreferrer"&gt;GitHub CLI&lt;/a&gt; installed.&lt;/p&gt;

&lt;p&gt;Grab three API keys before you start:&lt;/p&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Notion token&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://www.notion.so/profile/integrations" rel="nofollow noopener noreferrer"&gt;notion.so/profile/integrations&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;See steps below&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;GitHub PAT&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://github.com/settings/tokens" rel="noopener noreferrer"&gt;github.com/settings/tokens&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Classic token, &lt;code&gt;repo&lt;/code&gt; + &lt;code&gt;actions&lt;/code&gt; scopes&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;Gemini key&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://aistudio.google.com/apikey" rel="nofollow noopener noreferrer"&gt;aistudio.google.com/apikey&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Any project works&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;You can either follow the steps in the next section, or have a look at the &lt;a href="https://youtu.be/AwVQcZSCFgM?si=yRfQOhqyjYBC6zYR" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;demo video&lt;/strong&gt;&lt;/a&gt; to learn more about the tool and get step-by-step instruction for installing Ghost…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sbis04/ghost_maintainer" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Three main pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ghost_maintainer_mcp/&lt;/code&gt; — Dart MCP server. 5 tools, 2 resources, 2 prompts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;notion_setup/&lt;/code&gt; — CLI tool + the GitHub Action scripts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.github/workflows/&lt;/code&gt; — 4 workflows covering ingestion, triage, implementation, and archival.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI installs globally via &lt;code&gt;dart pub global activate&lt;/code&gt; straight from the repo — no need to publish to pub.dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Notion MCP
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7le0kfmpb58yrhw5ixfc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7le0kfmpb58yrhw5ixfc.png" alt="Gemini interacting with Notion MCP and Ghost Maintainer" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole system runs on two MCP servers working together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notion MCP&lt;/strong&gt; (&lt;code&gt;@notionhq/notion-mcp-server&lt;/code&gt;) is the foundation. It's what gives the AI access to the Notion workspace — searching databases, reading pages, creating content, appending blocks. Without it, the AI would be blind to what's going on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ghost Maintainer MCP&lt;/strong&gt; sits on top of that. It's a custom Dart server that adds the maintenance-specific stuff — &lt;code&gt;ghost_triage_issue&lt;/code&gt;, &lt;code&gt;ghost_investigate_issue&lt;/code&gt;, &lt;code&gt;ghost_deploy_fix&lt;/code&gt;. The prompts are written to use both servers together. The triage prompt, for instance, tells the AI to search for duplicates through Notion MCP before classifying, and to append its analysis notes to the Notion page afterward.&lt;/p&gt;

&lt;p&gt;Ghost Maintainer also exposes a couple of resources that pull from Notion — &lt;code&gt;ghost://vision&lt;/code&gt; grabs the Project Vision Statement, and &lt;code&gt;ghost://backlog/summary&lt;/code&gt; aggregates stats across all the databases. These save the AI from having to navigate the workspace manually every time.&lt;/p&gt;

&lt;p&gt;Everything lives in Notion. The Triage Queue, backlogs, and archive are all databases with properties like Stage, Priority, Labels, AI Summary, and PR URL. The Vision Statement is a regular Notion page — update it and the AI adjusts. If you write "security issues are always P0" in there, that's exactly what happens.&lt;/p&gt;

&lt;p&gt;PRs link back to the Notion page. When they get merged, the item auto-archives with a date.&lt;/p&gt;

&lt;p&gt;The GitHub Actions pipeline handles the automated side (new issue triggers triage, etc.), but the MCP layer is what makes it interactive. Connect both servers to Gemini CLI and you get conversations like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "What's in the backlog?"
AI: [uses ghost://backlog/summary] "3 bugs, 2 features..."

You: "Any duplicates for the dark mode request?"
AI: [uses Notion MCP search] "Found a similar one from last week."

You: "Triage the login crash"
AI: [uses ghost_triage_issue] "Bug, P1-High."

You: "Fix it"
AI: [uses ghost_investigate_issue + ghost_deploy_fix] "PR #15 created."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thing I like about this is that Notion ends up being the shared workspace for both me and the AI. I open Notion and see what's going on. The AI checks the same workspace through Notion MCP. Same board, same data, no surprises.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>WanderXP — Organize your travel with ease</title>
      <dc:creator>Souvik Biswas</dc:creator>
      <pubDate>Mon, 20 Feb 2023 16:09:40 +0000</pubDate>
      <link>https://dev.to/sbis04/wanderxp-organize-your-travel-with-ease-205d</link>
      <guid>https://dev.to/sbis04/wanderxp-organize-your-travel-with-ease-205d</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;It's always a hassle to manage all the necessities while deciding a travel plan. What if you could keep everything organized inside a single app?&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/N0MrxzBc7tk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WanderXP&lt;/strong&gt; helps you to keep your travel requirements organized including flight and hotel details, and the notable places that you don't want to miss visiting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;Integration Innovators&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;The app is designed for mobile platforms (&lt;em&gt;small form factor&lt;/em&gt;), but as Flutter is used for building so it's a cross-platform app capable of running on Android, iOS, Windows, Linux, and Web.&lt;/p&gt;

&lt;p&gt;Web app link: &lt;a href="https://wanderxp.flutterflow.app" rel="noopener noreferrer"&gt;https://wanderxp.flutterflow.app&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please scale the window to mobile form factor while running on web.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mobile app link (Android): &lt;a href="https://appdistribution.firebase.dev/i/a0b42613bd16e37e" rel="noopener noreferrer"&gt;https://appdistribution.firebase.dev/i/a0b42613bd16e37e&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please try this for better experience, as it's optimized for mobile platforms.&lt;/p&gt;

&lt;p&gt;You can also follow the steps on the GitHub project page if you want to try out the app on other platforms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Project Description
&lt;/h2&gt;

&lt;p&gt;The primary features of the app are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store multiple trip information (travel start &amp;amp; end dates, flight info, hotel info, places to visit during the trip).&lt;/li&gt;
&lt;li&gt;Upload documents in a organized manner (like flight and hotel booking documents).&lt;/li&gt;
&lt;li&gt;Secure user management with a robust authentication system.&lt;/li&gt;
&lt;li&gt;Discover new suggestions for popular places to travel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;Here's an overview of the entire architecture of the cross-platform application along with the backend infrastructure built with Flask and managed on Linode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnd1u4szw3w6r197weha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnd1u4szw3w6r197weha.png" alt="WanderXP Architecture" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tech stack used for building this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://flutterflow.io" rel="noopener noreferrer"&gt;&lt;strong&gt;FlutterFlow&lt;/strong&gt;&lt;/a&gt;: It's a no-code platform that I have used for designing the app from scratch, connecting with the REST API, and then generating the source code in Flutter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://flask.palletsprojects.com/en/2.2.x" rel="noopener noreferrer"&gt;&lt;strong&gt;Flask&lt;/strong&gt;&lt;/a&gt;: Used for building the REST API to manage user authentication, database CRUD operations, and storing files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.linode.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Linode&lt;/strong&gt;&lt;/a&gt;: For getting access to the cloud computing infrastructure along with their managed database (SQL) and object storage.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Frontend app
&lt;/h3&gt;

&lt;p&gt;The Flutter application consists of the following screens/pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SplashScreen&lt;/li&gt;
&lt;li&gt;HomePage&lt;/li&gt;
&lt;li&gt;LoginPage&lt;/li&gt;
&lt;li&gt;SignUpPage&lt;/li&gt;
&lt;li&gt;DiscoverPage&lt;/li&gt;
&lt;li&gt;TripViewPage&lt;/li&gt;
&lt;li&gt;CreateTripPage&lt;/li&gt;
&lt;li&gt;FlightInfoPage&lt;/li&gt;
&lt;li&gt;HotelReservationPage&lt;/li&gt;
&lt;li&gt;PlacesToVisitPage&lt;/li&gt;
&lt;li&gt;TripPage&lt;/li&gt;
&lt;li&gt;EditProfile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F466lw1hlyyy0htg5usig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F466lw1hlyyy0htg5usig.png" alt="HomePage, LoginPage, SignUpPage" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmzgidzkdq1o5g8uambt2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmzgidzkdq1o5g8uambt2.png" alt="DiscoverPage, TripViewPage, EditProfile" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fye3orqt3grsptvclahwv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fye3orqt3grsptvclahwv.png" alt="CreateTripPage, FlightInfoPage, HotelReservationPage, PlacesToVisitPage" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend REST API
&lt;/h3&gt;

&lt;p&gt;The REST API built with Flask mainly consists of the following endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/register&lt;/code&gt;&lt;/strong&gt;: To create account for a new user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/login&lt;/code&gt;&lt;/strong&gt;: To log in an already registered user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/places&lt;/code&gt;&lt;/strong&gt;: Fetching all the top places to discover.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/place&lt;/code&gt;&lt;/strong&gt;: To retrieve a single place with the ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/places_to_visit/&amp;lt;trip_id&amp;gt;&lt;/code&gt;&lt;/strong&gt;: Retrieve all the places to visit by the provided trip ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/trips/&amp;lt;trip_id&amp;gt;&lt;/code&gt;&lt;/strong&gt;: Retrieve a single trip by its ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/trips/&amp;lt;trip_id&amp;gt;/update&lt;/code&gt;&lt;/strong&gt;: Update the details of a trip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/trips&lt;/code&gt;&lt;/strong&gt;: Retrieve and store trip based on the &lt;code&gt;uid&lt;/code&gt; (Unique user identifier) provided.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/store_file&lt;/code&gt;&lt;/strong&gt;: For storing a file to the Object Storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;/get_file&lt;/code&gt;&lt;/strong&gt;: For retrieving a file from the storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Linode
&lt;/h3&gt;

&lt;p&gt;Overview of the Linode Cloud Console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrp1lq44pqb5teeyulfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrp1lq44pqb5teeyulfw.png" alt="Linode Cloud Console" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Managed Database using MySQL v8 for storing user data, trips, places, and more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9jedd5zu233ynxf8swj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9jedd5zu233ynxf8swj.png" alt="Managed Database" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Object Storage used for storing user flight and hotel booking  files:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fx941o6yrg8xbs10a13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fx941o6yrg8xbs10a13.png" alt="Object Storage" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;The entire app is open sourced - try it out and also feel free to contribute to this project 😉 :&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sbis04" rel="noopener noreferrer"&gt;
        sbis04
      &lt;/a&gt; / &lt;a href="https://github.com/sbis04/wander_xp" rel="noopener noreferrer"&gt;
        wander_xp
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Organise your travel with ease
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;WanderXP&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/wander_xpscreenshots/wander_xp_dev_cover.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fwander_xpscreenshots%2Fwander_xp_dev_cover.png" alt="WanderXP Cover"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Blog post about this project: &lt;a href="https://dev.to/sbis04/wanderxp-organize-your-travel-with-ease-205d" rel="nofollow"&gt;https://dev.to/sbis04/wanderxp-organize-your-travel-with-ease-205d&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Try out the app (Android): &lt;a href="https://appdistribution.firebase.dev/i/a0b42613bd16e37e" rel="nofollow noopener noreferrer"&gt;https://appdistribution.firebase.dev/i/a0b42613bd16e37e&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Try out the app (Web): &lt;a href="https://wanderxp.flutterflow.app" rel="nofollow noopener noreferrer"&gt;https://wanderxp.flutterflow.app&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;WanderXP&lt;/strong&gt; helps you to keep your travel requirements organized including flight and hotel details, and the notable places that you don't want to miss visiting.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/wander_xpscreenshots/wander-xp-short-demo-2.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fwander_xpscreenshots%2Fwander-xp-short-demo-2.gif" alt="WanderXP Demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Here's an overview of the entire architecture of the cross-platform application along with the backend infrastructure built with Flask and managed on Linode:&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/wander_xpscreenshots/wander-xp-architecture.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fwander_xpscreenshots%2Fwander-xp-architecture.png" alt="WanderXP Architecture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The tech stack used for building this project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://flutterflow.io" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;FlutterFlow&lt;/strong&gt;&lt;/a&gt;: It's a no-code platform that I have used for designing the app from scratch, connecting with the REST API, and then generating the source code in Flutter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://flask.palletsprojects.com/en/2.2.x" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Flask&lt;/strong&gt;&lt;/a&gt;: Used for building the REST API to manage user authentication, database CRUD operations, and storing files.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.linode.com" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;Linode&lt;/strong&gt;&lt;/a&gt;: For getting access to the cloud computing infrastructure along with their managed database (SQL) and object storage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Screenshots&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/wander_xpscreenshots/linode-app-1.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fwander_xpscreenshots%2Flinode-app-1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/wander_xpscreenshots/linode-app-2.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fwander_xpscreenshots%2Flinode-app-2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/wander_xpscreenshots/linode-app-3.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fwander_xpscreenshots%2Flinode-app-3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;License&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Copyright (c) 2023 Souvik Biswas&lt;/p&gt;
&lt;p&gt;Permission…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sbis04/wander_xp" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;The project is licensed under the &lt;a href="https://github.com/sbis04/wander_xp/blob/main/LICENSE" rel="noopener noreferrer"&gt;MIT License&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;To most people the problem with travel management might not seem that hard to solve. But upon searching we found that there's very limited applications available on the market that provides a minimalist UI and also gets the job done.&lt;/p&gt;

&lt;p&gt;The second reason behind building a travel management app was that I wanted to learn how to use Linode, and this seemed to me a very good usecase of Managed Database and Object Storage services provided by Linode.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;I have mainly used three services provided by Linode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.linode.com/products/shared" rel="noopener noreferrer"&gt;Shared CPU&lt;/a&gt;: I used a &lt;code&gt;Ubuntu 22.04&lt;/code&gt; shared compute instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.linode.com/products/databases" rel="noopener noreferrer"&gt;Managed Database&lt;/a&gt; (with &lt;code&gt;MySQL v8.0.26&lt;/code&gt;): For storing user data, location information and the trips planned by each user. I have also designed a robust email-password authentication system &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.linode.com/products/object-storage" rel="noopener noreferrer"&gt;Object storage&lt;/a&gt;: For storing the trip documents like flight bookings and hotel reservation files.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5o6rwj10s3rk6blq898u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5o6rwj10s3rk6blq898u.png" alt="Managed Database and Object Storage" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was my first time using Linode for managing the backend of a mobile application. And, the entire integration process was pretty smooth for me (some of the documentation pages helped a lot).&lt;/p&gt;

&lt;p&gt;This hackathon helped me to learn how to build a end-to-end product (consisting of a frontend, backend, and cloud server). Thanks to Linode &amp;amp; DEV team for organzing this hackathon! 🙂&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One suggestion of improvement: "&lt;em&gt;It would have been a lot faster while working with the Managed Database if there was a SQL viewer/editor inside the Linode Cloud Console (I spent a lot of time authenticating into the database locally and then running the SQL command to view the table data every time while testing the queries from the mobile app)&lt;/em&gt;"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;Some resources that helped while working on this project are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linode.com/docs/guides/flask-and-gunicorn-on-ubuntu" rel="noopener noreferrer"&gt;https://www.linode.com/docs/guides/flask-and-gunicorn-on-ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linode.com/docs/products/storage/object-storage/guides/aws-sdk-for-python" rel="noopener noreferrer"&gt;https://www.linode.com/docs/products/storage/object-storage/guides/aws-sdk-for-python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>workflow</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Slibro — a story writing platform</title>
      <dc:creator>Souvik Biswas</dc:creator>
      <pubDate>Thu, 12 May 2022 20:19:22 +0000</pubDate>
      <link>https://dev.to/sbis04/slibro-a-story-writing-platform-4oll</link>
      <guid>https://dev.to/sbis04/slibro-a-story-writing-platform-4oll</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Slibro&lt;/strong&gt; is a story writing platform that supports short and long format stories. &lt;a href="https://flutter.dev/" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; and &lt;a href="https://appwrite.io/" rel="noopener noreferrer"&gt;Appwrite&lt;/a&gt; is used to create this amazing cross-platform experience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Try out the app on Android from &lt;a href="https://appdistribution.firebase.dev/i/3fc14b5839069d3c" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo3ew6oqqtfbdo6hn0j5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo3ew6oqqtfbdo6hn0j5z.png" alt="Slibro cross-platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The inspiration behind this idea is to simplify the process of story writing, formatting, and publishing to reach a wider audience. Whether you just getting started with your first story or a seasoned writer, Slibro has got you covered!&lt;/p&gt;

&lt;h2&gt;
  
  
  Submission Category:
&lt;/h2&gt;

&lt;p&gt;Mobile Moguls&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;

&lt;p&gt;The app is completely open sourced, have a look around the code and also feel free to contribute to this project 😉 :&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sbis04" rel="noopener noreferrer"&gt;
        sbis04
      &lt;/a&gt; / &lt;a href="https://github.com/sbis04/slibro" rel="noopener noreferrer"&gt;
        slibro
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Platform for story writers and publishing houses
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Slibro &lt;a href="https://codemagic.io/apps/6240c24a66f743ede7aca591/android-workflow/latest_build" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a3ec5d2866a7b0cb290f22fa3a04e73749abddc01086a7b37957c25441d68ba9/68747470733a2f2f6170692e636f64656d616769632e696f2f617070732f3632343063323461363666373433656465376163613539312f616e64726f69642d776f726b666c6f772f7374617475735f62616467652e737667" alt="Codemagic build status"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/slibroscreenshots/slibro-dev-cover.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fslibroscreenshots%2Fslibro-dev-cover.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Slibro&lt;/strong&gt; is a story writing platform that supports short and long format stories. &lt;a href="https://flutter.dev/" rel="nofollow noopener noreferrer"&gt;Flutter&lt;/a&gt; and &lt;a href="https://appwrite.io/" rel="nofollow noopener noreferrer"&gt;Appwrite&lt;/a&gt; is used to create this amazing cross-platform experience.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Try out the app on Android from &lt;a href="https://appdistribution.firebase.dev/i/3fc14b5839069d3c" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/slibroscreenshots/slibro-cross-platform-2.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fslibroscreenshots%2Fslibro-cross-platform-2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;To run this from your system, you should have:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://docs.flutter.dev/get-started/install" rel="nofollow noopener noreferrer"&gt;Flutter SDK&lt;/a&gt; installed and configured on your system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup Appwrite using Docker.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Host the server locally using &lt;a href="https://ngrok.com/" rel="nofollow noopener noreferrer"&gt;ngrok&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;code&gt;lib&lt;/code&gt; directory, create a &lt;code&gt;secret.dart&lt;/code&gt; file, and add the server URL and Appwrite project ID to it. Example:&lt;/p&gt;
&lt;div class="highlight highlight-source-dart notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;class&lt;/span&gt; &lt;span class="pl-c1"&gt;Secrets&lt;/span&gt; {
  &lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-c1"&gt;String&lt;/span&gt; hostname &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;'https://127b-203-163-244-125.in.ngrok.io/v1'&lt;/span&gt;;
  &lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-c1"&gt;String&lt;/span&gt; projectID &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;'6276341092e81e829ab0'&lt;/span&gt;;
}&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run using the following command:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;flutter run&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;App Overview&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The app now has full-fledged &lt;strong&gt;story editor&lt;/strong&gt; (rich text - markdown), &lt;strong&gt;story reader&lt;/strong&gt;, and &lt;strong&gt;story management system&lt;/strong&gt; (to manage published/unpublished stories and explore other publisher's stories).&lt;/p&gt;
&lt;p&gt;Some glimpses of Slibro's user interface are as follows:&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/slibroscreenshots/slibro-auth-screens.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fslibroscreenshots%2Fslibro-auth-screens.png" alt="Slibro Auth Screens"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The above four screens cover the authentication…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sbis04/slibro" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How it started
&lt;/h2&gt;

&lt;p&gt;I initially started working on the idea of this app by creating rough UI sketches and notes ...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7jm56ooudtiifma431l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7jm56ooudtiifma431l.png" alt="Sketches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;... also some database structures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd6o9e8dibjrwdjwfsrg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd6o9e8dibjrwdjwfsrg.png" alt="Database Structures"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's going
&lt;/h2&gt;

&lt;p&gt;The app now has full-fledged &lt;strong&gt;story editor&lt;/strong&gt; (rich text - markdown), &lt;strong&gt;story reader&lt;/strong&gt;, and &lt;strong&gt;story management system&lt;/strong&gt; (to manage published/unpublished stories and explore other publisher's stories).&lt;/p&gt;

&lt;p&gt;Some glimpses of Slibro's user interface are as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckfpt2tqp4sggdstjk5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckfpt2tqp4sggdstjk5o.png" alt="Slibro Auth Screens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above four screens cover the authentication flow on the app using email/password method. These screens help a user to either create a new account or login using an existing account. Once a user signs up to the app, it navigates to the story creation flow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7625wndiuvazfpof1fv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7625wndiuvazfpof1fv.png" alt="Slibro Story Detail Screens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These screens help a user to create the first story as a draft in the Slibro app. The user can also publish the story if wanted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5nph9vo7wz31i5jrhxo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5nph9vo7wz31i5jrhxo.png" alt="Slibro Editor and Reader Screens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The editor and the reader screens are the most important ones, the editor also has rich text support using Markdown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpx0jkjubobvihpkr9fm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpx0jkjubobvihpkr9fm.png" alt="Slibro Dashboard Screens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The three screens (Home, My Stories, and My Profile) shown above are part of the dashboard of the app, user can navigate to any of these using the Navigation bar accessible from these pages.&lt;/p&gt;

&lt;p&gt;Navigation bar has a subtle animation to improve the UX of the app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9gfhrmw41fstc84ofd0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9gfhrmw41fstc84ofd0.gif" alt="Navigation bar animation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Description
&lt;/h2&gt;

&lt;p&gt;In this project, three of the major Appwrite APIs are used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://appwrite.io/docs/client/account?sdk=flutter-default" rel="noopener noreferrer"&gt;Account API&lt;/a&gt;: Used for implementing user authentication and user data management.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://appwrite.io/docs/client/database?sdk=flutter-default" rel="noopener noreferrer"&gt;Database API&lt;/a&gt;: Used for storing app data related to stories and chapters.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://appwrite.io/docs/client/storage?sdk=flutter-default" rel="noopener noreferrer"&gt;Storage API&lt;/a&gt;: Used for storing the Rich Text story file in JSON format.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Flutter plugins used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/appwrite" rel="noopener noreferrer"&gt;appwrite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/flutter_quill" rel="noopener noreferrer"&gt;flutter_quill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/path_provider" rel="noopener noreferrer"&gt;path_provider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/shared_preferences" rel="noopener noreferrer"&gt;shared_preferences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/google_nav_bar" rel="noopener noreferrer"&gt;google_nav_bar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/tuple" rel="noopener noreferrer"&gt;tuple&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Appwrite console view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fad3qe3pp5l8lqhtw5icy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fad3qe3pp5l8lqhtw5icy.png" alt="Appwrite console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two databases are used for this project: (1) stories, and (2) chapters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1dpqo8693s5f8by2yvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1dpqo8693s5f8by2yvs.png" alt="Appwrite database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stories database documents preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsgqkt7j8vxrodvz0ubf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsgqkt7j8vxrodvz0ubf.png" alt="Stories database"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stories database attributes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6e7o3u6vib5gop3wf15e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6e7o3u6vib5gop3wf15e.png" alt="Stories database attributes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chapters database attributes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4c5f1t0ii4qi4vlde7d1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4c5f1t0ii4qi4vlde7d1.png" alt="Chapters database attributes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The files storage preview (the chapters are stored as JSON rich text files):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vna78behcy1p3sjf7d0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vna78behcy1p3sjf7d0.png" alt="File storage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs" rel="noopener noreferrer"&gt;Appwrite Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/appwrite" rel="noopener noreferrer"&gt;Appwrite Flutter package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>appwritehack</category>
      <category>flutter</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Decifer — Generate transcripts from audio using Flutter and Deepgram</title>
      <dc:creator>Souvik Biswas</dc:creator>
      <pubDate>Sat, 02 Apr 2022 18:40:59 +0000</pubDate>
      <link>https://dev.to/sbis04/decifer-generate-transcripts-with-ease-5hl3</link>
      <guid>https://dev.to/sbis04/decifer-generate-transcripts-with-ease-5hl3</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Decifer&lt;/strong&gt; is a cross-platform mobile app that helps to generate transcripts either from a voice recording or by uploading an audio file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuisooun6gwsfa2kup79m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuisooun6gwsfa2kup79m.gif" alt="Transcription Playback"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Try out the app:&lt;/strong&gt; &lt;a href="https://play.google.com/store/apps/details?id=com.souvikbiswas.deepgram_transcribe" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.souvikbiswas.deepgram_transcribe&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typically, for using Deepgram API you would require to maintain a server but I have made this project totally &lt;strong&gt;serverless&lt;/strong&gt;. To know more continue reading.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's a brief demo of the entire app in action:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CqRzNNgeQOE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Submission Category:
&lt;/h2&gt;

&lt;p&gt;Analytics Ambassadors&lt;/p&gt;

&lt;h2&gt;
  
  
  Link to Code on GitHub
&lt;/h2&gt;

&lt;p&gt;The entire app is open sourced - try it out and also feel free to contribute to this project 😉 :&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sbis04" rel="noopener noreferrer"&gt;
        sbis04
      &lt;/a&gt; / &lt;a href="https://github.com/sbis04/decifer" rel="noopener noreferrer"&gt;
        decifer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Generate your audio transcripts with ease.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Decifer &lt;a href="https://codemagic.io/apps/6240c24a66f743ede7aca591/android-workflow/latest_build" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a3ec5d2866a7b0cb290f22fa3a04e73749abddc01086a7b37957c25441d68ba9/68747470733a2f2f6170692e636f64656d616769632e696f2f617070732f3632343063323461363666373433656465376163613539312f616e64726f69642d776f726b666c6f772f7374617475735f62616467652e737667" alt="Codemagic build status"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/deciferscreenshots/decifer_feature_graphic.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fdeciferscreenshots%2Fdecifer_feature_graphic.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Blog post about this project: &lt;a href="https://dev.to/sbis04/decifer-generate-transcripts-with-ease-5hl3" rel="nofollow"&gt;https://dev.to/sbis04/decifer-generate-transcripts-with-ease-5hl3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Try out the app: &lt;a href="https://appdistribution.firebase.dev/i/a57e37b2fda28351" rel="nofollow noopener noreferrer"&gt;https://appdistribution.firebase.dev/i/a57e37b2fda28351&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A cross-platform mobile app that helps you to generate transcripts either from a voice recording or by uploading an audio file. The project uses a totally serverless architecture.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/deciferscreenshots/transcipt_playback.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fdeciferscreenshots%2Ftranscipt_playback.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The mobile app is created using &lt;a href="https://flutter.dev/" rel="nofollow noopener noreferrer"&gt;Flutter&lt;/a&gt; which is integrated with &lt;a href="https://firebase.google.com/" rel="nofollow noopener noreferrer"&gt;Firebase&lt;/a&gt;. Firebase &lt;strong&gt;Cloud Functions&lt;/strong&gt; is used to deploy the backend code required for communicating with the Deepgram API.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/sbis04/deciferscreenshots/decifer_architecture.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fsbis04%2Fdeciferscreenshots%2Fdecifer_architecture.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;App overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The Flutter application consists of the following pages/screens:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Login Page&lt;/li&gt;
&lt;li&gt;Register Page&lt;/li&gt;
&lt;li&gt;Dashboard Page&lt;/li&gt;
&lt;li&gt;Record Page&lt;/li&gt;
&lt;li&gt;Upload Page&lt;/li&gt;
&lt;li&gt;Transcription Page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For authenticating the user inside the app -- &lt;strong&gt;Login&lt;/strong&gt; and &lt;strong&gt;Register&lt;/strong&gt; pages are used. Authentication is required to generate unique accounts for users required for storing the generated transcripts to &lt;a href="https://firebase.google.com/docs/firestore" rel="nofollow noopener noreferrer"&gt;Firestore&lt;/a&gt; and facilitate &lt;strong&gt;cloud-sync&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b9c7a276c5d2f80ce141026da3a16d6b849ecad6580c2a6548c8b4666c1d7d2b/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f37686c7a6e626366346e6c6838696564767433792e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/b9c7a276c5d2f80ce141026da3a16d6b849ecad6580c2a6548c8b4666c1d7d2b/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f37686c7a6e626366346e6c6838696564767433792e706e67" alt="Register Page"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Dashboard Page&lt;/strong&gt; displays a list of all the transcripts currently present on the user's account. It also has two buttons -…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sbis04/decifer" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Project Description
&lt;/h2&gt;

&lt;p&gt;The primary features of the app are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate transcript from audio recording &amp;amp; audio file using &lt;a href="https://deepgram.com/" rel="noopener noreferrer"&gt;Deepgram API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Cloud-sync for syncing across multiple devices using the same account.&lt;/li&gt;
&lt;li&gt;Transcribe confidence map view.&lt;/li&gt;
&lt;li&gt;Export as PDF and share with anyone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;I'm using a totally &lt;strong&gt;serverless&lt;/strong&gt; architecture for this project 🤯, let's have a look how it works:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47ixtw35g4ii66pav9z0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F47ixtw35g4ii66pav9z0.png" alt="Decifer architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The mobile app is created using &lt;a href="https://flutter.dev/" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; which is integrated with &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt;. I have used Firebase &lt;strong&gt;Cloud Functions&lt;/strong&gt; to deploy the backend code required for communicating with the Deepgram API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://firebase.google.com/docs/functions" rel="noopener noreferrer"&gt;Firebase Cloud Functions&lt;/a&gt; lets you run backend code in a severless architecture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have deployed the following function to Firebase:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Deepgram&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@deepgram/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTranscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deepgram&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Deepgram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEEPGRAM_API_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;audioSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;deepgram&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transcription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preRecorded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;punctuate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;utterances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utterances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;confidenceList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utterances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;confidenceList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utterances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;webvttTranscript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toWebVTT&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalTranscript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;webvttTranscript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;confidences&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;confidenceList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalTranscriptJSON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalTranscript&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalTranscriptJSON&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;finalTranscriptJSON&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unable to transcribe. Error &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpsError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aborted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Could not transcribe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;getTranscription&lt;/code&gt; function takes an audio URL, generates the transcripts using Deepgram API along with the respective confidences, and returns the data in a particular JSON format (that can be parsed within the app).&lt;/p&gt;

&lt;h3&gt;
  
  
  App screens
&lt;/h3&gt;

&lt;p&gt;The Flutter application consists of the following pages/screens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login Page&lt;/li&gt;
&lt;li&gt;Register Page&lt;/li&gt;
&lt;li&gt;Dashboard Page&lt;/li&gt;
&lt;li&gt;Record Page&lt;/li&gt;
&lt;li&gt;Upload Page&lt;/li&gt;
&lt;li&gt;Transcription Page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For authenticating the user inside the app -- &lt;strong&gt;Login&lt;/strong&gt; and &lt;strong&gt;Register&lt;/strong&gt; pages are used. Authentication is required to generate unique accounts for users required for storing the generated transcripts to &lt;a href="https://firebase.google.com/docs/firestore" rel="noopener noreferrer"&gt;Firestore&lt;/a&gt; and facilitate &lt;strong&gt;cloud-sync&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hlznbcf4nlh8iedvt3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7hlznbcf4nlh8iedvt3y.png" alt="Register Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Dashboard Page&lt;/strong&gt; displays a list of all the transcripts currently present on the user's account. It also has two buttons - one for navigating to the Record Page and the other for navigating to the Upload Page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xclqk0cpqpgfsd8506q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xclqk0cpqpgfsd8506q.png" alt="Dashboard Page"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Record Page&lt;/strong&gt; lets you record your audio using the device microphone and the transcribe it using Deepgram. You always have an option to re-record if you think the last recording wasn't good.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr52ejg10bpyozilhzmnu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr52ejg10bpyozilhzmnu.png" alt="Record Page"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;From the &lt;strong&gt;Upload Page&lt;/strong&gt;, you can choose any audio file present on your device and generate the transcript of it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbv2c96vg4kmga247jlr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbv2c96vg4kmga247jlr.png" alt="Upload Page"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transcription Page&lt;/strong&gt; is where the entire transcript can be viewed. It has an audio-transcript synchronized playback that highlights the text transcript part with respect to the audio that is playing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv96ekvfjm6hmx3muovud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv96ekvfjm6hmx3muovud.png" alt="Transcription Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also see the &lt;strong&gt;confidence map&lt;/strong&gt; of each of the parts of the transcript (it shows how much accurate is that part of transcript generation - &lt;em&gt;darker is higher confidence&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3m6ge6g885ia335neqv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3m6ge6g885ia335neqv.gif" alt="Confidence Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also easily print or share the generated transcript in the &lt;strong&gt;PDF&lt;/strong&gt; format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mep5k5adqafkvfqx5bb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mep5k5adqafkvfqx5bb.gif" alt="Export transcript"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deepgram
&lt;/h3&gt;

&lt;p&gt;Overview of my Deepgram dashboard (completed the mission, &lt;em&gt;Get a Transcript via API or SDK&lt;/em&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq5dznvzbgy1c8b4ktmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq5dznvzbgy1c8b4ktmz.png" alt="Deepgram Overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usage analytics of the Deepgram API:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fun52yb4q3qqtog1qw9vr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fun52yb4q3qqtog1qw9vr.png" alt="Deepgram Usage Analytics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Log of one of the API calls for transcribing from audio:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsutvli9mtuzne9u5ofdy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsutvli9mtuzne9u5ofdy.png" alt="Deepgram Logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.deepgram.com/api-reference/" rel="noopener noreferrer"&gt;Deepgram API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.flutter.dev/docs/auth/overview/" rel="noopener noreferrer"&gt;Firebase Authentication Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.flutter.dev/docs/firestore/overview" rel="noopener noreferrer"&gt;Firestore Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.flutter.dev/docs/functions/overview" rel="noopener noreferrer"&gt;Cloud Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hackwithdg</category>
      <category>flutter</category>
      <category>deepgram</category>
    </item>
    <item>
      <title>Plant Monitor - Using IoT, MongoDB and Flutter</title>
      <dc:creator>Souvik Biswas</dc:creator>
      <pubDate>Wed, 12 Jan 2022 17:58:56 +0000</pubDate>
      <link>https://dev.to/sbis04/plant-monitor-mongodb-atlas-hackathon-submission-34j0</link>
      <guid>https://dev.to/sbis04/plant-monitor-mongodb-atlas-hackathon-submission-34j0</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/vGCJaMlH0_A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Plant Monitor&lt;/strong&gt; is an IoT-based project for monitoring plant health with ease. The projects consists of three parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
IoT: Sensors (for monitoring plant data)&lt;/li&gt;
&lt;li&gt;
Database: MongoDB (Atlas, Realm and Chart)&lt;/li&gt;
&lt;li&gt;
Cross platform mobile app: Flutter (for getting realtime plant data)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Action Star&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;

&lt;p&gt;The code for both the app and the IoT part is present in the following GitHub repo:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sbis04" rel="noopener noreferrer"&gt;
        sbis04
      &lt;/a&gt; / &lt;a href="https://github.com/sbis04/plant-monitor" rel="noopener noreferrer"&gt;
        plant-monitor
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Plant monitoring system using IoT, MongoDB, and Flutter
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Plant Monitor&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;IoT based plant monitoring system which is connected to MongoDB. This is a Flutter app to display the realtime data from the sensors attached to the plant on a mobile device.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;License&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Copyright 2022 Souvik Biswas&lt;/p&gt;
&lt;p&gt;Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;http://www.apache.org/licenses/LICENSE-2.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sbis04/plant-monitor" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Project Description
&lt;/h2&gt;

&lt;p&gt;A detailed description of all the three parts of this project is present below.&lt;/p&gt;

&lt;h3&gt;
  
  
  IoT: Sensors
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0tzyl4ae1m6hmjx2fpni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0tzyl4ae1m6hmjx2fpni.png" alt="Hardware sensors"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ESP32&lt;/strong&gt; module is used for collecting data, processing and uploading to the MongoDB database. It is a low powered microcontroller integrated with WiFi and Bluetooth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DHT11&lt;/strong&gt; sensor is used for measuring raw temperate and humidity data from the surroundings of the plant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LDR&lt;/strong&gt; is used for calculating the light intensity that the plant is receiving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Soil Moisture&lt;/strong&gt; sensor module is used to measure the moisture or the water level of the soil. The sensor includes a potentiometer to set the desired moisture threshold.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database: MongoDB
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftils8x032t1dbq4wvhe0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftils8x032t1dbq4wvhe0.png" alt="MongoDB Atlas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MongoDB Atlas provides cloud database service using AWS, Azure, and Google Cloud. It also has various automation tools for performing various backend functionalities and comes with visualization tools. The services that are used in this project are described below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atlas&lt;/strong&gt; is used as the main cloud database for storing the sensor readings along with timestamps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmlkn99o13e8sds51kk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffmlkn99o13e8sds51kk7.png" alt="Atlas"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Realm Function&lt;/strong&gt; is defined to easily store the sensor data from the ESP32 module. A &lt;strong&gt;HTTP Endpoint&lt;/strong&gt; is created to access the MongoDB database from the ESP32.&lt;/p&gt;

&lt;p&gt;The following function is used for storing the sensor data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;atlas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongodb-atlas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;coll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;atlas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plantdata&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;readings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;EJSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;coll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error inserting doc: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Charts&lt;/strong&gt; are used to visualize the sensor readings directly inside the MongoDB web app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5da2rb8bgepbk9jfa1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5da2rb8bgepbk9jfa1j.png" alt="Charts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this project I have created four charts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plant Light&lt;/strong&gt; (%): Amount of light intensity plant is receiving&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plant Humidity&lt;/strong&gt; (%): Humidity around the plant&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plant Moisture&lt;/strong&gt; (%): Amount of water present in the soil &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plant Temperature&lt;/strong&gt; (°C): Current temperature around the plant&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mobile app: Flutter
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31ynnfmul2dvjoq6mrc8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31ynnfmul2dvjoq6mrc8.png" alt="Flutter app"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;To use the Realm data inside the Flutter application I have created a modified version of the &lt;a href="https://pub.dev/packages/flutter_mongodb_realm/versions/2.0.0-nullsafety.0" rel="noopener noreferrer"&gt;flutter_mongodb_realm&lt;/a&gt; plugin to support Dart null safety and run it on the latest version of the Flutter SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.atlas.mongodb.com/getting-started/" rel="noopener noreferrer"&gt;MongoDB Atlas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/realm/" rel="noopener noreferrer"&gt;MongoDB Realm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/charts/" rel="noopener noreferrer"&gt;MongoDB Charts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.mongodb.com/realm/endpoints" rel="noopener noreferrer"&gt;Realm HTTPS Endpoints&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pub.dev/packages/flutter_mongodb_realm/versions/2.0.0-nullsafety.0" rel="noopener noreferrer"&gt;flutter_mongodb_realm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html" rel="noopener noreferrer"&gt;ESP32 Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>atlashackathon</category>
      <category>flutter</category>
      <category>iot</category>
      <category>esp32</category>
    </item>
    <item>
      <title>Flutter: Custom Painter | PART-1</title>
      <dc:creator>Souvik Biswas</dc:creator>
      <pubDate>Thu, 23 Apr 2020 10:30:07 +0000</pubDate>
      <link>https://dev.to/sbis04/flutter-custom-painter-part-1-j4m</link>
      <guid>https://dev.to/sbis04/flutter-custom-painter-part-1-j4m</guid>
      <description>&lt;p&gt;You might have seen a lot of apps having highly customized designs and amazing animations. It is really time-consuming and painful to achieve that level of customization on a native &lt;strong&gt;Android&lt;/strong&gt; and &lt;strong&gt;iOS&lt;/strong&gt; apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flutter&lt;/strong&gt; has got your back. With the help of &lt;code&gt;CustomPainter&lt;/code&gt; combined with the legendary &lt;strong&gt;Hot Reload&lt;/strong&gt; feature of Flutter you can iterate upon your creations efficiently and fast.&lt;/p&gt;

&lt;p&gt;In this series, I will start with the basics of painting using &lt;code&gt;CustomPainter&lt;/code&gt; (drawing basic shapes) in the first few parts, and then I will go into the complex designs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The series will involve some basic concepts of mathematics (mainly Trigonometry and Coordinate Geometry).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial App Structure
&lt;/h2&gt;

&lt;p&gt;The basic structure of the app will just consist of a &lt;code&gt;Scaffold&lt;/code&gt; having an &lt;code&gt;AppBar&lt;/code&gt;, and a &lt;code&gt;CustomPaint&lt;/code&gt; widget in the &lt;strong&gt;body&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyPainter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Custom Painter'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;CustomPaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;painter:&lt;/span&gt; &lt;span class="n"&gt;ShapePainter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CustomPaint Widget Properties
&lt;/h2&gt;

&lt;p&gt;Some of the most important properties of the &lt;code&gt;CustomPaint&lt;/code&gt; widget are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;painter&lt;/strong&gt;: The painter that paints before the child.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;foregroundPainter&lt;/strong&gt;: The painter that paints after the child.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;child&lt;/strong&gt;: The canvas will by default take the size of the child, if it is defined.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;size&lt;/strong&gt;: If the child is not defined, then the size of the canvas should be specified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For getting started with the basic shapes, you will just need two of these properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;painter&lt;/li&gt;
&lt;li&gt;child&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the previous code snippet, I have defined a &lt;code&gt;Container&lt;/code&gt; as the &lt;strong&gt;child&lt;/strong&gt;. As you might know, &lt;code&gt;Container&lt;/code&gt; by default takes up the entire size of the screen when there is no child specified within it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro to CustomPainter
&lt;/h2&gt;

&lt;p&gt;Now, you have to define the &lt;strong&gt;ShapePainter&lt;/strong&gt; widget which should extend the &lt;strong&gt;&lt;a href="https://api.flutter.dev/flutter/rendering/CustomPainter-class.html" rel="noopener noreferrer"&gt;CustomPainter&lt;/a&gt;&lt;/strong&gt; class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;paint&lt;/strong&gt;: This method is called whenever the object needs to be repainted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;shouldRepaint&lt;/strong&gt;: This method is called when a new instance of the class is provided.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShapePainter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Canvas&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Size&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: implement paint&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;shouldRepaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomPainter&lt;/span&gt; &lt;span class="n"&gt;oldDelegate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: implement shouldRepaint&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deep dive into paint method
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;paint&lt;/code&gt; method has two parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;canvas&lt;/li&gt;
&lt;li&gt;size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we have a child specified inside the &lt;strong&gt;CustomPaint&lt;/strong&gt; widget, then the canvas will have the same size as that. In our case, the &lt;strong&gt;canvas&lt;/strong&gt; area will take the size of the entire Container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Canvas Area&lt;/strong&gt; uses a coordinate system in order to located positions and they can be connected in various fashion in order to generate different custom shapes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiznsm0q3ts8xyczquq66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiznsm0q3ts8xyczquq66.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, the &lt;strong&gt;origin (0, 0)&lt;/strong&gt; is located at the top-left corner of the canvas, and with respect to it all the drawings are done as the &lt;strong&gt;painter&lt;/strong&gt; starts from the origin.&lt;/p&gt;

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

&lt;p&gt;I believe you have enjoyed this first part of the series which should have given you a good insight into the small concepts of &lt;code&gt;CustomPainter&lt;/code&gt; and the &lt;strong&gt;Canvas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;From the next article onwards, we will start painting on this canvas. And trust me you will love &lt;strong&gt;Flutter&lt;/strong&gt; for this.&lt;/p&gt;




&lt;p&gt;I also write articles on &lt;a href="https://medium.com/@sbis1999" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; and &lt;a href="https://blog.codemagic.io/" rel="noopener noreferrer"&gt;Codemagic Blog&lt;/a&gt;. You can follow me on &lt;a href="https://twitter.com/sbis04" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and find some of my projects on &lt;a href="https://github.com/sbis04" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Also, don’t forget to check out my &lt;a href="https://www.souvikbiswas.com" rel="noopener noreferrer"&gt;website&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>painter</category>
      <category>dart</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
