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:
parent
e7d665399b
commit
7f942b0982
10 changed files with 203 additions and 480 deletions
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue