diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt index 9c5f123f40..c8ca0d8489 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt @@ -276,12 +276,12 @@ class SimplexApp: Application(), LifecycleEventObserver { @Suppress("DEPRECATION") val windowInsetController = ViewCompat.getWindowInsetsController(window.decorView) - val statusBar = (if (hasTop) { + val statusBar = (if (hasTop && appPrefs.onboardingStage.get() == OnboardingStage.OnboardingComplete) { backgroundColor.mixWith(CurrentColors.value.colors.onBackground, 0.97f) } else { backgroundColor }).toArgb() - val navBar = (if (hasBottom) { + val navBar = (if (hasBottom && appPrefs.onboardingStage.get() == OnboardingStage.OnboardingComplete) { backgroundColor.mixWith(CurrentColors.value.colors.onBackground, 0.97f) } else { backgroundColor diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.android.kt index bfe87b17d7..d9d3af7bb7 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.android.kt @@ -1,6 +1,8 @@ package chat.simplex.common.views.onboarding +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import chat.simplex.common.model.SharedPreference import chat.simplex.common.model.User import chat.simplex.res.MR @@ -8,8 +10,8 @@ import chat.simplex.res.MR @Composable actual fun OnboardingActionButton(user: User?, onboardingStage: SharedPreference, onclick: (() -> Unit)?) { if (user == null) { - OnboardingActionButton(MR.strings.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, true, onclick = onclick) + OnboardingActionButton(Modifier.fillMaxWidth(), labelId = MR.strings.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, onclick = onclick) } else { - OnboardingActionButton(MR.strings.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, true, onclick = onclick) + OnboardingActionButton(Modifier.fillMaxWidth(), labelId = MR.strings.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onclick = onclick) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt index 0df2633610..c779d2ae67 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/App.kt @@ -1,5 +1,7 @@ package chat.simplex.common +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.SizeTransform import androidx.compose.animation.core.Animatable import androidx.compose.foundation.* import androidx.compose.foundation.interaction.MutableInteractionSource @@ -29,6 +31,8 @@ import chat.simplex.common.views.chat.ChatView import chat.simplex.common.views.chatlist.* import chat.simplex.common.views.database.DatabaseErrorView import chat.simplex.common.views.helpers.* +import chat.simplex.common.views.helpers.ModalManager.Companion.fromEndToStartTransition +import chat.simplex.common.views.helpers.ModalManager.Companion.fromStartToEndTransition import chat.simplex.common.views.localauth.VerticalDivider import chat.simplex.common.views.onboarding.* import chat.simplex.common.views.usersettings.* @@ -148,17 +152,30 @@ fun MainScreen() { } } } - onboarding == OnboardingStage.Step1_SimpleXInfo -> { - SimpleXInfo(chatModel, onboarding = true) - if (appPlatform.isDesktop) { - ModalManager.fullscreen.showInView() + else -> AnimatedContent(targetState = onboarding, + transitionSpec = { + if (targetState > initialState) { + fromEndToStartTransition() + } else { + fromStartToEndTransition() + }.using(SizeTransform(clip = false)) + } + ) { state -> + when (state) { + OnboardingStage.OnboardingComplete -> { /* handled out of AnimatedContent block */} + OnboardingStage.Step1_SimpleXInfo -> { + SimpleXInfo(chatModel, onboarding = true) + if (appPlatform.isDesktop) { + ModalManager.fullscreen.showInView() + } + } + OnboardingStage.Step2_CreateProfile -> CreateFirstProfile(chatModel) {} + OnboardingStage.LinkAMobile -> LinkAMobile() + OnboardingStage.Step2_5_SetupDatabasePassphrase -> SetupDatabasePassphrase(chatModel) + OnboardingStage.Step3_CreateSimpleXAddress -> CreateSimpleXAddress(chatModel, null) + OnboardingStage.Step4_SetNotificationsMode -> SetNotificationsMode(chatModel) } } - onboarding == OnboardingStage.Step2_CreateProfile -> CreateFirstProfile(chatModel) {} - onboarding == OnboardingStage.LinkAMobile -> LinkAMobile() - onboarding == OnboardingStage.Step2_5_SetupDatabasePassphrase -> SetupDatabasePassphrase(chatModel) - onboarding == OnboardingStage.Step3_CreateSimpleXAddress -> CreateSimpleXAddress(chatModel, null) - onboarding == OnboardingStage.Step4_SetNotificationsMode -> SetNotificationsMode(chatModel) } if (appPlatform.isAndroid) { ModalManager.fullscreen.showInView() 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 41b30be640..53f494a5f7 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 @@ -2,8 +2,8 @@ package chat.simplex.common.views import SectionTextFooter import androidx.compose.foundation.* +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.* import androidx.compose.material.MaterialTheme.colors @@ -17,11 +17,12 @@ import androidx.compose.ui.graphics.SolidColor import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.* import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatModel.controller import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* @@ -112,47 +113,46 @@ fun CreateFirstProfile(chatModel: ChatModel, close: () -> Unit) { var savedKeyboardState by remember { mutableStateOf(keyboardState) } ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { - Box( + Column( modifier = Modifier - .fillMaxSize() - .padding(top = 20.dp) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally ) { - val displayName = rememberSaveable { mutableStateOf("") } - val focusRequester = remember { FocusRequester() } + 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 = Modifier.fillMaxSize() + modifier = if (appPlatform.isAndroid) Modifier.fillMaxSize() else Modifier.widthIn(max = 600.dp).fillMaxHeight(), ) { - /*CloseSheetBar(close = { - if (chatModel.users.isEmpty()) { - chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo - } else { - close() - } - })*/ + val displayName = rememberSaveable { mutableStateOf("") } + val focusRequester = remember { FocusRequester() } Column(Modifier.padding(horizontal = DEFAULT_PADDING)) { AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING) - ReadableText(MR.strings.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues(), style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary)) - ReadableText(MR.strings.profile_is_only_shared_with_your_contacts, TextAlign.Center, style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary)) + ProfileNameField(displayName, stringResource(MR.strings.display_name), { it.trim() == mkValidName(it) }, focusRequester) Spacer(Modifier.height(DEFAULT_PADDING)) - Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { - Text( - stringResource(MR.strings.display_name), - fontSize = 16.sp - ) - val name = displayName.value.trim() - val validName = mkValidName(name) - Spacer(Modifier.height(20.dp)) - if (name != validName) { - IconButton({ showInvalidNameAlert(mkValidName(displayName.value), displayName) }, Modifier.size(20.dp)) { - Icon(painterResource(MR.images.ic_info), null, tint = MaterialTheme.colors.error) - } - } - } - ProfileNameField(displayName, "", { it.trim() == mkValidName(it) }, focusRequester) + 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)) - OnboardingButtons(displayName, close) + 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) @@ -230,28 +230,6 @@ fun createProfileOnboarding(chatModel: ChatModel, displayName: String, close: () } } -@Composable -fun OnboardingButtons(displayName: MutableState, close: () -> Unit) { - Row { - SimpleButtonDecorated( - text = stringResource(MR.strings.about_simplex), - icon = painterResource(MR.images.ic_arrow_back_ios_new), - textDecoration = TextDecoration.None, - fontWeight = FontWeight.Medium - ) { chatModel.controller.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) } - Spacer(Modifier.fillMaxWidth().weight(1f)) - val enabled = canCreateProfile(displayName.value) - val createModifier: Modifier = Modifier.clickable(enabled) { createProfileOnboarding(chatModel, displayName.value, close) }.padding(8.dp) - val createColor: Color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary - Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent, contentColor = LocalContentColor.current) { - Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) { - Text(stringResource(MR.strings.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium) - Icon(painterResource(MR.images.ic_arrow_forward_ios), stringResource(MR.strings.create_profile_button), tint = createColor) - } - } - } -} - @Composable fun ProfileNameField(name: MutableState, placeholder: String = "", isValid: (String) -> Boolean = { true }, focusRequester: FocusRequester? = null) { var valid by rememberSaveable { mutableStateOf(true) } @@ -269,15 +247,13 @@ fun ProfileNameField(name: MutableState, placeholder: String = "", isVal } val modifier = Modifier .fillMaxWidth() - .padding(horizontal = DEFAULT_PADDING) + .heightIn(min = 50.dp) .navigationBarsWithImePadding() .onFocusChanged { focused = it.isFocused } - Box( + Column( Modifier - .fillMaxWidth() - .height(52.dp) - .border(border = BorderStroke(1.dp, strokeColor), shape = RoundedCornerShape(50)), - contentAlignment = Alignment.Center + .fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally ) { BasicTextField( value = name.value, @@ -285,8 +261,31 @@ fun ProfileNameField(name: MutableState, placeholder: String = "", isVal modifier = if (focusRequester == null) modifier else modifier.focusRequester(focusRequester), textStyle = TextStyle(fontSize = 18.sp, color = colors.onBackground), singleLine = true, - cursorBrush = SolidColor(MaterialTheme.colors.secondary) + cursorBrush = SolidColor(MaterialTheme.colors.secondary), + decorationBox = @Composable { innerTextField -> + TextFieldDefaults.TextFieldDecorationBox( + value = name.value, + innerTextField = innerTextField, + placeholder = if (placeholder != "") {{ Text(placeholder, style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary, lineHeight = 22.sp)) }} else null, + contentPadding = PaddingValues(), + label = null, + visualTransformation = VisualTransformation.None, + leadingIcon = null, + trailingIcon = if (!valid && placeholder != "") { + { + IconButton({ showInvalidNameAlert(mkValidName(name.value), name) }, Modifier.size(20.dp)) { + Icon(painterResource(MR.images.ic_info), null, tint = MaterialTheme.colors.error) + } + } + } else null, + singleLine = true, + enabled = true, + isError = false, + interactionSource = remember { MutableInteractionSource() }, + ) + } ) + Divider(color = strokeColor) } LaunchedEffect(Unit) { snapshotFlow { name.value } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt index d20d573bd2..d44476b91b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt @@ -174,28 +174,6 @@ class ModalManager(private val placement: ModalPlacement? = null) { block() atomicBoolean.set(false) } - - @OptIn(ExperimentalAnimationApi::class) - private fun fromStartToEndTransition() = - slideInHorizontally( - initialOffsetX = { fullWidth -> -fullWidth }, - animationSpec = animationSpec() - ) with slideOutHorizontally( - targetOffsetX = { fullWidth -> fullWidth }, - animationSpec = animationSpec() - ) - - @OptIn(ExperimentalAnimationApi::class) - private fun fromEndToStartTransition() = - slideInHorizontally( - initialOffsetX = { fullWidth -> fullWidth }, - animationSpec = animationSpec() - ) with slideOutHorizontally( - targetOffsetX = { fullWidth -> -fullWidth }, - animationSpec = animationSpec() - ) - -private fun animationSpec() = tween(durationMillis = 250, easing = FastOutSlowInEasing) // private fun animationSpecFromStart() = tween(durationMillis = 150, easing = FastOutLinearInEasing) // private fun animationSpecFromEnd() = tween(durationMillis = 100, easing = FastOutSlowInEasing) @@ -212,5 +190,27 @@ private fun animationSpec() = tween(durationMillis = 250, easing = FastOu end.closeModals() fullscreen.closeModals() } + + @OptIn(ExperimentalAnimationApi::class) + fun fromStartToEndTransition() = + slideInHorizontally( + initialOffsetX = { fullWidth -> -fullWidth }, + animationSpec = animationSpec() + ) with slideOutHorizontally( + targetOffsetX = { fullWidth -> fullWidth }, + animationSpec = animationSpec() + ) + + @OptIn(ExperimentalAnimationApi::class) + fun fromEndToStartTransition() = + slideInHorizontally( + initialOffsetX = { fullWidth -> fullWidth }, + animationSpec = animationSpec() + ) with slideOutHorizontally( + targetOffsetX = { fullWidth -> -fullWidth }, + animationSpec = animationSpec() + ) + + private fun animationSpec() = tween(durationMillis = 250, easing = FastOutSlowInEasing) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SimpleButton.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SimpleButton.kt index 7db001a4bd..1c4879dedd 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SimpleButton.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/SimpleButton.kt @@ -1,8 +1,10 @@ package chat.simplex.common.views.helpers import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import dev.icerock.moko.resources.compose.painterResource @@ -16,6 +18,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp +import chat.simplex.common.platform.appPlatform import chat.simplex.common.ui.theme.SimpleXTheme import chat.simplex.res.MR 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 5e50475951..027d977ada 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 @@ -1,15 +1,16 @@ package chat.simplex.common.views.onboarding -import SectionBottomSpacer +import androidx.compose.foundation.* import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.text.font.FontWeight import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextAlign @@ -76,78 +77,94 @@ private fun CreateSimpleXAddressLayout( nextStep: () -> Unit, ) { ColumnWithScrollBar( - Modifier.fillMaxSize().padding(top = DEFAULT_PADDING), + Modifier + .fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { + CloseSheetBar(showClose = false, close = {}) AppBarTitle(stringResource(MR.strings.simplex_address)) Spacer(Modifier.weight(1f)) if (userAddress != null) { SimpleXLinkQRCode(userAddress.connReqContact) - ShareAddressButton { share(simplexChatLink(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)) - ShareViaEmailButton { sendEmail(userAddress) } - Spacer(Modifier.weight(1f)) - ContinueButton(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.continue_to_next_step, + onboarding = null, + onclick = nextStep + ) + // Reserve space + TextButtonBelowOnboardingButton("", null) + } } else { - CreateAddressButton(createAddress) - TextBelowButton(stringResource(MR.strings.you_can_make_address_visible_via_settings)) + 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)) - SkipButton(nextStep) - } - SectionBottomSpacer() - } -} -@Composable -private fun CreateAddressButton(onClick: () -> Unit) { - TextButton(onClick) { - Text(stringResource(MR.strings.create_simplex_address), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary) + 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) + } + } } } @Composable fun ShareAddressButton(onClick: () -> Unit) { - SimpleButtonFrame(onClick) { - Icon( - painterResource(MR.images.ic_share_filled), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary, - modifier = Modifier.padding(end = 8.dp).size(18.dp) - ) - Text(stringResource(MR.strings.share_verb), style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary) + Column(horizontalAlignment = Alignment.CenterHorizontally) { + IconButton(onClick, Modifier.padding(bottom = DEFAULT_PADDING_HALF).border(1.dp, MaterialTheme.colors.secondary.copy(0.1f), CircleShape)) { + Icon( + painterResource(MR.images.ic_share_filled), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary, + modifier = Modifier.size(50.dp).padding(DEFAULT_PADDING_HALF) + ) + } + Text(stringResource(MR.strings.share_verb)) } } @Composable fun ShareViaEmailButton(onClick: () -> Unit) { - SimpleButtonFrame(onClick) { - Icon( - painterResource(MR.images.ic_mail), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary, - modifier = Modifier.padding(end = 8.dp).size(30.dp) - ) - Text(stringResource(MR.strings.invite_friends), style = MaterialTheme.typography.h6, color = MaterialTheme.colors.primary) + Column(horizontalAlignment = Alignment.CenterHorizontally) { + IconButton(onClick, Modifier.padding(bottom = DEFAULT_PADDING_HALF).border(1.dp, MaterialTheme.colors.secondary.copy(0.1f), CircleShape)) { + Icon( + painterResource(MR.images.ic_mail), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary, + modifier = Modifier.size(50.dp).padding(DEFAULT_PADDING_HALF) + ) + } + Text(stringResource(MR.strings.invite_friends_short)) } } -@Composable -private fun ContinueButton(onClick: () -> Unit) { - SimpleButtonIconEnded(stringResource(MR.strings.continue_to_next_step), painterResource(MR.images.ic_chevron_right), click = onClick) -} - -@Composable -private fun SkipButton(onClick: () -> Unit) { - SimpleButtonIconEnded(stringResource(MR.strings.dont_create_address), painterResource(MR.images.ic_chevron_right), click = onClick) - TextBelowButton(stringResource(MR.strings.you_can_create_it_later)) -} - @Composable private fun TextBelowButton(text: String) { Text( text, Modifier .fillMaxWidth() - .padding(horizontal = DEFAULT_PADDING * 3), + .padding(horizontal = DEFAULT_PADDING * 3, vertical = DEFAULT_PADDING_HALF), style = MaterialTheme.typography.subtitle1, + color = MaterialTheme.colors.secondary, textAlign = TextAlign.Center, ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt index 28fa1d3a48..3f2c035335 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/HowItWorks.kt @@ -25,7 +25,7 @@ import dev.icerock.moko.resources.StringResource fun HowItWorks(user: User?, onboardingStage: SharedPreference? = null) { ColumnWithScrollBar(Modifier .fillMaxWidth() - .padding(horizontal = DEFAULT_PADDING), + .padding(DEFAULT_PADDING), ) { AppBarTitle(stringResource(MR.strings.how_simplex_works), withPadding = false) ReadableText(MR.strings.many_people_asked_how_can_it_deliver) @@ -46,6 +46,7 @@ fun HowItWorks(user: User?, onboardingStage: SharedPreference? } Spacer(Modifier.fillMaxHeight().weight(1f)) } + Spacer(Modifier.height(DEFAULT_PADDING)) } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt index 0dae98559c..5627582956 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/LinkAMobileView.kt @@ -10,7 +10,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.model.ChatModel +import chat.simplex.common.platform.BackHandler import chat.simplex.common.platform.chatModel import chat.simplex.common.ui.theme.DEFAULT_PADDING import chat.simplex.common.views.helpers.* @@ -56,7 +58,13 @@ private fun LinkAMobileLayout( staleQrCode: MutableState, updateDeviceName: (String) -> Unit, ) { - Column(Modifier.padding(top = 20.dp)) { + Column { + CloseSheetBar(close = { + appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) + }) + BackHandler(onBack = { + appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) + }) AppBarTitle(stringResource(if (remember { chatModel.remoteHosts }.isEmpty()) MR.strings.link_a_mobile else MR.strings.linked_mobiles)) Row(Modifier.weight(1f).padding(horizontal = DEFAULT_PADDING * 2), verticalAlignment = Alignment.CenterVertically) { Column( @@ -82,11 +90,5 @@ private fun LinkAMobileLayout( } } } - SimpleButtonDecorated( - text = stringResource(MR.strings.about_simplex), - icon = painterResource(MR.images.ic_arrow_back_ios_new), - textDecoration = TextDecoration.None, - fontWeight = FontWeight.Medium - ) { chatModel.controller.appPrefs.onboardingStage.set(OnboardingStage.Step1_SimpleXInfo) } } } 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 61ecee74e4..81e99370f0 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 @@ -17,20 +17,19 @@ import androidx.compose.ui.unit.sp import chat.simplex.common.model.ChatModel import chat.simplex.common.model.NotificationsMode import chat.simplex.common.platform.ColumnWithScrollBar +import chat.simplex.common.platform.appPlatform import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.usersettings.changeNotificationsMode import chat.simplex.res.MR -import dev.icerock.moko.resources.StringResource @Composable fun SetNotificationsMode(m: ChatModel) { ColumnWithScrollBar( modifier = Modifier .fillMaxSize() - .padding(vertical = 14.dp) ) { - //CloseSheetBar(null) + 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)) { @@ -47,12 +46,18 @@ fun SetNotificationsMode(m: ChatModel) { } } Spacer(Modifier.fillMaxHeight().weight(1f)) - Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), contentAlignment = Alignment.Center) { - OnboardingActionButton(MR.strings.use_chat, OnboardingStage.OnboardingComplete, false) { - changeNotificationsMode(currentMode.value, m) - } + 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) } - Spacer(Modifier.fillMaxHeight().weight(1f)) } 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 a96cfa5a03..0239ddb8e5 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 @@ -1,11 +1,8 @@ package chat.simplex.common.views.onboarding -import SectionBottomSpacer import SectionTextFooter import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.verticalScroll import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable @@ -20,6 +17,7 @@ import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import chat.simplex.common.model.* +import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.database.* @@ -107,9 +105,10 @@ private fun SetupDatabasePassphraseLayout( nextStep: () -> Unit, ) { ColumnWithScrollBar( - Modifier.fillMaxSize().padding(top = DEFAULT_PADDING), + Modifier.fillMaxSize().padding(bottom = DEFAULT_PADDING * 2), horizontalAlignment = Alignment.CenterHorizontally, ) { + CloseSheetBar(showClose = false, close = {}) AppBarTitle(stringResource(MR.strings.setup_database_passphrase)) Spacer(Modifier.weight(1f)) @@ -184,8 +183,6 @@ private fun SetupDatabasePassphraseLayout( chatModel.desktopOnboardingRandomPassword.value = true nextStep() } - - SectionBottomSpacer() } } @@ -209,7 +206,8 @@ private fun SkipButton(disabled: Boolean, onClick: () -> Unit) { stringResource(MR.strings.you_can_change_it_later), Modifier .fillMaxWidth() - .padding(horizontal = DEFAULT_PADDING * 3), + .padding(horizontal = DEFAULT_PADDING * 3) + .padding(top = DEFAULT_PADDING, bottom = DEFAULT_PADDING - 5.dp), style = MaterialTheme.typography.subtitle1, color = MaterialTheme.colors.secondary, textAlign = TextAlign.Center, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt index 84c48bbc1b..57e15a37c3 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.kt @@ -1,23 +1,26 @@ package chat.simplex.common.views.onboarding +import androidx.compose.animation.core.animateDpAsState import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.* import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.layout.ContentScale import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.* import chat.simplex.common.model.* -import chat.simplex.common.platform.ColumnWithScrollBar -import chat.simplex.common.platform.chatModel +import chat.simplex.common.model.ChatController.appPrefs +import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* import chat.simplex.common.views.helpers.* import chat.simplex.common.views.migration.MigrateToDeviceView @@ -27,64 +30,67 @@ import dev.icerock.moko.resources.StringResource @Composable fun SimpleXInfo(chatModel: ChatModel, onboarding: Boolean = true) { - SimpleXInfoLayout( - user = chatModel.currentUser.value, - onboardingStage = if (onboarding) chatModel.controller.appPrefs.onboardingStage else null, - showModal = { modalView -> { if (onboarding) ModalManager.fullscreen.showModal { modalView(chatModel) } else ModalManager.start.showModal { modalView(chatModel) } } }, - ) + if (onboarding) { + ModalView({}, showClose = false, endButtons = { + IconButton({ ModalManager.fullscreen.showModal { HowItWorks(chatModel.currentUser.value, null) }}) { + Icon(painterResource(MR.images.ic_info), null, Modifier.size(28.dp), tint = MaterialTheme.colors.primary) + } + }) { + SimpleXInfoLayout( + user = chatModel.currentUser.value, + onboardingStage = chatModel.controller.appPrefs.onboardingStage + ) + } + } else { + SimpleXInfoLayout( + user = chatModel.currentUser.value, + onboardingStage = null + ) + } } @Composable fun SimpleXInfoLayout( user: User?, - onboardingStage: SharedPreference?, - showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), + onboardingStage: SharedPreference? ) { ColumnWithScrollBar( Modifier .fillMaxSize() - .padding(start = DEFAULT_PADDING , end = DEFAULT_PADDING, top = DEFAULT_PADDING), + .padding(horizontal = 16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Box(Modifier.fillMaxWidth().padding(top = 8.dp, bottom = 10.dp), contentAlignment = Alignment.Center) { + Box(Modifier.widthIn(max = if (appPlatform.isAndroid) 250.dp else 500.dp).padding(top = DEFAULT_PADDING + 8.dp), contentAlignment = Alignment.Center) { SimpleXLogo() } - Text(stringResource(MR.strings.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 48.dp).padding(horizontal = 36.dp), textAlign = TextAlign.Center) + Spacer(Modifier.weight(1f)) - Column { - InfoRow(painterResource(MR.images.privacy), MR.strings.privacy_redefined, MR.strings.first_platform_without_user_ids, width = 80.dp) - InfoRow(painterResource(MR.images.shield), MR.strings.immune_to_spam_and_abuse, MR.strings.people_can_connect_only_via_links_you_share) + Text( + stringResource(MR.strings.next_generation_of_private_messaging), + style = MaterialTheme.typography.h3, + color = MaterialTheme.colors.secondary, + textAlign = TextAlign.Center + ) + + Spacer(Modifier.weight(1f)) + + Column(Modifier.fillMaxWidth()) { + InfoRow(painterResource(MR.images.privacy), MR.strings.privacy_redefined, MR.strings.first_platform_without_user_ids, width = 60.dp) + InfoRow(painterResource(MR.images.shield), MR.strings.immune_to_spam_and_abuse, MR.strings.people_can_connect_only_via_links_you_share, width = 46.dp) InfoRow(painterResource(if (isInDarkTheme()) MR.images.decentralized_light else MR.images.decentralized), MR.strings.decentralized, MR.strings.opensource_protocol_and_code_anybody_can_run_servers) } Spacer(Modifier.fillMaxHeight().weight(1f)) if (onboardingStage != null) { - Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + Column(Modifier.padding(horizontal = DEFAULT_PADDING).widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) { OnboardingActionButton(user, onboardingStage) + TextButtonBelowOnboardingButton(stringResource(MR.strings.migrate_from_another_device)) { + chatModel.migrationState.value = MigrationToState.PasteOrScanLink + ModalManager.fullscreen.showCustomModal { close -> MigrateToDeviceView(close) } + } } - Spacer(Modifier.fillMaxHeight().weight(1f)) - - Box( - Modifier - .fillMaxWidth() - .padding(top = DEFAULT_PADDING), contentAlignment = Alignment.Center - ) { - SimpleButtonDecorated(text = stringResource(MR.strings.migrate_from_another_device), icon = painterResource(MR.images.ic_download), - click = { - chatModel.migrationState.value = MigrationToState.PasteOrScanLink - ModalManager.fullscreen.showCustomModal { close -> MigrateToDeviceView(close) } }) - } - } - - Box( - Modifier - .fillMaxWidth() - .padding(bottom = DEFAULT_PADDING.times(1.5f), top = if (onboardingStage == null) DEFAULT_PADDING else 0.dp), contentAlignment = Alignment.Center - ) { - SimpleButtonDecorated(text = stringResource(MR.strings.how_it_works), icon = painterResource(MR.images.ic_info), - click = showModal { HowItWorks(user, onboardingStage) }) } } LaunchedEffect(Unit) { @@ -99,21 +105,23 @@ fun SimpleXLogo() { Image( painter = painterResource(if (isInDarkTheme()) MR.images.logo_light else MR.images.logo), contentDescription = stringResource(MR.strings.image_descr_simplex_logo), + contentScale = ContentScale.FillWidth, modifier = Modifier .padding(vertical = DEFAULT_PADDING) - .fillMaxWidth(0.60f) + .fillMaxWidth() ) } @Composable -private fun InfoRow(icon: Painter, titleId: StringResource, textId: StringResource, width: Dp = 76.dp) { +private fun InfoRow(icon: Painter, titleId: StringResource, textId: StringResource, width: Dp = 58.dp) { Row(Modifier.padding(bottom = 27.dp), verticalAlignment = Alignment.Top) { + Spacer(Modifier.width((18.dp + 58.dp - width) / 2)) Image(icon, contentDescription = null, modifier = Modifier - .width(width) - .padding(top = 8.dp, start = 8.dp, end = 24.dp)) - Column { + .width(width)) + Spacer(Modifier.width((18.dp + 58.dp - width) / 2 + DEFAULT_PADDING_HALF)) + Column(Modifier.padding(top = 4.dp), verticalArrangement = Arrangement.spacedBy(DEFAULT_PADDING_HALF)) { Text(stringResource(titleId), fontWeight = FontWeight.Bold, style = MaterialTheme.typography.h3, lineHeight = 24.sp) - Text(stringResource(textId), lineHeight = 24.sp, style = MaterialTheme.typography.body1) + Text(stringResource(textId), lineHeight = 24.sp, style = MaterialTheme.typography.body1, color = MaterialTheme.colors.secondary) } } } @@ -123,38 +131,53 @@ expect fun OnboardingActionButton(user: User?, onboardingStage: SharedPreference @Composable fun OnboardingActionButton( + modifier: Modifier = Modifier, labelId: StringResource, onboarding: OnboardingStage?, - border: Boolean, + enabled: Boolean = true, icon: Painter? = null, - iconColor: Color = MaterialTheme.colors.primary, + iconColor: Color = Color.White, onclick: (() -> Unit)? ) { - val modifier = if (border) { - Modifier - .border(border = BorderStroke(1.dp, MaterialTheme.colors.primary), shape = RoundedCornerShape(50)) - .padding( - horizontal = if (icon == null) DEFAULT_PADDING * 2 else DEFAULT_PADDING_HALF, - vertical = 4.dp - ) - } else { - Modifier - } - - SimpleButtonFrame(click = { - onclick?.invoke() - if (onboarding != null) { - ChatController.appPrefs.onboardingStage.set(onboarding) - } - }, modifier) { + Button( + onClick = { + onclick?.invoke() + if (onboarding != null) { + appPrefs.onboardingStage.set(onboarding) + } + }, + modifier = modifier, + shape = CircleShape, + enabled = enabled, +// elevation = ButtonDefaults.elevation(defaultElevation = 0.dp, focusedElevation = 0.dp, pressedElevation = 0.dp, hoveredElevation = 0.dp), + contentPadding = PaddingValues(horizontal = if (icon == null) DEFAULT_PADDING * 2 else DEFAULT_PADDING * 1.5f, vertical = DEFAULT_PADDING), + colors = ButtonDefaults.buttonColors(MaterialTheme.colors.primary, disabledBackgroundColor = MaterialTheme.colors.secondary) + ) { if (icon != null) { Icon(icon, stringResource(labelId), Modifier.padding(end = DEFAULT_PADDING_HALF), tint = iconColor) } - Text(stringResource(labelId), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary, fontSize = 20.sp) - Icon( - painterResource(MR.images.ic_arrow_forward_ios), "next stage", tint = MaterialTheme.colors.primary, - modifier = Modifier.padding(start = DEFAULT_PADDING.div(4)).size(20.dp) - ) + Text(stringResource(labelId), style = MaterialTheme.typography.h2, color = Color.White, fontSize = 18.sp, fontWeight = FontWeight.Medium) + } +} + +@Composable +fun TextButtonBelowOnboardingButton(text: String, onClick: (() -> Unit)?) { + val state = getKeyboardState() + val topPadding by animateDpAsState(if (appPlatform.isAndroid && state.value == KeyboardState.Opened) 0.dp else DEFAULT_PADDING) + val bottomPadding by animateDpAsState(if (appPlatform.isAndroid && state.value == KeyboardState.Opened) 0.dp else DEFAULT_PADDING * 2) + if ((appPlatform.isAndroid && state.value == KeyboardState.Closed) || topPadding > 0.dp) { + TextButton({ onClick?.invoke() }, Modifier.padding(top = topPadding, bottom = bottomPadding).clip(CircleShape), enabled = onClick != null) { + Text( + text, + Modifier.padding(start = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING_HALF, bottom = 5.dp), + color = MaterialTheme.colors.primary, + fontWeight = FontWeight.Medium, + textAlign = TextAlign.Center + ) + } + } else { + // Hide from view when keyboard is open and move the view down + Spacer(Modifier.height(DEFAULT_PADDING * 2)) } } @@ -168,8 +191,7 @@ fun PreviewSimpleXInfo() { SimpleXTheme { SimpleXInfoLayout( user = null, - onboardingStage = null, - showModal = { {} } + onboardingStage = null ) } } diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index db0b407d9d..2dd7aab276 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -870,6 +870,7 @@ Don\'t create address You can create it later You can make it visible to your SimpleX contacts via Settings. + Invite Profile name: @@ -904,6 +905,7 @@ Enter your name: Create Create profile + Create Invalid name! Correct name to %s? About SimpleX @@ -956,13 +958,13 @@ Error initializing WebView. Update your system to the new version. Please contact developers.\nError: %s - The next generation of private messaging + The next generation\nof private messaging Privacy redefined - The 1st platform without any user identifiers – private by design. - Immune to spam and abuse - People can connect to you only via the links you share. + No user identifiers. + Immune to spam + You decide who can connect. Decentralized - Open-source protocol and code – anybody can run the servers. + Anybody can host servers. Create your profile Make a private connection Migrate from another device @@ -985,8 +987,8 @@ Periodic Instant Best for battery. You will receive notifications only when the app is running (NO background service).]]> - Good for battery. Background service checks messages every 10 minutes. You may miss calls or urgent messages.]]> - Uses more battery! Background service always runs – notifications are shown as soon as messages are available.]]> + Good for battery. App checks messages every 10 minutes. You may miss calls or urgent messages.]]> + Uses more battery! App always runs in background – notifications are shown instantly.]]> Setup database passphrase diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail_filled.svg b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail_filled.svg new file mode 100644 index 0000000000..5b43f32f04 --- /dev/null +++ b/apps/multiplatform/common/src/commonMain/resources/MR/images/ic_mail_filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml index d3fde45936..1339cf7f28 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -463,13 +463,13 @@ соединено завершен - Новое поколение приватных сообщений + Новое поколение\nприватных сообщений Более конфиденциальный - Первая в мире платформа без идентификаторов пользователей. + Без идентификаторов пользователей. Защищен от спама - С Вами можно соединиться только через созданные Вами ссылки. + Вы определяете, кто может соединиться. Децентрализованный - Открытый протокол и код - кто угодно может запустить сервер. + Кто угодно может запустить сервер. Создать профиль Добавьте контакт Как это работает diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.desktop.kt index 74c490445e..1b9582b7d2 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/views/onboarding/SimpleXInfo.desktop.kt @@ -1,8 +1,9 @@ package chat.simplex.common.views.onboarding -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import chat.simplex.common.model.ChatModel.controller import chat.simplex.common.model.SharedPreference import chat.simplex.common.model.User @@ -15,10 +16,10 @@ import dev.icerock.moko.resources.compose.painterResource actual fun OnboardingActionButton(user: User?, onboardingStage: SharedPreference, onclick: (() -> Unit)?) { if (user == null) { Row(horizontalArrangement = Arrangement.spacedBy(DEFAULT_PADDING * 2.5f)) { - OnboardingActionButton(MR.strings.link_a_mobile, onboarding = if (controller.appPrefs.initialRandomDBPassphrase.get() && !chatModel.desktopOnboardingRandomPassword.value) OnboardingStage.Step2_5_SetupDatabasePassphrase else OnboardingStage.LinkAMobile, true, icon = painterResource(MR.images.ic_smartphone_300), onclick = onclick) - OnboardingActionButton(MR.strings.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, true, icon = painterResource(MR.images.ic_desktop), onclick = onclick) + OnboardingActionButton(labelId = MR.strings.link_a_mobile, onboarding = if (controller.appPrefs.initialRandomDBPassphrase.get() && !chatModel.desktopOnboardingRandomPassword.value) OnboardingStage.Step2_5_SetupDatabasePassphrase else OnboardingStage.LinkAMobile, icon = painterResource(MR.images.ic_smartphone_300), onclick = onclick) + OnboardingActionButton(labelId = MR.strings.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, icon = painterResource(MR.images.ic_desktop), onclick = onclick) } } else { - OnboardingActionButton(MR.strings.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, true, onclick = onclick) + OnboardingActionButton(Modifier.widthIn(min = 300.dp), labelId = MR.strings.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onclick = onclick) } }