<?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: anoop p</title>
    <description>The latest articles on DEV Community by anoop p (@anoop_p_22f715057ac8b3901).</description>
    <link>https://dev.to/anoop_p_22f715057ac8b3901</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%2F2595876%2Fa1bf0c1b-a8c8-4700-9678-839660451a53.png</url>
      <title>DEV Community: anoop p</title>
      <link>https://dev.to/anoop_p_22f715057ac8b3901</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anoop_p_22f715057ac8b3901"/>
    <language>en</language>
    <item>
      <title>What I Shipped This Month Building Invoiso (v3.4.2)</title>
      <dc:creator>anoop p</dc:creator>
      <pubDate>Tue, 31 Mar 2026 13:50:27 +0000</pubDate>
      <link>https://dev.to/anoop_p_22f715057ac8b3901/what-i-shipped-this-month-building-invoiso-v342-31he</link>
      <guid>https://dev.to/anoop_p_22f715057ac8b3901/what-i-shipped-this-month-building-invoiso-v342-31he</guid>
      <description>&lt;p&gt;One of the best things about working on &lt;strong&gt;Invoiso&lt;/strong&gt;, a free offline invoice and billing tool available for Windows and Linux operating systems, has been “building in public.” This month has been particularly fruitful as a mix of long-pending features, quality-of-life enhancements, and critical bug fixes were included.&lt;/p&gt;

&lt;h3&gt;
  
  
  All Changes in &lt;strong&gt;v3.4.2&lt;/strong&gt; 👇
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a href="https://github.com/Anooppandikashala/invoiso" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://anooppandikashala.github.io/invoisoapp/" rel="noopener noreferrer"&gt;Website&lt;/a&gt; · &lt;a href="https://anooppandikashala.github.io/invoisoapp/download.html" rel="noopener noreferrer"&gt;Download&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  💡 The Focus This Month
&lt;/h3&gt;

&lt;p&gt;This release is all about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More flexibility&lt;/strong&gt; in invoicing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better real-world usage&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smoother payments and workflows&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🌍 Multi-Currency Support
&lt;/h3&gt;

&lt;p&gt;One of the most requested features is finally here.&lt;/p&gt;

&lt;p&gt;Create invoices in different currencies:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;INR · USD · EUR · GBP · JPY · AED · SGD · AUD · CAD · JMD&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Each invoice &lt;strong&gt;locks in the currency at creation time&lt;/strong&gt;, maintaining historical data’s accuracy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is multi-currency support important?&lt;/strong&gt;&lt;br&gt;
If you work with clients across borders, you know how annoying currency conversions can be.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧾 Per Item Tax Rates
&lt;/h3&gt;

&lt;p&gt;Tax rate is now set per item.&lt;/p&gt;

&lt;p&gt;Tax rate is no longer set at the invoice level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is per item tax rate useful?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mixed GST items&lt;/li&gt;
&lt;li&gt;Different tax rates for different service/product types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes things more similar to real-world usage.&lt;/p&gt;




&lt;h3&gt;
  
  
  💸 UPI QR Code on Invoices
&lt;/h3&gt;

&lt;p&gt;A significant feature update for users in India.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter your UPI ID in settings&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;QR code is automatically added&lt;/strong&gt; on every invoice you create in PDF format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clients can also scan and pay instantly using GPay, PhonePe, or Paytm. There is no need to type anything or get confused.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔁 Invoice Cloning
&lt;/h3&gt;

&lt;p&gt;Creating similar invoices was a tedious task. This feature lets you clone an invoice and use it as a starting point.&lt;/p&gt;

&lt;p&gt;A small feature, a big time saver.&lt;/p&gt;




&lt;h3&gt;
  
  
  📦 Bulk Actions
&lt;/h3&gt;

&lt;p&gt;You can select multiple invoices and perform actions on them in bulk.&lt;/p&gt;

&lt;p&gt;More efficiency, less clicks.&lt;/p&gt;




