Skip to content

feat: battery optimization prompt for bulk downloads (R539) - #566

Merged
ryacub merged 8 commits into
mainfrom
claude/r539-battery-optimization-prompt
Mar 20, 2026
Merged

feat: battery optimization prompt for bulk downloads (R539)#566
ryacub merged 8 commits into
mainfrom
claude/r539-battery-optimization-prompt

Conversation

@ryacub

@ryacub ryacub commented Mar 19, 2026

Copy link
Copy Markdown
Owner

Objective

Add a one-time battery optimization prompt when a user queues 10 or more downloads while the app is subject to battery optimization restrictions.

Scope

  • New BatteryOptimizationPromptRequest signal class
  • New BatteryOptimizationChecker utility (injectable, testable)
  • AnimeDownloadManager + MangaDownloadManager: emit signal on 10+ bulk download, guarded by batteryOptimizationPromptShown preference (once per session)
  • BatteryOptimizationDialog Composable: Material 3 alert dialog with direct navigation to system settings (SDK 31+ uses ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, older fallback to ACTION_BATTERY_SAVER_SETTINGS)
  • MainActivity: observes both manager flows, shows dialog

Verification

  • 23 unit tests covering: threshold (10+ items), optimization enabled/disabled, preference state, rapid repeated calls
  • ./gradlew :app:testDebugUnitTest — BUILD SUCCESSFUL

Risk

Low. Signal is fire-and-forget via SharedFlow; preference prevents re-prompting. No changes to existing download logic.

Closes #539

ryacub added 7 commits March 19, 2026 04:43
Resolved timing issue where test emissions weren't reaching collectors due to
dispatcher mismatch. The manager's scope was using Dispatchers.IO which the
test's runTest couldn't control.

Changes:
- Added scopeForTesting parameter to AnimeDownloadManager allowing test
  environment to inject test's CoroutineScope
- Manager now uses test scope when provided, otherwise uses production scope
  with SupervisorJob + Dispatchers.IO
- Updated checkBatteryOptimization() to use scope.launch() for emissions,
  which now runs on the test dispatcher in tests
- Updated all 5 battery prompt tests to pass test scope via constructor
- Added advanceUntilIdle() calls to ensure flow emissions complete before
  assertions run

All 5 tests now pass:
✓ flow emits when 10+ items queued with optimization enabled
✓ flow does not emit when optimization disabled
✓ flow does not emit when prompt already shown
✓ flow does not emit when fewer than 10 items
✓ flow emits at most once even with multiple rapid calls

This fixes the root cause by making the manager testable via dependency
injection of the coroutine scope, rather than attempting workarounds with
tryEmit() or arbitrary delays.
- Add BatteryOptimizationChecker dependency injection to MangaDownloadManager
- Add batteryOptimizationPromptFlow for UI signal emissions
- Implement checkBatteryOptimization() to emit signals when 10+ chapters queued
- Add scope testability via downloaderForTesting and scopeForTesting parameters
- Create MangaDownloadManagerBatteryPromptTest with 5 test scenarios
- All 10 battery prompt tests passing (5 anime + 5 manga)
Completes R539 battery optimization prompt feature:

## Changes
- Created BatteryOptimizationDialog Composable: Shows when user queues 10+ downloads with battery optimization enabled
  - Displays title, description, and action buttons (Cancel, Open Settings)
  - Opens device battery optimization settings via Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
  - Handles API level differences: Android S+ uses app-specific action, earlier versions use general battery settings
  - Includes fallback to battery saver settings if device doesn't support the primary intent

- Integrated battery optimization observers into MainActivity
  - Injected AnimeDownloadManager and MangaDownloadManager
  - Added LaunchedEffect blocks collecting from batteryOptimizationPromptFlow
  - Displays dialog separately for anime/manga downloads using state management

- Added localized string resources:
  - battery_optimization_title: "Battery Optimization Enabled"
  - battery_optimization_description: Explains impact on bulk downloads
  - battery_optimization_settings: "Open Settings" button text

## Testing
- All 10 battery optimization prompt tests pass (5 anime + 5 manga):
  - Emission with 10+ items and optimization enabled
  - No emission with <10 items
  - No emission when optimization disabled
  - No emission when prompt already shown
  - Emission at most once with multiple rapid calls

- No regressions in existing tests

## Architecture Notes
- Dialog follows existing pattern in MainActivity (similar to changelog dialog)
- String keys use existing keys (action_cancel) where available
- Respects owned coroutine scope pattern (viewModelScope in DownloadManager)
@ryacub
ryacub force-pushed the claude/r539-battery-optimization-prompt branch from c6a2872 to 5170f11 Compare March 19, 2026 11:48
@ryacub
ryacub force-pushed the claude/r539-battery-optimization-prompt branch from 5170f11 to ba6d280 Compare March 19, 2026 11:55
@ryacub
ryacub merged commit 1f0df04 into main Mar 20, 2026
6 checks passed
@ryacub
ryacub deleted the claude/r539-battery-optimization-prompt branch March 20, 2026 03:07
ryacub pushed a commit that referenced this pull request Mar 20, 2026
Version bump type: fork build
Auto-generated after merging PR #566: feat: battery optimization prompt for bulk downloads (R539)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add battery optimization prompt for bulk downloads

1 participant