Telegram

I BUILT A TINY SWIPE-BASED GALLERY CLEANER IN KOTLIN + COMPOSE ONLY A FEW MB

I Built a Tiny Swipe-Based Gallery Cleaner in Kotlin + Compose Only a Few MB

In the modern digital era, our smartphones have become the primary repository for our most cherished memories. High-resolution cameras and infinite cloud storage possibilities have led to an exponential growth in the number of photos we capture. However, this convenience comes with a significant downside: digital hoarding. We accumulate thousands of screenshots, blurry images, duplicate shots, and obsolete memes, resulting in a cluttered, disorganized photo gallery that slows down device performance and makes finding specific moments a frustrating endeavor.

Addressing this ubiquitous problem, we have developed a minimalist yet powerful Android application: a swipe-based gallery cleaner. This app is not just another utility; it is a carefully engineered solution designed to transform the tedious task of photo management into a fluid, intuitive experience. By leveraging the modern Kotlin programming language and the declarative power of Jetpack Compose, we have created an application that is not only lightweight—weighing in at just a few megabytes—but also exceptionally performant and user-friendly.

Our mission was to strip away the bloatware features found in many gallery management apps and focus entirely on the core functionality: rapidly deciding the fate of your images. Inspired by the frictionless swiping mechanics of popular dating applications, we have gamified the decluttering process. This article details the architecture, design philosophy, and technical implementation of our lightweight gallery cleaner, offering a comprehensive look at how we achieved a seamless user experience with a minimal footprint.

The Problem of Digital Photo Clutter

Before delving into the technical specifics of our application, it is crucial to understand the scope of the problem we aimed to solve. The average Android user possesses thousands of photos. Over time, a significant portion of these images lose their value. We take multiple shots to get the perfect angle, save screenshots for temporary reference, or download images that are viewed once and forgotten.

The Performance Impact of Unoptimized Media

A gallery filled with unnecessary data does more than just cause visual noise. It impacts the device’s performance. Media scanning services must index every file, consuming system resources. Backup applications attempt to upload gigabytes of low-value data, draining battery life and consuming bandwidth. Furthermore, large local storage usage can lead to sluggish file system operations, affecting the overall responsiveness of the device.

The Psychological Burden of Clutter

Beyond technical performance, there is a psychological component to digital clutter. A disorganized photo roll creates a subtle sense of anxiety. Searching for a specific memory amidst a sea of irrelevance is time-consuming and frustrating. Users often express a desire to “clean up” their galleries but abandon the task because traditional gallery apps require tedious tapping, selecting, and deleting—actions that are repetitive and fatiguing for the thumb.

Existing Solutions: Over-Engineered or Inefficient

The market is saturated with “cleaner” apps, but many suffer from significant drawbacks. Some are laden with intrusive advertisements, while others require excessive permissions, raising privacy concerns. Many existing solutions are heavy, requiring hundreds of megabytes of storage space just to perform a simple function. We recognized a gap in the market for a tool that is transparent, fast, privacy-focused, and aesthetically pleasing. Our solution addresses these pain points by focusing on a single, refined interaction model: the swipe.

Technical Architecture: Kotlin and Jetpack Compose

The decision to build this application using Kotlin and Jetpack Compose was deliberate and strategic. These technologies represent the modern standard for Android development, offering distinct advantages over legacy frameworks like Java and XML-based layouts.

The Power of Kotlin

Kotlin is a statically typed programming language developed by JetBrains and officially supported by Google for Android development. Its concise syntax reduces boilerplate code significantly, allowing developers to express logic with fewer lines while maintaining readability and type safety. For a lightweight app, every kilobyte counts. Kotlin’s features, such as lambda expressions, data classes, and extension functions, enabled us to streamline the codebase. This results in a smaller APK size, which is a critical factor for users conscious of their storage usage.

Jetpack Compose: A Declarative UI Paradigm

Jetpack Compose is Android’s modern toolkit for building native UI. Unlike the traditional View system, which is imperative, Compose is declarative. This means the UI is a direct reflection of the app’s state. When the state changes (for example, a photo is deleted), the UI automatically updates to reflect that change. This paradigm shift simplifies UI development and drastically reduces the code required to manage complex界面 interactions.

For our swipe-based gallery, Compose offers specific advantages. Its gesture detection APIs are robust and easy to implement. We can define how a card reacts to drag events with just a few lines of code. Furthermore, Compose’s lazy loading capabilities (specifically LazyColumn and LazyVerticalGrid) are essential for rendering large collections of images efficiently. These components only compose the items currently visible on the screen, ensuring that the app remains responsive even when scrolling through thousands of photos.

Achieving a Lightweight Footprint (Under 2MB)

One of our proudest achievements is keeping the application size to just a few megabytes. In an era where apps routinely exceed 100MB, this minimal footprint is a testament to efficient engineering. We avoided heavy third-party libraries for image loading and networking, opting instead for Android’s native Coil library, which is built on Kotlin Coroutines and excels at loading images quickly with minimal memory overhead.