&lt;h3&gt;
  
  
  💳 Payment Tracking &amp;amp; Receipts
&lt;/h3&gt;

&lt;p&gt;This was a big feature.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mark invoices as &lt;strong&gt;Paid / Partially Paid / Unpaid&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Track payment history&lt;/li&gt;
&lt;li&gt;Generate downloadable &lt;strong&gt;PDF payment receipts&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This feature alone makes Invoiso not just an invoice generator, but a basic invoicing system.&lt;/p&gt;




&lt;h3&gt;
  
  
  🔐 Role-Based Access Control (RBAC)
&lt;/h3&gt;

&lt;p&gt;This feature is for those who work in teams.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set admin and user roles&lt;/li&gt;
&lt;li&gt;Set access level for each user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This feature will pave the way for more user-based features.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧭 Invoice Type Indicator
&lt;/h3&gt;

&lt;p&gt;The invoice type is also visible on the invoice list and dashboard. There is no need to click on an invoice to know its type.&lt;/p&gt;

&lt;p&gt;A small feature, a big time saver.&lt;/p&gt;




&lt;h3&gt;
  
  
  🖥️ Ubuntu 24.04 LTS Support
&lt;/h3&gt;

&lt;p&gt;Linux users, rejoice! Builds are tested and working on &lt;strong&gt;Ubuntu 24.04 LTS&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  🎨 UI/UX Improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Redesigned: PDF Settings, Company Info, and Software Info screens&lt;/li&gt;
&lt;li&gt;Fixed: annoying bug where search fields lost focus on fast typing&lt;/li&gt;
&lt;li&gt;&lt;p&gt;General layout and visual polish on screens&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixed ₹ symbol rendering incorrectly in generated PDFs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixed database connection dropping after backup restore&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixed window resizing issues on Linux&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Updated Windows app icon (all sizes: 16, 32, 48, 256px)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  📊 What I Learned
&lt;/h3&gt;

&lt;p&gt;Some observations and insights from this release cycle:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small UX issues matter more than missing features.&lt;/strong&gt;&lt;br&gt;
The search field focus bug was reported most. More than any missing feature. Fixing UX issues is important.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payments are core, not optional.&lt;/strong&gt;&lt;br&gt;
Tracking and receipts are a big part of any payment process. This is a game-changer for the product. Should have done this earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speed of iteration &amp;gt; perfection.&lt;/strong&gt;&lt;br&gt;
Shipping is important. Consistency is key. Will improve and iterate soon. &lt;/p&gt;




&lt;h3&gt;
  
  
  🔮 What's Next?
&lt;/h3&gt;

&lt;p&gt;Exploring next for Invoiso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improving &lt;strong&gt;reporting &amp;amp; analytics&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Improving &lt;strong&gt;payment workflows&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Improving &lt;strong&gt;invoice customization options&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🙌 Feedback Welcome
&lt;/h3&gt;

&lt;p&gt;If you have tried Invoiso or have any thoughts on it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How are you using Invoiso?&lt;/li&gt;
&lt;li&gt;What is missing?&lt;/li&gt;
&lt;li&gt;What is clunky?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add a comment below or open an issue on &lt;a href="https://github.com/Anooppandikashala/invoiso/issues" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. I read all of them.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Invoiso is free, open source, and runs entirely offline. No account required. No data leaves your device.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Thanks for reading! More updates soon! 🚀&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>buildinpublic</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I built a free Android soundboard that works with a External keyboard</title>
      <dc:creator>anoop p</dc:creator>
      <pubDate>Wed, 25 Mar 2026 11:29:40 +0000</pubDate>
      <link>https://dev.to/anoop_p_22f715057ac8b3901/i-built-a-free-android-soundboard-that-works-with-a-external-keyboard-25fi</link>
      <guid>https://dev.to/anoop_p_22f715057ac8b3901/i-built-a-free-android-soundboard-that-works-with-a-external-keyboard-25fi</guid>
      <description>&lt;p&gt;A few months ago I needed a simple soundboard for a live session. I wanted to trigger audio clips from a Bluetooth/External keyboard connected to my Android phone - just press a key, hear the sound, instantly.&lt;/p&gt;

&lt;p&gt;Every app I found was either subscription-based, required an account, or didn't support physical keyboards at all. So I built &lt;strong&gt;CTunes&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  What CTunes does
&lt;/h3&gt;

&lt;p&gt;CTunes maps keyboard keys (A-Z and 0-9) to audio files on your device. Tap the on-screen button or press the physical key — the sound plays immediately.&lt;/p&gt;

&lt;p&gt;That's the whole pitch. &lt;strong&gt;36 keys. Any audio file. Zero lag.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Try it
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.anoop.myprojects.ctunes" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Play:&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anooppandikashala.github.io/ctunes.app/" rel="noopener noreferrer"&gt;&lt;strong&gt;Landing page:&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love feedback — especially from anyone who uses soundboards for live performance, streaming, or teaching. What features would make this more useful for your workflow?&lt;/p&gt;

&lt;h4&gt;
  
  
  Core features
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key mapping&lt;/strong&gt; — pick any audio file from your device and assign it to a key
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual input&lt;/strong&gt; — works with on-screen taps and physical Bluetooth keyboards
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;18-color palette&lt;/strong&gt; — each key gets a unique color so you can read the board at a glance
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Import / Export&lt;/strong&gt; — your entire layout serialises to a single JSON file
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent storage&lt;/strong&gt; — mappings survive reboots and reinstalls via SQLite + &lt;code&gt;takePersistableUriPermission()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt; — ad-supported, no subscription, no sign-in, works fully offline
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  The tech stack
&lt;/h3&gt;

&lt;p&gt;CTunes is a native Android app written in &lt;strong&gt;Java&lt;/strong&gt; (yes, Java — not Kotlin). Here's how the main pieces fit together:&lt;/p&gt;

