diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AccessibilityScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AccessibilityScreen.kt index e5c47e808..9fc12c634 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AccessibilityScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AccessibilityScreen.kt @@ -30,17 +30,10 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -63,14 +56,13 @@ import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.DynamicText import ee.ria.DigiDoc.ui.component.shared.HrefDynamicText import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.LINE_HEIGHT import ee.ria.DigiDoc.ui.theme.Dimensions.MPadding import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -79,34 +71,15 @@ fun AccessibilityScreen( navController: NavHostController, sharedMenuViewModel: SharedMenuViewModel, ) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("accessibilityScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AdvancedSettingsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AdvancedSettingsScreen.kt index f9a736395..fc2e3fa4d 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AdvancedSettingsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/AdvancedSettingsScreen.kt @@ -39,17 +39,12 @@ import androidx.compose.material3.Checkbox import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -73,6 +68,7 @@ import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.advanced.AdvancedSettingComponent import ee.ria.DigiDoc.ui.component.settings.advanced.AdvancedSettingComponentItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.MPadding import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding @@ -80,11 +76,10 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.utils.extensions.notAccessible import ee.ria.DigiDoc.utils.secure.SecureUtil -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -98,11 +93,6 @@ fun AdvancedSettingsScreen( val context = LocalContext.current val activity = LocalActivity.current - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val getIsRoleAskingEnabled = sharedSettingsViewModel.dataStore::getSettingsAskRoleAndAddress @@ -124,27 +114,13 @@ fun AdvancedSettingsScreen( val allowOpeningAllFileTypesButtonText = stringResource(R.string.main_settings_open_all_filetypes_title) val buttonName = stringResource(id = R.string.button_name) - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("advancedSettingsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, @@ -329,7 +305,7 @@ fun AdvancedSettingsScreen( checkedAllowScreenshots = false checkedAllowOpeningAllFileTypes = true sharedSettingsViewModel.resetToDefaultSettings() - showMessage(context, R.string.main_settings_use_default_settings_message) + showMessage(context, R.string.main_settings_use_default_settings_message, SnackbarType.SUCCESS) }) { Text( modifier = diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt index a46a5ae65..6a7fcd01d 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DecryptScreen.kt @@ -38,16 +38,11 @@ import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -67,6 +62,7 @@ import ee.ria.DigiDoc.domain.model.IdentityAction import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.signing.NFCView import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding @@ -74,11 +70,9 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.launch @Composable fun DecryptScreen( @@ -97,31 +91,12 @@ fun DecryptScreen( var cancelDecryptAction by remember { mutableStateOf<() -> Unit>({}) } var nfcSupported by remember { mutableStateOf(false) } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val identificationMethodText = stringResource(R.string.crypto_decrypt_method) val chosenMethodNameText = stringResource(R.string.signature_update_signature_add_method_nfc) val rememberMeText = stringResource(R.string.signature_update_remember_me) - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt index 80fbf0b29..66f0275d7 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt @@ -42,17 +42,13 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -79,6 +75,7 @@ import ee.ria.DigiDoc.ui.component.shared.HrefMessageDialog import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.PrimaryOutlinedButton import ee.ria.DigiDoc.ui.component.shared.SpannableBoldText +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding @@ -86,8 +83,8 @@ import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.ui.theme.buttonRoundCornerShape import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessibilityEventType import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType import ee.ria.DigiDoc.utilsLib.file.FileUtil.sanitizeString import ee.ria.DigiDoc.viewmodel.DiagnosticsViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel @@ -110,11 +107,6 @@ fun DiagnosticsScreen( ) { val context = LocalContext.current - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val currentConfiguration by diagnosticsViewModel.updatedConfiguration.asFlow().collectAsState( @@ -143,7 +135,7 @@ fun DiagnosticsScreen( actionFile?.let { file -> diagnosticsViewModel.saveFile(file, result) } - showMessage(context, R.string.file_saved) + showMessage(context, R.string.file_saved, SnackbarType.SUCCESS) } } @@ -153,7 +145,7 @@ fun DiagnosticsScreen( actionFile?.let { file -> diagnosticsViewModel.saveFile(file, result) } - showMessage(context, R.string.file_saved) + showMessage(context, R.string.file_saved, SnackbarType.SUCCESS) enableOneTimeLogGeneration = false diagnosticsViewModel.dataStore.setIsLogFileGenerationEnabled(false) diagnosticsViewModel.dataStore.setIsLogFileGenerationRunning(false) @@ -163,27 +155,13 @@ fun DiagnosticsScreen( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("diagnosticsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptRecipientScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptRecipientScreen.kt index fd0cf6cb8..cc4983633 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptRecipientScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptRecipientScreen.kt @@ -43,8 +43,6 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.SearchBarDefaults.inputFieldColors -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -86,6 +84,7 @@ import ee.ria.DigiDoc.ui.component.shared.LoadingScreen import ee.ria.DigiDoc.ui.component.shared.MessageDialog import ee.ria.DigiDoc.ui.component.shared.PreventResize import ee.ria.DigiDoc.ui.component.shared.Recipient +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding @@ -98,8 +97,8 @@ import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessibilityEventType import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent import ee.ria.DigiDoc.utils.extensions.reachedBottom -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType import ee.ria.DigiDoc.utilsLib.validator.PersonalCodeValidator import ee.ria.DigiDoc.viewmodel.EncryptRecipientViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel @@ -127,10 +126,6 @@ fun EncryptRecipientScreen( val focusManager = LocalFocusManager.current - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) val cryptoContainer by sharedContainerViewModel.cryptoContainer.asFlow().collectAsState(null) val showLoading = remember { mutableStateOf(false) } @@ -242,41 +237,27 @@ fun EncryptRecipientScreen( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - LaunchedEffect(recipientAddedSuccess.value) { if (recipientAddedSuccess.value) { - showMessage(recipientAddedSuccessText) + showMessage(recipientAddedSuccessText, SnackbarType.SUCCESS) recipientAddedSuccess.value = false } } LaunchedEffect(containerEncryptedSuccess.value) { if (containerEncryptedSuccess.value) { - showMessage(containerEncryptedSuccessText) + showMessage(containerEncryptedSuccessText, SnackbarType.SUCCESS) containerEncryptedSuccess.value = false } } Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("encryptRecipientsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { if (!expanded) { TopBar( diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptionServicesSettingsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptionServicesSettingsScreen.kt index 9fe83e629..eb20c032f 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptionServicesSettingsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/EncryptionServicesSettingsScreen.kt @@ -50,18 +50,14 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -91,6 +87,7 @@ import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.PrimaryTextField +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.shared.dialog.OptionChooserDialog import ee.ria.DigiDoc.ui.component.support.textFieldValueSaver @@ -102,7 +99,6 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.buttonRoundedCornerShape import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.EncryptionServicesViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedCertificateViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel @@ -129,10 +125,6 @@ fun EncryptionServicesSettingsScreen( navController: NavHostController, ) { val context = LocalContext.current - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } @@ -290,27 +282,13 @@ fun EncryptionServicesSettingsScreen( var openOptionChooserDialog by remember { mutableStateOf(false) } val interactionSource = remember { MutableInteractionSource() } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("encryptionServicesScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/HomeScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/HomeScreen.kt index 381b2523a..0b9779250 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/HomeScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/HomeScreen.kt @@ -39,8 +39,6 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -49,7 +47,6 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment.Companion.Center import androidx.compose.ui.Alignment.Companion.CenterHorizontally @@ -76,13 +73,13 @@ import ee.ria.DigiDoc.ui.component.main.CrashDialog import ee.ria.DigiDoc.ui.component.menu.MainMenuBottomSheet import ee.ria.DigiDoc.ui.component.menu.OpenMenuBottomSheet import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeM import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.utils.Route -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.HomeViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import kotlinx.coroutines.CoroutineScope @@ -109,11 +106,6 @@ fun HomeScreen( val openMenuAddFileNavigateTo = remember { mutableStateOf(Route.SigningFileChoosing.route) } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - BackHandler { activity?.finish() } @@ -128,15 +120,6 @@ fun HomeScreen( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - if (openCrashDetectorDialog.value && !homeViewModel.isCrashSendingAlwaysEnabled() && (homeViewModel.didAppCrashOnPreviousExecution() || hasUnsentReports.result) @@ -165,12 +148,6 @@ fun HomeScreen( } Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .fillMaxSize() @@ -178,6 +155,7 @@ fun HomeScreen( .semantics { testTagsAsResourceId = true }.testTag("homeScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InfoScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InfoScreen.kt index 11b8e500a..947e7e793 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InfoScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InfoScreen.kt @@ -41,8 +41,6 @@ import androidx.compose.material3.ElevatedButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -51,7 +49,6 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -82,6 +79,7 @@ import ee.ria.DigiDoc.ui.component.info.InfoComponent import ee.ria.DigiDoc.ui.component.info.InfoComponentItem import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.MCornerRadius import ee.ria.DigiDoc.ui.theme.Dimensions.MPadding @@ -91,10 +89,8 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.ui.theme.buttonRoundCornerShape import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utilsLib.text.TextUtil import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -105,11 +101,6 @@ fun InfoScreen( ) { val context = LocalContext.current - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val isEstonianLanguageUsed = remember { mutableStateOf(false) } @@ -121,27 +112,13 @@ fun InfoScreen( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("infoScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InitScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InitScreen.kt index 426615b03..98b4ea057 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InitScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/InitScreen.kt @@ -36,6 +36,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -91,6 +92,7 @@ fun InitScreen( Text( text = stringResource(id = R.string.digidoc_all_caps), style = MaterialTheme.typography.displayLarge, + color = Color.White, modifier = modifier .padding(bottom = LPadding) @@ -110,6 +112,7 @@ fun InitScreen( Text( text = stringResource(id = R.string.ria), style = MaterialTheme.typography.displaySmall, + color = Color.White, modifier = modifier .padding(bottom = MPadding) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt index fdf121202..69e512907 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/MyEidIdentificationScreen.kt @@ -38,16 +38,11 @@ import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -70,6 +65,7 @@ import ee.ria.DigiDoc.domain.model.IdentityAction import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.signing.NFCView import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding @@ -78,12 +74,10 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMyEidViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -103,31 +97,12 @@ fun MyEidIdentificationScreen( var cancelAction by remember { mutableStateOf<() -> Unit>({}) } var nfcSupported by remember { mutableStateOf(false) } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val identificationMethodText = stringResource(R.string.myeid_identification_method) val chosenMethodNameText = stringResource(R.string.signature_update_signature_add_method_nfc) val rememberMeText = stringResource(R.string.signature_update_remember_me) - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ProxyServicesSettingsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ProxyServicesSettingsScreen.kt index e8419f094..c22e4769e 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ProxyServicesSettingsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ProxyServicesSettingsScreen.kt @@ -40,13 +40,10 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -82,6 +79,7 @@ import ee.ria.DigiDoc.network.proxy.ProxySetting import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.PrimaryTextField +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.support.textFieldValueSaver import ee.ria.DigiDoc.ui.theme.Dimensions.LPadding @@ -91,7 +89,6 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.buttonRoundedCornerShape import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.isTalkBackEnabled import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel @@ -119,11 +116,6 @@ fun ProxyServicesSettingsScreen( val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - var passwordVisible by rememberSaveable { mutableStateOf(false) } val setProxySetting = sharedSettingsViewModel.dataStore::setProxySetting @@ -196,37 +188,24 @@ fun ProxyServicesSettingsScreen( val clearButtonText = stringResource(R.string.clear_text) val buttonName = stringResource(id = R.string.button_name) - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - LaunchedEffect(sharedSettingsViewModel.errorState) { sharedSettingsViewModel.errorState.collect { errorState -> errorState?.let { withContext(Main) { - showMessage(context, errorState) + showMessage(it.text, it.type) + sharedSettingsViewModel.resetErrorState() } } } } Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("proxyServicesSettingsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RecentDocumentsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RecentDocumentsScreen.kt index 4cca80e1c..ae74c9f54 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RecentDocumentsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RecentDocumentsScreen.kt @@ -43,15 +43,12 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.SearchBarDefaults.inputFieldColors -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue @@ -86,6 +83,7 @@ import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.LoadingScreen import ee.ria.DigiDoc.ui.component.shared.MessageDialog import ee.ria.DigiDoc.ui.component.shared.PreventResize +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.shared.dialog.SivaConfirmationDialog import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding @@ -99,7 +97,6 @@ import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessibilityEventType import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent import ee.ria.DigiDoc.utils.extensions.reachedBottom -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage import ee.ria.DigiDoc.utilsLib.extensions.isCades import ee.ria.DigiDoc.utilsLib.extensions.isXades @@ -126,12 +123,8 @@ fun RecentDocumentsScreen( val context = LocalContext.current - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() val scope = rememberCoroutineScope() - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val showLoading = rememberSaveable { mutableStateOf(false) } val showSivaDialog = rememberSaveable { mutableStateOf(false) } val selectedDocument = rememberSaveable { mutableStateOf(null) } @@ -216,27 +209,13 @@ fun RecentDocumentsScreen( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("recentDocumentsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { if (!expanded) { TopBar( diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RootScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RootScreen.kt index 817e8c404..2ca1cbe79 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RootScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/RootScreen.kt @@ -29,15 +29,8 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -48,39 +41,19 @@ import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.text.style.TextAlign import ee.ria.DigiDoc.R import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable fun RootScreen(modifier: Modifier = Modifier) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("rootScreen"), + snackbarHost = { StatusSnackbarHost() }, ) { innerPadding -> Column( modifier = modifier.padding(innerPadding), diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt index 41eaeb286..c0289976d 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureInputScreen.kt @@ -44,12 +44,8 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -82,6 +78,7 @@ import ee.ria.DigiDoc.domain.model.methods.SigningMethod import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.shared.notificationPermissionRequester import ee.ria.DigiDoc.ui.component.signing.MobileIdView @@ -94,7 +91,6 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.debugLog import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel @@ -134,32 +130,13 @@ fun SignatureInputScreen( var signAction by remember { mutableStateOf<() -> Unit>({}) } var cancelAction by remember { mutableStateOf<() -> Unit>({}) } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val chosenMethodNameText = stringResource(chosenMethodName) val signatureMethodText = stringResource(R.string.signature_method) val rememberMeText = stringResource(R.string.signature_update_remember_me) var nfcSupported by remember { mutableStateOf(false) } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureMethodScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureMethodScreen.kt index 462a7c871..eb9ce0328 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureMethodScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SignatureMethodScreen.kt @@ -37,16 +37,11 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -63,6 +58,7 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.domain.model.methods.SigningMethod +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.signing.SignatureAddRadioItem import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding @@ -70,10 +66,8 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -83,11 +77,6 @@ fun SignatureMethodScreen( sharedMenuViewModel: SharedMenuViewModel, sharedSettingsViewModel: SharedSettingsViewModel, ) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val currentSigningMethod = sharedSettingsViewModel.dataStore.getSignatureAddMethod() var selectedOption by remember { mutableStateOf( @@ -98,22 +87,8 @@ fun SignatureMethodScreen( val signingMethodText = stringResource(id = R.string.signature_method) val signingMethodSelectedText = stringResource(id = R.string.signature_method_selected) - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SigningServicesSettingsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SigningServicesSettingsScreen.kt index 8280d21b8..718fcb136 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SigningServicesSettingsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/SigningServicesSettingsScreen.kt @@ -28,16 +28,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -54,15 +47,13 @@ import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.settings.advanced.signingservices.MobileIdAndSmartIdServicesComponent import ee.ria.DigiDoc.ui.component.settings.advanced.signingservices.TimestampServicesComponent import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TabView import ee.ria.DigiDoc.ui.component.shared.TopBar -import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedCertificateViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -73,36 +64,17 @@ fun SigningServicesSettingsScreen( sharedSettingsViewModel: SharedSettingsViewModel, sharedCertificateViewModel: SharedCertificateViewModel, ) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val selectedSigningServiceTabIndex = rememberSaveable { mutableIntStateOf(0) } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("advancedSettingsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ValidationServicesSettingsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ValidationServicesSettingsScreen.kt index 59a7a5ccb..24d625750 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ValidationServicesSettingsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/ValidationServicesSettingsScreen.kt @@ -43,13 +43,10 @@ import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -80,6 +77,7 @@ import ee.ria.DigiDoc.network.siva.SivaSetting import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.PrimaryTextField +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.support.textFieldValueSaver import ee.ria.DigiDoc.ui.theme.Dimensions.LPadding @@ -89,7 +87,6 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.buttonRoundedCornerShape import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedCertificateViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel @@ -114,11 +111,6 @@ fun ValidationServicesSettingsScreen( val focusRequester = remember { FocusRequester() } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val configuration = sharedSettingsViewModel.updatedConfiguration.value @@ -180,15 +172,6 @@ fun ValidationServicesSettingsScreen( val clearButtonText = stringResource(R.string.clear_text) val buttonName = stringResource(id = R.string.button_name) - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - // Reset SiVa URL when the user navigates away from this screen and has set default choice DisposableEffect(Unit) { onDispose { @@ -199,17 +182,12 @@ fun ValidationServicesSettingsScreen( } Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("validationServicesSettingsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/ColoredRecipientStatusText.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/ColoredRecipientStatusText.kt index 7119d3a51..fc14b5443 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/ColoredRecipientStatusText.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/ColoredRecipientStatusText.kt @@ -24,14 +24,12 @@ package ee.ria.DigiDoc.ui.component.crypto import androidx.compose.foundation.focusable import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import ee.ria.DigiDoc.ui.component.shared.TagBadge -import ee.ria.DigiDoc.ui.theme.Green_2_50 -import ee.ria.DigiDoc.ui.theme.Green_2_700 -import ee.ria.DigiDoc.ui.theme.Red50 -import ee.ria.DigiDoc.ui.theme.Red800 +import ee.ria.DigiDoc.ui.theme.extendedColorScheme @OptIn(ExperimentalLayoutApi::class) @Composable @@ -40,8 +38,8 @@ fun ColoredRecipientStatusText( modifier: Modifier = Modifier, expired: Boolean = false, ) { - val tagBackgroundColor = if (!expired) Green_2_50 else Red50 - val tagContentColor = if (!expired) Green_2_700 else Red800 + val tagBackgroundColor = if (!expired) MaterialTheme.extendedColorScheme.successContainer else MaterialTheme.colorScheme.errorContainer + val tagContentColor = if (!expired) MaterialTheme.extendedColorScheme.onSuccessContainer else MaterialTheme.colorScheme.onErrorContainer FlowRow( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/CryptoFileOpeningNavigation.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/CryptoFileOpeningNavigation.kt index f23aadd9f..7478742ad 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/CryptoFileOpeningNavigation.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/CryptoFileOpeningNavigation.kt @@ -25,14 +25,12 @@ import android.net.Uri import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -45,7 +43,6 @@ import ee.ria.DigiDoc.ui.component.shared.LoadingScreen import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessibilityEventType import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage import ee.ria.DigiDoc.viewmodel.CryptoFileOpeningViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel @@ -65,11 +62,6 @@ fun CryptoFileOpeningNavigation( ) { val context = LocalContext.current - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val cryptoContainer by sharedContainerViewModel.cryptoContainer.asFlow().collectAsState(null) val externalFileUris by sharedContainerViewModel.externalFileUris.collectAsState() var isExternalFile by remember { mutableStateOf(false) } @@ -188,15 +180,6 @@ fun CryptoFileOpeningNavigation( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - if (errorText.first != 0) { showMessage(context.getString(errorText.first, errorText.second)) errorText = Pair(0, null) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/EncryptNavigation.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/EncryptNavigation.kt index 9af133278..1bda34d95 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/EncryptNavigation.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/EncryptNavigation.kt @@ -52,8 +52,6 @@ import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -101,6 +99,7 @@ import ee.ria.DigiDoc.ui.component.shared.CryptoDataFilesLocked import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.LoadingScreen import ee.ria.DigiDoc.ui.component.shared.MessageDialog +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TabView import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.shared.dialog.SivaConfirmationDialog @@ -116,8 +115,8 @@ import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessibilityEventType import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent import ee.ria.DigiDoc.utils.extensions.reachedBottom -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType import ee.ria.DigiDoc.utilsLib.container.ContainerUtil.createContainerAction import ee.ria.DigiDoc.utilsLib.container.ContainerUtil.removeExtensionFromContainerFilename import ee.ria.DigiDoc.utilsLib.extensions.isContainer @@ -385,7 +384,7 @@ fun EncryptNavigation( ) withContext(Main) { - showMessage(context, R.string.converted_to_signed_container) + showMessage(context, R.string.converted_to_signed_container, SnackbarType.SUCCESS) } delay(2000) @@ -421,11 +420,6 @@ fun EncryptNavigation( val selectedCryptoContainerTabIndex = rememberSaveable { mutableIntStateOf(0) } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val saveFileLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_OK) { @@ -434,12 +428,12 @@ fun EncryptNavigation( sharedContainerViewModel .getCryptoContainerDataFile(cryptoContainer, file) ?.let { sharedContainerViewModel.saveContainerFile(it, result) } - showMessage(context, R.string.file_saved) + showMessage(context, R.string.file_saved, SnackbarType.SUCCESS) isSaved = true } ?: run { cryptoContainer?.file?.let { sharedContainerViewModel.saveContainerFile(it, result) - showMessage(context, R.string.file_saved) + showMessage(context, R.string.file_saved, SnackbarType.SUCCESS) isSaved = true } ?: showMessage(context, R.string.file_saved_error) } @@ -540,15 +534,6 @@ fun EncryptNavigation( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - LaunchedEffect(sharedContainerViewModel.decryptNFCStatus) { sharedContainerViewModel.decryptNFCStatus.asFlow().collect { status -> status?.let { @@ -562,7 +547,7 @@ fun EncryptNavigation( ) containerDecryptedSuccess.value = false sharedContainerViewModel.setDecryptNFCStatus(null) - showMessage(containerDecryptedSuccessText) + showMessage(containerDecryptedSuccessText, SnackbarType.SUCCESS) } } } @@ -582,7 +567,7 @@ fun EncryptNavigation( ) containerDecryptedSuccess.value = false sharedContainerViewModel.setDecryptIDCardStatus(null) - showMessage(containerDecryptedSuccessText) + showMessage(containerDecryptedSuccessText, SnackbarType.SUCCESS) } } } @@ -591,24 +576,19 @@ fun EncryptNavigation( LaunchedEffect(filesAdded) { when { - filesAdded == 1 -> showMessage(context, R.string.file_added) - filesAdded > 1 -> showMessage(context, R.string.files_added) + filesAdded == 1 -> showMessage(context, R.string.file_added, SnackbarType.SUCCESS) + filesAdded > 1 -> showMessage(context, R.string.files_added, SnackbarType.SUCCESS) } sharedContainerViewModel.resetAddedFilesCount() } Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("encryptScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, @@ -704,12 +684,12 @@ fun EncryptNavigation( horizontalAlignment = Alignment.Start, ) { if (containerEncryptedSuccess.value == true) { - showMessage(containerEncryptedSuccessText) + showMessage(containerEncryptedSuccessText, SnackbarType.SUCCESS) containerEncryptedSuccess.value = false } if (containerDecryptedSuccess.value == true) { - showMessage(containerDecryptedSuccessText) + showMessage(containerDecryptedSuccessText, SnackbarType.SUCCESS) containerDecryptedSuccess.value = false } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/recipient/RecipientDetailsView.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/recipient/RecipientDetailsView.kt index 1ab9fdb2b..a94d6753d 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/recipient/RecipientDetailsView.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/crypto/recipient/RecipientDetailsView.kt @@ -31,16 +31,9 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -53,16 +46,15 @@ import androidx.navigation.NavHostController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utilsLib.container.NameUtil.formatName import ee.ria.DigiDoc.utilsLib.extensions.x509Certificate import ee.ria.DigiDoc.viewmodel.CertificateDetailViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedCertificateViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedRecipientViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -74,11 +66,6 @@ fun RecipientDetailsView( sharedCertificateViewModel: SharedCertificateViewModel, certificateDetailViewModel: CertificateDetailViewModel = hiltViewModel(), ) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val recipient = sharedRecipientViewModel.recipient.value @@ -92,29 +79,15 @@ fun RecipientDetailsView( handleBackButtonClick(navController, sharedRecipientViewModel) } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - if (recipient != null) { val recipientFormattedName = formatName(recipient.surname, recipient.givenName, recipient.identifier) Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("recipientDetailsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/home/ActionButton.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/home/ActionButton.kt index 3c4016a9d..ac43cf0d9 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/home/ActionButton.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/home/ActionButton.kt @@ -30,12 +30,10 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonColors import androidx.compose.material3.Card @@ -62,11 +60,10 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.constraintlayout.compose.ConstraintLayout import ee.ria.DigiDoc.R import ee.ria.DigiDoc.ui.component.shared.MiddleEllipsizeMultilineText -import ee.ria.DigiDoc.ui.theme.Dimensions.MSCornerRadius +import ee.ria.DigiDoc.ui.theme.Dimensions.LElevation import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.buttonShadowElevation +import ee.ria.DigiDoc.ui.theme.Dimensions.XXSPadding import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS -import ee.ria.DigiDoc.ui.theme.Dimensions.zeroPadding import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme import ee.ria.DigiDoc.ui.theme.buttonRoundedCornerShape @@ -83,136 +80,118 @@ fun ActionButton( ) { val titleText = stringResource(id = title) - Box( - modifier = - modifier - .fillMaxWidth() - .padding(vertical = XSPadding), - contentAlignment = Alignment.Center, + Card( + shape = buttonRoundedCornerShape, + colors = + CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerLow, + ), + elevation = + CardDefaults.elevatedCardElevation( + defaultElevation = LElevation, + ), + modifier = modifier.fillMaxWidth().padding(vertical = XSPadding), ) { - Box( + Button( modifier = modifier - .matchParentSize() - .offset(y = buttonShadowElevation) - .background( - color = MaterialTheme.colorScheme.primaryContainer, - shape = RoundedCornerShape(MSCornerRadius), - ), - ) - Card( + .fillMaxWidth() + .wrapContentHeight() + .semantics { + testTagsAsResourceId = true + }.testTag(testTag), shape = buttonRoundedCornerShape, + onClick = onClickItem, colors = - CardDefaults.cardColors( + ButtonColors( containerColor = MaterialTheme.colorScheme.surfaceContainerLow, + contentColor = MaterialTheme.colorScheme.onSurface, + disabledContainerColor = Color.Transparent, + disabledContentColor = Color.Transparent, ), - elevation = - CardDefaults.elevatedCardElevation( - defaultElevation = buttonShadowElevation, - ), - modifier = modifier.padding(bottom = zeroPadding), + contentPadding = PaddingValues(XSPadding), ) { - Button( + ConstraintLayout( modifier = modifier - .fillMaxWidth() .wrapContentHeight() - .semantics { - testTagsAsResourceId = true - }.testTag(testTag), - shape = buttonRoundedCornerShape, - onClick = onClickItem, - colors = - ButtonColors( - containerColor = MaterialTheme.colorScheme.surfaceContainerLow, - contentColor = MaterialTheme.colorScheme.onSurface, - disabledContainerColor = Color.Transparent, - disabledContentColor = Color.Transparent, - ), - contentPadding = PaddingValues(XSPadding), + .fillMaxWidth() + .align(Alignment.CenterVertically), ) { - ConstraintLayout( + val ( + actionButtonIcon, + actionButtonColumn, + ) = createRefs() + Box( modifier = modifier - .wrapContentHeight() - .fillMaxWidth() - .align(Alignment.CenterVertically), + .constrainAs(actionButtonIcon) { + start.linkTo(parent.start) + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + }.wrapContentHeight() + .padding(XSPadding), ) { - val ( - actionButtonIcon, - actionButtonColumn, - ) = createRefs() Box( modifier = - modifier - .constrainAs(actionButtonIcon) { - start.linkTo(parent.start) - top.linkTo(parent.top) - bottom.linkTo(parent.bottom) - }.wrapContentHeight() - .padding(XSPadding), + Modifier + .wrapContentHeight() + .background( + color = MaterialTheme.colorScheme.primary, + shape = CircleShape, + ), ) { - Box( + Icon( + imageVector = ImageVector.vectorResource(id = icon), + contentDescription = null, + tint = MaterialTheme.colorScheme.onPrimary, modifier = - Modifier - .wrapContentHeight() - .background( - color = MaterialTheme.colorScheme.primaryContainer, - shape = CircleShape, - ), - ) { - Icon( - imageVector = ImageVector.vectorResource(id = icon), - contentDescription = null, - tint = MaterialTheme.colorScheme.onPrimary, - modifier = - modifier - .padding(XSPadding) - .size(iconSizeXXS) - .wrapContentHeight(align = Alignment.CenterVertically), - ) - } + modifier + .padding(XSPadding) + .size(iconSizeXXS) + .wrapContentHeight(align = Alignment.CenterVertically), + ) } - Column( + } + Column( + modifier = + modifier + .wrapContentHeight(align = Alignment.CenterVertically) + .fillMaxWidth() + .padding(end = iconSizeXXS + XSPadding * 5) + .constrainAs(actionButtonColumn) { + start.linkTo(actionButtonIcon.end) + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + }, + ) { + Text( + text = titleText, modifier = modifier + .padding(start = XXSPadding, bottom = XSPadding / 2) .wrapContentHeight(align = Alignment.CenterVertically) - .fillMaxWidth() - .padding(end = iconSizeXXS + XSPadding * 5) - .constrainAs(actionButtonColumn) { - start.linkTo(actionButtonIcon.end) - top.linkTo(parent.top) - bottom.linkTo(parent.bottom) + .semantics { + this.contentDescription = contentDescription }, - ) { - Text( - text = titleText, - modifier = - modifier - .padding(bottom = XSPadding / 2) - .wrapContentHeight(align = Alignment.CenterVertically) - .semantics { - this.contentDescription = contentDescription - }, - style = MaterialTheme.typography.titleMedium, - textAlign = TextAlign.Start, - ) + style = MaterialTheme.typography.titleMedium, + textAlign = TextAlign.Start, + ) - MiddleEllipsizeMultilineText( - modifier = - modifier - .padding(zeroPadding) - .wrapContentHeight(align = Alignment.CenterVertically) - .focusable(false) - .semantics { - this.contentDescription = contentDescription - }.testTag("actionButtonDescription"), - text = description, - maxLines = 4, - textColor = MaterialTheme.colorScheme.onSurface.toArgb(), - textStyle = MaterialTheme.typography.bodyMedium, - ) - } + MiddleEllipsizeMultilineText( + modifier = + modifier + .padding(horizontal = XXSPadding) + .wrapContentHeight(align = Alignment.CenterVertically) + .focusable(false) + .semantics { + this.contentDescription = contentDescription + }.testTag("actionButtonDescription"), + text = description, + maxLines = 4, + textColor = MaterialTheme.colorScheme.onSurface.toArgb(), + textStyle = MaterialTheme.typography.bodyMedium, + ) } } } @@ -224,7 +203,7 @@ fun ActionButton( @Composable fun SettingsItemPreview() { RIADigiDocTheme { - Surface(color = MaterialTheme.colorScheme.surface) { + Surface(color = MaterialTheme.colorScheme.surfaceContainerLow) { Column(horizontalAlignment = Alignment.CenterHorizontally) { ActionButton( title = R.string.main_home_crypto_title, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/menu/LanguageButton.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/menu/LanguageButton.kt index 7f5a2fc04..be1128b71 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/menu/LanguageButton.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/menu/LanguageButton.kt @@ -30,7 +30,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -57,7 +57,6 @@ import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS import ee.ria.DigiDoc.ui.theme.Dimensions.zeroPadding -import ee.ria.DigiDoc.ui.theme.OnPrimary import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme @OptIn(ExperimentalComposeUiApi::class) @@ -82,11 +81,9 @@ fun LanguageButton( shape = RectangleShape, onClick = onClickItem, colors = - ButtonColors( + ButtonDefaults.buttonColors( containerColor = Color.Transparent, - contentColor = OnPrimary, - disabledContainerColor = Color.Transparent, - disabledContentColor = Color.Transparent, + contentColor = Color.White ), contentPadding = PaddingValues( diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt index a4060d57b..6e50aebc8 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/MyEidScreen.kt @@ -37,18 +37,13 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -76,18 +71,17 @@ import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.myeid.mydata.MyEidMyDataView import ee.ria.DigiDoc.ui.component.myeid.pinandcertificate.MyEidPinAndCertificateView import ee.ria.DigiDoc.ui.component.shared.HrefDynamicText +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TabView import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.shared.dialog.PinGuideDialog import ee.ria.DigiDoc.ui.theme.Dimensions.LINE_HEIGHT import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.utils.Route -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utilsLib.date.DateUtil.formattedDateTime import ee.ria.DigiDoc.utilsLib.extensions.x509Certificate import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMyEidViewModel -import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Locale @@ -101,11 +95,6 @@ fun MyEidScreen( ) { val listState = rememberLazyListState() - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val idCardData by sharedMyEidViewModel.idCardData.asFlow().collectAsState(null) @@ -214,27 +203,13 @@ fun MyEidScreen( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("myEidScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, @@ -649,4 +624,4 @@ fun MyEidScreen( ) } -fun getAlphaForBlockedState(isBlocked: Boolean) = if (!isBlocked) 1f else 0.7f +fun getAlphaForBlockedState(isBlocked: Boolean) = if (!isBlocked) 1f else 0.8f diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/mydata/MyEidMyDataItem.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/mydata/MyEidMyDataItem.kt index 9a12581e4..07b7b92c1 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/mydata/MyEidMyDataItem.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/mydata/MyEidMyDataItem.kt @@ -51,11 +51,8 @@ import androidx.compose.ui.tooling.preview.Preview import ee.ria.DigiDoc.R import ee.ria.DigiDoc.ui.component.shared.TagBadge import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding -import ee.ria.DigiDoc.ui.theme.Green_2_50 -import ee.ria.DigiDoc.ui.theme.Green_2_700 import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.ui.theme.Red50 -import ee.ria.DigiDoc.ui.theme.Red500 +import ee.ria.DigiDoc.ui.theme.extendedColorScheme import ee.ria.DigiDoc.utils.extensions.notAccessible @OptIn(ExperimentalComposeUiApi::class) @@ -130,15 +127,15 @@ fun MyEidMyDataItem( text = status.getLocalized(context), backgroundColor = if (status == MyEidDocumentStatus.VALID) { - Green_2_50 + MaterialTheme.extendedColorScheme.successContainer } else { - Red500 + MaterialTheme.colorScheme.errorContainer }, contentColor = if (status == MyEidDocumentStatus.VALID) { - Green_2_700 + MaterialTheme.extendedColorScheme.onSuccessContainer } else { - Red50 + MaterialTheme.colorScheme.onErrorContainer }, ) } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt index ad006c72f..92e52ad8b 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/myeid/pinandcertificate/MyEidPinScreen.kt @@ -40,8 +40,6 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -76,7 +74,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.zIndex import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.asFlow -import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.common.Constant @@ -86,6 +83,7 @@ import ee.ria.DigiDoc.smartcardreader.ApduResponseException import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.PrimaryOutlinedButton import ee.ria.DigiDoc.ui.component.shared.SecurePinTextField +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.signing.NFCSignatureUpdateContainer import ee.ria.DigiDoc.ui.theme.Dimensions.MPadding @@ -97,8 +95,8 @@ import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessi import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.isTalkBackEnabled import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType import ee.ria.DigiDoc.viewmodel.NFCViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMyEidViewModel @@ -121,12 +119,8 @@ fun MyEidPinScreen( val activity = LocalActivity.current val context = LocalContext.current val scope = rememberCoroutineScope() - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() val focusManager = LocalFocusManager.current - val messages by SnackBarManager.messages.collectAsStateWithLifecycle(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val idCardData by sharedMyEidViewModel.idCardData.asFlow().collectAsState(null) @@ -287,20 +281,11 @@ fun MyEidPinScreen( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - LaunchedEffect(pinChangingState) { if (pinChangingState == true) { sharedMyEidViewModel.resetPinChangingState() resetPins() - showMessage(pinChangedSuccess) + showMessage(pinChangedSuccess, SnackbarType.SUCCESS) navController.navigateUp() } } @@ -379,17 +364,12 @@ fun MyEidPinScreen( } Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("myEidPinScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/LoadingScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/LoadingScreen.kt index 231352e66..25ff79d03 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/LoadingScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/LoadingScreen.kt @@ -28,15 +28,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -44,35 +37,13 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId import ee.ria.DigiDoc.ui.theme.Dimensions.MPadding -import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.loadingBarSize -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable fun LoadingScreen(modifier: Modifier = Modifier) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, + snackbarHost = { StatusSnackbarHost() }, ) { innerPadding -> Surface( modifier = diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryButton.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryButton.kt index de465f3ba..592712453 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryButton.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryButton.kt @@ -31,7 +31,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -85,11 +85,9 @@ fun PrimaryButton( contentPadding = PaddingValues(zeroPadding), enabled = enabled, colors = - ButtonColors( + ButtonDefaults.buttonColors( containerColor = containerColor, contentColor = contentColor, - disabledContainerColor = MaterialTheme.colorScheme.background, - disabledContentColor = MaterialTheme.colorScheme.tertiary, ), border = if (isSubButton) { @@ -97,11 +95,6 @@ fun PrimaryButton( width = SBorder, color = contentColor, ) - } else if (!enabled) { - BorderStroke( - width = SBorder, - color = MaterialTheme.colorScheme.tertiary, - ) } else { BorderStroke(noBorderStroke, Transparent) }, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryOutlinedButton.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryOutlinedButton.kt index 4e646c0ed..a99929973 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryOutlinedButton.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/PrimaryOutlinedButton.kt @@ -32,7 +32,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.material3.ButtonColors +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton @@ -91,11 +91,9 @@ fun PrimaryOutlinedButton( contentPadding = PaddingValues(zeroPadding), enabled = enabled, colors = - ButtonColors( + ButtonDefaults.buttonColors( containerColor = containerColor, contentColor = contentColor, - disabledContainerColor = MaterialTheme.colorScheme.background, - disabledContentColor = MaterialTheme.colorScheme.tertiary, ), onClick = onClickItem, ) { diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/StatusSnackbar.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/StatusSnackbar.kt new file mode 100644 index 000000000..66358e2a7 --- /dev/null +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/StatusSnackbar.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2017 - 2026 Riigi Infosüsteemi Amet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +@file:Suppress("PackageName", "FunctionName") + +package ee.ria.DigiDoc.ui.component.shared + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +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.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.vectorResource +import ee.ria.DigiDoc.R +import ee.ria.DigiDoc.ui.theme.Dimensions.LElevation +import ee.ria.DigiDoc.ui.theme.Dimensions.MSCornerRadius +import ee.ria.DigiDoc.ui.theme.Dimensions.MSPadding +import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding +import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding +import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS +import ee.ria.DigiDoc.ui.theme.extendedColorScheme +import ee.ria.DigiDoc.utils.snackbar.SnackBarManager +import ee.ria.DigiDoc.utils.snackbar.SnackBarMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType + +@Composable +fun StatusSnackbarHost() { + val currentMessage by SnackBarManager.currentMessage.collectAsState() + var lastMessage by remember { mutableStateOf(null) } + if (currentMessage != null) lastMessage = currentMessage + + AnimatedVisibility( + visible = currentMessage != null, + enter = slideInVertically(initialOffsetY = { it }) + fadeIn(), + exit = slideOutVertically(targetOffsetY = { it }) + fadeOut(), + ) { + lastMessage?.let { StatusSnackbar(message = it) } + } +} + +@Composable +fun StatusSnackbar(message: SnackBarMessage) { + val isError = message.type == SnackbarType.ERROR + + val backgroundColor = + if (isError) { + MaterialTheme.colorScheme.errorContainer + } else { + MaterialTheme.extendedColorScheme.successContainer + } + val contentColor = + if (isError) { + MaterialTheme.colorScheme.onErrorContainer + } else { + MaterialTheme.extendedColorScheme.onSuccessContainer + } + + val iconRes = + if (isError) { + R.drawable.ic_m3_info_48dp_wght400 + } else { + R.drawable.ic_m3_check_48dp_wght400 + } + + Box( + modifier = + Modifier + .fillMaxWidth() + .padding(horizontal = MSPadding) + .padding(bottom = XSPadding) + .shadow( + elevation = LElevation, + shape = RoundedCornerShape(MSCornerRadius), + ambientColor = Color.Transparent, + ) + .clip(RoundedCornerShape(MSCornerRadius)) + .background(color = backgroundColor), + ) { + Row( + modifier = Modifier.padding(horizontal = SPadding, vertical = MSPadding), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = ImageVector.vectorResource(iconRes), + contentDescription = null, + tint = contentColor, + modifier = Modifier.size(iconSizeXXS), + ) + Spacer(modifier = Modifier.width(XSPadding)) + Text( + text = message.text, + style = MaterialTheme.typography.bodyMedium, + color = contentColor, + ) + } + } +} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TagBadge.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TagBadge.kt index bb398d611..a6c3e316c 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TagBadge.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TagBadge.kt @@ -36,16 +36,15 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.XSPadding -import ee.ria.DigiDoc.ui.theme.Green_2_50 -import ee.ria.DigiDoc.ui.theme.Green_2_700 import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme +import ee.ria.DigiDoc.ui.theme.extendedColorScheme @Composable fun TagBadge( text: String, modifier: Modifier = Modifier, - backgroundColor: Color = Green_2_50, - contentColor: Color = Green_2_700, + backgroundColor: Color = MaterialTheme.extendedColorScheme.successContainer, + contentColor: Color = MaterialTheme.extendedColorScheme.onSuccessContainer, ) { Box( modifier = diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TopBar.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TopBar.kt index 99105611e..75f2718e5 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TopBar.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/TopBar.kt @@ -49,7 +49,6 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusProperties import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusTarget -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext @@ -65,7 +64,6 @@ import androidx.core.net.toUri import androidx.lifecycle.asFlow import ee.ria.DigiDoc.R import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS -import ee.ria.DigiDoc.ui.theme.Red500 import ee.ria.DigiDoc.utilsLib.text.TextUtil import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import kotlinx.coroutines.CoroutineScope @@ -212,8 +210,8 @@ fun TopBar( badge = { if (extraButtonItemCount > 0) { Badge( - containerColor = Red500, - contentColor = Color.White, + containerColor = MaterialTheme.colorScheme.error, + contentColor = MaterialTheme.colorScheme.onError, ) { Text("$extraButtonItemCount") } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/VerticalButtonColumn.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/VerticalButtonColumn.kt index bad89ee88..2bb8234ed 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/VerticalButtonColumn.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/shared/VerticalButtonColumn.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -41,8 +42,8 @@ data class VerticalButtonConfig( val contentDescription: String = "", val isEnabled: Boolean = true, val isSubButton: Boolean = true, - val containerColor: Color = Color.White, - val contentColor: Color = Color.Blue, + val containerColor: Color, + val contentColor: Color, val onClick: () -> Unit = {}, val testTag: String = "", ) @@ -85,9 +86,13 @@ fun VerticalButtonColumnPreview() { listOf( VerticalButtonConfig( title = R.string.ok_button, + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary, ), VerticalButtonConfig( title = R.string.cancel_button, + containerColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary, ), ), ) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/ColoredSignedStatusText.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/ColoredSignedStatusText.kt index 7a8af40cc..873c62455 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/ColoredSignedStatusText.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/ColoredSignedStatusText.kt @@ -34,11 +34,8 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import ee.ria.DigiDoc.libdigidoclib.domain.model.ValidatorInterface import ee.ria.DigiDoc.ui.component.shared.TagBadge -import ee.ria.DigiDoc.ui.theme.Green_2_50 -import ee.ria.DigiDoc.ui.theme.Green_2_700 import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme -import ee.ria.DigiDoc.ui.theme.Red50 -import ee.ria.DigiDoc.ui.theme.Red800 +import ee.ria.DigiDoc.ui.theme.extendedColorScheme @OptIn(ExperimentalLayoutApi::class) @Composable @@ -54,11 +51,11 @@ fun ColoredSignedStatusText( status == ValidatorInterface.Status.Warning || status == ValidatorInterface.Status.NonQSCD - val tagBackgroundColor = if (isSignatureValidOrWarning) Green_2_50 else Red50 - val tagContentColor = if (isSignatureValidOrWarning) Green_2_700 else Red800 + val tagBackgroundColor = if (isSignatureValidOrWarning) MaterialTheme.extendedColorScheme.successContainer else MaterialTheme.colorScheme.errorContainer + val tagContentColor = if (isSignatureValidOrWarning) MaterialTheme.extendedColorScheme.onSuccessContainer else MaterialTheme.colorScheme.onErrorContainer val additionalTextColor = if (status == ValidatorInterface.Status.Valid) { - Red800 + MaterialTheme.extendedColorScheme.onWarningContainer } else { MaterialTheme.colorScheme.onErrorContainer } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/FileOpeningNavigation.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/FileOpeningNavigation.kt index 61a8d3e3b..4f94098a9 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/FileOpeningNavigation.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/FileOpeningNavigation.kt @@ -25,7 +25,6 @@ import android.net.Uri import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -50,7 +49,6 @@ import ee.ria.DigiDoc.ui.component.shared.dialog.SivaConfirmationDialog import ee.ria.DigiDoc.utils.Route import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.getAccessibilityEventType import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage import ee.ria.DigiDoc.viewmodel.FileOpeningViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel @@ -72,11 +70,6 @@ fun FileOpeningNavigation( val scope = rememberCoroutineScope() - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val signedContainer by sharedContainerViewModel.signedContainer.asFlow().collectAsState(null) val cryptoContainer by sharedContainerViewModel.cryptoContainer.asFlow().collectAsState(null) val externalFileUris by sharedContainerViewModel.externalFileUris.collectAsState() @@ -280,15 +273,6 @@ fun FileOpeningNavigation( } } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - SivaConfirmationDialog( showDialog = showSivaDialog, modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SigningNavigation.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SigningNavigation.kt index 7a958d7f0..c01dc659f 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SigningNavigation.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/SigningNavigation.kt @@ -26,7 +26,6 @@ import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent import android.content.res.Configuration -import android.util.Log import android.widget.Toast import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult @@ -55,8 +54,6 @@ import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -109,6 +106,7 @@ import ee.ria.DigiDoc.ui.component.shared.DataFileItem import ee.ria.DigiDoc.ui.component.shared.InvisibleElement import ee.ria.DigiDoc.ui.component.shared.LoadingScreen import ee.ria.DigiDoc.ui.component.shared.MessageDialog +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TabView import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.shared.dialog.SivaConfirmationDialog @@ -130,8 +128,8 @@ import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.isTalkBack import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.sendAccessibilityEvent import ee.ria.DigiDoc.utils.extensions.reachedBottom import ee.ria.DigiDoc.utils.libdigidoc.SignatureStatusUtil -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utils.snackbar.SnackBarManager.showMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType import ee.ria.DigiDoc.utilsLib.container.ContainerUtil.createContainerAction import ee.ria.DigiDoc.utilsLib.container.ContainerUtil.removeExtensionFromContainerFilename import ee.ria.DigiDoc.utilsLib.extensions.isContainer @@ -416,7 +414,7 @@ fun SigningNavigation( ) withContext(Main) { - showMessage(context, R.string.converted_to_crypto_container) + showMessage(context, R.string.converted_to_crypto_container, SnackbarType.SUCCESS) } delay(2000) @@ -439,11 +437,6 @@ fun SigningNavigation( val selectedSignedContainerTabIndex = rememberSaveable { mutableIntStateOf(0) } - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val containerNotifications by sharedContainerViewModel.containerNotifications.collectAsState() val saveFileLauncher = @@ -454,13 +447,13 @@ fun SigningNavigation( sharedContainerViewModel .getContainerDataFile(signedContainer, datafile) ?.let { sharedContainerViewModel.saveContainerFile(it, result) } - showMessage(context, R.string.file_saved) + showMessage(context, R.string.file_saved, SnackbarType.SUCCESS) clickedDataFile.value = null isSaved = true } ?: run { signedContainer?.getContainerFile()?.let { sharedContainerViewModel.saveContainerFile(it, result) - showMessage(context, R.string.file_saved) + showMessage(context, R.string.file_saved, SnackbarType.SUCCESS) isSaved = true } ?: showMessage(context, R.string.file_saved_error) } @@ -685,40 +678,23 @@ fun SigningNavigation( LaunchedEffect(filesAdded) { when { - filesAdded == 1 -> showMessage(context, R.string.file_added) - filesAdded > 1 -> showMessage(context, R.string.files_added) + filesAdded == 1 -> showMessage(context, R.string.file_added, SnackbarType.SUCCESS) + filesAdded > 1 -> showMessage(context, R.string.files_added, SnackbarType.SUCCESS) } sharedContainerViewModel.resetAddedFilesCount() } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar( - message = message, - withDismissAction = true, - ) - } - SnackBarManager.removeMessage(message) - } - } - if (signedContainerExists == false) { return } Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("signingScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, @@ -829,7 +805,7 @@ fun SigningNavigation( ) } } - showMessage(signatureAddedSuccessText) + showMessage(signatureAddedSuccessText, SnackbarType.SUCCESS) signatureAddedSuccess.value = false } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/bottombar/ShareButtonBottomBar.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/bottombar/ShareButtonBottomBar.kt index 4934502af..0dedeabef 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/bottombar/ShareButtonBottomBar.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/bottombar/ShareButtonBottomBar.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource @@ -55,6 +56,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.tooling.preview.Preview import ee.ria.DigiDoc.R +import ee.ria.DigiDoc.ui.theme.Dimensions.MElevation import ee.ria.DigiDoc.ui.theme.Dimensions.MPadding import ee.ria.DigiDoc.ui.theme.Dimensions.MSCornerRadius import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding @@ -94,10 +96,10 @@ fun ShareButtonBottomBar( modifier = modifier .shadow( - elevation = MSCornerRadius, + elevation = MElevation, shape = RoundedCornerShape(MSCornerRadius), - ambientColor = MaterialTheme.colorScheme.onSurface, - spotColor = MaterialTheme.colorScheme.onSurface, + ambientColor = MaterialTheme.colorScheme.surfaceContainerHigh, + spotColor = Color.Black, ).clip(buttonRoundedCornerShape) .semantics { contentDescription = shareButtonContentDescriptionText diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/CertificateDetailsView.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/CertificateDetailsView.kt index 58898833d..c74d0d23e 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/CertificateDetailsView.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/CertificateDetailsView.kt @@ -36,17 +36,10 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -64,12 +57,12 @@ import androidx.navigation.NavHostController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.MPadding import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.formatNumbers import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utilsLib.date.DateUtil import ee.ria.DigiDoc.utilsLib.extensions.formatHexString import ee.ria.DigiDoc.utilsLib.extensions.hexString @@ -77,7 +70,6 @@ import ee.ria.DigiDoc.utilsLib.text.TextUtil import ee.ria.DigiDoc.viewmodel.CertificateDetailViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedCertificateViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import kotlinx.coroutines.launch import org.bouncycastle.asn1.x500.style.BCStyle import kotlin.text.Charsets.UTF_8 @@ -92,38 +84,19 @@ fun CertificateDetailsView( ) { val certificate = sharedCertificateViewModel.certificate.value - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } BackHandler { handleBackButtonClick(navController, sharedCertificateViewModel) } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("certificateDetailsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/SignerDetailsView.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/SignerDetailsView.kt index c5482f037..4656237a3 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/SignerDetailsView.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/certificate/SignerDetailsView.kt @@ -39,17 +39,10 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -72,6 +65,7 @@ import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet import ee.ria.DigiDoc.ui.component.shared.DynamicText import ee.ria.DigiDoc.ui.component.shared.ExpandableButton import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TabView import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.component.signing.ColoredSignedStatusText @@ -84,7 +78,6 @@ import ee.ria.DigiDoc.utils.accessibility.AccessibilityUtil.Companion.formatNumb import ee.ria.DigiDoc.utils.extensions.notAccessible import ee.ria.DigiDoc.utils.libdigidoc.SignatureStatusUtil import ee.ria.DigiDoc.utils.libdigidoc.SignatureStatusUtil.getSignatureStatusText -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.utilsLib.container.NameUtil.formatName import ee.ria.DigiDoc.utilsLib.extensions.x509Certificate import ee.ria.DigiDoc.viewmodel.CertificateDetailViewModel @@ -92,7 +85,6 @@ import ee.ria.DigiDoc.viewmodel.shared.SharedCertificateViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedSignatureViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -105,11 +97,6 @@ fun SignerDetailsView( sharedContainerViewModel: SharedContainerViewModel, certificateDetailViewModel: CertificateDetailViewModel = hiltViewModel(), ) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val signature = sharedSignatureViewModel.signature.value @@ -165,28 +152,14 @@ fun SignerDetailsView( handleBackButtonClick(navController, sharedSignatureViewModel) } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - if (signature != null) { Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("signatureDetailsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/notifications/ContainerNotificationsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/notifications/ContainerNotificationsScreen.kt index 3774653f3..78be694e5 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/notifications/ContainerNotificationsScreen.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/component/signing/notifications/ContainerNotificationsScreen.kt @@ -40,17 +40,12 @@ import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -66,14 +61,13 @@ import androidx.navigation.NavHostController import ee.ria.DigiDoc.R import ee.ria.DigiDoc.domain.model.notifications.ContainerNotificationType import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet +import ee.ria.DigiDoc.ui.component.shared.StatusSnackbarHost import ee.ria.DigiDoc.ui.component.shared.TopBar import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding import ee.ria.DigiDoc.ui.theme.Dimensions.iconSizeXXS import ee.ria.DigiDoc.utils.extensions.notAccessible -import ee.ria.DigiDoc.utils.snackbar.SnackBarManager import ee.ria.DigiDoc.viewmodel.shared.SharedContainerViewModel import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel -import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -83,11 +77,6 @@ fun ContainerNotificationsScreen( sharedContainerViewModel: SharedContainerViewModel, sharedMenuViewModel: SharedMenuViewModel, ) { - val snackBarHostState = remember { SnackbarHostState() } - val snackBarScope = rememberCoroutineScope() - - val messages by SnackBarManager.messages.collectAsState(emptyList()) - val isSettingsMenuBottomSheetVisible = rememberSaveable { mutableStateOf(false) } val containerNotifications by sharedContainerViewModel.containerNotifications.collectAsState() @@ -96,27 +85,13 @@ fun ContainerNotificationsScreen( navController.navigateUp() } - LaunchedEffect(messages) { - messages.forEach { message -> - snackBarScope.launch { - snackBarHostState.showSnackbar(message) - } - SnackBarManager.removeMessage(message) - } - } - Scaffold( - snackbarHost = { - SnackbarHost( - modifier = modifier.padding(vertical = SPadding), - hostState = snackBarHostState, - ) - }, modifier = modifier .semantics { testTagsAsResourceId = true }.testTag("containerNotificationsScreen"), + snackbarHost = { StatusSnackbarHost() }, topBar = { TopBar( modifier = modifier, diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Color.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Color.kt index 178d62f9e..7c8ad3407 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Color.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Color.kt @@ -23,80 +23,94 @@ package ee.ria.DigiDoc.ui.theme import androidx.compose.ui.graphics.Color -// yellow -val Yellow800 = Color(0xFF83612d) - -// red -val Red800 = Color(0xFF571e27) -val Red500 = Color(0xFFad2a45) -val Red50 = Color(0xFFf5ebed) - -// green -val Green_2_50 = Color(0xFFEAF8EA) -val Green_2_700 = Color(0xFF218123) - -val OnPrimary = Color.White val BlueBackground = Color(0xFF003168) -// light -val LightPrimary = Color(0xFF002048) -val LightPrimaryContainer = Color(0xFF194178) -val LightSecondaryContainer = Color(0xFFD9E4FF) -val LightTertiary = Color(0xFF300e41) -val LightTertiaryContainer = Color(0xFF533166) -val LightError = Color(0xFFBA1A1A) -val LightErrorContainer = Color(0xFFFFDAD6) +// Light +val LightPrimary = Color(0xFF003168) +val LightPrimaryContainer = Color(0xFFDDE8F3) +val LightSecondary = Color(0xFF747781) +val LightSecondaryContainer = Color(0xFFE2E2E7) +val LightError = Color(0xFFB00020) +val LightErrorContainer = Color(0xFFF6DBE0) +val LightSuccess = Color(0xFF2FB631) +val LightSuccessContainer = Color(0xFFE0F4E0) +val LightWarning = Color(0xFF7A3E00) +val LightWarningContainer = Color(0xFFFAE7C9) + val LightOnPrimary = Color.White -val LightOnPrimaryContainer = Color(0xFFC5D7FF) -val LightOnSecondaryContainer = Color(0xFF3D4960) -val LightOnTertiary = Color.White -val LightOnTertiaryContainer = Color(0xFFF3C7FF) +val LightOnPrimaryContainer = Color(0xFF0C2246) +val LightOnSecondary = Color.White +val LightOnSecondaryContainer = Color(0xFF282A2E) val LightOnError = Color.White -val LightOnErrorContainer = Color(0xFF410002) +val LightOnErrorContainer = Color(0xFF710015) +val LightOnSuccess = Color.White +val LightOnSuccessContainer = Color(0xFF144C15) +val LightOnWarning = Color.White +val LightOnWarningContainer = Color(0xFF5A2E00) + val LightOutline = Color(0xFF747781) val LightOutlineVariant = Color(0xFFC3C6D1) val LightSurface = Color(0xFFFAF9FE) val LightSurfaceContainer = Color(0xFFEEEDF3) +val LightSurfaceContainerLowest = Color.White val LightSurfaceContainerLow = Color(0xFFF4F3F8) val LightSurfaceContainerHigh = Color(0xFFE8E7ED) val LightSurfaceContainerHighest = Color(0xFFE2E2E7) -val LightSurfaceVariant = Color(0xFFEEEDF3) +val LightSurfaceVariant = Color(0xFFE0E2ED) val LightOnSurface = Color(0xFF1A1C1F) val LightOnSurfaceVariant = Color(0xFF434750) val LightInversePrimary = Color(0xFFAAC7FF) val LightInverseSurface = Color(0xFF2F3034) -val LightInverseOnSurface = Color(0xFFF1F0F5) +val LightInverseOnSurface = Color(0xFFF4F3F8) + +// Dark +val DarkPrimary = Color(0xFFAAC7FF) +val DarkPrimaryContainer = Color(0xFF0F2C5A) +val DarkSecondary = Color(0xFFE0E2ED) +val DarkSecondaryContainer = Color(0xFF2F3034) +val DarkError = Color(0xFFFF5C79) +val DarkErrorContainer = Color(0xFF50000F) +val DarkSuccess = Color(0xFF74CE75) +val DarkSuccessContainer = Color(0xFF0C2E0C) +val DarkWarning = Color(0xFFFBAE38) +val DarkWarningContainer = Color(0xFF5A2E00) + +val DarkOnPrimary = Color(0xFF0C2246) +val DarkOnPrimaryContainer = Color(0xFFB5BFCF) +val DarkOnSecondary = Color(0xFF2F3034) +val DarkOnSecondaryContainer = Color(0xFFFAF9FE) +val DarkOnError = Color(0xFF34000A) +val DarkOnErrorContainer = Color(0xFFEFCCD2) +val DarkOnSuccess = Color(0xFF144C15) +val DarkOnSuccessContainer = Color(0xFF74CE75) +val DarkOnWarning = Color(0xFF5A2E00) +val DarkOnWarningContainer = Color(0xFFF2C174) -// dark -val DarkPrimary = Color(0xFFB1CBFF) -val DarkPrimaryContainer = Color(0xFF6F91CE) -val DarkSecondaryContainer = Color(0xFF313D54) -val DarkTertiary = Color(0xFFE8B4F8) -val DarkTertiaryContainer = Color(0xFF401750) -val DarkError = Color(0xFFFFB4AB) -val DarkErrorContainer = Color(0xFF93000A) -val DarkOnPrimary = Color(0xFF002F65) -val DarkOnPrimaryContainer = Color(0xFF95B6F5) -val DarkOnSecondaryContainer = Color(0xFFC4D1ED) -val DarkOnTertiary = Color(0xFF471E57) -val DarkOnTertiaryContainer = Color(0xFFD7A4E6) -val DarkOnError = Color(0xFF690005) -val DarkOnErrorContainer = Color(0xFFFFDAD6) val DarkOutline = Color(0xFF8D909B) val DarkOutlineVariant = Color(0xFF434750) val DarkSurface = Color(0xFF121317) val DarkSurfaceContainer = Color(0xFF1E2023) +val DarkSurfaceContainerLowest = Color(0xFF0D0E12) val DarkSurfaceContainerLow = Color(0xFF1A1C1F) val DarkSurfaceContainerHigh = Color(0xFF282A2E) val DarkSurfaceContainerHighest = Color(0xFF333539) -val DarkSurfaceVariant = Color(0xFF1E2023) +val DarkSurfaceVariant = Color(0xFF434750) val DarkOnSurface = Color(0xFFE2E2E7) val DarkOnSurfaceVariant = Color(0xFFC3C6D1) -val DarkInversePrimary = Color(0xFF3B5E97) +val DarkInversePrimary = Color(0xFF003168) val DarkInverseSurface = Color(0xFFE2E2E7) val DarkInverseOnSurface = Color(0xFF2F3034) -// general -val White = Color.White +// General val Transparent = Color(0x00FFFFFF) -val Black = Color(0xFF000000) + +data class ExtendedColorScheme( + val success: Color, + val successContainer: Color, + val onSuccess: Color, + val onSuccessContainer: Color, + val warning: Color, + val warningContainer: Color, + val onWarning: Color, + val onWarningContainer: Color, +) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Dimensions.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Dimensions.kt index b00f52c23..254472768 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Dimensions.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Dimensions.kt @@ -63,4 +63,8 @@ object Dimensions { // Line height const val LINE_HEIGHT = 20f + + // Elevation + val MElevation = 2.dp + val LElevation = 4.dp } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Theme.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Theme.kt index 075208bea..3493f5665 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Theme.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Theme.kt @@ -39,6 +39,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.SideEffect import androidx.compose.runtime.remember +import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext @@ -53,33 +54,28 @@ val buttonRoundCornerShape = RoundedCornerShape(MCornerRadius) private val DarkColorScheme = darkColorScheme( primary = DarkPrimary, - onPrimary = DarkOnPrimary, primaryContainer = DarkPrimaryContainer, - onPrimaryContainer = DarkOnPrimaryContainer, secondary = DarkSecondaryContainer, - onSecondary = DarkOnSecondaryContainer, secondaryContainer = DarkSecondaryContainer, - onSecondaryContainer = DarkOnSecondaryContainer, - tertiary = DarkTertiary, - onTertiary = DarkOnTertiary, - tertiaryContainer = DarkTertiaryContainer, - onTertiaryContainer = DarkOnTertiaryContainer, error = DarkError, - onError = DarkOnError, errorContainer = DarkErrorContainer, + onPrimary = DarkOnPrimary, + onPrimaryContainer = DarkOnPrimaryContainer, + onSecondary = DarkOnSecondaryContainer, + onSecondaryContainer = DarkOnSecondaryContainer, + onError = DarkOnError, onErrorContainer = DarkOnErrorContainer, - background = Black, - onBackground = White, outline = DarkOutline, outlineVariant = DarkOutlineVariant, surface = DarkSurface, - surfaceVariant = DarkSurfaceVariant, - onSurface = DarkOnSurface, - onSurfaceVariant = DarkOnSurfaceVariant, surfaceContainer = DarkSurfaceContainer, + surfaceContainerLowest = DarkSurfaceContainerLowest, surfaceContainerLow = DarkSurfaceContainerLow, surfaceContainerHigh = DarkSurfaceContainerHigh, surfaceContainerHighest = DarkSurfaceContainerHighest, + surfaceVariant = DarkSurfaceVariant, + onSurface = DarkOnSurface, + onSurfaceVariant = DarkOnSurfaceVariant, inversePrimary = DarkInversePrimary, inverseSurface = DarkInverseSurface, inverseOnSurface = DarkInverseOnSurface, @@ -88,38 +84,65 @@ private val DarkColorScheme = private val LightColorScheme = lightColorScheme( primary = LightPrimary, - onPrimary = LightOnPrimary, primaryContainer = LightPrimaryContainer, - onPrimaryContainer = LightOnPrimaryContainer, secondary = LightSecondaryContainer, - onSecondary = LightOnSecondaryContainer, secondaryContainer = LightSecondaryContainer, - onSecondaryContainer = LightOnSecondaryContainer, - tertiary = LightTertiary, - onTertiary = LightOnTertiary, - tertiaryContainer = LightTertiaryContainer, - onTertiaryContainer = LightOnTertiaryContainer, error = LightError, - onError = LightOnError, errorContainer = LightErrorContainer, + onPrimary = LightOnPrimary, + onPrimaryContainer = LightOnPrimaryContainer, + onSecondary = LightOnSecondaryContainer, + onSecondaryContainer = LightOnSecondaryContainer, + onError = LightOnError, onErrorContainer = LightOnErrorContainer, - background = White, - onBackground = Black, outline = LightOutline, outlineVariant = LightOutlineVariant, surface = LightSurface, - surfaceVariant = LightSurfaceVariant, - onSurface = LightOnSurface, - onSurfaceVariant = LightOnSurfaceVariant, surfaceContainer = LightSurfaceContainer, + surfaceContainerLowest = LightSurfaceContainerLowest, surfaceContainerLow = LightSurfaceContainerLow, surfaceContainerHigh = LightSurfaceContainerHigh, surfaceContainerHighest = LightSurfaceContainerHighest, + surfaceVariant = LightSurfaceVariant, + onSurface = LightOnSurface, + onSurfaceVariant = LightOnSurfaceVariant, inversePrimary = LightInversePrimary, inverseSurface = LightInverseSurface, inverseOnSurface = LightInverseOnSurface, ) +private val DarkExtendedColors = + ExtendedColorScheme( + success = DarkSuccess, + successContainer = DarkSuccessContainer, + onSuccess = DarkOnSuccess, + onSuccessContainer = DarkOnSuccessContainer, + warning = DarkWarning, + warningContainer = DarkWarningContainer, + onWarning = DarkOnWarning, + onWarningContainer = DarkOnWarningContainer, + ) + +private val LightExtendedColors = + ExtendedColorScheme( + success = LightSuccess, + successContainer = LightSuccessContainer, + onSuccess = LightOnSuccess, + onSuccessContainer = LightOnSuccessContainer, + warning = LightWarning, + warningContainer = LightWarningContainer, + onWarning = LightOnWarning, + onWarningContainer = LightOnWarningContainer, + ) + +val LocalExtendedColorScheme = + staticCompositionLocalOf { + error("No ExtendedColorScheme provided") + } + +val MaterialTheme.extendedColorScheme: ExtendedColorScheme + @Composable get() = LocalExtendedColorScheme.current + @OptIn(ExperimentalLayoutApi::class) @Composable fun RIADigiDocTheme( @@ -154,6 +177,7 @@ fun RIADigiDocTheme( useDarkTheme -> DarkColorScheme else -> LightColorScheme } + val extendedColors = if (useDarkTheme) DarkExtendedColors else LightExtendedColors val view = LocalView.current if (!view.isInEditMode) { SideEffect { @@ -167,17 +191,19 @@ fun RIADigiDocTheme( } } - MaterialTheme( - colorScheme = colorScheme, - typography = getTypography(), - content = { - AccessibilityFocusProvider( - focusColor = accessibilityFocusColor, - alpha = accessibilityFocusAlpha, - content = content, - ) - }, - ) + CompositionLocalProvider(LocalExtendedColorScheme provides extendedColors) { + MaterialTheme( + colorScheme = colorScheme, + typography = getTypography(), + content = { + AccessibilityFocusProvider( + focusColor = accessibilityFocusColor, + alpha = accessibilityFocusAlpha, + content = content, + ) + }, + ) + } } @OptIn(ExperimentalMaterial3Api::class) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Type.kt b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Type.kt index 1bf54c688..bf7cbfff2 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Type.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/ui/theme/Type.kt @@ -46,7 +46,6 @@ fun getTypography(): Typography { fontSize = 26.sp, fontWeight = FontWeight.Light, fontStyle = FontStyle.Normal, - color = OnPrimary, textAlign = TextAlign.Center, // Disable ligatures fontFeatureSettings = "'liga' off, 'clig' off", @@ -57,7 +56,6 @@ fun getTypography(): Typography { fontSize = 16.sp, fontWeight = FontWeight.Normal, fontStyle = FontStyle.Normal, - color = OnPrimary, textAlign = TextAlign.Center, // Disable ligatures fontFeatureSettings = "'liga' off, 'clig' off", diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/utils/snackbar/SnackBarManager.kt b/app/src/main/kotlin/ee/ria/DigiDoc/utils/snackbar/SnackBarManager.kt index 476850b91..9cfb195fd 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/utils/snackbar/SnackBarManager.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/utils/snackbar/SnackBarManager.kt @@ -24,31 +24,52 @@ package ee.ria.DigiDoc.utils.snackbar import android.content.Context import androidx.annotation.StringRes import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch object SnackBarManager { - private val _messages = MutableStateFlow>(emptyList()) - val messages: SharedFlow> = _messages + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) - fun showMessage(message: String) { - CoroutineScope(Main).launch { - _messages.value = _messages.value + message + private val queue = mutableListOf() + private val _currentMessage = MutableStateFlow(null) + val currentMessage: StateFlow = _currentMessage.asStateFlow() + + private var isPresenting = false + + fun showMessage( + text: String, + type: SnackbarType = SnackbarType.ERROR, + ) { + scope.launch { + val message = SnackBarMessage(text, type) + if (queue.lastOrNull() == message) return@launch + queue.add(message) + processNext() } } fun showMessage( context: Context, - @StringRes message: Int, + @StringRes resId: Int, + type: SnackbarType = SnackbarType.ERROR, ) { - CoroutineScope(Main).launch { - _messages.value = _messages.value + context.getString(message) - } + showMessage(context.getString(resId), type) } - fun removeMessage(message: String) { - _messages.value = _messages.value.filter { it != message } + private fun processNext() { + if (isPresenting || queue.isEmpty()) return + isPresenting = true + _currentMessage.value = queue.removeAt(0) + scope.launch { + delay(4_000) + _currentMessage.value = null + isPresenting = false + processNext() + } } } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/utils/snackbar/SnackBarMessage.kt b/app/src/main/kotlin/ee/ria/DigiDoc/utils/snackbar/SnackBarMessage.kt new file mode 100644 index 000000000..a0a8b3b1a --- /dev/null +++ b/app/src/main/kotlin/ee/ria/DigiDoc/utils/snackbar/SnackBarMessage.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2017 - 2026 Riigi Infosüsteemi Amet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +@file:Suppress("PackageName") + +package ee.ria.DigiDoc.utils.snackbar + +enum class SnackbarType { SUCCESS, ERROR } + +data class SnackBarMessage( + val text: String, + val type: SnackbarType = SnackbarType.ERROR, +) diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModel.kt b/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModel.kt index 6c21e2f2c..8a51a0047 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModel.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModel.kt @@ -50,6 +50,8 @@ import ee.ria.DigiDoc.network.siva.SivaSetting import ee.ria.DigiDoc.network.utils.NetworkUtil.constructClientBuilder import ee.ria.DigiDoc.network.utils.ProxyUtil import ee.ria.DigiDoc.network.utils.UserAgentUtil +import ee.ria.DigiDoc.utils.snackbar.SnackBarMessage +import ee.ria.DigiDoc.utils.snackbar.SnackbarType import ee.ria.DigiDoc.utilsLib.file.FileUtil import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.debugLog import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog @@ -125,8 +127,8 @@ class SharedSettingsViewModel private val _cryptoCertificate = MutableStateFlow(null) val cryptoCertificate: StateFlow = _cryptoCertificate - private val _errorState = MutableStateFlow(null) - val errorState: StateFlow = _errorState + private val _errorState = MutableStateFlow(null) + val errorState: StateFlow = _errorState init { CoroutineScope(Main).launch { @@ -144,7 +146,7 @@ class SharedSettingsViewModel resetCryptoSettings() resetCertificateInfo() - resetErrors() + resetErrorState() } private fun resetProxySettings() { @@ -507,7 +509,7 @@ class SharedSettingsViewModel _cryptoCertificate.value = null } - private fun resetErrors() { + fun resetErrorState() { _errorState.value = null } @@ -537,15 +539,15 @@ class SharedSettingsViewModel val response = call.execute() if (response.code == 403) { debugLog(logTag, "Forbidden error with proxy configuration") - _errorState.value = R.string.main_settings_proxy_check_username_and_password + _errorState.value = SnackBarMessage(context.getString(R.string.main_settings_proxy_check_username_and_password)) } if (response.code != 200) { debugLog(logTag, "No Internet connection detected") - _errorState.value = R.string.main_settings_proxy_check_connection_unsuccessful + _errorState.value = SnackBarMessage(context.getString(R.string.main_settings_proxy_check_connection_unsuccessful)) } else { debugLog(logTag, "Internet connection detected successfully") - _errorState.value = R.string.main_settings_proxy_check_connection_success + _errorState.value = SnackBarMessage(context.getString(R.string.main_settings_proxy_check_connection_success), SnackbarType.SUCCESS) } } catch (e: IOException) { val message = e.message @@ -560,10 +562,10 @@ class SharedSettingsViewModel "Received HTTP status 403 or failed to authenticate. " + "Unable to connect with proxy configuration", ) - _errorState.value = R.string.main_settings_proxy_check_connection_unsuccessful + _errorState.value = SnackBarMessage(context.getString(R.string.main_settings_proxy_check_connection_unsuccessful)) } errorLog(logTag, "Unable to check Internet connection", e) - _errorState.value = R.string.main_settings_proxy_check_connection_unsuccessful + _errorState.value = SnackBarMessage(context.getString(R.string.main_settings_proxy_check_connection_unsuccessful)) } } }