By stripping away unnecessary dependencies and utilizing the compact nature of Kotlin/Compose, we ensured that the app downloads quickly even on slower networks and occupies negligible storage space. This lightweight nature also contributes to faster startup times and reduced RAM usage, preventing the app from bogging down the user’s device.

Core Features and Functionality

Our gallery cleaner is built around a singular, focused workflow. We stripped away non-essential features to create a streamlined user experience centered on the “Keep vs. Delete” decision-making process.

The Tinder-Inspired Swipe Mechanic

The defining feature of our app is the swipe-based interface. Drawing inspiration from the ubiquitous swiping gestures of dating apps, we implemented a card-stack layout. Each photo is presented as a card that the user can interact with.

This interaction model is ergonomic and fast. It utilizes the natural reach of the thumb and minimizes the cognitive load required to make a decision. The fluid animations provided by Jetpack Compose ensure that these transitions are smooth and satisfying, encouraging users to continue cleaning their gallery.

Local-First Privacy Architecture

Privacy is a paramount concern in the current app ecosystem. Many cleaner apps upload thumbnails or metadata to the cloud for processing. We strictly oppose this practice. Our application operates entirely on-device.

Native Localization Support

Recognizing our global user base, we built the application with robust localization support from the ground up. Using Android’s resource system and Kotlin’s string handling, the interface automatically adapts to the user’s system language. We currently support a wide array of languages, including English, Spanish, French, German, Chinese, and more. This ensures that users worldwide can navigate the app intuitively without language barriers.

Efficient Image Rendering

Performance is critical when dealing with large media libraries. We utilize Coil for image loading, which efficiently manages memory by using an in-memory cache and downsampling images to fit the UI view. This prevents OutOfMemory errors, which are common in poorly optimized gallery apps. Furthermore, we implemented placeholders and cross-fade animations to ensure a polished visual experience while images load from the storage.

Deep Dive into the Development Process

Building a seemingly simple app like a gallery cleaner requires rigorous planning and precise execution. Here is an inside look at the development journey.

State Management in Compose

Managing state is the heart of any Compose application. For our gallery, we defined a ViewModel that holds the list of images and the current swipe state.

  1. Flow of Data: We query the MediaStore to fetch image URIs. This data is converted into a StateFlow in the ViewModel.
  2. UI State: The Compose UI collects this flow using collectAsState. When the user swipes a card, we update the state in the ViewModel.
  3. Undo Functionality: To prevent accidental deletions, we implemented a temporary “trash” state. When a photo is deleted, it is moved to a temporary holding area for a few seconds, displaying an “Undo” snackbar. If the user taps Undo, the file is restored; otherwise, the file is permanently deleted from the storage. This requires careful handling of file descriptors and ensuring that the file is not immediately unrecoverable.

Handling Permissions Gracefully

Android’s storage permissions have evolved with Scoped Storage. Our app targets the latest Android versions and handles permissions responsibly.

Animation and Haptics

The “feel” of an app is just as important as its functionality. We leveraged Compose’s AnimatedVisibility and animate*AsState APIs to create buttery-smooth transitions. When a card is swiped away, it doesn’t just disappear; it slides, rotates, and fades out, providing visual feedback that reinforces the user’s action. Additionally, we integrated haptic feedback. A subtle vibration occurs when the user initiates a swipe, and a distinct pattern plays when a photo is successfully deleted. This tactile feedback makes the digital interaction feel physical and grounded.

UI/UX Design Principles

Our design philosophy revolves around minimalism and clarity. The interface is designed to be invisible, allowing the photos to take center stage.

Visual Hierarchy and Color Palette

We utilized a neutral color palette with high contrast to distinguish actions. Typically, green or blue tones indicate “Keep,” while red tones indicate “Delete.” However, to avoid color blindness issues, we also use distinct icons and text labels. The app layout consists of a top bar with a simple title and a settings icon, and a central content area containing the card stack. The bottom bar provides context, such as the remaining image count and progress indicators. We avoided heavy shadows and complex gradients, sticking to Material Design 3 guidelines for a clean, modern look.

Reducing Cognitive Load

A major challenge in photo cleaning is “decision fatigue.” To mitigate this, we designed the UI to present one task at a time: Keep or Delete? We removed progress bars that constantly remind the user of the remaining work, focusing instead on the immediate task. The swipe mechanics allow the user to enter a “flow state,” where decisions become rapid and intuitive.

Accessibility Considerations

While the app is swipe-centric, we ensured it remains accessible.

Performance Optimization Strategies

A “tiny” app must also be a “fast” app. We implemented several optimization strategies to ensure the app runs smoothly on low-end devices as well as flagship phones.

Memory Management

Handling thousands of image URIs requires careful memory management. We do not load full-resolution bitmaps into memory. Instead, we load thumbnails provided by the MediaStore. This significantly reduces RAM usage. The Coil library handles the caching strategy, ensuring that once an image is viewed, it stays in the memory cache for rapid re-access without hitting the disk again.

Asynchronous Processing

File I/O operations (reading the gallery and deleting files) are performed on background threads using Kotlin Coroutines. The Dispatchers.IO context is used for these heavy operations, ensuring that the UI thread remains unblocked. This guarantees that animations and touch responses remain 60fps (frames per second), even while the app is scanning the device for images.

Lazy Loading with Compose

As mentioned, Jetpack Compose’s lazy layouts are a game-changer. When the user browses the gallery in grid view (if we implement a secondary view) or simply scrolls through the list of pending decisions, Compose recycles the UI components. It does not render items that are off-screen. This technique allows the app to handle libraries containing tens of thousands of images without stuttering or lagging.

Challenges and Solutions in Kotlin Compose

Developing with a relatively new framework like Jetpack Compose presents unique challenges. We navigated these to deliver a stable product.

Gesture Handling Complexity

Coordinating swipe gestures with the underlying scrollable containers can be tricky. If the sensitivity is too high, accidental swipes occur; too low, and the app feels unresponsive. We fine-tuned the pointerInput modifiers to detect horizontal swipes distinctly from vertical scrolls. We also implemented a threshold logic: the card must be dragged a certain percentage of the screen width before the delete action is triggered.

List Performance with Large Datasets

Initially, rendering a list of 10,000 images caused recomposition bottlenecks. We optimized this by ensuring that we only pass stable references to Composables. We used remember effectively to prevent unnecessary recalculations of image bitmaps and utilized derivedStateOf to compute the progress bar updates only when the underlying dataset changed, rather than on every frame.

Localization and Global Reach

To ensure our app resonates with a global audience, we treated localization as a core feature, not an afterthought.

String Resource Management

We structured our string resources strictly, avoiding hard-coded text. Every user-facing string is stored in strings.xml with appropriate placeholders and formatting arguments. This structure makes it seamless for community contributors to add new languages or for professional translators to provide accurate localization.

Cultural Adaptation

Beyond direct translation, we considered cultural contexts. For example, the interpretation of colors (e.g., red for “delete” vs. “good luck”) varies. Our design uses universally understood icons alongside text to bridge potential cultural gaps. The swipe direction (left vs. right) is also intuitive across most cultures, as it mimics physical interactions like flipping through a deck of cards.

Future Roadmap and Potential Features

While the current version is lean and focused, we have a roadmap for future enhancements that align with our philosophy of minimalism.

Smart Filtering and AI Suggestions

Future versions may leverage on-device Machine Learning (ML) to categorize images. We could implement a “fuzzy” detector to identify blurry photos or an OCR scanner to find text-heavy screenshots that might no longer be relevant. These features would be computed entirely locally to maintain our privacy-first promise.

Advanced Sorting and Tagging

We plan to introduce basic sorting options, allowing users to filter their gallery by date, size, or resolution before starting the cleaning process. A “favorites” tagging system could also allow users to quickly archive important photos without leaving the app interface.

Cloud Sync Integration (Optional)

While the core app is offline, we are considering a modular approach where users can optionally enable a plugin to sync their “kept” photos to specific cloud providers. This would remain an opt-in feature, ensuring the base app remains lightweight and offline-first.

We have successfully engineered a swipe-based gallery cleaner that meets the demands of modern Android users. By utilizing Kotlin and Jetpack Compose, we delivered a high-performance application with a footprint of only a few megabytes. The Tinder-inspired swipe mechanic transforms a mundane chore into an engaging, fluid experience.

Our commitment to privacy, localization, and lightweight architecture sets this application apart from the bloated alternatives currently available. We believe that software should serve the user, respect their device resources, and protect their data. This app is the embodiment of those principles. Whether you are a power user seeking to optimize your device’s performance or a casual user looking to rediscover the joy of a decluttered photo library, our solution provides the perfect tool for the job.

We invite you to experience the future of photo management. Swipe away the clutter, keep the memories, and enjoy a streamlined, responsive gallery experience tailored to your needs. Download the app today and take the first step toward digital organization.


Magisk Modules: Enhancing Your Android Experience

Welcome to Magisk Modules, your premier destination for Android customization and system enhancement. At Magisk Module Repository (https://magiskmodule.gitlab.io), we host a comprehensive collection of modules designed to elevate your device’s performance, aesthetics, and functionality.

Our repository is dedicated to providing high-quality, safe, and innovative modules that leverage the power of Magisk root. Whether you are looking to optimize system resources, install custom fonts, or add unique features unavailable in standard firmware, our repository is the ultimate resource for the Android enthusiast community. We ensure that every module is tested and curated to maintain system stability while pushing the boundaries of what your Android device can achieve. Visit us today to explore the full potential of your device.

Explore More
Redirecting in 20 seconds...