&lt;h4&gt;
  
  
  Architecture
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Single-module project, Activities only
&lt;/li&gt;
&lt;li&gt;No Fragments, no Navigation component
&lt;/li&gt;
&lt;li&gt;SQLite via a hand-rolled &lt;code&gt;SQLiteOpenHelper&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SharedPreferences&lt;/code&gt; for UI settings (grid size, column count, keyboard visibility)
&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Audio playback
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
java
// A new MediaPlayer is created per keypress
// The previous one is released first to avoid leaks
if (currentPlayer != null) {
    currentPlayer.release();
}
MediaPlayer mp = MediaPlayer.create(this, uri);
if (mp != null) {
    mp.setOnCompletionListener(MediaPlayer::release);
    mp.start();
    currentPlayer = mp;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>android</category>
      <category>showdev</category>
      <category>music</category>
      <category>soundboard</category>
    </item>
    <item>
      <title>I Built an Android App Because Android Kept Deleting My Clipboard</title>
      <dc:creator>anoop p</dc:creator>
      <pubDate>Thu, 19 Mar 2026 04:52:06 +0000</pubDate>
      <link>https://dev.to/anoop_p_22f715057ac8b3901/i-built-an-android-app-because-android-kept-deleting-my-clipboard-39o2</link>
      <guid>https://dev.to/anoop_p_22f715057ac8b3901/i-built-an-android-app-because-android-kept-deleting-my-clipboard-39o2</guid>
      <description>&lt;p&gt;Here's something that has happened to all of us.&lt;/p&gt;

&lt;p&gt;You copy a link. Then you copy someone's phone number. You go to paste the link - and it's gone. Replaced by the phone number. Android only remembers the last thing you copied. That's it. One item. Always.&lt;/p&gt;

&lt;p&gt;I kept running into this. Copying a piece of text, copying something else on top of it, then needing the first thing back with no way to get it. I'd go back to the original source, find it again, copy it again. Every time. It was a small annoyance, but it happened constantly.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://anooppandikashala.github.io/copyduo.app/" rel="noopener noreferrer"&gt;&lt;strong&gt;CopyDuo&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What CopyDuo Does
&lt;/h2&gt;

&lt;p&gt;CopyDuo runs quietly in the background and saves everything you copy - up to 50 items. Whenever you need something you copied earlier, you open the app, find it in the list, and tap it to copy it back to your clipboard.&lt;/p&gt;

&lt;p&gt;That's it. No accounts. No cloud. No internet connection. Your clipboard history stays on your device, private and instant.&lt;/p&gt;

&lt;p&gt;It also handles something I found genuinely annoying about other clipboard apps: duplicates. If you copy the same text twice, CopyDuo stores it only once. Your history stays clean.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Problem Is Harder to Solve Than It Looks
&lt;/h2&gt;

&lt;p&gt;When I started building this, I thought it would be straightforward - just listen for clipboard changes and save them to a local database. Simple, right?&lt;/p&gt;

&lt;p&gt;Not quite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android 12 Made Background Services Much Harder
&lt;/h3&gt;

&lt;p&gt;To capture clipboard items when the app isn't open, I needed a background service - a piece of code that keeps running even when you're not actively using the app. On older Android versions, this was manageable.&lt;/p&gt;

&lt;p&gt;On Android 12 and above, Google introduced strict restrictions on background services. Apps can no longer just run freely in the background. There are limits on when a service can start, and if you don't handle it correctly, the system kills your service entirely - meaning you miss clipboard items.&lt;/p&gt;

&lt;p&gt;Getting this right took significant work. CopyDuo uses a &lt;strong&gt;foreground service&lt;/strong&gt; (the kind Android officially supports for long-running tasks) with a persistent notification. This keeps the service alive reliably without fighting the system - and without draining your battery.&lt;/p&gt;

&lt;h3&gt;
  
  
  On New Devices, Apps Can't Read Your Clipboard in the Background
&lt;/h3&gt;

&lt;p&gt;This one genuinely surprised me.&lt;/p&gt;

&lt;p&gt;Starting with Android 10, Google added a privacy restriction: apps can only read clipboard data when they are &lt;strong&gt;actively in use&lt;/strong&gt; - meaning they're the foreground app the user is currently interacting with. A background service can't silently read your clipboard anymore.&lt;/p&gt;

&lt;p&gt;This is actually a good privacy decision. You don't want random apps reading everything you copy in the background. But it created a real problem for a clipboard manager.&lt;/p&gt;

&lt;p&gt;I had to find another way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt; a button in the notification panel.&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%2Fovwd8tepeaoccgojwmeh.jpeg" 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%2Fovwd8tepeaoccgojwmeh.jpeg" alt="Notification Panel" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When CopyDuo is running, it shows a persistent notification. That notification has a &lt;strong&gt;"SAVE TEXT"&lt;/strong&gt; button. When you tap it, the app briefly comes to the foreground, reads your current clipboard content, saves it, and steps back. It's a one-tap action that takes less than a second.&lt;/p&gt;

&lt;p&gt;It's not the invisible magic I originally wanted, but it works reliably on every Android version - including the latest ones - without any workarounds that could break with future updates.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;Your day-to-day usage looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You copy something → CopyDuo saves it automatically (on older devices) or you tap the notification button (on newer devices)&lt;/li&gt;
&lt;li&gt;You copy something else on top of it → no problem, both are saved&lt;/li&gt;
&lt;li&gt;Ten minutes later you need the first thing → open CopyDuo, tap it, done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list shows your most recent 50 items. You can delete individual ones or clear everything at once.&lt;/p&gt;




&lt;h2&gt;
  
  
  Another Way to Save: the Text Selection Menu
&lt;/h2&gt;

&lt;p&gt;While working around the Android 10+ clipboard restriction, I found another clean solution that fits even more naturally into how people actually use their phones.&lt;/p&gt;

&lt;p&gt;When you long-press any text in any app — a browser, a PDF reader, a messaging app — Android shows a floating toolbar with options like Copy, Cut, and Share. CopyDuo adds its own button to that menu: &lt;strong&gt;"Save to CopyDuo"&lt;/strong&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%2Fd6bq16hlnua5vm5u284h.webp" 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%2Fd6bq16hlnua5vm5u284h.webp" alt="Save to Copyduo" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select any text → tap Save to CopyDuo → it's in your history. No need to copy first. No need to open the notification. No steps in between.&lt;/p&gt;

&lt;p&gt;This works everywhere Android shows the text selection menu. Reading an article and want to save a quote? Select it, tap Save to CopyDuo. Found a useful command in a tutorial? Same flow.&lt;/p&gt;

&lt;p&gt;Between the notification button and the text selection action, CopyDuo covers every scenario — whether you're copy-pasting quickly or deliberately saving something you just read.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Kept It Offline
&lt;/h2&gt;

&lt;p&gt;A lot of productivity apps want your data in the cloud. Sync across devices, access from anywhere - it sounds convenient.&lt;/p&gt;

&lt;p&gt;But your clipboard is where passwords live. Phone numbers. Bank account details. Private messages. One-time codes. The idea of that data leaving your device and sitting on someone's server made me uncomfortable - and I figured it would make you uncomfortable too.&lt;/p&gt;

&lt;p&gt;CopyDuo has &lt;strong&gt;no internet permission&lt;/strong&gt;. It physically cannot send your data anywhere. Everything is stored locally using a lightweight on-device database, and it never leaves your phone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Download CopyDuo
&lt;/h2&gt;

&lt;p&gt;It's free on the Google Play Store.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.anoop.myprojects.copyduo" rel="noopener noreferrer"&gt;&lt;strong&gt;Get CopyDuo on Google Play →&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Works on Android 8.0 and above. No account required. No subscription.&lt;/p&gt;




&lt;p&gt;If you've ever lost something you copied, give it a try. It solves exactly one problem - but it solves it well.&lt;/p&gt;

</description>
      <category>android</category>
      <category>productivity</category>
      <category>appdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built a Free, Offline Invoice App with Flutter - No Cloud, No Subscription, No BS</title>
      <dc:creator>anoop p</dc:creator>
      <pubDate>Thu, 12 Mar 2026 15:48:17 +0000</pubDate>
      <link>https://dev.to/anoop_p_22f715057ac8b3901/i-built-a-free-offline-invoice-app-with-flutter-no-cloud-no-subscription-no-bs-16dl</link>
      <guid>https://dev.to/anoop_p_22f715057ac8b3901/i-built-a-free-offline-invoice-app-with-flutter-no-cloud-no-subscription-no-bs-16dl</guid>
      <description>&lt;p&gt;Every time I needed to invoice a client, I ran into the same wall: every decent invoice tool either locks your data in the cloud, wants a monthly subscription, or both. I just wanted something that &lt;strong&gt;works offline, keeps my data on my machine, and doesn't cost me anything&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So I built it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Anooppandikashala/invoiso" rel="noopener noreferrer"&gt;Invoiso&lt;/a&gt;&lt;/strong&gt; is a free, open-source desktop invoice app for Windows and Linux. No account. No internet. No recurring fee. Just a binary you run on your machine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Flutter for a Desktop App?
&lt;/h2&gt;

&lt;p&gt;Flutter is usually talked about in the context of mobile. But Flutter's desktop support has matured a lot - and it gave me a few things I really wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One codebase for Windows and Linux&lt;/strong&gt; - I didn't want to maintain separate projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A rich widget ecosystem&lt;/strong&gt; - building forms, data tables, and PDF previews is fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dart's type safety&lt;/strong&gt; - for a data-heavy app with models, migrations, and services, it helps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The build output is a native binary - no Electron, no Chromium, no 300 MB runtime. The Linux AppImage is lean and starts instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Flutter 3.x (Dart)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;SQLite via &lt;code&gt;sqflite&lt;/code&gt; + &lt;code&gt;sqflite_common_ffi&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State Management&lt;/td&gt;
&lt;td&gt;Riverpod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF Generation&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pdf&lt;/code&gt; + &lt;code&gt;printing&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;QR Codes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;qr&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSV Export&lt;/td&gt;
&lt;td&gt;&lt;code&gt;csv&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Window Management&lt;/td&gt;
&lt;td&gt;&lt;code&gt;window_manager&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File Picker&lt;/td&gt;
&lt;td&gt;&lt;code&gt;file_picker&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SQLite with &lt;code&gt;sqflite_common_ffi&lt;/code&gt; is the key piece for desktop. The mobile &lt;code&gt;sqflite&lt;/code&gt; package doesn't work on Linux/Windows - &lt;code&gt;sqflite_common_ffi&lt;/code&gt; wraps the native SQLite library and exposes the same API, so the transition is seamless. All data lives in a single &lt;code&gt;.db&lt;/code&gt; file the user controls.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lib/
├── main.dart
├── common.dart          # Shared enums and data classes
├── constants.dart       # UI constants
├── database/            # SQLite helpers and CRUD services
├── models/              # Invoice, Customer, Product, ...
├── providers/           # Riverpod state providers
├── screens/             # All UI screens
├── services/            # PDF generation, CSV/PDF export
├── backup/              # Backup and restore logic
└── utils/               # Logger, formatters, error handler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database layer follows a service pattern - each entity (invoices, customers, products) has its own service class wrapping raw SQL. Migrations are handled manually in &lt;code&gt;database_helper.dart&lt;/code&gt; with a version counter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interesting Technical Bits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. PDF Generation with Three Templates
&lt;/h3&gt;

&lt;p&gt;PDF output is generated using the &lt;code&gt;pdf&lt;/code&gt; package (not a web renderer - actual vector PDF). I built three templates: &lt;strong&gt;Classic&lt;/strong&gt;, &lt;strong&gt;Modern&lt;/strong&gt;, and &lt;strong&gt;Minimal&lt;/strong&gt; - each with a distinct layout and color scheme.&lt;/p&gt;

&lt;p&gt;The tricky part was making the layout adaptive to variable-length item lists, long product descriptions, and optional sections (GST, UPI QR, logo). The &lt;code&gt;pdf&lt;/code&gt; package has its own layout model (similar to Flutter widgets but without hot reload - so a lot of trial and error).&lt;/p&gt;

&lt;h3&gt;
  
  
  2. UPI Payment QR Code on Invoices
&lt;/h3&gt;

&lt;p&gt;For Indian users, I added UPI QR code embedding. When a UPI ID is configured in settings, the PDF generation encodes a &lt;code&gt;upi://pay?pa={upi_id}&amp;amp;am={total}&lt;/code&gt; URI into a QR code using the &lt;code&gt;qr&lt;/code&gt; package and renders it directly in the PDF footer. Clients can scan it with GPay, PhonePe, or Paytm to pay instantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Multi-Currency with Per-Invoice Snapshots
&lt;/h3&gt;

&lt;p&gt;Currency is selected globally in settings, but each invoice &lt;strong&gt;stores its own &lt;code&gt;currency_code&lt;/code&gt; and &lt;code&gt;currency_symbol&lt;/code&gt; at creation time&lt;/strong&gt;. This means if you change your default currency later, old invoices still display correctly. A simple but important detail - got it wrong the first time and had to add a DB migration.&lt;/p&gt;

&lt;p&gt;Speaking of migrations: I maintain a &lt;code&gt;DB_VERSION&lt;/code&gt; constant and a chain of &lt;code&gt;_upgradeDbV{n}&lt;/code&gt; functions. Each upgrade is additive (new columns with defaults, new tables) - no destructive changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Backup and Restore
&lt;/h3&gt;

&lt;p&gt;The backup feature is a plain file copy of the SQLite &lt;code&gt;.db&lt;/code&gt; file to a user-chosen directory. Restore reverses it. Simple, robust, and the user owns the backup file - they can put it on a USB drive, copy it to another machine, or commit it to their own repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Features at a Glance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PDF invoices&lt;/strong&gt; - one-click generation in Classic, Modern, or Minimal templates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invoices and Quotations&lt;/strong&gt; - with color-coded tracking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invoice cloning&lt;/strong&gt; - duplicate any document with one click&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bulk actions&lt;/strong&gt; - multi-select to export CSV, generate PDFs, or delete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UPI QR code&lt;/strong&gt; - embedded scannable payment QR in every PDF&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GST ready&lt;/strong&gt; - GSTIN fields, HSN codes, per-item or global tax rate&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-currency&lt;/strong&gt; - INR, USD, EUR, GBP, JPY, AED, SGD, AUD, CAD, JMD&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer and product management&lt;/strong&gt; - full CRUD with search and pagination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soft delete / Trash&lt;/strong&gt; - recoverable deleted invoices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSV export&lt;/strong&gt; - for spreadsheets or accounting software&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup and restore&lt;/strong&gt; - one-click, local file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; - login with brute-force protection and session timeout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100% offline&lt;/strong&gt; - zero network calls, ever&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Download
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.exe&lt;/code&gt; installer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.AppImage&lt;/code&gt; (portable)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.deb&lt;/code&gt; package&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Grab the latest from the &lt;strong&gt;&lt;a href="https://anooppandikashala.github.io/invoisoapp/download.html" rel="noopener noreferrer"&gt;Download page&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Build from Source
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Anooppandikashala/invoiso.git
&lt;span class="nb"&gt;cd &lt;/span&gt;invoiso
flutter pub get

&lt;span class="c"&gt;# Run in debug mode&lt;/span&gt;
flutter run &lt;span class="nt"&gt;-d&lt;/span&gt; linux    &lt;span class="c"&gt;# or -d windows&lt;/span&gt;

&lt;span class="c"&gt;# Release build&lt;/span&gt;
flutter build linux &lt;span class="nt"&gt;--release&lt;/span&gt;
flutter build windows &lt;span class="nt"&gt;--release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prerequisites: Flutter SDK &amp;gt;= 3.3.3. On Linux you'll also need &lt;code&gt;clang&lt;/code&gt;, &lt;code&gt;cmake&lt;/code&gt;, &lt;code&gt;ninja-build&lt;/code&gt;, and &lt;code&gt;libgtk-3-dev&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;There's a solid list of planned features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Invoice status tracking&lt;/strong&gt; (Paid / Unpaid / Overdue / Draft) - the biggest gap right now&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Due dates and payment terms&lt;/strong&gt; (Net 7, Net 30, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payment recording&lt;/strong&gt; with partial payment support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recurring invoices&lt;/strong&gt; for retainers and subscriptions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revenue reports&lt;/strong&gt; with date range filters&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dark mode&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global search&lt;/strong&gt; across invoices, customers, and products&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GST report export&lt;/strong&gt; in GSTR-1 compatible format (for Indian users)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of these interests you, contributions are welcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repo&lt;/li&gt;
&lt;li&gt;Create a branch: &lt;code&gt;git checkout -b feature/your-feature&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open a pull request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bug reports and feature requests go in &lt;a href="https://github.com/Anooppandikashala/invoiso/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;The whole thing is MIT licensed. If it saves you time or money, great - that's the point. If you want to help make it better, even better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub: &lt;a href="https://github.com/Anooppandikashala/invoiso" rel="noopener noreferrer"&gt;github.com/Anooppandikashala/invoiso&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Website: &lt;a href="https://anooppandikashala.github.io/invoisoapp/" rel="noopener noreferrer"&gt;anooppandikashala.github.io/invoisoapp&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>invoise</category>
    </item>
  </channel>
</rss>
