1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-1360 Onboarding | Enhancement | Removed invite code screen

DROID-1360 Onboarding | Enhancement | Removed invite code screen
This commit is contained in:
Allan Quatermain 2023-06-07 15:00:04 +03:00 committed by GitHub
parent e7d665399b
commit 7f942b0982
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 203 additions and 480 deletions

View file

@ -64,7 +64,6 @@ import com.anytypeio.anytype.di.feature.cover.UnsplashModule
import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent
import com.anytypeio.anytype.di.feature.library.DaggerLibraryComponent
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingAuthComponent
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingInviteCodeComponent
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingMnemonicComponent
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingSoulCreationAnimComponent
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingSoulCreationComponent
@ -908,12 +907,6 @@ class ComponentManager(
.create(findComponentDependencies())
}
val onboardingInviteCodeComponent = Component {
DaggerOnboardingInviteCodeComponent
.factory()
.create(findComponentDependencies())
}
val onboardingMnemonicComponent = Component {
DaggerOnboardingMnemonicComponent
.factory()

View file

@ -2,10 +2,20 @@ package com.anytypeio.anytype.di.feature.onboarding
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.auth.interactor.CreateAccount
import com.anytypeio.anytype.domain.auth.interactor.SetupWallet
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
import com.anytypeio.anytype.ui.onboarding.OnboardingAuthViewModel
import dagger.Binds
import dagger.Component
import dagger.Module
import dagger.Provides
import javax.inject.Scope
@Component(
@ -29,6 +39,33 @@ interface OnboardingAuthComponent {
@Module
object OnboardingAuthModule {
@JvmStatic
@Provides
@AuthScreenScope
fun gradientProvider(): SpaceGradientProvider = SpaceGradientProvider.Impl()
@JvmStatic
@Provides
@AuthScreenScope
fun provideCreateAccountUseCase(
authRepository: AuthRepository,
configStorage: ConfigStorage,
workspaceManager: WorkspaceManager
): CreateAccount = CreateAccount(
repository = authRepository,
configStorage = configStorage,
workspaceManager = workspaceManager
)
@JvmStatic
@Provides
@AuthScreenScope
fun provideSetupWalletUseCase(
authRepository: AuthRepository
): SetupWallet = SetupWallet(
repository = authRepository
)
@Module
interface Declarations {
@ -39,7 +76,14 @@ object OnboardingAuthModule {
}
}
interface OnboardingAuthDependencies : ComponentDependencies
interface OnboardingAuthDependencies : ComponentDependencies {
fun authRepository(): AuthRepository
fun configStorage(): ConfigStorage
fun workspaceManager(): WorkspaceManager
fun relationsSubscriptionManager(): RelationsSubscriptionManager
fun objectTypesSubscriptionManager(): ObjectTypesSubscriptionManager
fun pathProvider(): PathProvider
}
@Scope
@Retention(AnnotationRetention.RUNTIME)

View file

@ -1,90 +0,0 @@
package com.anytypeio.anytype.di.feature.onboarding
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.auth.interactor.CreateAccount
import com.anytypeio.anytype.domain.auth.interactor.SetupWallet
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
import com.anytypeio.anytype.ui.onboarding.OnboardingInviteCodeViewModel
import dagger.Binds
import dagger.Component
import dagger.Module
import dagger.Provides
import javax.inject.Scope
@Component(
dependencies = [OnboardingInviteCodeDependencies::class],
modules = [
OnboardingInviteCodeModule::class,
OnboardingInviteCodeModule.Declarations::class
]
)
@InviteCodeScreenScope
interface OnboardingInviteCodeComponent {
@Component.Factory
interface Builder {
fun create(dependencies: OnboardingInviteCodeDependencies): OnboardingInviteCodeComponent
}
fun getViewModel(): OnboardingInviteCodeViewModel
}
@Module
object OnboardingInviteCodeModule {
@JvmStatic
@Provides
@InviteCodeScreenScope
fun gradientProvider(): SpaceGradientProvider = SpaceGradientProvider.Impl()
@JvmStatic
@Provides
@InviteCodeScreenScope
fun provideCreateAccountUseCase(
authRepository: AuthRepository,
configStorage: ConfigStorage,
workspaceManager: WorkspaceManager
): CreateAccount = CreateAccount(
repository = authRepository,
configStorage = configStorage,
workspaceManager = workspaceManager
)
@JvmStatic
@Provides
@InviteCodeScreenScope
fun provideSetupWalletUseCase(
authRepository: AuthRepository
): SetupWallet = SetupWallet(
repository = authRepository
)
@Module
interface Declarations {
@Binds
@InviteCodeScreenScope
fun bindViewModelFactory(factory: OnboardingInviteCodeViewModel.Factory): ViewModelProvider.Factory
}
}
interface OnboardingInviteCodeDependencies : ComponentDependencies {
fun authRepository(): AuthRepository
fun configStorage(): ConfigStorage
fun workspaceManager(): WorkspaceManager
fun relationsSubscriptionManager(): RelationsSubscriptionManager
fun objectTypesSubscriptionManager(): ObjectTypesSubscriptionManager
fun pathProvider(): PathProvider
}
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class InviteCodeScreenScope

View file

@ -22,7 +22,6 @@ import com.anytypeio.anytype.di.feature.auth.DeletedAccountDependencies
import com.anytypeio.anytype.di.feature.home.HomeScreenDependencies
import com.anytypeio.anytype.di.feature.library.LibraryDependencies
import com.anytypeio.anytype.di.feature.onboarding.OnboardingAuthDependencies
import com.anytypeio.anytype.di.feature.onboarding.OnboardingInviteCodeDependencies
import com.anytypeio.anytype.di.feature.onboarding.OnboardingMnemonicDependencies
import com.anytypeio.anytype.di.feature.onboarding.OnboardingSoulCreationAnimDependencies
import com.anytypeio.anytype.di.feature.onboarding.OnboardingSoulCreationDependencies
@ -83,7 +82,6 @@ interface MainComponent :
BacklinkOrAddToObjectDependencies,
FilesStorageDependencies,
OnboardingAuthDependencies,
OnboardingInviteCodeDependencies,
OnboardingMnemonicDependencies,
OnboardingSoulCreationDependencies,
AboutAppDependencies,
@ -199,11 +197,6 @@ private abstract class ComponentDependenciesModule private constructor() {
@ComponentDependenciesKey(OnboardingAuthDependencies::class)
abstract fun provideOnboardingAuthDependencies(component: MainComponent): ComponentDependencies
@Binds
@IntoMap
@ComponentDependenciesKey(OnboardingInviteCodeDependencies::class)
abstract fun provideOnboardingInviteCodeDependencies(component: MainComponent): ComponentDependencies
@Binds
@IntoMap
@ComponentDependenciesKey(OnboardingMnemonicDependencies::class)

View file

@ -2,19 +2,112 @@ package com.anytypeio.anytype.ui.onboarding
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.domain.auth.interactor.CreateAccount
import com.anytypeio.anytype.domain.auth.interactor.SetupWallet
import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import timber.log.Timber
class OnboardingAuthViewModel @Inject constructor(): ViewModel() {
class OnboardingAuthViewModel @Inject constructor(
private val createAccount: CreateAccount,
private val setupWallet: SetupWallet,
private val pathProvider: PathProvider,
private val spaceGradientProvider: SpaceGradientProvider,
private val relationsSubscriptionManager: RelationsSubscriptionManager,
private val objectTypesSubscriptionManager: ObjectTypesSubscriptionManager
) : ViewModel() {
fun onAction(action: OnboardingScreenContract) {
private val _navigationFlow = MutableSharedFlow<InviteCodeNavigation>()
val navigationFlow: SharedFlow<InviteCodeNavigation> = _navigationFlow
val joinFlowState = MutableStateFlow<JoinFlowState>(JoinFlowState.Active)
fun signUp() {
joinFlowState.value = JoinFlowState.Loading
setupWallet.invoke(
scope = viewModelScope,
params = SetupWallet.Params(
path = pathProvider.providePath()
)
) { result ->
result.either(
fnL = {
Timber.e(it, "Error while setting up wallet")
},
fnR = {
setupAccount()
}
)
}
}
private fun setupAccount() {
createAccount.invoke(
scope = viewModelScope,
params = CreateAccount.Params(
name = "",
avatarPath = null,
invitationCode = "elbrus",
iconGradientValue = spaceGradientProvider.randomId()
)
) { result ->
result.either(
fnL = { error ->
Timber.d("Error while creating account: ${error.message}")
},
fnR = { account ->
// updateUserProps(account.id)
// sendAuthEvent(startTime)
relationsSubscriptionManager.onStart()
objectTypesSubscriptionManager.onStart()
joinFlowState.value = JoinFlowState.Active
navigateTo(InviteCodeNavigation.Void)
}
)
}
}
private fun navigateTo(destination: InviteCodeNavigation) {
viewModelScope.launch {
_navigationFlow.emit(destination)
}
}
interface InviteCodeNavigation {
object Idle : InviteCodeNavigation
object Void : InviteCodeNavigation
}
interface JoinFlowState {
object Active: JoinFlowState
object Loading: JoinFlowState
}
class Factory @Inject constructor(
private val createAccount: CreateAccount,
private val setupWallet: SetupWallet,
private val pathProvider: PathProvider,
private val spaceGradientProvider: SpaceGradientProvider,
private val relationsSubscriptionManager: RelationsSubscriptionManager,
private val objectTypesSubscriptionManager: ObjectTypesSubscriptionManager
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return OnboardingAuthViewModel(
createAccount = createAccount,
setupWallet = setupWallet,
pathProvider = pathProvider,
spaceGradientProvider = spaceGradientProvider,
relationsSubscriptionManager = relationsSubscriptionManager,
objectTypesSubscriptionManager = objectTypesSubscriptionManager
) as T
}
}

View file

@ -44,7 +44,6 @@ import com.anytypeio.anytype.ext.daggerViewModel
import com.anytypeio.anytype.ui.onboarding.screens.AuthScreenWrapper
import com.anytypeio.anytype.ui.onboarding.screens.CreateSoulAnimWrapper
import com.anytypeio.anytype.ui.onboarding.screens.CreateSoulWrapper
import com.anytypeio.anytype.ui.onboarding.screens.InviteCodeScreenWrapper
import com.anytypeio.anytype.ui.onboarding.screens.MnemonicPhraseScreenWrapper
import com.anytypeio.anytype.ui.onboarding.screens.RecoveryScreenWrapper
import com.anytypeio.anytype.ui.onboarding.screens.VoidScreenWrapper
@ -98,30 +97,6 @@ class OnboardingFragment : BaseComposeFragment() {
currentPage.value = Page.AUTH
Auth(navController)
}
composable(
route = OnboardingNavigation.inviteCode,
enterTransition = {
when (initialState.destination.route) {
OnboardingNavigation.void -> {
slideIntoContainer(Right, tween(ANIMATION_LENGTH_SLIDE))
}
else -> null
}
},
exitTransition = {
when (targetState.destination.route) {
OnboardingNavigation.auth -> {
fadeOut(tween(ANIMATION_LENGTH_FADE))
}
else -> {
slideOutOfContainer(Left, tween(ANIMATION_LENGTH_SLIDE))
}
}
}
) {
currentPage.value = Page.INVITE_CODE
InviteCode(navController)
}
composable(
route = OnboardingNavigation.recovery,
enterTransition = {
@ -144,8 +119,8 @@ class OnboardingFragment : BaseComposeFragment() {
route = OnboardingNavigation.void,
enterTransition = {
when (initialState.destination.route) {
OnboardingNavigation.inviteCode -> {
slideIntoContainer(Left, tween(ANIMATION_LENGTH_SLIDE))
OnboardingNavigation.auth -> {
fadeIn(tween(ANIMATION_LENGTH_FADE))
}
else -> {
slideIntoContainer(Right, tween(ANIMATION_LENGTH_SLIDE))
@ -154,11 +129,11 @@ class OnboardingFragment : BaseComposeFragment() {
},
exitTransition = {
when (targetState.destination.route) {
OnboardingNavigation.mnemonic -> {
slideOutOfContainer(Left, tween(ANIMATION_LENGTH_SLIDE))
OnboardingNavigation.auth -> {
fadeOut(tween(ANIMATION_LENGTH_FADE))
}
else -> {
slideOutOfContainer(Right, tween(ANIMATION_LENGTH_SLIDE))
slideOutOfContainer(Left, tween(ANIMATION_LENGTH_SLIDE))
}
}
}
@ -180,7 +155,16 @@ class OnboardingFragment : BaseComposeFragment() {
}
}
},
exitTransition = { fadeOut(tween(ANIMATION_LENGTH_SLIDE)) }
exitTransition = {
when (targetState.destination.route) {
OnboardingNavigation.void -> {
slideOutOfContainer(Right, tween(ANIMATION_LENGTH_SLIDE))
}
else -> {
slideOutOfContainer(Left, tween(ANIMATION_LENGTH_SLIDE))
}
}
}
) {
currentPage.value = Page.MNEMONIC
Mnemonic(navController)
@ -188,7 +172,16 @@ class OnboardingFragment : BaseComposeFragment() {
composable(
route = OnboardingNavigation.createSoul,
enterTransition = { slideIntoContainer(Left, tween(ANIMATION_LENGTH_SLIDE)) },
exitTransition = { fadeOut(tween(ANIMATION_LENGTH_FADE)) }
exitTransition = {
when (targetState.destination.route) {
OnboardingNavigation.mnemonic -> {
slideOutOfContainer(Right, tween(ANIMATION_LENGTH_SLIDE))
}
else -> {
fadeOut(tween(ANIMATION_LENGTH_FADE))
}
}
}
) {
currentPage.value = Page.SOUL_CREATION
CreateSoul(navController)
@ -273,24 +266,24 @@ class OnboardingFragment : BaseComposeFragment() {
}
@Composable
private fun InviteCode(navController: NavHostController) {
val component = componentManager().onboardingInviteCodeComponent.ReleaseOn(
private fun Auth(navController: NavHostController) {
val component = componentManager().onboardingAuthComponent.ReleaseOn(
viewLifecycleOwner = viewLifecycleOwner,
state = Lifecycle.State.DESTROYED
)
val viewModel: OnboardingInviteCodeViewModel = daggerViewModel {
component.get().getViewModel()
}
InviteCodeScreenWrapper(viewModel = viewModel)
val navigationCommands =
viewModel.navigationFlow.collectAsState(
initial = OnboardingInviteCodeViewModel.InviteCodeNavigation.Idle
)
val viewModel = daggerViewModel { component.get().getViewModel() }
AuthScreenWrapper(
viewModel = viewModel,
navigateToLogin = {
navController.navigate(OnboardingNavigation.recovery)
}
)
val navigationCommands = viewModel.navigationFlow.collectAsState(
initial = OnboardingAuthViewModel.InviteCodeNavigation.Idle
)
LaunchedEffect(key1 = navigationCommands.value) {
when (navigationCommands.value) {
is OnboardingInviteCodeViewModel.InviteCodeNavigation.Void -> {
is OnboardingAuthViewModel.InviteCodeNavigation.Void -> {
navController.navigate(OnboardingNavigation.void)
}
else -> {
@ -300,23 +293,6 @@ class OnboardingFragment : BaseComposeFragment() {
}
}
@Composable
private fun Auth(navController: NavHostController) {
val component = componentManager().onboardingAuthComponent.ReleaseOn(
viewLifecycleOwner = viewLifecycleOwner,
state = Lifecycle.State.DESTROYED
)
AuthScreenWrapper(
viewModel = daggerViewModel { component.get().getViewModel() },
navigateToInviteCode = {
navController.navigate(OnboardingNavigation.inviteCode)
},
navigateToLogin = {
navController.navigate(OnboardingNavigation.recovery)
}
)
}
override fun injectDependencies() {}
override fun releaseDependencies() {}

View file

@ -1,149 +0,0 @@
package com.anytypeio.anytype.ui.onboarding
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.core_models.exceptions.CreateAccountException
import com.anytypeio.anytype.domain.auth.interactor.CreateAccount
import com.anytypeio.anytype.domain.auth.interactor.SetupWallet
import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
import javax.inject.Inject
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import timber.log.Timber
class OnboardingInviteCodeViewModel @Inject constructor(
private val createAccount: CreateAccount,
private val setupWallet: SetupWallet,
private val pathProvider: PathProvider,
private val spaceGradientProvider: SpaceGradientProvider,
private val relationsSubscriptionManager: RelationsSubscriptionManager,
private val objectTypesSubscriptionManager: ObjectTypesSubscriptionManager
) : ViewModel() {
val state = MutableStateFlow<InviteCodeViewState>(InviteCodeViewState.WalletCreating)
private val _navigationFlow = MutableSharedFlow<InviteCodeNavigation>()
val navigationFlow: SharedFlow<InviteCodeNavigation> = _navigationFlow
init {
createWallet()
}
private fun createWallet() {
setupWallet.invoke(
scope = viewModelScope,
params = SetupWallet.Params(
path = pathProvider.providePath()
)
) { result ->
result.either(
fnL = {
Timber.e(it, "Error while setting up wallet")
},
fnR = {
setupScreen()
}
)
}
}
private fun setupScreen() {
state.value = InviteCodeViewState.Idle
}
fun onInviteCodeEntered(inviteCode: String) {
createAccount.invoke(
scope = viewModelScope,
params = CreateAccount.Params(
name = "",
avatarPath = null,
invitationCode = inviteCode,
iconGradientValue = spaceGradientProvider.randomId()
)
) { result ->
result.either(
fnL = { error ->
when (error) {
CreateAccountException.BadInviteCode -> {
state.value = InviteCodeViewState.InvalidCodeError(
"Invalid invitation code!"
)
}
CreateAccountException.NetworkError -> {
state.value = InviteCodeViewState.ErrorNetwork(
"Failed to create your account due to a network error: ${error.message}"
)
}
CreateAccountException.OfflineDevice -> {
state.value = InviteCodeViewState.ErrorNetwork(
"Your device seems to be offline. Please, check your connection and try again."
)
}
else -> {
state.value = InviteCodeViewState.Error(
"Error while creating an account: ${error.message ?: "Unknown error"}"
)
}
}
},
fnR = { account ->
// updateUserProps(account.id)
// sendAuthEvent(startTime)
relationsSubscriptionManager.onStart()
objectTypesSubscriptionManager.onStart()
state.value = InviteCodeViewState.Idle
navigateTo(InviteCodeNavigation.Void)
}
)
}
}
private fun navigateTo(void: InviteCodeNavigation.Void) {
viewModelScope.launch {
_navigationFlow.emit(void)
}
}
sealed class InviteCodeViewState {
object WalletCreating : InviteCodeViewState()
object Idle : InviteCodeViewState()
data class Error(val message: String) : InviteCodeViewState()
data class InvalidCodeError(val message: String) : InviteCodeViewState()
data class ErrorNetwork(val msg: String) : InviteCodeViewState()
}
interface InviteCodeNavigation {
object Idle : InviteCodeNavigation
object Void : InviteCodeNavigation
}
class Factory @Inject constructor(
private val createAccount: CreateAccount,
private val setupWallet: SetupWallet,
private val pathProvider: PathProvider,
private val spaceGradientProvider: SpaceGradientProvider,
private val relationsSubscriptionManager: RelationsSubscriptionManager,
private val objectTypesSubscriptionManager: ObjectTypesSubscriptionManager
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return OnboardingInviteCodeViewModel(
createAccount,
setupWallet,
pathProvider,
spaceGradientProvider,
relationsSubscriptionManager,
objectTypesSubscriptionManager
) as T
}
}
}

View file

@ -9,9 +9,8 @@ sealed interface OnboardingScreenContract {
enum class Page(val num: Int, val visible: Boolean) {
AUTH(0, false),
INVITE_CODE(1, true),
VOID(2, true),
MNEMONIC(3, true),
SOUL_CREATION(4, true),
SOUL_CREATION_ANIM(5, false)
VOID(1, true),
MNEMONIC(2, true),
SOUL_CREATION(3, true),
SOUL_CREATION_ANIM(4, false)
}

View file

@ -21,6 +21,7 @@ import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.OnBoardingTextPrimaryColor
import com.anytypeio.anytype.core_ui.OnBoardingTextSecondaryColor
@ -31,29 +32,31 @@ import com.anytypeio.anytype.core_ui.views.OnBoardingButtonPrimary
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonSecondary
import com.anytypeio.anytype.core_ui.views.TextOnBoardingDescription
import com.anytypeio.anytype.ui.onboarding.OnboardingAuthViewModel
import com.anytypeio.anytype.ui.onboarding.OnboardingScreenContract
@Preview
@Composable
fun AuthScreenPreview() {
AuthScreen({}, {}, {})
AuthScreen({}, {}, OnboardingAuthViewModel.JoinFlowState.Active)
}
@Composable
fun AuthScreenWrapper(
viewModel: OnboardingAuthViewModel,
navigateToInviteCode: () -> Unit,
navigateToLogin: () -> Unit
) {
AuthScreen(contract = viewModel::onAction, navigateToInviteCode, navigateToLogin)
AuthScreen(
viewModel::signUp,
navigateToLogin,
viewModel.joinFlowState.collectAsStateWithLifecycle().value
)
}
@Composable
fun AuthScreen(
contract: (OnboardingScreenContract) -> Unit,
navigateToInviteCode: () -> Unit,
navigateToLogin: () -> Unit
signup: () -> Unit,
navigateToLogin: () -> Unit,
joinState: OnboardingAuthViewModel.JoinFlowState
) {
Box(
modifier = Modifier
@ -67,8 +70,8 @@ fun AuthScreen(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Bottom
) {
SignButtons(navigateToInviteCode, navigateToLogin)
TermsAndPolicy(Modifier, contract)
SignButtons(signup, navigateToLogin, joinState)
TermsAndPolicy(Modifier)
}
}
}
@ -107,13 +110,18 @@ fun Description(modifier: Modifier = Modifier) {
}
@Composable
fun SignButtons(navigateToInviteCode: () -> Unit, navigateToLogin: () -> Unit) {
fun SignButtons(
signup: () -> Unit,
navigateToLogin: () -> Unit,
joinFlowState: OnboardingAuthViewModel.JoinFlowState
) {
Row {
OnBoardingButtonPrimary(
text = stringResource(id = R.string.onboarding_join),
onClick = {
navigateToInviteCode.invoke()
signup.invoke()
},
enabled = joinFlowState is OnboardingAuthViewModel.JoinFlowState.Active,
size = ButtonSize.Large,
modifier = Modifier
.weight(1f)
@ -137,7 +145,6 @@ fun SignButtons(navigateToInviteCode: () -> Unit, navigateToLogin: () -> Unit) {
@Composable
fun TermsAndPolicy(
modifier: Modifier = Modifier,
contract: (OnboardingScreenContract) -> Unit
) {
val annotatedString = buildAnnotatedString {
append(
@ -169,11 +176,11 @@ fun TermsAndPolicy(
onClick = {
annotatedString.getStringAnnotations(TermsOfUseTag, it, it)
.firstOrNull()?.let {
contract.invoke(OnboardingScreenContract.TermsOfUseClick)
// do nothing
}
annotatedString.getStringAnnotations(PrivacyPolicyTag, it, it)
.firstOrNull()?.let {
contract.invoke(OnboardingScreenContract.PrivacyPolicyClick)
// do nothing
}
}
)

View file

@ -1,143 +0,0 @@
package com.anytypeio.anytype.ui.onboarding.screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
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.OnBoardingTextPrimaryColor
import com.anytypeio.anytype.core_ui.OnBoardingTextSecondaryColor
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.HeadlineOnBoardingDescription
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonPrimary
import com.anytypeio.anytype.core_ui.views.Title1
import com.anytypeio.anytype.ui.onboarding.OnboardingInput
import com.anytypeio.anytype.ui.onboarding.OnboardingInviteCodeViewModel
@Composable
fun InviteCodeScreenWrapper(viewModel: OnboardingInviteCodeViewModel) {
val state = viewModel.state.collectAsStateWithLifecycle().value
InviteCodeScreen(
state = state,
onInviteCodeEntered = {
viewModel.onInviteCodeEntered(it)
}
)
}
@Composable
fun InviteCodeScreen(
state: OnboardingInviteCodeViewModel.InviteCodeViewState,
onInviteCodeEntered: (String) -> Unit,
) {
when (state) {
is OnboardingInviteCodeViewModel.InviteCodeViewState.WalletCreating -> {}
else -> {
val inviteCode = remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
InviteCodeTitle(modifier = Modifier.padding(bottom = 16.dp))
InviteCodeInput(inviteCode)
Spacer(modifier = Modifier.height(9.dp))
InviteCodeDescription()
Spacer(modifier = Modifier.height(18.dp))
InviteCodeNextButton(
onInviteCodeEntered,
inviteCode
)
}
}
}
}
@Composable
fun InviteCodeTitle(modifier: Modifier) {
Box(
modifier = modifier.then(
Modifier
.fillMaxWidth()
.wrapContentHeight()
), contentAlignment = Alignment.Center
) {
Text(
modifier = Modifier,
text = stringResource(R.string.onboarding_invite_code_title),
style = Title1.copy(
color = OnBoardingTextPrimaryColor
)
)
}
}
@Composable
fun InviteCodeInput(text: MutableState<String>) {
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
contentAlignment = Alignment.Center
) {
OnboardingInput(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
text = text,
placeholder = ""
)
}
}
@Composable
fun InviteCodeDescription() {
Box(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
contentAlignment = Alignment.Center
) {
Text(
text = stringResource(id = R.string.onboarding_invite_code_description),
style = HeadlineOnBoardingDescription.copy(
color = OnBoardingTextSecondaryColor,
textAlign = TextAlign.Center
)
)
}
}
@Composable
fun InviteCodeNextButton(
onInviteCodeEntered: (String) -> Unit,
text: MutableState<String>
) {
OnBoardingButtonPrimary(
text = stringResource(id = R.string.next),
onClick = {
onInviteCodeEntered.invoke(text.value)
},
size = ButtonSize.Large,
enabled = text.value.trim().isNotEmpty(),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
)
}