mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3629 Onboarding | Email screen (#2395)
This commit is contained in:
parent
734eeecbc1
commit
94042fe4b9
16 changed files with 474 additions and 34 deletions
|
@ -3,6 +3,7 @@ package com.anytypeio.anytype.di.feature.onboarding.signup
|
|||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.anytypeio.anytype.CrashReporter
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.di.common.ComponentDependencies
|
||||
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
|
||||
import com.anytypeio.anytype.domain.auth.interactor.CreateAccount
|
||||
|
@ -16,7 +17,9 @@ import com.anytypeio.anytype.domain.device.PathProvider
|
|||
import com.anytypeio.anytype.domain.misc.LocaleProvider
|
||||
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
|
||||
import com.anytypeio.anytype.domain.`object`.ImportGetStartedUseCase
|
||||
import com.anytypeio.anytype.domain.payments.SetMembershipEmail
|
||||
import com.anytypeio.anytype.domain.platform.InitialParamsProvider
|
||||
import com.anytypeio.anytype.domain.resources.StringResourceProvider
|
||||
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
|
||||
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
|
||||
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscriptionManager
|
||||
|
@ -94,6 +97,14 @@ object OnboardingSoulCreationModule {
|
|||
dispatchers = dispatchers
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@SoulCreationScreenScope
|
||||
fun provideSetMembershipEmail(
|
||||
repo: BlockRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): SetMembershipEmail = SetMembershipEmail(repo = repo, dispatchers = dispatchers)
|
||||
|
||||
@Module
|
||||
interface Declarations {
|
||||
@Binds
|
||||
|
@ -119,6 +130,7 @@ interface OnboardingSoulCreationDependencies : ComponentDependencies {
|
|||
fun userPermissionProvider(): UserPermissionProvider
|
||||
fun awaitAccountStartManager(): AwaitAccountStartManager
|
||||
fun globalSubscriptionManager(): GlobalSubscriptionManager
|
||||
fun stringResourceProvider(): StringResourceProvider
|
||||
}
|
||||
|
||||
@Scope
|
||||
|
|
|
@ -66,7 +66,6 @@ import androidx.navigation.compose.composable
|
|||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.navArgument
|
||||
import androidx.navigation.navOptions
|
||||
import com.anytypeio.anytype.BuildConfig.USE_EDGE_TO_EDGE
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
|
@ -74,7 +73,6 @@ import com.anytypeio.anytype.core_models.NO_VALUE
|
|||
import com.anytypeio.anytype.core_ui.BuildConfig.LIBRARY_PACKAGE_NAME
|
||||
import com.anytypeio.anytype.core_ui.MNEMONIC_WORD_COUNT
|
||||
import com.anytypeio.anytype.core_ui.MnemonicPhrasePaletteColors
|
||||
import com.anytypeio.anytype.core_ui.foundation.GenericAlert
|
||||
import com.anytypeio.anytype.core_ui.views.BaseAlertDialog
|
||||
import com.anytypeio.anytype.core_utils.ext.argOrNull
|
||||
import com.anytypeio.anytype.core_utils.ext.shareFirstFileFromPath
|
||||
|
@ -94,6 +92,7 @@ import com.anytypeio.anytype.ui.home.HomeScreenFragment
|
|||
import com.anytypeio.anytype.ui.onboarding.screens.AuthScreenWrapper
|
||||
import com.anytypeio.anytype.ui.onboarding.screens.signin.RecoveryScreenWrapper
|
||||
import com.anytypeio.anytype.ui.onboarding.screens.signup.MnemonicPhraseScreenWrapper
|
||||
import com.anytypeio.anytype.ui.onboarding.screens.signup.SetEmailWrapper
|
||||
import com.anytypeio.anytype.ui.onboarding.screens.signup.SetProfileNameWrapper
|
||||
import com.anytypeio.anytype.ui.vault.VaultFragment
|
||||
import com.google.android.exoplayer2.ExoPlayer
|
||||
|
@ -377,6 +376,40 @@ class OnboardingFragment : Fragment() {
|
|||
)
|
||||
BackHandler { onBackClicked() }
|
||||
}
|
||||
composable(
|
||||
route = "${OnboardingNavigation.setEmail}?$ONBOARDING_NAME_PARAM={$ONBOARDING_NAME_PARAM}",
|
||||
arguments = listOf(
|
||||
navArgument(ONBOARDING_NAME_PARAM) {
|
||||
type = NavType.StringType
|
||||
defaultValue = ""
|
||||
nullable = false
|
||||
}
|
||||
),
|
||||
enterTransition = {
|
||||
fadeIn(tween(ANIMATION_LENGTH_FADE))
|
||||
},
|
||||
exitTransition = {
|
||||
fadeOut(tween(ANIMATION_LENGTH_FADE))
|
||||
}
|
||||
) {
|
||||
val focus = LocalFocusManager.current
|
||||
val onBackClicked : () -> Unit = {
|
||||
val lastDestination = navController.currentBackStackEntry
|
||||
if (lastDestination?.destination?.route?.startsWith(OnboardingNavigation.setEmail) == true) {
|
||||
focus.clearFocus(true)
|
||||
navController.popBackStack()
|
||||
} else {
|
||||
Timber.d("Skipping exit click...")
|
||||
}
|
||||
}
|
||||
currentPage.value = OnboardingPage.SET_EMAIL
|
||||
backButtonCallback.value = onBackClicked
|
||||
AddEmail(
|
||||
navController = navController,
|
||||
onBackClicked = onBackClicked
|
||||
)
|
||||
BackHandler { onBackClicked() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,6 +588,16 @@ class OnboardingFragment : Fragment() {
|
|||
is OnboardingSetProfileNameViewModel.Navigation.GoBack -> {
|
||||
//
|
||||
}
|
||||
|
||||
is OnboardingSetProfileNameViewModel.Navigation.NavigateToAddEmailScreen -> {
|
||||
if (keyboardInsets.getBottom(density) > 0) {
|
||||
focusManager.clearFocus(force = true)
|
||||
delay(KEYBOARD_HIDE_DELAY)
|
||||
}
|
||||
navController.navigate(
|
||||
route = "${OnboardingNavigation.setEmail}?$ONBOARDING_NAME_PARAM=${command.name}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -731,6 +774,63 @@ class OnboardingFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AddEmail(
|
||||
navController: NavHostController,
|
||||
onBackClicked: () -> Unit
|
||||
) {
|
||||
val component = componentManager().onboardingSoulCreationComponent
|
||||
val vm = daggerViewModel { component.get().getViewModel() }
|
||||
|
||||
val focusManager = LocalFocusManager.current
|
||||
val keyboardInsets = WindowInsets.ime
|
||||
val density = LocalDensity.current
|
||||
|
||||
val name = navController.currentBackStackEntry?.arguments?.getString(ONBOARDING_NAME_PARAM) ?: ""
|
||||
|
||||
SetEmailWrapper(
|
||||
viewModel = vm,
|
||||
name = name,
|
||||
onBackClicked = onBackClicked
|
||||
)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
vm.navigation.collect { command ->
|
||||
when (command) {
|
||||
is OnboardingSetProfileNameViewModel.Navigation.NavigateToMnemonic -> {
|
||||
if (keyboardInsets.getBottom(density) > 0) {
|
||||
focusManager.clearFocus(force = true)
|
||||
delay(KEYBOARD_HIDE_DELAY)
|
||||
}
|
||||
val space = command.space
|
||||
val startingObject = command.startingObject
|
||||
navController.navigate(
|
||||
route = buildString {
|
||||
append("${OnboardingNavigation.mnemonic}?$ONBOARDING_SPACE_PARAM=${space.id}")
|
||||
startingObject?.let { append("&$ONBOARDING_STARTING_OBJECT_PARAM=${it}") }
|
||||
}
|
||||
)
|
||||
}
|
||||
is OnboardingSetProfileNameViewModel.Navigation.GoBack -> {
|
||||
//
|
||||
}
|
||||
|
||||
is OnboardingSetProfileNameViewModel.Navigation.NavigateToAddEmailScreen -> {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
vm.toasts.collect {
|
||||
toast(it)
|
||||
}
|
||||
}
|
||||
DisposableEffect(Unit) {
|
||||
onDispose { component.release() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getVideoPlayer(context: Context, videoPath: Uri): Player {
|
||||
val player = ExoPlayer.Builder(context).build()
|
||||
val source = DefaultDataSource.Factory(
|
||||
|
@ -772,6 +872,8 @@ class OnboardingFragment : Fragment() {
|
|||
|
||||
private const val ONBOARDING_SPACE_PARAM = "space"
|
||||
private const val ONBOARDING_STARTING_OBJECT_PARAM = "startingObject"
|
||||
|
||||
private const val ONBOARDING_NAME_PARAM = "name"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,5 +6,5 @@ object OnboardingNavigation {
|
|||
const val void = "void"
|
||||
const val mnemonic = "mnemonic"
|
||||
const val setProfileName = "createSoul"
|
||||
const val enterTheVoid = "enterTheVoid"
|
||||
const val setEmail = "setEmail"
|
||||
}
|
|
@ -7,5 +7,6 @@ enum class OnboardingPage(val num: Int, val visible: Boolean) {
|
|||
SET_PROFILE_NAME(1, false),
|
||||
SOUL_CREATION_ANIM(4, false),
|
||||
RECOVERY(5, false),
|
||||
ENTER_THE_VOID(6, false)
|
||||
ENTER_THE_VOID(6, false),
|
||||
SET_EMAIL(3, false)
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
package com.anytypeio.anytype.ui.onboarding.screens.signup
|
||||
|
||||
import android.util.Patterns
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineTitleSemibold
|
||||
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonPrimary
|
||||
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonSecondary
|
||||
import com.anytypeio.anytype.core_ui.views.PreviewTitle1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.UXBody
|
||||
import com.anytypeio.anytype.presentation.onboarding.signup.OnboardingSetProfileNameViewModel
|
||||
import kotlin.also
|
||||
import kotlin.text.isNotEmpty
|
||||
|
||||
@Composable
|
||||
fun SetEmailWrapper(
|
||||
viewModel: OnboardingSetProfileNameViewModel,
|
||||
name: String,
|
||||
onBackClicked: () -> Unit,
|
||||
) {
|
||||
OnboardingEmailScreen(
|
||||
onContinueClicked = { email ->
|
||||
viewModel.onEmailContinueClicked(
|
||||
name = name,
|
||||
email = email
|
||||
)
|
||||
},
|
||||
onSkipClicked = {
|
||||
viewModel.onEmailSkippedClicked(
|
||||
name = name,
|
||||
)
|
||||
},
|
||||
isLoading = viewModel.state
|
||||
.collectAsStateWithLifecycle()
|
||||
.value is OnboardingSetProfileNameViewModel.ScreenState.Loading,
|
||||
onBackClicked = onBackClicked
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OnboardingEmailScreen(
|
||||
onContinueClicked: (String) -> Unit,
|
||||
onSkipClicked: () -> Unit,
|
||||
onBackClicked: () -> Unit,
|
||||
isLoading: Boolean
|
||||
) {
|
||||
var innerValue by remember { mutableStateOf(TextFieldValue()) }
|
||||
var isError by remember { mutableStateOf(false) }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
fun isValidEmail(email: String): Boolean {
|
||||
return Patterns.EMAIL_ADDRESS.matcher(email).matches()
|
||||
}
|
||||
|
||||
fun validateAndSubmit() {
|
||||
if (isValidEmail(innerValue.text)) {
|
||||
isError = false
|
||||
focusRequester.freeFocus()
|
||||
keyboardController?.hide()
|
||||
onContinueClicked(innerValue.text)
|
||||
} else {
|
||||
isError = true
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.imePadding()
|
||||
//.background(color = colorResource(id = R.color.black))
|
||||
.fillMaxSize()
|
||||
) {
|
||||
Column {
|
||||
Spacer(modifier = Modifier.height(148.dp))
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
text = stringResource(R.string.onboarding_email_add_title),
|
||||
color = colorResource(id = R.color.text_white),
|
||||
style = HeadlineTitleSemibold,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp),
|
||||
text = stringResource(R.string.onboarding_email_add_description),
|
||||
style = UXBody,
|
||||
color = colorResource(id = R.color.text_white),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
OutlinedTextField(
|
||||
value = innerValue,
|
||||
onValueChange = { input ->
|
||||
innerValue = input
|
||||
isError = false
|
||||
},
|
||||
shape = RoundedCornerShape(size = 16.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp)
|
||||
.focusRequester(focusRequester),
|
||||
placeholder = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.onboarding_enter_email),
|
||||
style = PreviewTitle1Regular,
|
||||
color = colorResource(id = R.color.text_tertiary)
|
||||
)
|
||||
},
|
||||
textStyle = PreviewTitle1Regular.copy(
|
||||
color = Color(0xFFC2C2C2)
|
||||
),
|
||||
singleLine = true,
|
||||
isError = isError,
|
||||
supportingText = {
|
||||
if (isError) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.onboarding_email_error),
|
||||
color = colorResource(id = R.color.palette_system_red),
|
||||
style = Caption1Regular
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = TextFieldDefaults.colors(
|
||||
disabledTextColor = colorResource(id = R.color.text_primary),
|
||||
cursorColor = Color(0xFFC2C2C2),
|
||||
focusedContainerColor = Color(0xFF212121),
|
||||
unfocusedContainerColor = Color(0xFF212121),
|
||||
errorContainerColor = Color(0xFF212121),
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions {
|
||||
validateAndSubmit()
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
}
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.padding(top = 16.dp, start = 9.dp)
|
||||
.noRippleClickable {
|
||||
onBackClicked()
|
||||
},
|
||||
painter = painterResource(id = R.drawable.ic_back_onboarding_32),
|
||||
contentDescription = stringResource(R.string.content_description_back_button_icon)
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
start = 20.dp,
|
||||
end = 20.dp,
|
||||
bottom = 20.dp
|
||||
)
|
||||
.align(Alignment.BottomCenter)
|
||||
) {
|
||||
OnBoardingButtonPrimary(
|
||||
text = stringResource(id = R.string.onboarding_button_continue),
|
||||
onClick = {
|
||||
validateAndSubmit()
|
||||
},
|
||||
size = ButtonSize.Large,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
isLoading = isLoading,
|
||||
enabled = innerValue.text.isNotEmpty()
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
OnBoardingButtonSecondary(
|
||||
text = stringResource(id = R.string.onboarding_button_skip),
|
||||
onClick = {
|
||||
onSkipClicked().also {
|
||||
focusRequester.freeFocus()
|
||||
}
|
||||
},
|
||||
textColor = colorResource(id = R.color.text_white),
|
||||
size = ButtonSize.Large,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DefaultPreviews
|
||||
@Composable
|
||||
private fun SetProfileNameScreenPreview() {
|
||||
OnboardingEmailScreen(
|
||||
onContinueClicked = {},
|
||||
onBackClicked = {},
|
||||
onSkipClicked = {},
|
||||
isLoading = false
|
||||
)
|
||||
}
|
|
@ -42,7 +42,6 @@ import com.anytypeio.anytype.core_ui.extensions.conditional
|
|||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineOnBoardingDescription
|
||||
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonPrimary
|
||||
|
|
|
@ -45,12 +45,13 @@ fun SetProfileNameWrapper(
|
|||
viewModel: OnboardingSetProfileNameViewModel,
|
||||
onBackClicked: () -> Unit,
|
||||
) {
|
||||
val defaultSpaceName = stringResource(id = R.string.onboarding_my_first_space)
|
||||
val name = remember { mutableStateOf("") }
|
||||
|
||||
SetProfileNameScreen(
|
||||
onNextClicked = { name ->
|
||||
onNextClicked = { inputName ->
|
||||
name.value = inputName
|
||||
viewModel.onNextClicked(
|
||||
name = name,
|
||||
spaceName = defaultSpaceName
|
||||
name = inputName
|
||||
)
|
||||
},
|
||||
isLoading = viewModel.state
|
||||
|
|
|
@ -550,7 +550,8 @@ sealed class Command {
|
|||
data class Finalize(val name: String, val nameType: NameServiceNameType) : Membership()
|
||||
data class GetVerificationEmail(
|
||||
val email: String,
|
||||
val subscribeToNewsletter: Boolean
|
||||
val subscribeToNewsletter: Boolean,
|
||||
val isFromOnboarding: Boolean
|
||||
) : Membership()
|
||||
|
||||
data class VerifyEmailCode(val code: String) : Membership()
|
||||
|
|
|
@ -11,12 +11,12 @@ val OnboardingSubtitleColor = Color(0xFF505050)
|
|||
val OnBoardingTextPrimaryColor = Color(0xFFF3F2EC)
|
||||
val OnBoardingTextSecondaryColor = Color(0x80F3F2EC)
|
||||
|
||||
val ColorButtonPrimaryActive = Color(0xFF252525)
|
||||
val ColorButtonPrimaryActive = Color(0xFF3A3A3A)
|
||||
val ColorButtonPrimaryPressed = Color(0xFF464646)
|
||||
val ColorButtonPrimaryText = Color(0xFFF2F3EC)
|
||||
|
||||
val ColorButtonPrimaryInactive = Color(0xFF1F1E1D)
|
||||
val ColorButtonPrimaryInactiveText = Color(0xFF64635B)
|
||||
val ColorButtonPrimaryInactive = Color(0xFF1F1F1F)
|
||||
val ColorButtonPrimaryInactiveText = Color(0xFF646464)
|
||||
|
||||
val ColorButtonSecondaryActive = Color.Transparent
|
||||
val ColorButtonSecondaryPressed = Color(0xFF1F1E1C)
|
||||
|
|
|
@ -328,4 +328,14 @@ val ModalTitle = TextStyle(
|
|||
val AvatarTitle = TextStyle(
|
||||
fontFamily = fontInterRegular,
|
||||
fontWeight = FontWeight.W600
|
||||
)
|
||||
)
|
||||
|
||||
//Content/Headlines/Title Semibold
|
||||
val HeadlineTitleSemibold =
|
||||
TextStyle(
|
||||
fontFamily = fontInterSemibold,
|
||||
fontWeight = FontWeight.W600,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 32.sp,
|
||||
letterSpacing = (-0.017).em
|
||||
)
|
|
@ -14,13 +14,15 @@ class SetMembershipEmail @Inject constructor(
|
|||
override suspend fun doWork(params: Params) {
|
||||
val command = Command.Membership.GetVerificationEmail(
|
||||
email = params.email,
|
||||
subscribeToNewsletter = params.subscribeToNewsletter
|
||||
subscribeToNewsletter = params.subscribeToNewsletter,
|
||||
isFromOnboarding = params.isFromOnboarding
|
||||
)
|
||||
repo.membershipGetVerificationEmail(command)
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val email: String,
|
||||
val subscribeToNewsletter: Boolean
|
||||
val subscribeToNewsletter: Boolean,
|
||||
val isFromOnboarding: Boolean = false
|
||||
)
|
||||
}
|
|
@ -9,4 +9,5 @@ interface StringResourceProvider {
|
|||
fun getUntitledObjectTitle(): String
|
||||
fun getSetOfObjectsTitle(): String
|
||||
fun getPropertiesFormatPrettyString(format: RelationFormat): String
|
||||
fun getDefaultSpaceName(): String
|
||||
}
|
|
@ -1132,8 +1132,6 @@
|
|||
<string name="onboarding_key_skip">Skip</string>
|
||||
<string name="onboarding_key_not_now">Not now</string>
|
||||
<string name="onboarding_key_copy">Copy to clipboard</string>
|
||||
<string name="onboarding_set_your_name_title">Set your name</string>
|
||||
<string name="onboarding_soul_creation_description">Only seen by people you share something with. There is no central registry of these names.</string>
|
||||
<string name="onboarding_soul_creation_placeholder">Anytype Identity</string>
|
||||
<string name="onboarding_soul_creation">Creating your Identity…</string>
|
||||
<string name="onboarding_type_your_key">Type your recovery phrase</string>
|
||||
|
@ -2044,4 +2042,13 @@ Please provide specific details of your needs here.</string>
|
|||
<string name="space_properties_screen_menu_move_to_bin">Move to bin</string>
|
||||
<string name="onboarding_error_while_creating_account_space_is_missing">Error while creating account: space is missing</string>
|
||||
|
||||
<string name="onboarding_set_your_name_title">Add Your Name</string>
|
||||
<string name="onboarding_soul_creation_description">Only seen by people you share something with. There is no central registry for these names.</string>
|
||||
<string name="onboarding_email_add_title">Stay in the loop</string>
|
||||
<string name="onboarding_email_add_description">We’d love to share tips, tricks and product updates with you. Your email is never linked to your identity. We won’t share your data. Ever.</string>
|
||||
<string name="onboarding_enter_email">Enter your email</string>
|
||||
<string name="onboarding_button_continue">Continue</string>
|
||||
<string name="onboarding_button_skip">Skip</string>
|
||||
<string name="onboarding_email_error">Incorrect email</string>
|
||||
|
||||
</resources>
|
|
@ -2663,7 +2663,8 @@ class Middleware @Inject constructor(
|
|||
fun membershipGetVerificationEmail(command: Command.Membership.GetVerificationEmail) {
|
||||
val request = Rpc.Membership.GetVerificationEmail.Request(
|
||||
email = command.email,
|
||||
subscribeToNewsletter = command.subscribeToNewsletter
|
||||
subscribeToNewsletter = command.subscribeToNewsletter,
|
||||
isOnboardingList = command.isFromOnboarding
|
||||
)
|
||||
logRequestIfDebug(request)
|
||||
val (response, time) = measureTimedValue { service.membershipGetVerificationEmail(request) }
|
||||
|
|
|
@ -19,9 +19,12 @@ import com.anytypeio.anytype.domain.device.PathProvider
|
|||
import com.anytypeio.anytype.domain.misc.LocaleProvider
|
||||
import com.anytypeio.anytype.domain.`object`.ImportGetStartedUseCase
|
||||
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
|
||||
import com.anytypeio.anytype.domain.payments.SetMembershipEmail
|
||||
import com.anytypeio.anytype.domain.resources.StringResourceProvider
|
||||
import com.anytypeio.anytype.domain.spaces.SetSpaceDetails
|
||||
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscriptionManager
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
import com.anytypeio.anytype.presentation.BuildConfig
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
import com.anytypeio.anytype.presentation.extension.proceedWithAccountEvent
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsOnboardingScreenEvent
|
||||
|
@ -46,7 +49,9 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
private val crashReporter: CrashReporter,
|
||||
private val localeProvider: LocaleProvider,
|
||||
private val globalSubscriptionManager: GlobalSubscriptionManager,
|
||||
private val spaceManager: SpaceManager
|
||||
private val spaceManager: SpaceManager,
|
||||
private val stringProvider: StringResourceProvider,
|
||||
private val setMembershipEmail: SetMembershipEmail,
|
||||
) : BaseViewModel() {
|
||||
|
||||
init {
|
||||
|
@ -62,22 +67,23 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
val navigation = MutableSharedFlow<Navigation>()
|
||||
|
||||
fun onNextClicked(
|
||||
name: String,
|
||||
spaceName: String
|
||||
name: String
|
||||
) {
|
||||
if (state.value !is ScreenState.Loading) {
|
||||
proceedWithCreatingWallet(
|
||||
name = name,
|
||||
spaceName = spaceName
|
||||
)
|
||||
viewModelScope.launch {
|
||||
navigation.emit(
|
||||
Navigation.NavigateToAddEmailScreen(
|
||||
name = name
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
sendToast(LOADING_MSG)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithCreatingWallet(
|
||||
name: String,
|
||||
spaceName: String
|
||||
name: String
|
||||
) {
|
||||
state.value = ScreenState.Loading
|
||||
setupWallet.invoke(
|
||||
|
@ -92,8 +98,7 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
},
|
||||
fnR = {
|
||||
proceedWithCreatingAccount(
|
||||
name = name,
|
||||
spaceName = spaceName
|
||||
name = name
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -101,9 +106,9 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun proceedWithCreatingAccount(
|
||||
name: String,
|
||||
spaceName: String
|
||||
name: String
|
||||
) {
|
||||
val spaceName = stringProvider.getDefaultSpaceName()
|
||||
val startTime = System.currentTimeMillis()
|
||||
val params = CreateAccount.Params(
|
||||
name = name,
|
||||
|
@ -248,6 +253,53 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
//region Email screen
|
||||
fun onEmailContinueClicked(
|
||||
email: String,
|
||||
name: String,
|
||||
) {
|
||||
proceedWithSettingEmail(email = email)
|
||||
if (state.value !is ScreenState.Loading) {
|
||||
proceedWithCreatingWallet(
|
||||
name = name
|
||||
)
|
||||
} else {
|
||||
sendToast(LOADING_MSG)
|
||||
}
|
||||
}
|
||||
|
||||
fun onEmailSkippedClicked(
|
||||
name: String
|
||||
) {
|
||||
if (state.value !is ScreenState.Loading) {
|
||||
proceedWithCreatingWallet(
|
||||
name = name
|
||||
)
|
||||
} else {
|
||||
sendToast(LOADING_MSG)
|
||||
}
|
||||
}
|
||||
|
||||
private fun proceedWithSettingEmail(email: String) {
|
||||
val params = SetMembershipEmail.Params(
|
||||
email = email,
|
||||
subscribeToNewsletter = false,
|
||||
isFromOnboarding = true
|
||||
)
|
||||
viewModelScope.launch {
|
||||
setMembershipEmail.async(params).fold(
|
||||
onSuccess = { Timber.d("Email set") },
|
||||
onFailure = { error ->
|
||||
if (BuildConfig.DEBUG) {
|
||||
sendToast("Error setting email")
|
||||
}
|
||||
Timber.e("Error setting email: $error")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
class Factory @Inject constructor(
|
||||
private val setObjectDetails: SetObjectDetails,
|
||||
private val setSpaceDetails: SetSpaceDetails,
|
||||
|
@ -261,7 +313,9 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
private val crashReporter: CrashReporter,
|
||||
private val localeProvider: LocaleProvider,
|
||||
private val globalSubscriptionManager: GlobalSubscriptionManager,
|
||||
private val spaceManager: SpaceManager
|
||||
private val spaceManager: SpaceManager,
|
||||
private val stringProvider: StringResourceProvider,
|
||||
private val setMembershipEmail: SetMembershipEmail
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
|
@ -278,7 +332,9 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
crashReporter = crashReporter,
|
||||
localeProvider = localeProvider,
|
||||
globalSubscriptionManager = globalSubscriptionManager,
|
||||
spaceManager = spaceManager
|
||||
spaceManager = spaceManager,
|
||||
stringProvider = stringProvider,
|
||||
setMembershipEmail = setMembershipEmail
|
||||
) as T
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +348,9 @@ class OnboardingSetProfileNameViewModel @Inject constructor(
|
|||
|
||||
sealed class Navigation {
|
||||
data class NavigateToMnemonic(val space: SpaceId, val startingObject: Id?): Navigation()
|
||||
data class NavigateToAddEmailScreen(
|
||||
val name: String
|
||||
) : Navigation()
|
||||
data object GoBack: Navigation()
|
||||
}
|
||||
|
||||
|
|
|
@ -51,4 +51,8 @@ class StringResourceProviderImpl @Inject constructor(private val context: Contex
|
|||
RelationFormat.UNDEFINED -> context.getString(R.string.undefined)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultSpaceName(): String {
|
||||
return context.getString(R.string.onboarding_my_first_space)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue