<?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: Getinfo Toyou</title>
    <description>The latest articles on DEV Community by Getinfo Toyou (@getinfotoyou).</description>
    <link>https://dev.to/getinfotoyou</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3794901%2Fcdf356ed-ee53-474c-a1a2-73ee4d5bbeb5.png</url>
      <title>DEV Community: Getinfo Toyou</title>
      <link>https://dev.to/getinfotoyou</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/getinfotoyou"/>
    <language>en</language>
    <item>
      <title>Optimizing CameraX and ML Kit for Real-World Workflows: Building Sharp QR</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 07 Sep 2026 14:31:12 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/optimizing-camerax-and-ml-kit-for-real-world-workflows-building-sharp-qr-19fp</link>
      <guid>https://dev.to/getinfotoyou/optimizing-camerax-and-ml-kit-for-real-world-workflows-building-sharp-qr-19fp</guid>
      <description>&lt;h1&gt;
  
  
  Optimizing CameraX and ML Kit for Real-World Workflows: Building Sharp QR
&lt;/h1&gt;

&lt;p&gt;Most modern Android phones ship with a default camera app capable of detecting QR codes. Yet, if you look at the Play Store, barcode and QR scanning utilities remain persistently popular. &lt;/p&gt;

&lt;p&gt;Why? Because default camera implementations are designed for casual photography, not high-throughput, specialized utility tasks. Most third-party alternatives swing too far in the opposite direction: bloated with intrusive ads, full-screen video interruptions, and sketchy permissions.&lt;/p&gt;

&lt;p&gt;When I set out to build &lt;a href="https://play.google.com/store/apps/details?id=com.getinfotoyou.sharpqr" rel="noopener noreferrer"&gt;Sharp QR&lt;/a&gt;, my goal was to build a clean, reliable scanner and generator focused on performance and practical utility.&lt;/p&gt;

&lt;p&gt;Here is a look at who this tool was built for, the technical challenges behind it, and what I learned building it with modern Android tooling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Actually Needs a Dedicated QR Tool?
&lt;/h2&gt;

&lt;p&gt;While everyday users occasionally scan a restaurant menu, certain professional workflows demand something far more dependable and focused:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Event Organizers and Check-in Staff:&lt;/strong&gt; When you need to process hundreds of attendees entering a venue, a standard camera app hunting for focus on wrinkled paper or dim phone screens causes massive bottlenecks. They need instant feedback, persistent history logs, and offline reliability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketers and Print Designers:&lt;/strong&gt; Marketers regularly generate URLs, vCards, and Wi-Fi credentials for packaging, posters, and business cards. They need a tool that can instantly generate precise, high-contrast QR matrices, verify how they parse across different data schemas, and test them locally before sending assets to the print shop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Field Technicians and IT Administrators:&lt;/strong&gt; Technicians regularly scan asset tags, network router credentials, and serial numbers in poorly lit server racks or warehouses. They need direct access to torch controls, instant clipboard copying, and zero ad popups blocking their workflow.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;To keep the footprint small and the UI responsive, I relied on modern, first-party Android libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language:&lt;/strong&gt; Kotlin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Layer:&lt;/strong&gt; Jetpack Compose (Material 3)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Camera Pipeline:&lt;/strong&gt; AndroidX CameraX (&lt;code&gt;camera-camera2&lt;/code&gt;, &lt;code&gt;camera-lifecycle&lt;/code&gt;, &lt;code&gt;camera-view&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vision Processing:&lt;/strong&gt; Google ML Kit Barcode Scanning API (bundled model)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Persistence:&lt;/strong&gt; Room Database with Kotlin Coroutines and Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QR Generation:&lt;/strong&gt; ZXing Core (strictly used for the encoding matrix logic)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Technical Challenges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Frame Analysis Bottlenecks with CameraX
&lt;/h3&gt;

&lt;p&gt;Setting up CameraX with &lt;code&gt;ImageAnalysis.Analyzer&lt;/code&gt; is straightforward on paper, but keeping the frame rate steady across diverse hardware is tricky. Feeding every 30fps YUV frame directly into ML Kit's detector quickly leads to thermal throttling and dropped frames on budget devices.&lt;/p&gt;

&lt;p&gt;To solve this, I decoupled frame delivery from analysis. Using &lt;code&gt;ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST&lt;/code&gt; ensured the camera pipeline never blocked waiting for ML Kit to complete inference on the previous frame. Additionally, I scoped the target analysis resolution to 1080p, which provides the sweet spot between reading dense, small QR codes and maintaining sub-50ms inference times.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Eliminating Detection Jitter
&lt;/h3&gt;

&lt;p&gt;When scanning in continuous mode or saving scan history, ML Kit will report the same barcode across 15 consecutive frames. Without debouncing, your database fills up with duplicates instantly.&lt;/p&gt;

&lt;p&gt;I built a simple time-window debounce mechanism using Kotlin Flows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;lastScannedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;lastScannedTimestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0L&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;scanCooldownMs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1500L&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onBarcodeDetected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;now&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentTimeMillis&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="n"&gt;rawValue&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;lastScannedValue&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastScannedTimestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;scanCooldownMs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lastScannedValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rawValue&lt;/span&gt;
        &lt;span class="n"&gt;lastScannedTimestamp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;
        &lt;span class="nf"&gt;processBarcode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawValue&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;h3&gt;
  
  
  3. Asynchronous Code Generation
&lt;/h3&gt;

&lt;p&gt;Generating QR codes with custom error correction levels (L, M, Q, H) using ZXing can cause perceptible frame drops if executed on the main dispatcher, particularly for large payloads like vCards. I offloaded all BitMatrix calculations and Bitmap rendering to &lt;code&gt;Dispatchers.Default&lt;/code&gt;, passing the finished bitmap to Compose via a state holder.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don't overcomplicate the vision pipeline:&lt;/strong&gt; Google ML Kit's bundled barcode model adds minimal app size while running fully on-device without an active internet connection. It consistently outperformed custom OpenCV pipelines for standard 2D formats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Haptic feedback matters:&lt;/strong&gt; In high-speed workflows (like scanning asset tags), visual cues on screen aren't enough. Adding subtle, immediate haptic feedback via &lt;code&gt;Vibrator&lt;/code&gt; upon successful parsing drastically improves the operator's scanning rhythm.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;Sharp QR is built to do one job with speed and precision, without paywalls or distracting banner ads.&lt;/p&gt;

&lt;p&gt;If you regularly work with QR codes or need a reliable utility for your workflow, you can download &lt;strong&gt;Sharp QR&lt;/strong&gt; on &lt;a href="https://play.google.com/store/apps/details?id=com.getinfotoyou.sharpqr" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also explore more independent utilities built for practical use cases at &lt;a href="https://getinfotoyou.com" rel="noopener noreferrer"&gt;getinfotoyou.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>camerax</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Building a Zero-Bloat Android Runner: Object Pooling, Low-Latency Input, and Optimization</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Fri, 04 Sep 2026 14:31:08 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/building-a-zero-bloat-android-runner-object-pooling-low-latency-input-and-optimization-2lbc</link>
      <guid>https://dev.to/getinfotoyou/building-a-zero-bloat-android-runner-object-pooling-low-latency-input-and-optimization-2lbc</guid>
      <description>&lt;p&gt;Modern mobile gaming often comes with an unspoken tax: 500MB download sizes, endless splash screens, and aggressive background services that drain batteries. When you just want a quick three-minute distraction while standing in line or riding the train, waiting through loading bars and shader pre-compilations ruins the experience.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Echo Runner&lt;/strong&gt; to solve that specific annoyance. It is a lean, fast-paced endless runner designed to launch instantly, run at a locked 60 frames per second on budget devices, and deliver straightforward arcade reflex gameplay without unnecessary bloat.&lt;/p&gt;

&lt;p&gt;Here is a look at the technical decisions behind Echo Runner, the engineering challenges of low-spec Android optimization, and who gains the most from this approach.&lt;/p&gt;




&lt;h3&gt;
  
  
  Who Benefits Most From This Architecture?
&lt;/h3&gt;

&lt;p&gt;Before diving into the code, it helps to understand the target profile. Echo Runner was designed specifically for two groups:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Commuters and casual mobile gamers on budget or aging hardware:&lt;/strong&gt; Players who do not own flagship phones, have limited storage, or deal with spotty network connections. They need a responsive game that opens in two seconds, consumes minimal battery, and does not hitch when an obstacle appears.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Players who value reflex-driven gameplay over pay-to-win systems:&lt;/strong&gt; Many modern runners introduce artificial speed caps or energy meters that recharge with microtransactions. Echo Runner is built on clean, pure skill progression where level difficulty scales mathematically rather than commercially.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;To balance rapid development with low-level control, I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Engine:&lt;/strong&gt; Unity (stripped-down Universal Render Pipeline with all post-processing passes removed except minimal bloom).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language:&lt;/strong&gt; C# using strictly allocation-free patterns during the main loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target Platform:&lt;/strong&gt; Android (targeting API level 34, backward-compatible to Android 8.0).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asset Pipeline:&lt;/strong&gt; Low-poly meshes, unlit vertex-colored shaders, and compressed audio buffers to keep total APK download size low.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Technical Challenges and Solutions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Eliminating Garbage Collection Spikes
&lt;/h4&gt;

&lt;p&gt;In an endless runner, spawning and destroying platforms, obstacles, and pick-ups dynamically is the standard pattern. In C#, frequent calls to &lt;code&gt;Instantiate()&lt;/code&gt; and &lt;code&gt;Destroy()&lt;/code&gt; trigger the Mono runtime's garbage collector. When the GC runs on low-end Android hardware, it causes noticeable micro-stutter (50-100ms frame drops)—which instantly kills a player in a precision reflex game.&lt;/p&gt;

&lt;p&gt;To fix this, I implemented an aggressive generic object pooling system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ObjectPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_availableObjects&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;_prefab&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Transform&lt;/span&gt; &lt;span class="n"&gt;_parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ObjectPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;prefab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;initialSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Transform&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_prefab&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefab&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_parent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent&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="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;initialSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_prefab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_parent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_availableObjects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&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="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_availableObjects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_availableObjects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dequeue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_prefab&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_parent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&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;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_availableObjects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&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;Every track segment, barrier, and power-up is pre-warmed during initial scene setup. During active gameplay, allocations per frame drop to zero bytes.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Input Latency Calibration
&lt;/h4&gt;

&lt;p&gt;Touch latency on Android varies wildly across manufacturers due to display refresh rates and touch-polling implementations. In a runner game where a lane switch requires split-second timing, queued touch events caused players to feel like controls were sluggish.&lt;/p&gt;

&lt;p&gt;Instead of reading touch inputs in Unity's standard &lt;code&gt;Update()&lt;/code&gt; loop with raw delta checks, I migrated the input stack to Unity's modern Input System, consuming tap and swipe events directly from the hardware queue during &lt;code&gt;FixedUpdate()&lt;/code&gt; sync phases. This cut perceived input lag significantly on 60Hz panels.&lt;/p&gt;




&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Profiling on real low-end hardware is mandatory:&lt;/strong&gt; Testing on modern Snapdragon processors hides memory leaks and fill-rate limits. Testing on an entry-level MediaTek chip exposed visual bottlenecks in the particle systems within five minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity beats feature bloat:&lt;/strong&gt; Trimming complex UI menus and third-party analytics SDKs dropped load times from four seconds to under one second.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Try It Out
&lt;/h3&gt;

&lt;p&gt;If you want a lightweight, distraction-free arcade game for your daily commute, you can download &lt;strong&gt;Echo Runner&lt;/strong&gt; directly on Google Play:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Play Store:&lt;/strong&gt; &lt;a href="https://play.google.com/store/apps/details?id=com.echorunner.game" rel="noopener noreferrer"&gt;Download Echo Runner&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web &amp;amp; Info:&lt;/strong&gt; &lt;a href="https://echorunner.getinfotoyou.com" rel="noopener noreferrer"&gt;echorunner.getinfotoyou.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback on performance across different Android hardware configurations is always welcome in the comments.&lt;/p&gt;

</description>
      <category>android</category>
      <category>gamedev</category>
      <category>unity3d</category>
      <category>performance</category>
    </item>
    <item>
      <title>How I Built a Markdown Editor for Android That Doesn't Squeeze Out Your Productivity</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:30:36 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/how-i-built-a-markdown-editor-for-android-that-doesnt-squeeze-out-your-productivity-1e28</link>
      <guid>https://dev.to/getinfotoyou/how-i-built-a-markdown-editor-for-android-that-doesnt-squeeze-out-your-productivity-1e28</guid>
      <description>&lt;p&gt;Writing documentation, drafting blog posts, or taking structured notes on a phone is generally a frustrating experience. While desktop markdown editors have evolved to offer smooth, distraction-free environments, mobile tools often force you to choose between a clunky text input area or a heavily restricted UI.&lt;/p&gt;

&lt;p&gt;As a developer, I frequently get ideas for technical posts or need to update repository readmes while away from my desk. The struggle of manually typing backticks, hashes, and brackets on a standard mobile keyboard—coupled with the lack of instant previews—led me to build AIMarkdownPro Editor.&lt;/p&gt;

&lt;p&gt;Here is the story of how I tackled the challenges of mobile markdown editing, the tech stack I chose, and what I learned along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Main Problem: Mobile Friction
&lt;/h3&gt;

&lt;p&gt;The core issue with editing Markdown on mobile is friction. Keyboards aren’t optimized for syntax symbols, and switching back and forth between edit mode and preview mode breaks your writing flow. Furthermore, standard AI writing assistants often strip away your markdown formatting or return poorly structured blocks that require manual cleanup.&lt;/p&gt;

&lt;p&gt;I wanted an app that solved these specific issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Quick access to markdown syntax elements.&lt;/li&gt;
&lt;li&gt;A live, side-by-side or tabbed preview that renders correctly.&lt;/li&gt;
&lt;li&gt;An AI assistant that respects and works directly with Markdown structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;To build a responsive editor, I selected a modern Android stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kotlin&lt;/strong&gt;: For concise and safe code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jetpack Compose&lt;/strong&gt;: To build a declarative, fluid UI that adapts easily to different screen sizes and orientations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markwon / Flexmark (adapted)&lt;/strong&gt;: For parsing and rendering Markdown to rich text in the preview.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coroutines&lt;/strong&gt;: To handle parsing and AI generation off the main thread, keeping the UI responsive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges
&lt;/h3&gt;

&lt;p&gt;Two main challenges arose during development:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Real-Time Syntax Highlighting
&lt;/h4&gt;

&lt;p&gt;In Jetpack Compose, the &lt;code&gt;TextField&lt;/code&gt; component is powerful but can lag if you attempt heavy parsing on every keystroke. Applying syntax highlighting to the raw editor text in real-time meant writing a highly efficient, incremental parser. I had to throttle the highlighting updates to prevent the keyboard input from stuttering, especially on larger documents.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. AI Integration that Understands Context
&lt;/h4&gt;

&lt;p&gt;Integrating an AI writer meant teaching the assistant to output raw Markdown that fits seamlessly into the user's document. Instead of replacing the entire text, the AI needs to understand the cursor's location and generate contextually relevant headings, lists, or code blocks. This required carefully structured prompts and parsing the stream of incoming tokens to dynamically update the active editing block.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep it local first&lt;/strong&gt;: Relying entirely on cloud APIs can make a mobile app feel sluggish. Keeping as many editing operations local as possible—and streamlining network calls—is crucial for a smooth user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard accessory bars are essential&lt;/strong&gt;: Adding a simple helper row above the virtual keyboard for quick symbols like hashes, asterisks, backticks, and brackets reduces the friction of writing Markdown by at least 80%.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Try It Out
&lt;/h3&gt;

&lt;p&gt;If you've ever wanted to write or edit your technical documentation on the go without the usual hassle, you can try AIMarkdownPro Editor. It is available on &lt;a href="https://play.google.com/store/apps/details?id=com.aimarkdownpro.app" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;. You can also learn more about the project at the &lt;a href="https://aimarkdownpro.getinfotoyou.com" rel="noopener noreferrer"&gt;AIMarkdownPro website&lt;/a&gt;, which is part of my solo developer portfolio at &lt;a href="https://getinfotoyou.com" rel="noopener noreferrer"&gt;getinfotoyou.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'd love to hear how you handle mobile writing workflows and what features you find most helpful.&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>android</category>
      <category>productivity</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building a High-Performance Batch Image Compressor for Android: Native Bitmap Optimization and Pipeline Challenges</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 26 Aug 2026 14:30:30 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/building-a-high-performance-batch-image-compressor-for-android-native-bitmap-optimization-and-2j3</link>
      <guid>https://dev.to/getinfotoyou/building-a-high-performance-batch-image-compressor-for-android-native-bitmap-optimization-and-2j3</guid>
      <description>&lt;p&gt;As a mobile developer, I frequently find myself needing to tweak, resize, or compress image files on the go. While web-based compression tools exist, uploading multi-megapixel source files over cellular data is slow, insecure, and expensive. I wanted a way to process high-resolution photos locally on Android, matching the precision and batch capabilities of desktop software.&lt;/p&gt;

&lt;p&gt;This led me to build ImageSlim Pro. Throughout the process, I focused on addressing the specific needs of three groups of people who rely heavily on mobile media processing: content creators, web designers, and field photographers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who Benefits Most?
&lt;/h3&gt;

&lt;p&gt;During development, I prioritized features that solve distinct friction points for specific users:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;On-the-go Content Creators&lt;/strong&gt;: When you are uploading to social platforms or publishing articles from the field, bandwidth is precious. Content creators need to reduce file sizes drastically without introducing blocky compression artifacts. By allowing precise control over quality percentage and resolution dials, they can find the sweet spot between visual fidelity and small file sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile Web Designers&lt;/strong&gt;: Mobile layouts require optimized WebP or PNG assets. Designers using tablets or phones to manage websites can convert and batch-resize assets to exact pixel dimensions, ensuring fast page load speeds for their clients.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Photographers Sharing Drafts&lt;/strong&gt;: Photographers often need to send quick proofing galleries to clients. Sending raw files is impractical, but using low-quality automated compressors strips away crucial color profiles. ImageSlim Pro preserves EXIF metadata and maintains color integrity while shrinking the file footprint.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Technical Stack
&lt;/h3&gt;

&lt;p&gt;To keep the application responsive during heavy batches, I chose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kotlin &amp;amp; Jetpack Compose&lt;/strong&gt;: For a lightweight, modern UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kotlin Coroutines &amp;amp; Flow&lt;/strong&gt;: To manage background processing queues and stream real-time progress updates to the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Android NDK (Native Development Kit)&lt;/strong&gt;: Specifically utilizing native libraries for encoding WebP and JPEG format variations, bypassing some of the higher-overhead Java-level Bitmap APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Overcoming the Memory Bottleneck
&lt;/h3&gt;

&lt;p&gt;The biggest technical hurdle was Android's strict memory management. If a user drops twenty 48-megapixel images into a batch queue, decoding them all into memory simultaneously will instantly trigger an Out Of Memory (OOM) crash.&lt;/p&gt;

&lt;p&gt;To solve this, I designed a pipeline that processes images sequentially using a worker queue. Instead of decoding full-resolution bitmaps directly, the app reads the image dimensions first using &lt;code&gt;inJustDecodeBounds = true&lt;/code&gt;. Based on the target output dimensions, it calculates the optimal &lt;code&gt;inSampleSize&lt;/code&gt; to sub-sample the image during the actual decode phase. This keeps the memory footprint low and predictable, even when processing dozens of files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building this app taught me a lot about garbage collection (GC) churn. In early iterations, allocating new byte arrays for every image compression operation caused frequent GC pauses, leading to visible UI stuttering despite using background threads. Transitioning to a reusable byte buffer pool resolved the issue, smoothing out the performance.&lt;/p&gt;

&lt;p&gt;Additionally, I learned the importance of preserving metadata. Stripping EXIF data is easy, but keeping it intact while rebuilding the image structure requires carefully parsing and writing the JPEG APP1 segments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give it a Try
&lt;/h3&gt;

&lt;p&gt;If you are a photographer, designer, or creator looking for a clean, local-first tool to handle your mobile image processing, you can try the app on the &lt;a href="https://play.google.com/store/apps/details?id=com.getinfotoyou.imageslim.pro" rel="noopener noreferrer"&gt;Google Play Store&lt;/a&gt; or read more about the project at &lt;a href="https://imageslim.getinfotoyou.com" rel="noopener noreferrer"&gt;imageslim.getinfotoyou.com&lt;/a&gt;. You can also view my other projects at &lt;a href="https://getinfotoyou.com" rel="noopener noreferrer"&gt;getinfotoyou.com&lt;/a&gt;. I would love to hear your feedback on the processing pipeline or any features you would like to see added.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>performance</category>
      <category>mobile</category>
    </item>
    <item>
      <title>How I Built a Zero-Network Android Image Compressor to Solve the 10MB Photo Problem</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 24 Aug 2026 14:30:35 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/how-i-built-a-zero-network-android-image-compressor-to-solve-the-10mb-photo-problem-1cgl</link>
      <guid>https://dev.to/getinfotoyou/how-i-built-a-zero-network-android-image-compressor-to-solve-the-10mb-photo-problem-1cgl</guid>
      <description>&lt;p&gt;Modern phone cameras are incredible, but they have a massive side effect: file size. A single photo taken on a mid-range Android phone can easily range from 6MB to 15MB. While that detail is great for printing posters, it is complete overkill for sharing on chat apps, uploading to a blog, or storing on your phone.&lt;/p&gt;

&lt;p&gt;As my device storage filled up and my cloud storage warnings started popping up, I realized I needed a quick way to shrink my photos. I looked at web-based tools, but I didn't feel comfortable uploading private family photos to random servers just to resize them. I looked at existing apps, but they were bloated with ads, trackers, and demanded internet access.&lt;/p&gt;

&lt;p&gt;So, I decided to build ImageSlim Free, an offline-first Android app designed to solve this exact problem: shrinking image file sizes by up to 90% without sacrificing visible quality.&lt;/p&gt;

&lt;p&gt;Here is how I built it, the technical hurdles I faced, and what I learned along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Problem: Mobile Storage and Bandwidth Bloat
&lt;/h3&gt;

&lt;p&gt;When you share a 10MB photo over a weak mobile connection, it takes forever. If you run a self-hosted blog, uploading multiple 10MB images destroys your page load speeds and hikes up your hosting bills. The core value of ImageSlim is simple: let users select one or multiple images, scale them down, compress the bytes, and save them—all in a few seconds, and entirely on-device.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Challenges of On-Device Processing
&lt;/h3&gt;

&lt;p&gt;Processing high-resolution images on Android is notoriously difficult due to memory limitations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The OutOfMemory (OOM) Trap&lt;/strong&gt;: If you load a 108 megapixel photo directly into Android's memory as a Bitmap, it can require hundreds of megabytes of RAM. Android will instantly kill your app process if you exceed the heap limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Thread Blocking&lt;/strong&gt;: Image compression is CPU-intensive. Running it on the main thread freezes the user interface, causing the system to throw an "Application Not Responding" (ANR) dialog.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To tackle the OOM issue, I used sub-sampling. Instead of loading the full-resolution image into memory just to resize it, I used &lt;code&gt;BitmapFactory.Options&lt;/code&gt; with &lt;code&gt;inJustDecodeBounds = true&lt;/code&gt; to query the image dimensions first. Once I knew the original size, I calculated an appropriate &lt;code&gt;inSampleSize&lt;/code&gt; to decode a downscaled version directly into memory, dramatically reducing the RAM footprint.&lt;/p&gt;

&lt;p&gt;To keep the app responsive, I wrapped the entire compression workflow inside Kotlin Coroutines, specifically utilizing &lt;code&gt;Dispatchers.Default&lt;/code&gt; for CPU-bound tasks. This keeps the UI buttery smooth even when processing a batch of images.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;I wanted the project to be lightweight and modern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language&lt;/strong&gt;: Kotlin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Framework&lt;/strong&gt;: Jetpack Compose. This allowed me to build a clean, minimal interface without the boilerplate of XML layouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency&lt;/strong&gt;: Kotlin Coroutines and Flow to manage background processing states.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graphics Pipeline&lt;/strong&gt;: Native Android Graphics libraries (&lt;code&gt;android.graphics.Bitmap&lt;/code&gt;), utilizing JPEG/WEBP compression algorithms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building this app taught me a lot about native memory management. Unlike Java objects, Bitmaps in older Android versions allocated memory in the native heap, but even in modern versions, garbage collection behavior can be unpredictable during heavy image manipulation. Explicitly calling &lt;code&gt;bitmap.recycle()&lt;/code&gt; and ensuring references are cleared as soon as the file is written made a massive difference in stability.&lt;/p&gt;

&lt;p&gt;Additionally, I learned that restricting your app's capabilities can actually be a feature. By choosing not to request the Internet permission (&lt;code&gt;android.permission.INTERNET&lt;/code&gt;) in the manifest, I made it impossible for the app to send data anywhere. This built immediate trust with privacy-conscious users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try It Out
&lt;/h3&gt;

&lt;p&gt;If you're tired of running out of phone space or waiting for photo uploads to finish, you can download ImageSlim Free on &lt;a href="https://play.google.com/store/apps/details?id=com.getinfotoyou.imageslim.free" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more details on the project and other tools, feel free to check out the portfolio page at &lt;a href="https://imageslim.getinfotoyou.com" rel="noopener noreferrer"&gt;imageslim.getinfotoyou.com&lt;/a&gt;. Let me know your thoughts or if you have any questions about the implementation!&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>performance</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why I Built an Offline-First Android App to Manage My AI Prompts</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 19 Aug 2026 14:30:25 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/why-i-built-an-offline-first-android-app-to-manage-my-ai-prompts-2caa</link>
      <guid>https://dev.to/getinfotoyou/why-i-built-an-offline-first-android-app-to-manage-my-ai-prompts-2caa</guid>
      <description>&lt;p&gt;As developers, we are constantly switching contexts. On any given day, we might be jump-starting a new project, writing tests, or debugging legacy code. Over the last couple of years, large language models (LLMs) like ChatGPT, Claude, and Gemini have become core parts of my daily coding and documentation workflow. But as my usage grew, I noticed a frustrating bottleneck: prompt management.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: Where Did I Put That Prompt?
&lt;/h3&gt;

&lt;p&gt;I started with a fragmented setup. I had a markdown file on my desktop for coding prompts, a note-taking app on my phone for writing prompts, and a few drafts saved in my email. Whenever I needed a specific prompt that had worked perfectly a week ago, I had to search through multiple apps, copy the text, tweak the variables, and paste it into the browser.&lt;/p&gt;

&lt;p&gt;This process was inefficient. I wanted a single, dedicated library on my mobile device—something I could access instantly, search through, and copy from with a single tap. Since I couldn't find a lightweight, privacy-focused solution that fit my needs without unnecessary complexity, I decided to build one myself: AI Prompt Vault.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the Tech Stack
&lt;/h3&gt;

&lt;p&gt;Since speed and privacy were my top priorities, I chose a modern, native Android tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Language:&lt;/strong&gt; Kotlin, because of its safety features and concise syntax.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;UI Framework:&lt;/strong&gt; Jetpack Compose. Building UIs declaratively allowed me to quickly prototype the interface and handle dynamic states (like search queries and category filters) cleanly.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Local Database:&lt;/strong&gt; Room Database. I wanted the app to be completely offline-first. Your prompts should remain your own data, stored locally on your device.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dependency Injection:&lt;/strong&gt; Hilt, to keep the codebase clean, modular, and testable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges
&lt;/h3&gt;

&lt;p&gt;Building a simple utility app doesn't mean there aren't interesting engineering challenges. Three aspects stood out during development:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Instant Full-Text Search
&lt;/h4&gt;

&lt;p&gt;When you have dozens of prompts, scrolling is too slow. I needed instant search that matches terms in both the prompt title and the body. To achieve this without relying on a backend server, I integrated SQLite's FTS4 (Full-Text Search) module via Room.&lt;/p&gt;

&lt;p&gt;Setting up the virtual FTS table required mapping the database entities correctly to ensure search queries were executed in milliseconds. The result is a highly responsive search bar that filters your prompt library as you type.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. State Management and MVI
&lt;/h4&gt;

&lt;p&gt;In Jetpack Compose, managing UI state across configuration changes (like screen rotation) can get tricky, especially when dealing with active search queries, category selections, and list states. I adopted a Model-View-Intent (MVI) architecture. By exposing a single immutable state flow from the ViewModel, the UI remains predictable. When a user selects a category, it triggers an action that updates the state, which in turn recalculates the filtered list via Room's Flow integration. This means the database is the single source of truth, and the UI reacts instantly to any changes.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Clean Clipboard Integration
&lt;/h4&gt;

&lt;p&gt;The core user action in the app is copying a prompt to the clipboard. Android handles clipboard access via the &lt;code&gt;ClipboardManager&lt;/code&gt;. However, ensuring a seamless user experience across different Android versions (especially with the clipboard overlay introduced in Android 13) meant I had to carefully handle background threads and system notifications. I implemented a simple one-tap copy gesture that updates the clipboard and gives subtle haptic feedback to confirm the action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building AI Prompt Vault taught me a valuable lesson in product scope. Initially, I wanted to build a cloud sync feature. I planned to use Firebase, set up user authentication, and synchronize prompts across multiple devices.&lt;/p&gt;

&lt;p&gt;But as I talked to potential users (and looked at my own habits), I realized that a cloud database introduced unnecessary friction. Users didn't want to create another account just to store prompts. They valued privacy and speed. By stripping away the cloud synchronization and focusing entirely on a fast, local SQLite database, I delivered a more secure and responsive product.&lt;/p&gt;

&lt;p&gt;I also realized how important it is to design for variable inputs. Often, a prompt is not static—it has placeholders (e.g., &lt;code&gt;[Insert code here]&lt;/code&gt;). Handling dynamic variables within a local database and presenting them in a clean UI is a feature I'm actively refining.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try It Out
&lt;/h3&gt;

&lt;p&gt;If you find yourself copying and pasting the same instructions into LLMs or losing track of your best prompts, you can download AI Prompt Vault on Google Play:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.getinfotoyou.aipromptvaultpro" rel="noopener noreferrer"&gt;AI Prompt Vault on Google Play Store&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is a simple, practical utility designed to make your daily AI interactions a little more productive. I would love to hear your feedback on how you manage your prompts and what features you would find useful.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>productivity</category>
      <category>ai</category>
    </item>
    <item>
      <title>Why I Built a Free Venting Space for Developers (Instead of Joining Another $30/Month Slack)</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 17 Aug 2026 14:30:28 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/why-i-built-a-free-venting-space-for-developers-instead-of-joining-another-30month-slack-3op5</link>
      <guid>https://dev.to/getinfotoyou/why-i-built-a-free-venting-space-for-developers-instead-of-joining-another-30month-slack-3op5</guid>
      <description>&lt;p&gt;We’ve all seen them: the premium developer Slack groups, the private Discord channels, the paid mentorship circles. They promise a safe space to share your struggles, network, and grow. They charge $20, $50, or even $100 a month. But there’s a fundamental contradiction at the heart of these paid spaces. When you pay to join a professional network, you’re incentivized to present the polished, successful version of yourself. You want to look like the developer who has it all figured out.&lt;/p&gt;

&lt;p&gt;What happens when you actually need to vent? What happens when you just spent six hours debugging a missing semicolon, or when you accidentally dropped a production table and your stomach is in knots?&lt;/p&gt;

&lt;p&gt;You can’t post that on a paid networking Slack where recruiters, peers, or potential clients are watching. You need a space that is raw, honest, and completely free of professional stakes. That is why I built DevConfessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem with Paid Developer Networks
&lt;/h3&gt;

&lt;p&gt;Paid developer platforms serve a purpose, but they aren't built for vulnerability. They require your real name, your GitHub profile, your LinkedIn resume, and your credit card. They are transactional. &lt;/p&gt;

&lt;p&gt;In contrast, the goal of DevConfessions is to strip away the career-oriented posturing. It’s an Android app designed for developers to share their coding secrets, daily struggles, and honest developer humor anonymously. There are no profiles, no monthly fees, and no networking pressure. It’s just you and a feed of real, unfiltered developer life. If you want to check it out, you can download it on &lt;a href="https://play.google.com/store/apps/details?id=com.getinfotoyou.devconfessions" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing the Tech Stack
&lt;/h3&gt;

&lt;p&gt;Because I wanted DevConfessions to be entirely free to use and sustainable to run, I had to design a highly efficient, low-overhead system. The architecture is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Jetpack Compose. Using native Android components allowed me to create a fluid, responsive UI without the bloat of cross-platform frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: A serverless REST API built with Node.js and hosted on Cloudflare Workers. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: PostgreSQL (Supabase) with strict row-level security (RLS) policies to ensure absolute anonymity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt;: Redis layer to minimize database queries for popular confessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By keeping the stack modular and serverless, my running costs are virtually zero. This allows me to keep the app free for everyone, without needing to lock features behind a premium subscription.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Technical Challenges of Absolute Anonymity
&lt;/h3&gt;

&lt;p&gt;Building an anonymous app presents unique engineering challenges, particularly around data privacy and moderation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Zero Tracking by Design&lt;/strong&gt;: To ensure true anonymity, I decided not to collect IP addresses, device IDs, or user accounts. But this made rate-limiting spam posts difficult. I solved this by implementing client-side cryptographic puzzles (Proof-of-Work) using hashcash-like algorithms. Before a post is accepted, the client must solve a small mathematical puzzle, slowing down automated spam scripts without requiring user identification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Moderation Without Central Control&lt;/strong&gt;: Paid platforms use paid moderators. Since this app is free, I had to build a self-moderating ecosystem. Users can flag inappropriate content. If a post receives a threshold of flags relative to its views within a short timeframe, it is automatically quarantined and moved to a review queue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Security&lt;/strong&gt;: PostgreSQL RLS handles read/write boundaries, ensuring that client requests can only perform insertion or read operations without administrative access to the underlying table.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building DevConfessions taught me that developers don't need another place to build their "personal brand." We are constantly bombarded with messages to optimize our portfolios, post on LinkedIn, and network in exclusive groups.&lt;/p&gt;

&lt;p&gt;Sometimes, the most helpful thing is simply knowing that someone else out there also has no idea how to configure Webpack, or that a senior engineer with ten years of experience still copies code from Stack Overflow. Peer validation doesn't have to cost a dime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;If you are tired of the polished, professional echo chambers and want a quick laugh or a place to vent about your latest merge conflict, give the app a try. It’s a simple, free space made by a developer, for developers.&lt;/p&gt;

&lt;p&gt;You can download it today from &lt;a href="https://play.google.com/store/apps/details?id=com.getinfotoyou.devconfessions" rel="noopener noreferrer"&gt;Google Play&lt;/a&gt; and share your first confession. Let's keep it real.&lt;/p&gt;

</description>
      <category>android</category>
      <category>programming</category>
      <category>showdev</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Solving the Mobile Image Conversion Bottleneck: Building an Offline Batch Processor for Android</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Fri, 14 Aug 2026 14:30:33 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/solving-the-mobile-image-conversion-bottleneck-building-an-offline-batch-processor-for-android-lll</link>
      <guid>https://dev.to/getinfotoyou/solving-the-mobile-image-conversion-bottleneck-building-an-offline-batch-processor-for-android-lll</guid>
      <description>&lt;p&gt;Imagine you're traveling, working on a quick web update from your tablet or phone, and a collaborator sends you a zip file of 50 high-resolution PNG screenshots that you need to upload. The platform only accepts WebP or JPG, or maybe the file sizes are simply too massive for a spotty cellular connection.&lt;/p&gt;

&lt;p&gt;Uploading these files to an online service is frustrating. You run into upload limits, bandwidth constraints, and the unsettling reality that you're sending potentially sensitive screenshots to an unknown remote server.&lt;/p&gt;

&lt;p&gt;This exact scenario is why I built PhotoConvert. I needed a way to batch convert images directly on my Android device—quickly, securely, and entirely offline. Here is how I tackled the engineering challenges of building a local image converter for Android, and what I learned along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Built It: The Mobile Workflow Gap
&lt;/h3&gt;

&lt;p&gt;Most developers and designers have a solid desktop workflow for bulk image conversion. A quick terminal script using ImageMagick or a dedicated desktop app does the job in seconds. But when you move to a mobile device—like an Android tablet or phone—the options thin out.&lt;/p&gt;

&lt;p&gt;Existing tools on Google Play were either ad-choked wrappers for web-based APIs or heavy, complex photo editors. I wanted something simple: a utility app that does one thing well. Select images, choose the target format (JPG, PNG, WebP, GIF, or BMP), adjust the quality, and hit convert.&lt;/p&gt;

&lt;p&gt;The core rule was that it had to run 100% offline. No servers, no data collection, no telemetry. Just pure local processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;To keep the application responsive and lightweight, I chose a native Android stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language:&lt;/strong&gt; Kotlin, which makes asynchronous programming clean and readable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Framework:&lt;/strong&gt; Jetpack Compose for a minimalist, intuitive interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency:&lt;/strong&gt; Kotlin Coroutines and Flow to manage background conversion tasks without freezing the user interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image Processing:&lt;/strong&gt; Android's native &lt;code&gt;Bitmap&lt;/code&gt; and &lt;code&gt;ImageDecoder&lt;/code&gt; APIs, coupled with custom file stream handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges: Handling Memory on Mobile
&lt;/h3&gt;

&lt;p&gt;Converting a single image is easy. Batch converting 50 large images simultaneously on a mobile device is a quick way to trigger &lt;code&gt;OutOfMemoryError&lt;/code&gt; (OOM) crashes. Android allocates a limited heap size to each application, and loading multiple raw Bitmaps into memory at once can exhaust that limit instantly.&lt;/p&gt;

&lt;p&gt;To solve this, I implemented several optimizations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sequential Queueing with Coroutines:&lt;/strong&gt; Instead of processing all images in parallel, which would spike memory usage, the app queues the conversions. I used a custom Coroutine worker pool that processes a limited number of files concurrently (typically scaled to the device's CPU cores, but capped to avoid memory saturation).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming and Recycling:&lt;/strong&gt; Bitmaps are loaded, compressed, and written to the output stream, and then immediately recycled using &lt;code&gt;bitmap.recycle()&lt;/code&gt;. Garbage collection on Android can sometimes be lazy, so explicitly freeing native memory is vital.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-Sample Size Scaling:&lt;/strong&gt; If the user chooses to scale down images to save space, the app reads the image dimensions first (without loading the full pixel data) using &lt;code&gt;inJustDecodeBounds = true&lt;/code&gt;, calculates the scale factor, and loads a downsampled version directly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Navigating Android's Scoped Storage
&lt;/h3&gt;

&lt;p&gt;Another hurdle was Android’s Scoped Storage system. Accessing files outside the app's private directory requires interacting with the Storage Access Framework (SAF) or using media store APIs.&lt;/p&gt;

&lt;p&gt;To make the app user-friendly, I wanted a workflow where users could select images from their system gallery and save them directly to a public folder like &lt;code&gt;Pictures/PhotoConvert&lt;/code&gt;. I used &lt;code&gt;MediaStore&lt;/code&gt; APIs to write output files, ensuring they immediately show up in the user's system gallery without requiring manual file-syncing apps. Handling URI permissions across different Android OS versions (from Android 10 up to 14) required a fair share of conditional logic and thorough testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Local beats cloud for utility:&lt;/strong&gt; Keeping everything on-device is not only a privacy win, but it's also incredibly fast. Without network latency, local conversion is almost instantaneous.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory is the primary constraint:&lt;/strong&gt; When building mobile developer utilities, you cannot treat memory as infinite. Profiling memory usage with Android Studio's Profiler was essential to catch leaks early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the UI simple:&lt;/strong&gt; Users want utility apps to get out of their way. Jetpack Compose helped keep the code clean and let me focus on the underlying performance of the conversion engine.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Try It Out
&lt;/h3&gt;

&lt;p&gt;If you have ever found yourself needing to convert image formats on the go, you can try out the app. It's completely free, runs offline, and doesn't track you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Play Link:&lt;/strong&gt; &lt;a href="https://play.google.com/store/apps/details?id=com.sudarshan.photoconvert" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.sudarshan.photoconvert&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Details:&lt;/strong&gt; You can find more details and other projects at the site &lt;a href="https://photoconvert.getinfotoyou.com" rel="noopener noreferrer"&gt;https://photoconvert.getinfotoyou.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know what you think, or what features you would like to see added next!&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>mobiledev</category>
      <category>imageconverter</category>
    </item>
    <item>
      <title>Ditching the Command Line: How I Built a Client-Side Image Compressor</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 12 Aug 2026 14:30:29 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/ditching-the-command-line-how-i-built-a-client-side-image-compressor-3a2j</link>
      <guid>https://dev.to/getinfotoyou/ditching-the-command-line-how-i-built-a-client-side-image-compressor-3a2j</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Every web developer knows the drill: you are wrapping up a project, writing a blog post, or preparing assets for a client, and you realize your images are massive. A single 4MB hero image will devastate your Google PageSpeed score.&lt;/p&gt;

&lt;p&gt;So, how do you handle it?&lt;/p&gt;

&lt;h1&gt;
  
  
  The Hard Way: CLI Pipelines, Photo Editors, and Privacy Risks
&lt;/h1&gt;

&lt;p&gt;Usually, developers solve this in one of three ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The CLI / Build Script Route&lt;/strong&gt;: You install dependencies and write a custom Node.js script using Sharp or configure an imagemin pipeline. It works, but it is absolute overkill when you just need to compress a single image for a readme file or a landing page section. Plus, native dependency compilation issues on different operating systems are a constant headache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Desktop Software Route&lt;/strong&gt;: You open Figma, Photoshop, or GIMP, export the image, adjust settings, and export again. It works, but it breaks your workflow and adds unnecessary steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Online Server-Based Route&lt;/strong&gt;: You search for a quick web-based tool. You drag your image in, wait for it to upload, let their server process it, and then download it. But what about privacy? If you are handling proprietary designs or client assets, uploading them to an unknown server is a security concern. Moreover, these sites are often cluttered with ads or restrict you with paywalls and daily usage limits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wanted a better workflow: the speed of an online tool, the privacy of a local script, and zero configuration.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enter ImageSlim: Doing It the Easy Way
&lt;/h1&gt;

&lt;p&gt;To solve this, I built &lt;a href="https://imageslim.getinfotoyou.com" rel="noopener noreferrer"&gt;ImageSlim&lt;/a&gt;. It is a web application that compresses and resizes JPG, PNG, and WebP files directly in your browser. Because the processing occurs entirely on the client side, your images never touch an external server. It is fast, secure, and doesn't require command-line setups.&lt;/p&gt;

&lt;h1&gt;
  
  
  Technical Insights: Under the Hood
&lt;/h1&gt;

&lt;p&gt;Creating an image compressor that runs completely on the client side presented some interesting engineering decisions. Here is how I structured the tool.&lt;/p&gt;

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

&lt;p&gt;I kept the architecture as lightweight as possible to ensure instant load times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 &amp;amp; CSS&lt;/strong&gt;: A responsive interface built with vanilla CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt;: Leveraging browser APIs to read, resize, and compress image data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 Canvas&lt;/strong&gt;: The core renderer that handles drawing and export operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Web-First Compression Flow
&lt;/h2&gt;

&lt;p&gt;The application logic uses three native browser features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;File Reader API&lt;/strong&gt;: We capture the user's uploaded file and load it into memory as an image source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canvas Rendering&lt;/strong&gt;: We draw the image onto an off-screen &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; element at the desired resolution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blob Conversion&lt;/strong&gt;: We call the native &lt;code&gt;toBlob()&lt;/code&gt; method on the canvas. This method accepts parameters for target format and compression quality (a float between 0.0 and 1.0):
&lt;code&gt;canvas.toBlob((blob) =&amp;gt; { /* Handle the compressed file */ }, 'image/jpeg', quality);&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Handling Technical Hurdles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory Limits&lt;/strong&gt;: Large images (like 10MB camera uploads) can exhaust browser memory on mobile devices. The app dynamically checks and bounds resolution scaling to keep performance stable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alpha Channel Support&lt;/strong&gt;: Transparent PNGs often lose their transparency when processed. The tool handles alpha channels correctly, allowing users to convert PNGs to modern WebP files while maintaining transparent backgrounds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Lessons Learned
&lt;/h1&gt;

&lt;p&gt;Building this showed me how capable modern web browsers have become. Tasks that once required heavy backend processors can now run locally in milliseconds. By utilizing client-side computing, we can build tools that respect user privacy, eliminate hosting bills for server-side processing, and provide instant results.&lt;/p&gt;

&lt;p&gt;If you are looking for a straightforward way to optimize your assets without compromising privacy, give &lt;a href="https://imageslim.getinfotoyou.com" rel="noopener noreferrer"&gt;ImageSlim&lt;/a&gt; a try. I would love to hear your feedback on how it fits into your workflow.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>performance</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why I Built an Ad-Free SIP Calculator (and How to Handle Clean Math in JavaScript)</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Mon, 10 Aug 2026 14:30:27 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/why-i-built-an-ad-free-sip-calculator-and-how-to-handle-clean-math-in-javascript-imf</link>
      <guid>https://dev.to/getinfotoyou/why-i-built-an-ad-free-sip-calculator-and-how-to-handle-clean-math-in-javascript-imf</guid>
      <description>&lt;p&gt;We've all been there: you're trying to plan your monthly budget or figure out how much a Systematic Investment Plan (SIP) will yield over the next decade. You search for a mutual fund calculator, click on a top result, and are immediately hit with cookie banners, sticky ads, and a pop-up asking for your phone number to "unlock your results". If you manage to bypass that, you're left fighting with clunky slider controls that jump from 5 years to 20 years on a mobile screen.&lt;/p&gt;

&lt;p&gt;I got tired of giving away my contact details just to run a simple compound interest calculation. I wanted a tool that was fast, ad-free, and worked instantly on any device without trackers. So, I decided to build one myself: &lt;a href="https://sipcalculator.getinfotoyou.com" rel="noopener noreferrer"&gt;https://sipcalculator.getinfotoyou.com&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Built It
&lt;/h3&gt;

&lt;p&gt;The goal was straightforward: create a tool that does one thing exceptionally well. For Indian investors and finance enthusiasts, calculating SIP returns is a frequent task. The mathematics behind it isn't complex, yet existing tools wrap it in layers of marketing bloat. I wanted to see if I could build a calculator that loads under 500ms, stores no user data, and offers an intuitive visual breakdown of wealth gained versus principal invested.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tech Stack
&lt;/h3&gt;

&lt;p&gt;To keep the page load times minimal and avoid running up hosting costs, I opted for a serverless, static approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML5 &amp;amp; Vanilla CSS&lt;/strong&gt;: No heavy UI frameworks. CSS grid and flexbox handled the layout, while CSS custom variables made styling the sliders and toggle states straightforward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla JavaScript&lt;/strong&gt;: Used for all the calculations, chart updates, and DOM manipulation. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight SVG Canvas&lt;/strong&gt;: Instead of pulling in a massive charting library like Chart.js or D3, I wrote a custom SVG renderer to draw the pie chart showing the investment breakdown. This saved about 100kb in bundle size.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Slider Usability on Mobile&lt;/strong&gt;&lt;br&gt;
Standard HTML sliders (&lt;code&gt;&amp;lt;input type="range"&amp;gt;&lt;/code&gt;) can be frustrating to use on touch screens. If you want to select exactly 12% expected return, a tiny swipe might jump from 10% to 15%. I solved this by implementing a dual-control input: users can either drag the slider or tap the output number to type in an exact value. Syncing these two states in vanilla JS without creating infinite loops required careful event listener handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Compounding Formula&lt;/strong&gt;&lt;br&gt;
The formula for SIP returns is:&lt;br&gt;
&lt;code&gt;M = P * [ ( (1 + i)^n - 1 ) / i ] * (1 + i)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;M&lt;/code&gt; is the maturity amount&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;P&lt;/code&gt; is the monthly investment&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt; is the periodic rate of interest (annual rate / 12 / 100)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt; is the number of payments (tenure in years * 12)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Translating this into JavaScript is straightforward, but formatting large numbers in the Indian numbering system (Lakhs and Crores) rather than the standard Western millions/billions format required implementing &lt;code&gt;Intl.NumberFormat('en-IN')&lt;/code&gt; to ensure localized readability for the target audience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;p&gt;Building this project reinforced a valuable web development lesson: you don't always need a framework. By keeping the app client-side, the load time is virtually instantaneous, and the user's financial inputs never leave their browser. &lt;/p&gt;

&lt;p&gt;If you want to calculate your investment planning without the noise, you can try out the tool here: &lt;a href="https://sipcalculator.getinfotoyou.com" rel="noopener noreferrer"&gt;https://sipcalculator.getinfotoyou.com&lt;/a&gt;. I'd love to hear your feedback on the slider behavior and calculations.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>finance</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Built a Hashtag Safety Checker After Watching a Brand Accidentally Promote a Banned Tag to 50K Followers</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Fri, 07 Aug 2026 14:31:07 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/i-built-a-hashtag-safety-checker-after-watching-a-brand-accidentally-promote-a-banned-tag-to-50k-46k2</link>
      <guid>https://dev.to/getinfotoyou/i-built-a-hashtag-safety-checker-after-watching-a-brand-accidentally-promote-a-banned-tag-to-50k-46k2</guid>
      <description>&lt;h2&gt;
  
  
  The Incident That Started Everything
&lt;/h2&gt;

&lt;p&gt;A few years ago, I was doing some freelance social media consulting for a small e-commerce brand. Their marketing coordinator — smart, detail-oriented, genuinely good at her job — spent an afternoon crafting the perfect product launch post. Right hashtag count, good mix of niche and broad tags, timed for peak engagement.&lt;/p&gt;

&lt;p&gt;One of the hashtags she picked had been quietly banned by Instagram months earlier. Not flagged, not removed — just silently suppressed. The post went out to 50,000 followers and effectively went nowhere. No reach. No engagement spike. The launch flopped, and it took us three days to figure out why.&lt;/p&gt;

&lt;p&gt;That stayed with me. It's such a solvable problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What HashtagSafety Actually Does
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://hashtagsafety.getinfotoyou.com" rel="noopener noreferrer"&gt;HashtagSafety&lt;/a&gt; to catch exactly that kind of mistake before it costs you. Paste in a hashtag, and it checks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Banned or restricted status&lt;/strong&gt; — tags that platforms have flagged and suppressed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inappropriate associations&lt;/strong&gt; — tags that look harmless but are commonly used alongside problematic content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk scoring&lt;/strong&gt; — a simple indicator of whether a tag is likely to hurt your reach&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The target user isn't a developer. It's a social media manager who has fifteen minutes before a post goes live and needs a quick gut-check.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Side
&lt;/h2&gt;

&lt;p&gt;The stack is deliberately boring in a good way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Vanilla JS, no framework. The UI is simple enough that React would've been overkill and would've added load time I didn't want.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Node.js with a lightweight Express server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data layer&lt;/strong&gt;: A combination of a maintained banned hashtag dataset (community-sourced, periodically updated) and some pattern-matching logic I wrote for detecting contextual risk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting&lt;/strong&gt;: Deployed on a simple VPS — nothing fancy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hardest part wasn't the tech. It was the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Challenge: Hashtag Data Is a Moving Target
&lt;/h2&gt;

&lt;p&gt;Platforms don't publish lists of banned hashtags. There's no API for it. Instagram, TikTok, and Twitter/X have never made this information officially accessible — probably intentionally.&lt;/p&gt;

&lt;p&gt;What exists is a patchwork of community-maintained lists, anecdotal reports from creators, and periodic crowdsourced audits. I spent a significant amount of time just evaluating data sources, cross-referencing lists, and building a pipeline to keep things reasonably current.&lt;/p&gt;

&lt;p&gt;The pattern-matching layer was its own challenge. Some hashtags aren't banned outright but consistently appear alongside content that gets suppressed. Detecting that association without manual curation of every tag is genuinely tricky. I ended up building a scoring heuristic that weighs several signals rather than trying to make a binary safe/unsafe call.&lt;/p&gt;

&lt;p&gt;False positives are a real concern here. Telling someone a perfectly fine hashtag is dangerous would be worse than not checking at all. So I err toward flagging uncertainty rather than making confident wrong calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons From Building It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ship something useful, not something complete.&lt;/strong&gt; The first version of this had maybe 20% of the features I originally planned. It was still useful. I launched it, got feedback, and iterated. Waiting for the "full" version would've meant waiting another six months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data maintenance is a product feature.&lt;/strong&gt; The code is the easy part. Keeping the dataset current, handling edge cases, understanding why a tag got flagged — that ongoing work is what makes the tool trustworthy. I underestimated how much time this would take.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simple UX is a design decision, not a shortcut.&lt;/strong&gt; I resisted the urge to add dashboards, history tracking, bulk analysis, and a dozen other features. The tool does one thing and tries to do it well. That constraint is intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who This Is Actually For
&lt;/h2&gt;

&lt;p&gt;If you're a solo developer, this probably isn't your daily-use tool. But if you're building something for social media managers or content creators, or if you're doing any kind of social media work yourself, it's worth bookmarking.&lt;/p&gt;

&lt;p&gt;The scenario that comes up most often: you're about to post something time-sensitive — a product launch, a response to a trending topic, a campaign tied to a live event — and you want a quick sanity check before you hit publish. That's exactly what this is for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hashtagsafety.getinfotoyou.com" rel="noopener noreferrer"&gt;HashtagSafety&lt;/a&gt; is free to use. Paste a hashtag, get a result. No account required.&lt;/p&gt;

&lt;p&gt;If you're building something in the social media tooling space and want to compare notes on data sourcing or API approaches, I'm always up for that conversation in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>socialmedia</category>
      <category>javascript</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Building a Minimalist Global Public Holiday Tracker Without the Bloat</title>
      <dc:creator>Getinfo Toyou</dc:creator>
      <pubDate>Wed, 05 Aug 2026 14:30:26 +0000</pubDate>
      <link>https://dev.to/getinfotoyou/building-a-minimalist-global-public-holiday-tracker-without-the-bloat-1bbc</link>
      <guid>https://dev.to/getinfotoyou/building-a-minimalist-global-public-holiday-tracker-without-the-bloat-1bbc</guid>
      <description>&lt;p&gt;When working across borders—whether as a remote developer, HR manager, or frequent traveler—keeping track of international holidays is a daily necessity. A few months ago, I was coordinating a release schedule with colleagues in three different countries. I needed to verify which days our team members would be out of the office. What should have taken 10 seconds ended up taking several minutes of wading through ad-cluttered websites, broken drop-down menus, and multi-step forms just to see a basic list of dates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I Built It
&lt;/h3&gt;

&lt;p&gt;I realized there was a clear gap for a simple, fast tool focused entirely on clarity. That friction led me to build &lt;a href="https://holidaysync.getinfotoyou.com" rel="noopener noreferrer"&gt;HolidaySync&lt;/a&gt;. The philosophy behind it is straightforward: give users immediate access to public holiday calendars worldwide without requiring registration, downloads, or navigation through intrusive popups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplicity in Design and Tech Stack
&lt;/h3&gt;

&lt;p&gt;To achieve a genuinely frictionless experience, every design and engineering decision was evaluated against one question: Does this make finding a holiday faster for the user?&lt;/p&gt;

&lt;p&gt;Here is a breakdown of the tech stack chosen to enforce this principle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight Frontend:&lt;/strong&gt; Vanilla JavaScript and semantic HTML. Avoiding heavy framework runtimes kept the initial page weight under 40KB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive CSS System:&lt;/strong&gt; Written from scratch using modern CSS Grid and Flexbox with CSS variables for seamless light and dark themes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge Data Layer:&lt;/strong&gt; An API integration with public holiday databases, wrapped in a lightweight edge worker that handles caching and response normalization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Challenges and Trade-offs
&lt;/h3&gt;

&lt;p&gt;Creating a simple UI often requires resolving underlying complexity behind the scenes. Here are two main challenges I encountered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handling Region-Specific and Variable Date Holidays:&lt;/strong&gt; Not all holidays land on fixed calendar dates. Easter, Lunar New Year, and religious observances move every year, while regional holidays might only apply to specific states or provinces. Structuring the data model to handle state-level variations without cluttering the primary overview meant introducing a secondary view that reveals regional breakdowns only when requested.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Smart Edge Caching:&lt;/strong&gt; To ensure fast response times anywhere in the world, I set up a stale-while-revalidate caching layer at the edge. Since holiday data changes infrequently, requests are served directly from edge locations near the user, with background revalidation ensuring any official date changes update smoothly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resisting Feature Creep:&lt;/strong&gt; It was tempting to add user accounts, custom calendar syncs, and complex notifications right away. Keeping the launch scope strictly focused on quick lookup proved to be the right choice for usability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance is User Experience:&lt;/strong&gt; When a web app loads instantly and displays exactly what the user came for, the experience feels intuitive and reliable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;If you need a quick, clean way to check public holidays for your remote team, HR planning, or upcoming travel, you can try &lt;a href="https://holidaysync.getinfotoyou.com" rel="noopener noreferrer"&gt;HolidaySync&lt;/a&gt;. I would love to hear your feedback on how to make it even more useful while maintaining its minimal footprint.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
