v1.0.63: live sync progress counters, pause/resume, .gitignore fix
Build & Release APK / build (push) Has been cancelled
Build & Release APK / build (push) Has been cancelled
- SyncEngine: accepts onProgress callback — emits uploaded/downloaded/ deleted/bytes counts atomically as each file completes - SyncWorker: streams progress to WorkManager data so the UI can poll it live; reports per-run counters in the completion notification; adds pause/resume support - HomeViewModel/PairDetailViewModel: subscribe to live WorkManager progress and surface it via SyncProgress state - SyncPairEntity/SyncPairDao/SyncDatabase: persist last-run counters (uploaded, downloaded, deleted, bytesTransferred) in the DB with a Room migration (v3→v4) - AppModule: provides WorkManager as an injectable singleton - .gitignore: add .kotlin/ to exclude compiler session files Security: no new issues — all logging via Timber (debug-only), DB queries use Room parameterized API, file sharing via FileProvider. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,20 +15,27 @@ import com.syncflow.data.db.entities.*
|
||||
SyncConflictEntity::class,
|
||||
SyncEventEntity::class,
|
||||
],
|
||||
version = 3,
|
||||
version = 4,
|
||||
exportSchema = true,
|
||||
)
|
||||
@TypeConverters(DbConverters::class)
|
||||
abstract class SyncDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
// Wipe file states: timestamps were stored as epoch-seconds, now epoch-millis.
|
||||
// All previously saved states are wrong so we drop and re-learn on next sync.
|
||||
val MIGRATION_2_3 = object : Migration(2, 3) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("DELETE FROM sync_file_states")
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_3_4 = object : Migration(3, 4) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE sync_pairs ADD COLUMN lastSyncUploaded INTEGER NOT NULL DEFAULT 0")
|
||||
db.execSQL("ALTER TABLE sync_pairs ADD COLUMN lastSyncDownloaded INTEGER NOT NULL DEFAULT 0")
|
||||
db.execSQL("ALTER TABLE sync_pairs ADD COLUMN lastSyncDeleted INTEGER NOT NULL DEFAULT 0")
|
||||
db.execSQL("ALTER TABLE sync_pairs ADD COLUMN lastSyncBytesTransferred INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
}
|
||||
abstract fun cloudAccountDao(): CloudAccountDao
|
||||
abstract fun syncPairDao(): SyncPairDao
|
||||
|
||||
@@ -29,8 +29,8 @@ interface SyncPairDao {
|
||||
@Delete
|
||||
suspend fun delete(entity: SyncPairEntity)
|
||||
|
||||
@Query("UPDATE sync_pairs SET lastSyncAt = :at, lastSyncResult = :result, pendingConflicts = :conflicts WHERE id = :id")
|
||||
suspend fun updateSyncResult(id: Long, at: Instant, result: SyncStatus, conflicts: Int)
|
||||
@Query("UPDATE sync_pairs SET lastSyncAt = :at, lastSyncResult = :result, pendingConflicts = :conflicts, lastSyncUploaded = :uploaded, lastSyncDownloaded = :downloaded, lastSyncDeleted = :deleted, lastSyncBytesTransferred = :bytes WHERE id = :id")
|
||||
suspend fun updateSyncResult(id: Long, at: Instant, result: SyncStatus, conflicts: Int, uploaded: Int, downloaded: Int, deleted: Int, bytes: Long)
|
||||
|
||||
@Query("UPDATE sync_pairs SET lastSyncResult = :status WHERE id = :id")
|
||||
suspend fun updateStatus(id: Long, status: SyncStatus)
|
||||
|
||||
@@ -53,6 +53,11 @@ data class SyncPairEntity(
|
||||
val lastSyncAt: Instant?,
|
||||
val lastSyncResult: SyncStatus,
|
||||
val pendingConflicts: Int,
|
||||
// Last sync outcome counters (persist across pause/resume)
|
||||
val lastSyncUploaded: Int = 0,
|
||||
val lastSyncDownloaded: Int = 0,
|
||||
val lastSyncDeleted: Int = 0,
|
||||
val lastSyncBytesTransferred: Long = 0L,
|
||||
)
|
||||
|
||||
fun SyncPairEntity.toDomain() = SyncPair(
|
||||
|
||||
Reference in New Issue
Block a user