feat: snackbar after sync (synced N / nothing to sync / server unreachable)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,8 +7,9 @@ import me.hgsky.synq.data.db.CaptureDao
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
suspend fun syncPending(dao: CaptureDao, client: SynqApiClient, settings: SynqSettings) {
|
||||
suspend fun syncPending(dao: CaptureDao, client: SynqApiClient, settings: SynqSettings): Int {
|
||||
val pending = dao.getPendingAndFailed()
|
||||
var synced = 0
|
||||
for (capture in pending) {
|
||||
dao.updateStatus(capture.id, "syncing", null)
|
||||
val result = client.postCapture(capture, settings)
|
||||
@@ -16,8 +17,10 @@ suspend fun syncPending(dao: CaptureDao, client: SynqApiClient, settings: SynqSe
|
||||
is PostResult.Accepted, is PostResult.AlreadySeen -> {
|
||||
val now = OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
|
||||
dao.markSynced(capture.id, now)
|
||||
synced++
|
||||
}
|
||||
is PostResult.Failed -> dao.updateStatus(capture.id, "failed", result.error)
|
||||
}
|
||||
}
|
||||
return synced
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
@@ -62,9 +64,13 @@ fun CaptureScreen(
|
||||
val recentTags by vm.recentTags.collectAsState()
|
||||
val lastSyncedAt by vm.lastSyncedAt.collectAsState()
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val snackbarState = remember { SnackbarHostState() }
|
||||
val context = LocalContext.current
|
||||
|
||||
LaunchedEffect(Unit) { focusRequester.requestFocus() }
|
||||
LaunchedEffect(Unit) {
|
||||
vm.snackbar.collect { msg -> snackbarState.showSnackbar(msg) }
|
||||
}
|
||||
LaunchedEffect(prefill) {
|
||||
if (!prefill.isNullOrEmpty()) vm.setBody(prefill)
|
||||
}
|
||||
@@ -83,6 +89,7 @@ fun CaptureScreen(
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
snackbarHost = { SnackbarHost(snackbarState) },
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("synq") },
|
||||
|
||||
@@ -4,9 +4,11 @@ import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
@@ -37,6 +39,9 @@ class CaptureViewModel(app: Application) : AndroidViewModel(app) {
|
||||
private val _state = MutableStateFlow(CaptureUiState())
|
||||
val state: StateFlow<CaptureUiState> = _state.asStateFlow()
|
||||
|
||||
private val _snackbar = MutableSharedFlow<String>(extraBufferCapacity = 1)
|
||||
val snackbar = _snackbar.asSharedFlow()
|
||||
|
||||
val recentTags: StateFlow<List<String>> = dao.getRecentTagsJson()
|
||||
.map { jsonList ->
|
||||
val seen = LinkedHashSet<String>()
|
||||
@@ -93,9 +98,12 @@ class CaptureViewModel(app: Application) : AndroidViewModel(app) {
|
||||
try {
|
||||
val settings = synqApp.settings.settings.first()
|
||||
val client = SynqApiClient()
|
||||
if (client.checkHealth(settings.serverUrl)) {
|
||||
syncPending(dao, client, settings)
|
||||
if (!client.checkHealth(settings.serverUrl)) {
|
||||
_snackbar.tryEmit("server unreachable")
|
||||
return@launch
|
||||
}
|
||||
val synced = syncPending(dao, client, settings)
|
||||
_snackbar.tryEmit(if (synced == 0) "nothing to sync" else "synced $synced")
|
||||
} finally {
|
||||
_state.value = _state.value.copy(isSyncing = false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user