diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt index e90a581416..f5dcc6b54a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/WelcomeView.kt @@ -111,53 +111,59 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) { val scrollState = rememberScrollState() val keyboardState by getKeyboardState() var savedKeyboardState by remember { mutableStateOf(keyboardState) } - - ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { - Column( - modifier = Modifier - .fillMaxSize() - .themedBackground(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - CloseSheetBar(close = { - if (chatModel.users.none { !it.user.hidden }) { - appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) - } else { - close() - } - }) - BackHandler(onBack = { - appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) - }) - - ColumnWithScrollBar( - modifier = if (appPlatform.isAndroid) Modifier.fillMaxSize() else Modifier.widthIn(max = 600.dp).fillMaxHeight(), + val handler = remember { AppBarHandler() } + CompositionLocalProvider( + LocalAppBarHandler provides handler + ) { + ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { + Column( + modifier = Modifier + .fillMaxSize() + .themedBackground(), + horizontalAlignment = Alignment.CenterHorizontally ) { - val displayName = rememberSaveable { mutableStateOf("") } - val focusRequester = remember { FocusRequester() } - Column(Modifier.padding(horizontal = DEFAULT_PADDING)) { - AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING) - ProfileNameField(displayName, stringResource(MR.strings.display_name), { it.trim() == mkValidName(it) }, focusRequester) - Spacer(Modifier.height(DEFAULT_PADDING)) - ReadableText(MR.strings.your_profile_is_stored_on_your_device, TextAlign.Start, padding = PaddingValues(), style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary)) - ReadableText(MR.strings.profile_is_only_shared_with_your_contacts, TextAlign.Start, style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary)) - } - Spacer(Modifier.fillMaxHeight().weight(1f)) - Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { - OnboardingActionButton( - if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), - labelId = MR.strings.create_profile_button, - onboarding = null, - enabled = canCreateProfile(displayName.value), - onclick = { createProfileOnboarding(chat.simplex.common.platform.chatModel, displayName.value, close) } - ) - // Reserve space - TextButtonBelowOnboardingButton("", null) - } + CloseSheetBar(close = { + if (chatModel.users.none { !it.user.hidden }) { + appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) + } else { + close() + } + }) + BackHandler(onBack = { + appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) + }) - LaunchedEffect(Unit) { - delay(300) - focusRequester.requestFocus() + ColumnWithScrollBar( + modifier = Modifier.fillMaxSize() + ) { + val displayName = rememberSaveable { mutableStateOf("") } + val focusRequester = remember { FocusRequester() } + Column(if (appPlatform.isAndroid) Modifier.fillMaxSize().padding(horizontal = DEFAULT_PADDING) else Modifier.widthIn(max = 600.dp).fillMaxHeight().padding(horizontal = DEFAULT_PADDING).align(Alignment.CenterHorizontally)) { + Box(Modifier.align(Alignment.CenterHorizontally)) { + AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING, withPadding = false) + } + ProfileNameField(displayName, stringResource(MR.strings.display_name), { it.trim() == mkValidName(it) }, focusRequester) + Spacer(Modifier.height(DEFAULT_PADDING)) + ReadableText(MR.strings.your_profile_is_stored_on_your_device, TextAlign.Start, padding = PaddingValues(), style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary)) + ReadableText(MR.strings.profile_is_only_shared_with_your_contacts, TextAlign.Start, style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary)) + } + Spacer(Modifier.fillMaxHeight().weight(1f)) + Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { + OnboardingActionButton( + if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), + labelId = MR.strings.create_profile_button, + onboarding = null, + enabled = canCreateProfile(displayName.value), + onclick = { createProfileOnboarding(chat.simplex.common.platform.chatModel, displayName.value, close) } + ) + // Reserve space + TextButtonBelowOnboardingButton("", null) + } + + LaunchedEffect(Unit) { + delay(300) + focusRequester.requestFocus() + } } } LaunchedEffect(Unit) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt index fddf964f28..20a7ada3aa 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/CreateSimpleXAddress.kt @@ -76,56 +76,62 @@ private fun CreateSimpleXAddressLayout( createAddress: () -> Unit, nextStep: () -> Unit, ) { - ColumnWithScrollBar( - Modifier - .fillMaxSize() - .themedBackground(), - horizontalAlignment = Alignment.CenterHorizontally, + val handler = remember { AppBarHandler() } + CompositionLocalProvider( + LocalAppBarHandler provides handler ) { - CloseSheetBar(showClose = false, close = {}) - AppBarTitle(stringResource(MR.strings.simplex_address)) + ModalView({}, showClose = false) { + ColumnWithScrollBar( + Modifier + .fillMaxSize() + .themedBackground(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + AppBarTitle(stringResource(MR.strings.simplex_address)) - Spacer(Modifier.weight(1f)) + Spacer(Modifier.weight(1f)) - if (userAddress != null) { - SimpleXLinkQRCode(userAddress.connReqContact) - Spacer(Modifier.height(DEFAULT_PADDING_HALF)) - Row { - ShareAddressButton { share(simplexChatLink(userAddress.connReqContact)) } - Spacer(Modifier.width(DEFAULT_PADDING * 2)) - ShareViaEmailButton { sendEmail(userAddress) } - } - Spacer(Modifier.height(DEFAULT_PADDING)) - Spacer(Modifier.weight(1f)) - Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { - OnboardingActionButton( - modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), - labelId = MR.strings.continue_to_next_step, - onboarding = null, - onclick = nextStep - ) - // Reserve space - TextButtonBelowOnboardingButton("", null) - } - } else { - Button(createAddress, Modifier, shape = CircleShape, contentPadding = PaddingValues()) { - Icon(painterResource(MR.images.ic_mail_filled), null, Modifier.size(100.dp).background(MaterialTheme.colors.primary, CircleShape).padding(25.dp), tint = Color.White) - } - Spacer(Modifier.height(DEFAULT_PADDING)) - Spacer(Modifier.weight(1f)) - Text(stringResource(MR.strings.create_simplex_address), style = MaterialTheme.typography.h3, fontWeight = FontWeight.Bold) - TextBelowButton(stringResource(MR.strings.you_can_make_address_visible_via_settings)) - Spacer(Modifier.height(DEFAULT_PADDING)) - Spacer(Modifier.weight(1f)) + if (userAddress != null) { + SimpleXLinkQRCode(userAddress.connReqContact) + Spacer(Modifier.height(DEFAULT_PADDING_HALF)) + Row { + ShareAddressButton { share(simplexChatLink(userAddress.connReqContact)) } + Spacer(Modifier.width(DEFAULT_PADDING * 2)) + ShareViaEmailButton { sendEmail(userAddress) } + } + Spacer(Modifier.height(DEFAULT_PADDING)) + Spacer(Modifier.weight(1f)) + Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { + OnboardingActionButton( + modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), + labelId = MR.strings.continue_to_next_step, + onboarding = null, + onclick = nextStep + ) + // Reserve space + TextButtonBelowOnboardingButton("", null) + } + } else { + Button(createAddress, Modifier, shape = CircleShape, contentPadding = PaddingValues()) { + Icon(painterResource(MR.images.ic_mail_filled), null, Modifier.size(100.dp).background(MaterialTheme.colors.primary, CircleShape).padding(25.dp), tint = Color.White) + } + Spacer(Modifier.height(DEFAULT_PADDING)) + Spacer(Modifier.weight(1f)) + Text(stringResource(MR.strings.create_simplex_address), style = MaterialTheme.typography.h3, fontWeight = FontWeight.Bold) + TextBelowButton(stringResource(MR.strings.you_can_make_address_visible_via_settings)) + Spacer(Modifier.height(DEFAULT_PADDING)) + Spacer(Modifier.weight(1f)) - Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { - OnboardingActionButton( - modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), - labelId = MR.strings.create_address_button, - onboarding = null, - onclick = createAddress - ) - TextButtonBelowOnboardingButton(stringResource(MR.strings.dont_create_address), nextStep) + Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { + OnboardingActionButton( + modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier.widthIn(min = 300.dp), + labelId = MR.strings.create_address_button, + onboarding = null, + onclick = createAddress + ) + TextButtonBelowOnboardingButton(stringResource(MR.strings.dont_create_address), nextStep) + } + } } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt index 96e1ce8e34..1903b3cf81 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt @@ -25,39 +25,47 @@ import chat.simplex.res.MR @Composable fun SetNotificationsMode(m: ChatModel) { - ColumnWithScrollBar( - modifier = Modifier - .fillMaxSize() - .themedBackground() + val handler = remember { AppBarHandler() } + CompositionLocalProvider( + LocalAppBarHandler provides handler ) { - CloseSheetBar(showClose = false, close = {}) - AppBarTitle(stringResource(MR.strings.onboarding_notifications_mode_title)) - val currentMode = rememberSaveable { mutableStateOf(NotificationsMode.default) } - Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) { - Text(stringResource(MR.strings.onboarding_notifications_mode_subtitle), Modifier.fillMaxWidth(), textAlign = TextAlign.Center) - Spacer(Modifier.height(DEFAULT_PADDING * 2f)) - SelectableCard(currentMode, NotificationsMode.OFF, stringResource(MR.strings.onboarding_notifications_mode_off), annotatedStringResource(MR.strings.onboarding_notifications_mode_off_desc)) { - currentMode.value = NotificationsMode.OFF - } - SelectableCard(currentMode, NotificationsMode.PERIODIC, stringResource(MR.strings.onboarding_notifications_mode_periodic), annotatedStringResource(MR.strings.onboarding_notifications_mode_periodic_desc)){ - currentMode.value = NotificationsMode.PERIODIC - } - SelectableCard(currentMode, NotificationsMode.SERVICE, stringResource(MR.strings.onboarding_notifications_mode_service), annotatedStringResource(MR.strings.onboarding_notifications_mode_service_desc)){ - currentMode.value = NotificationsMode.SERVICE - } - } - Spacer(Modifier.fillMaxHeight().weight(1f)) - Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { - OnboardingActionButton( - modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier, - labelId = MR.strings.use_chat, - onboarding = OnboardingStage.OnboardingComplete, - onclick = { - changeNotificationsMode(currentMode.value, m) + ModalView({}, showClose = false) { + ColumnWithScrollBar( + modifier = Modifier + .fillMaxSize() + .themedBackground() + ) { + Box(Modifier.align(Alignment.CenterHorizontally)) { + AppBarTitle(stringResource(MR.strings.onboarding_notifications_mode_title)) } - ) - // Reserve space - TextButtonBelowOnboardingButton("", null) + val currentMode = rememberSaveable { mutableStateOf(NotificationsMode.default) } + Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) { + Text(stringResource(MR.strings.onboarding_notifications_mode_subtitle), Modifier.fillMaxWidth(), textAlign = TextAlign.Center) + Spacer(Modifier.height(DEFAULT_PADDING * 2f)) + SelectableCard(currentMode, NotificationsMode.OFF, stringResource(MR.strings.onboarding_notifications_mode_off), annotatedStringResource(MR.strings.onboarding_notifications_mode_off_desc)) { + currentMode.value = NotificationsMode.OFF + } + SelectableCard(currentMode, NotificationsMode.PERIODIC, stringResource(MR.strings.onboarding_notifications_mode_periodic), annotatedStringResource(MR.strings.onboarding_notifications_mode_periodic_desc)) { + currentMode.value = NotificationsMode.PERIODIC + } + SelectableCard(currentMode, NotificationsMode.SERVICE, stringResource(MR.strings.onboarding_notifications_mode_service), annotatedStringResource(MR.strings.onboarding_notifications_mode_service_desc)) { + currentMode.value = NotificationsMode.SERVICE + } + } + Spacer(Modifier.fillMaxHeight().weight(1f)) + Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { + OnboardingActionButton( + modifier = if (appPlatform.isAndroid) Modifier.padding(horizontal = DEFAULT_PADDING * 2).fillMaxWidth() else Modifier, + labelId = MR.strings.use_chat, + onboarding = OnboardingStage.OnboardingComplete, + onclick = { + changeNotificationsMode(currentMode.value, m) + } + ) + // Reserve space + TextButtonBelowOnboardingButton("", null) + } + } } } SetNotificationsModeAdditions() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt index 7a1b7cccb4..858ca68af3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetupDatabasePassphrase.kt @@ -104,84 +104,90 @@ private fun SetupDatabasePassphraseLayout( onConfirmEncrypt: () -> Unit, nextStep: () -> Unit, ) { - ColumnWithScrollBar( - Modifier.fillMaxSize().themedBackground().padding(bottom = DEFAULT_PADDING * 2), - horizontalAlignment = Alignment.CenterHorizontally, + val handler = remember { AppBarHandler() } + CompositionLocalProvider( + LocalAppBarHandler provides handler ) { - CloseSheetBar(showClose = false, close = {}) - AppBarTitle(stringResource(MR.strings.setup_database_passphrase)) + ModalView({}, showClose = false) { + ColumnWithScrollBar( + Modifier.fillMaxSize().themedBackground().padding(bottom = DEFAULT_PADDING * 2), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + AppBarTitle(stringResource(MR.strings.setup_database_passphrase)) - Spacer(Modifier.weight(1f)) + Spacer(Modifier.weight(1f)) - Column(Modifier.width(600.dp)) { - val focusRequester = remember { FocusRequester() } - val focusManager = LocalFocusManager.current - LaunchedEffect(Unit) { - delay(100L) - focusRequester.requestFocus() - } - PassphraseField( - newKey, - generalGetString(MR.strings.new_passphrase), - modifier = Modifier - .padding(horizontal = DEFAULT_PADDING) - .focusRequester(focusRequester) - .onPreviewKeyEvent { - if ((it.key == Key.Enter || it.key == Key.NumPadEnter) && it.type == KeyEventType.KeyUp) { - focusManager.moveFocus(FocusDirection.Down) - true - } else { - false + Column(Modifier.width(600.dp)) { + val focusRequester = remember { FocusRequester() } + val focusManager = LocalFocusManager.current + LaunchedEffect(Unit) { + delay(100L) + focusRequester.requestFocus() + } + PassphraseField( + newKey, + generalGetString(MR.strings.new_passphrase), + modifier = Modifier + .padding(horizontal = DEFAULT_PADDING) + .focusRequester(focusRequester) + .onPreviewKeyEvent { + if ((it.key == Key.Enter || it.key == Key.NumPadEnter) && it.type == KeyEventType.KeyUp) { + focusManager.moveFocus(FocusDirection.Down) + true + } else { + false + } + }, + showStrength = true, + isValid = ::validKey, + keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), + ) + val onClickUpdate = { + // Don't do things concurrently. Shouldn't be here concurrently, just in case + if (!progressIndicator.value) { + encryptDatabaseAlert(onConfirmEncrypt) } - }, - showStrength = true, - isValid = ::validKey, - keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }), - ) - val onClickUpdate = { - // Don't do things concurrently. Shouldn't be here concurrently, just in case - if (!progressIndicator.value) { - encryptDatabaseAlert(onConfirmEncrypt) + } + val disabled = currentKey.value == newKey.value || + newKey.value != confirmNewKey.value || + newKey.value.isEmpty() || + !validKey(currentKey.value) || + !validKey(newKey.value) || + progressIndicator.value + + PassphraseField( + confirmNewKey, + generalGetString(MR.strings.confirm_new_passphrase), + modifier = Modifier + .padding(horizontal = DEFAULT_PADDING) + .onPreviewKeyEvent { + if (!disabled && (it.key == Key.Enter || it.key == Key.NumPadEnter) && it.type == KeyEventType.KeyUp) { + onClickUpdate() + true + } else { + false + } + }, + isValid = { confirmNewKey.value == "" || newKey.value == confirmNewKey.value }, + keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done) }), + ) + + Box(Modifier.align(Alignment.CenterHorizontally).padding(vertical = DEFAULT_PADDING)) { + SetPassphraseButton(disabled, onClickUpdate) + } + + Column { + SectionTextFooter(generalGetString(MR.strings.you_have_to_enter_passphrase_every_time)) + SectionTextFooter(annotatedStringResource(MR.strings.impossible_to_recover_passphrase)) + } + } + + Spacer(Modifier.weight(1f)) + SkipButton(progressIndicator.value) { + chatModel.desktopOnboardingRandomPassword.value = true + nextStep() } } - val disabled = currentKey.value == newKey.value || - newKey.value != confirmNewKey.value || - newKey.value.isEmpty() || - !validKey(currentKey.value) || - !validKey(newKey.value) || - progressIndicator.value - - PassphraseField( - confirmNewKey, - generalGetString(MR.strings.confirm_new_passphrase), - modifier = Modifier - .padding(horizontal = DEFAULT_PADDING) - .onPreviewKeyEvent { - if (!disabled && (it.key == Key.Enter || it.key == Key.NumPadEnter) && it.type == KeyEventType.KeyUp) { - onClickUpdate() - true - } else { - false - } - }, - isValid = { confirmNewKey.value == "" || newKey.value == confirmNewKey.value }, - keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done) }), - ) - - Box(Modifier.align(Alignment.CenterHorizontally).padding(vertical = DEFAULT_PADDING)) { - SetPassphraseButton(disabled, onClickUpdate) - } - - Column { - SectionTextFooter(generalGetString(MR.strings.you_have_to_enter_passphrase_every_time)) - SectionTextFooter(annotatedStringResource(MR.strings.impossible_to_recover_passphrase)) - } - } - - Spacer(Modifier.weight(1f)) - SkipButton(progressIndicator.value) { - chatModel.desktopOnboardingRandomPassword.value = true - nextStep() } } }