feat: confirm dialog before starting sync on mobile data

Replace the disabled-Start + secondary-Start-Anyway button pattern
with a single always-enabled Start button that shows an AlertDialog
when the connection is metered/mobile, requiring explicit confirmation
before running a potentially gigabyte-scale operation.

https://claude.ai/code/session_01U8qF9mK4UBvXsXP1zNMXfX
This commit is contained in:
Claude
2026-03-13 22:49:40 +00:00
parent 90d7b0c678
commit 9d49b2da4f
2 changed files with 37 additions and 10 deletions
@@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
@@ -40,8 +41,12 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
@@ -63,6 +68,7 @@ fun EventSyncScreen(
val syncState by syncViewModel.syncState.collectAsStateWithLifecycle()
val isMobileOrMetered by accountViewModel.settings.isMobileOrMeteredConnection.collectAsStateWithLifecycle()
var showMobileDataDialog by remember { mutableStateOf(false) }
Scaffold(
topBar = {
@@ -152,20 +158,17 @@ fun EventSyncScreen(
is EventSyncViewModel.SyncState.Error,
-> {
Button(
onClick = { syncViewModel.start() },
onClick = {
if (isMobileOrMetered) {
showMobileDataDialog = true
} else {
syncViewModel.start()
}
},
modifier = Modifier.fillMaxWidth(),
enabled = !isMobileOrMetered || syncState !is EventSyncViewModel.SyncState.Idle,
) {
Text(stringRes(R.string.event_sync_start))
}
if (isMobileOrMetered && syncState is EventSyncViewModel.SyncState.Idle) {
OutlinedButton(
onClick = { syncViewModel.start() },
modifier = Modifier.fillMaxWidth(),
) {
Text(stringRes(R.string.event_sync_start_anyway))
}
}
}
is EventSyncViewModel.SyncState.Running -> {
@@ -182,6 +185,29 @@ fun EventSyncScreen(
}
}
if (showMobileDataDialog) {
AlertDialog(
onDismissRequest = { showMobileDataDialog = false },
title = { Text(stringRes(R.string.event_sync_mobile_data_dialog_title)) },
text = { Text(stringRes(R.string.event_sync_wifi_warning)) },
confirmButton = {
Button(
onClick = {
showMobileDataDialog = false
syncViewModel.start()
},
) {
Text(stringRes(R.string.event_sync_start_anyway))
}
},
dismissButton = {
TextButton(onClick = { showMobileDataDialog = false }) {
Text(stringRes(R.string.event_sync_cancel))
}
},
)
}
Spacer(Modifier.height(16.dp))
}
}
+1
View File
@@ -1760,6 +1760,7 @@
<string name="event_sync_step2">Download all events that mention you and send them to your inbox relays.</string>
<string name="event_sync_step3">Download all direct messages addressed to you and send them to your DM relays.</string>
<string name="event_sync_wifi_warning">⚠ You appear to be on a metered or mobile connection. This operation can transfer a very large amount of data. Connect to Wi-Fi before starting.</string>
<string name="event_sync_mobile_data_dialog_title">Use Mobile Data?</string>
<string name="event_sync_start">Start Sync</string>
<string name="event_sync_start_anyway">Start Anyway (mobile data)</string>
<string name="event_sync_cancel">Cancel</string>