An Android app that makes data annotation fun and efficient! Swipe through your JSON entries, label them with custom fields, and export your work to CSV.
Want to try the app without building from source?
- π Beta Access: Sign up at swipelabel.com for early access
- π οΈ Build from Source: Follow the Building the App instructions below
- π± Tinder-style interface: Swipe gestures or tap buttons to dislike/like - cards fill the screen for maximum visibility
- π Multi-card views: Configure multiple card views per entry, tap left/right to navigate between them
- β¬ οΈ Undo functionality: Go back to previous cards with confirmation dialog (deletes annotation on undo)
β οΈ Data protection: Warning dialog prevents accidental data loss when starting new projects- π― Unlimited custom fields: Add as many annotation fields as you need
- π 4 Field Types: TEXT, NUMBER, CHECKBOX (multi-select), SLIDER (numeric range)
- π Multiple JSON formats: Auto-detects JSON Array, JSONL, and Label Studio formats
- π Format compliance: UTF-8 BOM support, key-order independence, spec-compliant parsing
- π Nested field support: Dot-notation paths for accessing nested JSON (e.g.,
data.image) - π 3 Display Modes: Reading (scrollable text), Scaled (ASCII art optimized), Image (URL/base64)
- πΌοΈ Image Support: Display images from URLs or base64 data with smart caching (Coil) and pinch-to-zoom
- π¨ ASCII Art Support: Monospace font, auto-sizing, and proper alignment for ASCII art
- π Statistics Dashboard: View like/dislike ratio, dataset progress, and field completion rates
- πΎ CSV & Label Studio export: Export to CSV or back to Label Studio JSON format
- βοΈ Settings Screen: Manage privacy and appearance preferences
- π Privacy Controls: GDPR-compliant crash reporting opt-out
- π Theme Selection: Light/Dark/System modes with lavender & sage color palette
- π¨ Material Design 3: Beautiful, modern UI with custom brand icon
- π·οΈ Custom App Icon: Adaptive icon featuring lavender card and swipe gesture on sage green
- ποΈ MVVM Architecture: Clean, maintainable code structure
- π Crash Reporting: Production-ready error tracking with Firebase Crashlytics
- Select JSON File: Choose a JSON file containing your data
- Configure Fields:
- Select identifier field (unique ID for each entry)
- Add card views: select field + display mode (Reading/Scaled/Image) for each
- Add unlimited custom annotation fields with 4 types:
- TEXT: Free-form text input
- NUMBER: Numeric input with validation
- CHECKBOX: Multi-select from custom options (min 2)
- SLIDER: Numeric slider with custom min/max/step
- Start Swiping:
- Tap left/right sides of card to navigate between card views
- Swipe left or tap Dislike button to dislike an entry
- Swipe right or tap Like button to label it
- Fill Annotations: Enter data for your custom fields (tap Done on keyboard to dismiss)
- View Statistics: Check like/dislike ratio, dataset progress, and field completion
- Export Results: Choose export format and save to Downloads folder
- CSV: For spreadsheets and data analysis
- Label Studio JSON: Re-import to Label Studio (only for Label Studio source files)
- Manage Settings: Tap "Settings" on home screen to:
- Control crash reporting (on/off)
- Choose theme (Light/Dark/System)
- Test crash reporting: Tap "System default" 7 times to unlock Developer Tools (debug builds only)
Multiple test files included for different JSON formats:
examples/sample_data.json- 10 simple text entriesexamples/asciieverything_batch_000_100pieces_20250928_141020.json- 100 ASCII art entries
examples/test_jsonl.jsonl- Standard JSONL formatexamples/test_jsonl_with_bom.jsonl- Tests UTF-8 BOM handling
examples/test_labelstudio.json- Standard Label Studio tasksexamples/test_labelstudio_unordered.json- Tests key-order independence
All formats auto-detected - just select the file!
Example configuration (any format):
- Identifier Field:
id - Display Field:
textorart(arrays render line-by-line) - Custom Fields: Define based on your labeling needs
- Language: Kotlin 2.2.0
- UI: Jetpack Compose with Material Design 3
- Architecture: MVVM + Clean Architecture
- Dependency Injection: Hilt 2.57.2
- Database: Room 2.8.1 (v6 with entry status tracking and normalized annotation_values table)
- Background Processing: WorkManager with Hilt integration
- JSON Parsing: Kotlinx Serialization with streaming API (memory-efficient for large files)
- State Management: DataStore for session persistence and app preferences
- Image Loading: Coil 3.3.0 with smart caching (25% memory + 250MB disk) and network support (OkHttp)
- Crash Reporting: Firebase Crashlytics with custom instrumentation
- Analytics: Firebase Analytics
- CSV Export: OpenCSV
- Navigation: Navigation Compose
- Build: Gradle 8.9, AGP 8.7.3
This app handles JSON file access using a streaming + background import approach with automatic format detection:
- File Selection: Uses
ActivityResultContracts.OpenDocument()to let users select JSON files - Format Detection:
JsonFormatDetectorauto-detects JSON Array, JSONL, or Label Studio format - UTF-8 BOM Handling: Automatically strips BOM if present (common in Windows files)
- Immediate Copy: Selected file copied to app storage with temporary URI permission
- Background Import: WorkManager processes large files in background with progress tracking
- Streaming Parser:
JsonStreamingParseruses kotlinx.serialization streaming API- Processes entries one-by-one (memory-efficient)
- Batch inserts every 100 entries to Room database
- Tested with 100-entry ASCII art dataset
- Session Persistence: DataStore maintains config and progress across app restarts
Supported JSON Formats:
- JSON Array:
[{...}, {...}]- Standard array format - JSONL:
{...}\n{...}\n- Newline-delimited (one object per line) - Label Studio:
[{"data": {...}}]- Nested data key format with dot-notation support (e.g.,id,data.image)
Why this approach?
- Android's DownloadProvider doesn't support persistent URI permissions
- Large JSON files (100+ MB) won't crash the app
- Users can close app during import - WorkManager continues in background
- Format auto-detection provides seamless user experience
Key Implementation Files:
HomeScreen.kt/FileManager.kt- Copies file to app storageJsonFormatDetector.kt- Auto-detects JSON format with BOM supportImportWorker.kt- Background processing with WorkManagerJsonStreamingParser.kt- Memory-efficient streaming with batch insertionSessionManager.kt- DataStore persistence for config and progressdocs/format-specifications/- Complete format specs and compliance docs
com.example.swipelabel/
βββ data/
β βββ local/ # Room database and DAOs (Entry, Project, Annotation)
β βββ model/ # Data models
β βββ repository/ # DataRepository, JsonStreamingParser, FileManager
β βββ workers/ # WorkManager background tasks
βββ domain/
β βββ usecase/ # Business logic use cases
βββ ui/
β βββ components/ # Shared composables (display modes)
β βββ navigation/ # Navigation graph
β βββ screens/ # UI screens (Home, ProjectList, Settings, Config, Swipe, Statistics, Export)
β βββ theme/ # App theming
βββ util/ # Utilities (CrashlyticsLogger)
βββ di/ # Dependency injection modules
- Android Studio Hedgehog (2023.1.1) or newer
- JDK 17
- Android SDK with API 34
- Firebase project (for crash reporting)
To build this app, create your own Firebase project and add google-services.json - see FIREBASE_SETUP.md
Quick steps:
- Create a Firebase project at https://console.firebase.google.com/
- Register your Android app with package name:
com.example.swipelabel - Download
google-services.jsonand place it in theapp/directory - See FIREBASE_SETUP.md for detailed instructions
Note: The google-services.json file is gitignored. A template (google-services.json.example) is provided for reference.
- Clone the repository
- Set up Firebase (see above)
- Open project in Android Studio
- Sync Gradle files
- Run on emulator or physical device (API 26+)
./gradlew build./gradlew installDebug- Copy
examples/sample_data.jsonto your Android device - Open SwipeLabel app
- Tap "Select JSON File" and choose the sample data
- Configure as suggested above
- Start swiping and labeling!
- Export your annotations to CSV
See what's new: Check out the Releases page for detailed release notes and version history.
Download the app: To get the latest beta version, sign up at swipelabel.com
Potential features for future versions:
Support for more field typesβ Implemented in v1.3.0Multiple display fields on cardsβ Implemented in v1.5.0Undo swipe functionalityβ Implemented in v1.0.8Image display supportβ Implemented in v1.6.0Nested field supportβ Implemented in v1.6.1Statistics dashboardβ Implemented in v1.7.0Crash reportingβ Implemented in v1.8.0Privacy controlsβ Implemented in v1.8.0- Performance monitoring (Firebase Performance)
- Remote configuration
- Search and filter entries
- Batch operations
- Cloud sync
SwipeLabel is licensed under the Apache License, Version 2.0. See LICENSE for the full license text.
Copyright 2025 SwipeLabel Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This project uses several open source libraries. See NOTICE for full attribution and license information for all dependencies.
Built with β€οΈ using modern Android development practices and Claude AI assistance.