Skip to content

Commit fd1bf8e

Browse files
feat: indicator for backup in progress
1 parent 0af3609 commit fd1bf8e

File tree

3 files changed

+47
-6
lines changed

3 files changed

+47
-6
lines changed

app/src/main/java/org/androidlabs/applistbackup/BackupService.kt

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ import android.util.Log
2424
import androidx.core.app.NotificationCompat
2525
import androidx.core.net.toFile
2626
import androidx.documentfile.provider.DocumentFile
27+
import kotlinx.coroutines.CoroutineScope
28+
import kotlinx.coroutines.Dispatchers
29+
import kotlinx.coroutines.SupervisorJob
30+
import kotlinx.coroutines.flow.MutableStateFlow
31+
import kotlinx.coroutines.launch
2732
import org.androidlabs.applistbackup.data.BackupAppDetails
2833
import org.androidlabs.applistbackup.data.BackupAppInfo
2934
import org.androidlabs.applistbackup.data.BackupFormat
@@ -49,12 +54,17 @@ data class BackupFile(
4954
class BackupService : Service() {
5055
private val tag: String = "BackupService"
5156

57+
private val serviceJob = SupervisorJob()
58+
private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)
59+
5260
companion object {
5361
const val SERVICE_CHANNEL_ID = "BackupService"
5462
const val BACKUP_CHANNEL_ID = "Backup"
5563

5664
const val FILE_NAME_PREFIX = "app-list-backup-"
5765

66+
val isRunning = MutableStateFlow(false)
67+
5868
private var onCompleteCallback: ((Uri) -> Unit)? = null
5969

6070
fun getBackupFolder(context: Context): BackupRawFile? {
@@ -224,9 +234,23 @@ class BackupService : Service() {
224234

225235
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
226236
Log.d(tag, "start: ${intent.toString()}")
227-
val startDate = Date()
237+
228238
val source = intent?.getStringExtra("source")
229239
val inputFormat = intent?.getStringExtra("format")
240+
241+
serviceScope.launch {
242+
performBackup(source, inputFormat)
243+
stopForeground(STOP_FOREGROUND_REMOVE)
244+
stopSelf()
245+
}
246+
247+
return START_STICKY
248+
}
249+
250+
private fun performBackup(source: String?, inputFormat: String?) {
251+
isRunning.value = true
252+
253+
val startDate = Date()
230254
createNotificationChannels()
231255

232256
val backupsDir = getBackupFolder(this)
@@ -712,9 +736,7 @@ class BackupService : Service() {
712736
manager.notify(getNotificationId(), endNotification)
713737
}
714738

715-
stopForeground(STOP_FOREGROUND_REMOVE)
716-
717-
return START_STICKY
739+
isRunning.value = false
718740
}
719741

720742
private fun getNotificationId(): Int {
@@ -765,6 +787,7 @@ class BackupService : Service() {
765787

766788
override fun onDestroy() {
767789
super.onDestroy()
790+
serviceJob.cancel()
768791
Log.d(tag, "destroy")
769792
}
770793
}

app/src/main/java/org/androidlabs/applistbackup/backupnow/BackupFragment.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import androidx.compose.material3.Text
1818
import androidx.compose.runtime.Composable
1919
import androidx.compose.runtime.DisposableEffect
2020
import androidx.compose.runtime.LaunchedEffect
21+
import androidx.compose.runtime.collectAsState
22+
import androidx.compose.runtime.getValue
2123
import androidx.compose.runtime.livedata.observeAsState
2224
import androidx.compose.ui.Alignment
2325
import androidx.compose.ui.Modifier
@@ -81,6 +83,7 @@ private fun ActivityState(
8183
val isNotificationEnabled = viewModel.notificationEnabled.observeAsState(initial = false)
8284
val backupUri = viewModel.backupUri.observeAsState()
8385
val backupFiles = viewModel.backupFiles.observeAsState(initial = emptyList())
86+
val isRunning by viewModel.isBackupRunning.collectAsState()
8487

8588
LaunchedEffect(key1 = true) {
8689
viewModel.refreshNotificationStatus()
@@ -123,8 +126,11 @@ private fun ActivityState(
123126
Spacer(modifier = Modifier.height(16.dp))
124127

125128
if (backupUri.value != null) {
126-
Button(onClick = runBackup) {
127-
Text(text = stringResource(R.string.backup_now))
129+
Button(
130+
onClick = runBackup,
131+
enabled = !isRunning
132+
) {
133+
Text(text = stringResource(if (isRunning) R.string.in_progress else R.string.backup_now))
128134
}
129135

130136
if (backupFiles.value.isNotEmpty()) {

app/src/main/java/org/androidlabs/applistbackup/backupnow/BackupViewModel.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import androidx.lifecycle.viewModelScope
1111
import kotlinx.coroutines.Dispatchers
1212
import kotlinx.coroutines.Job
1313
import kotlinx.coroutines.delay
14+
import kotlinx.coroutines.flow.MutableStateFlow
15+
import kotlinx.coroutines.flow.StateFlow
16+
import kotlinx.coroutines.flow.asStateFlow
1417
import kotlinx.coroutines.isActive
1518
import kotlinx.coroutines.launch
1619
import org.androidlabs.applistbackup.BackupFile
@@ -29,6 +32,9 @@ class BackupViewModel(application: Application) : AndroidViewModel(application)
2932
private val _backupFiles = MutableLiveData<List<BackupFile>>(emptyList())
3033
val backupFiles: LiveData<List<BackupFile>> = _backupFiles
3134

35+
private val _isBackupRunning = MutableStateFlow(false)
36+
val isBackupRunning: StateFlow<Boolean> = _isBackupRunning.asStateFlow()
37+
3238
private var backupSettingsListener: SharedPreferences.OnSharedPreferenceChangeListener? = null
3339
private var pollingJob: Job? = null
3440

@@ -39,6 +45,12 @@ class BackupViewModel(application: Application) : AndroidViewModel(application)
3945

4046
backupSettingsListener =
4147
Settings.observeBackupUri(getApplication(), ::refreshBackups)
48+
49+
viewModelScope.launch {
50+
BackupService.isRunning.collect { state ->
51+
_isBackupRunning.value = state
52+
}
53+
}
4254
}
4355

4456
private fun refreshBackups() {

0 commit comments

Comments
 (0)