mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
fix(settings): confirm deleting all transfers
This commit is contained in:
@@ -48,6 +48,7 @@ fun SettingsScreen(
|
|||||||
Column(Modifier.weight(1f)) {
|
Column(Modifier.weight(1f)) {
|
||||||
SettingsSectionContent(
|
SettingsSectionContent(
|
||||||
state = state,
|
state = state,
|
||||||
|
windowClass = windowClass,
|
||||||
section = state.selectedSection.takeUnless { it == SettingsSection.Overview } ?: SettingsSection.Preferences,
|
section = state.selectedSection.takeUnless { it == SettingsSection.Overview } ?: SettingsSection.Preferences,
|
||||||
onBack = {},
|
onBack = {},
|
||||||
showBack = false,
|
showBack = false,
|
||||||
@@ -79,6 +80,7 @@ fun SettingsScreen(
|
|||||||
SettingsSection.Overview -> SettingsOverview(state, onSectionSelected, largeTitle = true)
|
SettingsSection.Overview -> SettingsOverview(state, onSectionSelected, largeTitle = true)
|
||||||
else -> SettingsSectionContent(
|
else -> SettingsSectionContent(
|
||||||
state = state,
|
state = state,
|
||||||
|
windowClass = windowClass,
|
||||||
section = state.selectedSection,
|
section = state.selectedSection,
|
||||||
onBack = {
|
onBack = {
|
||||||
onSectionSelected(
|
onSectionSelected(
|
||||||
@@ -118,6 +120,7 @@ fun SettingsScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun SettingsSectionContent(
|
private fun SettingsSectionContent(
|
||||||
state: SettingsState,
|
state: SettingsState,
|
||||||
|
windowClass: WindowClass,
|
||||||
section: SettingsSection,
|
section: SettingsSection,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
showBack: Boolean,
|
showBack: Boolean,
|
||||||
@@ -157,7 +160,7 @@ private fun SettingsSectionContent(
|
|||||||
showBack = showBack,
|
showBack = showBack,
|
||||||
)
|
)
|
||||||
SettingsSection.Notifications -> NotificationSettings(state, onNotificationsChanged, onOpenNotificationSettings, onBack, showBack)
|
SettingsSection.Notifications -> NotificationSettings(state, onNotificationsChanged, onOpenNotificationSettings, onBack, showBack)
|
||||||
SettingsSection.Storage -> StorageSettings(state, onDeleteAllTransfers, onBack, showBack)
|
SettingsSection.Storage -> StorageSettings(state, windowClass, onDeleteAllTransfers, onBack, showBack)
|
||||||
SettingsSection.About -> AboutSettings(
|
SettingsSection.About -> AboutSettings(
|
||||||
state = state,
|
state = state,
|
||||||
onDiagnosticsChanged = onDiagnosticsChanged,
|
onDiagnosticsChanged = onDiagnosticsChanged,
|
||||||
|
|||||||
@@ -13,17 +13,28 @@ import androidx.compose.material3.CircularProgressIndicator
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.vnidrop.app.ui.components.AdaptiveDrawer
|
||||||
|
import com.vnidrop.app.ui.components.DestructiveButton
|
||||||
|
import com.vnidrop.app.ui.components.SecondaryButton
|
||||||
import com.vnidrop.app.ui.state.formatBytes
|
import com.vnidrop.app.ui.state.formatBytes
|
||||||
|
import com.vnidrop.app.ui.state.WindowClass
|
||||||
import com.vnidrop.app.ui.theme.LocalVniDropColors
|
import com.vnidrop.app.ui.theme.LocalVniDropColors
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import vnidrop.shared.generated.resources.Res
|
import vnidrop.shared.generated.resources.Res
|
||||||
|
import vnidrop.shared.generated.resources.button_cancel
|
||||||
import vnidrop.shared.generated.resources.storage_app_data
|
import vnidrop.shared.generated.resources.storage_app_data
|
||||||
import vnidrop.shared.generated.resources.storage_calculating
|
import vnidrop.shared.generated.resources.storage_calculating
|
||||||
import vnidrop.shared.generated.resources.storage_delete_transfers
|
import vnidrop.shared.generated.resources.storage_delete_transfers
|
||||||
|
import vnidrop.shared.generated.resources.storage_delete_transfers_description
|
||||||
import vnidrop.shared.generated.resources.storage_deleting
|
import vnidrop.shared.generated.resources.storage_deleting
|
||||||
import vnidrop.shared.generated.resources.storage_total
|
import vnidrop.shared.generated.resources.storage_total
|
||||||
import vnidrop.shared.generated.resources.storage_received_files
|
import vnidrop.shared.generated.resources.storage_received_files
|
||||||
@@ -35,10 +46,12 @@ import vnidrop.shared.generated.resources.storage_footer
|
|||||||
@Composable
|
@Composable
|
||||||
internal fun StorageSettings(
|
internal fun StorageSettings(
|
||||||
state: SettingsState,
|
state: SettingsState,
|
||||||
|
windowClass: WindowClass,
|
||||||
onDeleteAllTransfers: () -> Unit,
|
onDeleteAllTransfers: () -> Unit,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
showBack: Boolean,
|
showBack: Boolean,
|
||||||
) {
|
) {
|
||||||
|
var showDeleteConfirmation by rememberSaveable { mutableStateOf(false) }
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||||
SettingsTopBar(stringResource(Res.string.storage_title), onBack, showBack)
|
SettingsTopBar(stringResource(Res.string.storage_title), onBack, showBack)
|
||||||
val storage = state.storage
|
val storage = state.storage
|
||||||
@@ -67,7 +80,7 @@ internal fun StorageSettings(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
onClick = onDeleteAllTransfers,
|
onClick = { showDeleteConfirmation = true },
|
||||||
enabled = !state.isDeletingTransfers,
|
enabled = !state.isDeletingTransfers,
|
||||||
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error),
|
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error),
|
||||||
) {
|
) {
|
||||||
@@ -79,6 +92,50 @@ internal fun StorageSettings(
|
|||||||
color = LocalVniDropColors.current.foregroundLighter,
|
color = LocalVniDropColors.current.foregroundLighter,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (showDeleteConfirmation) {
|
||||||
|
AdaptiveDrawer(
|
||||||
|
windowClass = windowClass,
|
||||||
|
onDismissRequest = { showDeleteConfirmation = false },
|
||||||
|
) {
|
||||||
|
DeleteAllTransfersPanel(
|
||||||
|
onCancel = { showDeleteConfirmation = false },
|
||||||
|
onConfirm = {
|
||||||
|
showDeleteConfirmation = false
|
||||||
|
onDeleteAllTransfers()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DeleteAllTransfersPanel(
|
||||||
|
onCancel: () -> Unit,
|
||||||
|
onConfirm: () -> Unit,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier.fillMaxWidth().padding(horizontal = 20.dp, vertical = 14.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(Res.string.storage_delete_transfers),
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
stringResource(Res.string.storage_delete_transfers_description),
|
||||||
|
color = LocalVniDropColors.current.foregroundLighter,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.End)) {
|
||||||
|
SecondaryButton(stringResource(Res.string.button_cancel), onClick = onCancel)
|
||||||
|
DestructiveButton(
|
||||||
|
stringResource(Res.string.storage_delete_transfers),
|
||||||
|
onClick = onConfirm,
|
||||||
|
modifier = Modifier.testTag("confirm-delete-all-transfers"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ import com.vnidrop.app.ui.theme.VniDropTheme
|
|||||||
import com.vnidrop.app.ui.theme.LocalVniDropColors
|
import com.vnidrop.app.ui.theme.LocalVniDropColors
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
@OptIn(ExperimentalTestApi::class)
|
@OptIn(ExperimentalTestApi::class)
|
||||||
@@ -172,6 +173,45 @@ class FoundationComposeTest {
|
|||||||
runOnIdle { assertTrue(applied) }
|
runOnIdle { assertTrue(applied) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun storageDeleteAllTransfersRequiresConfirmation() = runComposeUiTest {
|
||||||
|
var deleteRequested = false
|
||||||
|
setContent {
|
||||||
|
VniDropTheme(isDarkTheme = false) {
|
||||||
|
SettingsScreen(
|
||||||
|
state = SettingsState(selectedSection = SettingsSection.Storage),
|
||||||
|
windowClass = WindowClass.Desktop,
|
||||||
|
onSectionSelected = {},
|
||||||
|
onUsernameChanged = {},
|
||||||
|
onThemeModeChanged = {},
|
||||||
|
onChooseFolder = {},
|
||||||
|
onResetFolder = {},
|
||||||
|
onNotificationsChanged = {},
|
||||||
|
onOpenNotificationSettings = {},
|
||||||
|
onDiagnosticsChanged = {},
|
||||||
|
onBugWhatChanged = {},
|
||||||
|
onBugExpectedChanged = {},
|
||||||
|
onBugStepsChanged = {},
|
||||||
|
onBugContactChanged = {},
|
||||||
|
onBugIncludeLogsChanged = {},
|
||||||
|
onSubmitBugReport = {},
|
||||||
|
onDeleteAllTransfers = { deleteRequested = true },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onNodeWithText("Delete all transfers").performClick()
|
||||||
|
onNodeWithText(
|
||||||
|
"This clears all sent and received transfer records from your history. Your received files are not deleted. " +
|
||||||
|
"Cached shared content that is no longer needed is reclaimed automatically, which may take a little time. " +
|
||||||
|
"This can’t be undone.",
|
||||||
|
).assertIsDisplayed()
|
||||||
|
runOnIdle { assertFalse(deleteRequested) }
|
||||||
|
|
||||||
|
onNodeWithTag("confirm-delete-all-transfers").performClick()
|
||||||
|
runOnIdle { assertTrue(deleteRequested) }
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun aboutSettingsShowsTheSharedProductAndPrivacyContent() = runComposeUiTest {
|
fun aboutSettingsShowsTheSharedProductAndPrivacyContent() = runComposeUiTest {
|
||||||
setContent {
|
setContent {
|
||||||
|
|||||||
Reference in New Issue
Block a user