v1.0.25: multi-select files, unified notification, dark theme, icon redesign
- FilesScreen: long-press enters selection mode, bulk share/delete toolbar, BackHandler - FilesViewModel: ShareMultiple action, isSelectionMode/selectedCount state, download-to-cache for open/share - FileWatchService: recursive FileObserver per subdirectory; unified notification updated with sync result via WorkManager flow observation - SyncWorker: silent flag suppresses notifications when triggered by watcher; emits KEY_RESULT_SUMMARY output data - Passbolt-inspired dark theme (Red700/Red500 primary, near-black surface) - App icon: circular AutoSync-style sync arrows (cyan gradient, deep navy background) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,9 @@ import android.os.Looper
|
||||
import android.provider.DocumentsContract
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import kotlinx.coroutines.flow.first
|
||||
import com.syncflow.MainActivity
|
||||
import com.syncflow.R
|
||||
import com.syncflow.data.db.SyncFileStateDao
|
||||
@@ -214,9 +216,34 @@ class FileWatchService : Service() {
|
||||
val pair = syncPairDao.getById(pairId)
|
||||
if (pair == null || !pair.isEnabled) return@launch
|
||||
Timber.d("FileWatchService: triggering sync for pair $pairId after debounce")
|
||||
val req = SyncWorker.buildOneTimeRequest(pairId, wifiOnly, chargingOnly)
|
||||
|
||||
val req = SyncWorker.buildOneTimeRequest(pairId, wifiOnly, chargingOnly, silent = true)
|
||||
WorkManager.getInstance(applicationContext)
|
||||
.enqueueUniqueWork("onchange_$pairId", ExistingWorkPolicy.KEEP, req)
|
||||
|
||||
// Update notification while sync is in progress
|
||||
updateNotificationDynamic("Syncing: ${pair.name}…")
|
||||
|
||||
// Wait for completion and show result in the persistent notification
|
||||
scope.launch {
|
||||
try {
|
||||
val info = WorkManager.getInstance(applicationContext)
|
||||
.getWorkInfoByIdFlow(req.id)
|
||||
.first { it?.state?.isFinished == true }
|
||||
val summary = info?.outputData?.getString(SyncWorker.KEY_RESULT_SUMMARY)
|
||||
val watchCount = fileObservers.keys.size + contentObservers.size
|
||||
val watching = "Watching $watchCount folder${if (watchCount != 1) "s" else ""}"
|
||||
if (info?.state == WorkInfo.State.SUCCEEDED && summary != null) {
|
||||
updateNotificationDynamic("${pair.name}: $summary — $watching")
|
||||
} else {
|
||||
updateNotificationDynamic("$watching")
|
||||
}
|
||||
delay(12_000)
|
||||
updateNotificationDynamic(null) // revert to default watching text
|
||||
} catch (_: Exception) {
|
||||
updateNotificationDynamic(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +268,7 @@ class FileWatchService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildNotification(count: Int): Notification {
|
||||
private fun buildNotification(count: Int, overrideText: String? = null): Notification {
|
||||
val tapIntent = PendingIntent.getActivity(
|
||||
this, 0,
|
||||
Intent(this, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP },
|
||||
@@ -250,7 +277,7 @@ class FileWatchService : Service() {
|
||||
return NotificationCompat.Builder(this, CHANNEL_WATCH)
|
||||
.setContentTitle("SyncFlow")
|
||||
.setContentText(
|
||||
if (count > 0) "Watching $count folder${if (count != 1) "s" else ""} for changes"
|
||||
overrideText ?: if (count > 0) "Watching $count folder${if (count != 1) "s" else ""} for changes"
|
||||
else "Starting file watcher…"
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_sync)
|
||||
@@ -264,4 +291,10 @@ class FileWatchService : Service() {
|
||||
val nm = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
nm.notify(NOTIFICATION_ID, buildNotification(count))
|
||||
}
|
||||
|
||||
private fun updateNotificationDynamic(overrideText: String?) {
|
||||
val count = fileObservers.keys.size + contentObservers.size
|
||||
val nm = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
nm.notify(NOTIFICATION_ID, buildNotification(count, overrideText))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user