Major Changes:
- Convert ChunkedUploadManager.java to Kotlin with coroutines
- Convert ZipUtil.java to Kotlin with Dispatchers.IO
- Convert FileController.java to Kotlin
ANR Fixes:
- All file I/O now runs on Dispatchers.IO (prevents main thread blocking)
- Chunk reading (4-10MB) moved to background thread
- File compression (zipping) moved to background thread
- Instant cancellation with proper coroutine handling
Chunking Improvements:
- Update thresholds to match chunk sizes (4MB mobile, 10MB WiFi)
- Files smaller than chunk size use standard upload
- Proper zipping logic: skip single .zip files, zip everything else
Progress & UX:
- Add PREPARING state for file compression phase
- Show 'Compressing file: X%' in notification during zip
- Throttle updates to 500ms for smooth notification display
- Broadcast ACTION_ZIP_PROGRESS for in-app UI
- ViewModel listens and displays zip progress
- Cancel button visible and functional during all phases
Cancellation:
- Instant cancel during zipping (checks every 8KB)
- Clean cancellation using CancellationException
- Automatic cleanup of partial zip files
- No error logs for user-initiated cancellation
Files Changed:
- ChunkedUploadManager: Java → Kotlin, uses coroutines + Dispatchers.IO
- ZipUtil: Java → Kotlin, cancellable with progress throttling
- FileController: Java → Kotlin, proper async job management
- UploadStrategySelector: Updated chunk size thresholds
- FileUploadForegroundService: Added PREPARING state, zip progress handling
- MainViewModel: Listen for ACTION_ZIP_PROGRESS, display status
- AppConstants: Added ACTION_ZIP_PROGRESS constant
- Add parallel uploads toggle in settings (experimental, disabled by default)
- Increase mobile chunk size from 2MB to 4MB
- Configure parallel uploads: 3 chunks on WiFi, 2 on mobile (if enabled), 1 sequential (if disabled)
- Fix progress tracking when retrying missing chunks (subtract bytes to prevent >100%)
- Implement URI to File conversion using FileController.saveContentUriToFile()
- Properly extract filename from URI using ContentResolver
- Store actual File object instead of null, enabling uploads to work
- Add pause/resume/cancel actions to notification bar
- Add pause/resume/cancel buttons to in-app upload progress card
- Track upload state (paused, uploading, cancelled) and upload type (chunked vs standard)
- Chunked uploads support pause/resume, standard uploads only support cancel
- Fix notification to persist cancelled state without flickering
- Implement automatic zipping when multiple dumpstate files are selected
- Single file uploads directly (preserves existing behavior)
- Multiple files are zipped with timestamp naming (e.g., dumpstates_20251227_205530.zip)
- Zip files stored in cache directory and cleaned up after upload completes or on error
- Add upload progress persistence across app restarts
- Track upload state in SharedPreferences to detect ongoing uploads
- ViewModel checks for in-progress uploads on initialization and shows loading state
- Fixes crash when reopening app during upload by properly maintaining state
- Improve upload completion notification
- Display upload code in notification text (e.g., "Upload complete! Code: ABC123")
- Use stopForeground(STOP_FOREGROUND_DETACH) to keep notification visible after service stops
- Notification persists until user dismisses it, ensuring code is always visible
- Add progress broadcast from service to ViewModel with bytes and percentage
- Display global progress bar above tab content in MainScreen
- Show upload progress (MB uploaded/total, percentage) persistently
- Remove redundant in-tab progress indicators
- Progress stays visible when switching between Upload and Dumpstate tabs
- Matches cloud storage app UX (Google Drive, Dropbox)
- Convert UploadController, FileUploadForegroundService, and UploadHistory from Java to Kotlin
- Move all upload logic from UploadController into FileUploadForegroundService for better encapsulation
- Service now directly manages ChunkedUploadManager instances instead of delegating to controller
- Add FOREGROUND_SERVICE_IMMEDIATE flag to bypass Android 14+ notification display delay (up to 10s for DATA_SYNC services)
- Add notification update logging for better debugging
- Simplify UploadController to only handle service launching and server file deletion
Fixes notification appearing late during uploads (was showing around 70% progress instead of immediately).
Replaces separate welcome and server setup screens with a unified 5-page
onboarding carousel that guides users through:
- App introduction and backend requirements
- Notification permission with explanation
- All files access permission with explanation
- Server configuration (address, port, key) with QR scanning
- Completion confirmation
Also adds notification permission checks before uploads to ensure upload
progress notifications can be displayed. Users are prompted for permission
if not already granted, then upload proceeds automatically.
Changes:
- Create OnboardingScreen.kt with 5-page carousel flow
- Add onboarding completion tracking to PreferencesUtil
- Update navigation to show onboarding on first launch
- Add notification permission checks to upload tabs
- Add roundIcon attribute to manifest for better icon display
Add password masking to the client key field for better security. Users can toggle visibility using an eye icon button to view or hide the key as needed.
Reposition the QR code scan button to appear immediately after the server configuration fields (address, port, and client key) that it populates, improving the logical flow and making it clearer what the button does.
Add visual cues and instructions to clarify that upload parameter fields can be edited:
- Add instructional text at top of dialog
- Add edit icons to both text fields
- Update labels to include "(tap to edit)" hint
- Change placeholders to action-oriented text
- Auto-focus first field to show keyboard immediately
- Add keyboard actions for better navigation
Users can now set default upload parameters (max downloads and expiry hours) in settings and choose whether to show the upload parameters dialog or use saved defaults directly.
Changes:
- Add upload preferences: default max downloads, default expiry hours, and ask before upload toggle
- Update SettingsScreen with new upload defaults section
- Modify UploadParamsDialog to initialize with saved defaults instead of hardcoded values
- Update DumpstateTab and GeneralUploadTab to check askBeforeUpload preference and bypass dialog when disabled
- Replace READ_EXTERNAL_STORAGE permission with all files access check
- Open app settings when permission is needed so user can grant it
- Check permission status when returning from settings
- Launch file picker automatically if permission is granted
- Replace XML layouts with Compose screens for all 5 Activities
- Implement Material 3 theme with Google Blue/Green color scheme matching app icon
- Add device-aware navigation with bottom tabs for Samsung devices
- Remove action bar for modern edge-to-edge UI design
- Update Kotlin to 1.9.22 for Compose Compiler compatibility
- Add Compose dependencies and configure build system
- Implement MainViewModel for upload state management
- Create reusable dialog components for upload parameters and results
- Preserve all existing Java controllers and services (UI-only migration)
Adds QR code scanning functionality to both ServerSetupActivity and
SettingsActivity, allowing users to auto-fill server configuration by
scanning a QR code from the server's admin dashboard.
Changes:
- Add ZXing Android Embedded library (v4.3.0) for QR scanning
- Add CAMERA permission to AndroidManifest
- Create QrServerConfig model to parse and validate QR JSON data
- Create QrScannerUtil for shared scanning functionality
- Extend PermissionUtil with camera permission handling
- Add "Scan QR Code" button to ServerSetupActivity with hint text
- Add "Scan QR Code" button to SettingsActivity
- Add QR scan icon and string resources
- Configure Gradle Java toolchain auto-detection
The QR code contains JSON with server address, port, and client key
which are automatically populated into the input fields when scanned.