feat(android): Quick Settings tile toggling camera backup

TileService reporting active/inactive from CameraUploadSettings; a tap
arms or disarms the periodic MediaStore backup worker.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
pull/3589/head
Tomas Dvorak 2 weeks ago
parent ae8d8566b9
commit 226a41bd61

@ -242,7 +242,7 @@ Lives in `android/` in this repo. Kotlin + Jetpack Compose, Material 3.
- **API**: `api/v4` REST + OAuth token (entities exist: `oauthclient`, `oauthgrant`) — same surface the desktop `cloudreve-api` crate documents; port its models as the spec - **API**: `api/v4` REST + OAuth token (entities exist: `oauthclient`, `oauthgrant`) — same surface the desktop `cloudreve-api` crate documents; port its models as the spec
- **Core features**: browse/download/upload files, share links, full-text search (done — query bar + offset pagination + parent-path/snippet rows), camera-upload (done — periodic WorkManager MediaStore sync, Wi-Fi-only constraint, ID dedup, settings dialog), offline-favorite files (done — "Keep offline" downloads to filesDir/offline, DataStore registry, star dialog with open/refresh/remove), local sync folder (done — SAF tree → remote mirror, upload-only, mtime/size dedup) - **Core features**: browse/download/upload files, share links, full-text search (done — query bar + offset pagination + parent-path/snippet rows), camera-upload (done — periodic WorkManager MediaStore sync, Wi-Fi-only constraint, ID dedup, settings dialog), offline-favorite files (done — "Keep offline" downloads to filesDir/offline, DataStore registry, star dialog with open/refresh/remove), local sync folder (done — SAF tree → remote mirror, upload-only, mtime/size dedup)
- **System integration** (the "native, complete" ask): share-sheet target (done — SEND/SEND_MULTIPLE → UploadWorker), DocumentsProvider (done — Files-app browse/open/thumb/rename/delete/search), quick-share tile, notifications on share/task events (done — periodic /workflow poll → terminal-state notifications) - **System integration** (the "native, complete" ask): share-sheet target (done — SEND/SEND_MULTIPLE → UploadWorker), DocumentsProvider (done — Files-app browse/open/thumb/rename/delete/search), quick-share tile (done — QS tile toggles camera backup), notifications on share/task events (done — periodic /workflow poll → terminal-state notifications)
- **Auth**: OAuth flow (done — browser consent + PKCE + `cloudreve://mount` deep link); later passkey if backend exposes - **Auth**: OAuth flow (done — browser consent + PKCE + `cloudreve://mount` deep link); later passkey if backend exposes
- **WebDAV bridge**: `/dav` works as fallback file access until SDK matures - **WebDAV bridge**: `/dav` works as fallback file access until SDK matures
- Non-goals: iOS, tablet-first layouts (works, not optimized) - Non-goals: iOS, tablet-first layouts (works, not optimized)

@ -51,8 +51,8 @@ CI runs `assembleDebug` on every PR.
and a remote folder — periodic WorkManager worker mirrors new/changed and a remote folder — periodic WorkManager worker mirrors new/changed
files upstream, subdirectory structure preserved, unchanged files files upstream, subdirectory structure preserved, unchanged files
skipped via mtime/size signatures, Wi-Fi-only option skipped via mtime/size signatures, Wi-Fi-only option
- Quick Settings tile toggling camera backup, with active/inactive state
## Planned next ## Planned next
- Quick-share tile
- No iOS. Ever. - No iOS. Ever.

@ -54,6 +54,17 @@
android:resource="@xml/file_paths" /> android:resource="@xml/file_paths" />
</provider> </provider>
<service
android:name=".tile.SyncTileService"
android:exported="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<provider <provider
android:name=".provider.CloudreveDocumentsProvider" android:name=".provider.CloudreveDocumentsProvider"
android:authorities="${applicationId}.documents" android:authorities="${applicationId}.documents"

@ -0,0 +1,56 @@
package org.cloudreve.android.tile
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import org.cloudreve.android.CloudreveApp
import org.cloudreve.android.work.CameraUploadWorker
/**
* Quick Settings tile: shows whether camera backup is armed and toggles
* it. Tap → backup on; tap again → off.
*/
class SyncTileService : TileService() {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onStartListening() {
super.onStartListening()
scope.launch { refresh() }
}
override fun onClick() {
super.onClick()
val app = applicationContext as CloudreveApp
scope.launch {
val cam = app.cameraUploadSettings.snapshotNow()
if (cam.enabled) {
app.cameraUploadSettings.setEnabled(false)
CameraUploadWorker.cancel(applicationContext)
} else {
app.cameraUploadSettings.setEnabled(true)
CameraUploadWorker.apply(applicationContext, cam.wifiOnly)
}
refresh()
}
}
private suspend fun refresh() {
val app = applicationContext as CloudreveApp
val enabled = app.cameraUploadSettings.snapshotNow().enabled
qsTile?.apply {
state = if (enabled) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
subtitle = if (enabled) "Camera backup on" else "Camera backup off"
updateTile()
}
}
override fun onDestroy() {
super.onDestroy()
scope.cancel()
}
}
Loading…
Cancel
Save