mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2861 Vault | Enhancement | Show introduce-vault screen to new users or after the first login (#1618)
This commit is contained in:
parent
9ab3237716
commit
9d28c5d61b
15 changed files with 188 additions and 33 deletions
|
@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModelProvider
|
|||
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.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
|
@ -54,4 +55,5 @@ interface VaultComponentDependencies : ComponentDependencies {
|
|||
fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer
|
||||
fun userSettingsRepository(): UserSettingsRepository
|
||||
fun spaceManager(): SpaceManager
|
||||
fun auth(): AuthRepository
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.anytypeio.anytype.ui.vault
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.ui.settings.typography
|
||||
|
||||
class IntroduceVaultFragment : BaseBottomSheetComposeFragment() {
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setContent {
|
||||
MaterialTheme(typography = typography) {
|
||||
IntroduceVaultScreen(
|
||||
onDoneClicked = {
|
||||
dismiss()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
skipCollapsed()
|
||||
expand()
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.Row
|
||||
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.size
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
|
@ -63,7 +64,7 @@ fun IntroduceVaultScreen(
|
|||
) {
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val (title, first, second, third, pager, dots, btn) = createRefs()
|
||||
val (title, first, pager, dots, btn) = createRefs()
|
||||
|
||||
val pagerState = rememberPagerState(pageCount = { 2 })
|
||||
|
||||
|
@ -89,39 +90,35 @@ fun IntroduceVaultScreen(
|
|||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier
|
||||
.padding(bottom = 16.dp, top = 38.dp)
|
||||
.padding(bottom = 16.dp, top = 42.dp)
|
||||
.height(452.dp)
|
||||
.fillMaxWidth()
|
||||
.constrainAs(pager) {
|
||||
top.linkTo(title.bottom)
|
||||
bottom.linkTo(dots.top)
|
||||
height = Dimension.fillToConstraints
|
||||
}
|
||||
.fillMaxSize()
|
||||
) { page ->
|
||||
when(page) {
|
||||
0 -> {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.img_introduce_vault_1),
|
||||
contentDescription = "Screenshot 1",
|
||||
modifier = Modifier.align(Alignment.BottomCenter)
|
||||
modifier = Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.img_introduce_vault_1),
|
||||
painter = painterResource(id = R.drawable.img_introduce_vault_2),
|
||||
contentDescription = "Screenshot 2",
|
||||
modifier = Modifier.align(Alignment.BottomCenter)
|
||||
)
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_sharing_step_third),
|
||||
contentDescription = "Screenshot 3",
|
||||
modifier = Modifier.align(Alignment.BottomCenter)
|
||||
modifier = Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -131,9 +128,9 @@ fun IntroduceVaultScreen(
|
|||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 46.dp)
|
||||
.padding(top = 4.dp)
|
||||
.constrainAs(dots) {
|
||||
bottom.linkTo(first.top)
|
||||
bottom.linkTo(pager.bottom)
|
||||
},
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
|
@ -164,10 +161,11 @@ fun IntroduceVaultScreen(
|
|||
style = BodyRegular,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
modifier = Modifier
|
||||
.padding(bottom = 8.dp, start = 24.dp, end = 24.dp)
|
||||
.padding(bottom = 30.dp, start = 24.dp, end = 24.dp)
|
||||
.constrainAs(first) {
|
||||
bottom.linkTo(btn.top)
|
||||
}
|
||||
},
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
ButtonSecondary(
|
||||
|
|
|
@ -82,6 +82,13 @@ class VaultFragment : BaseComposeFragment() {
|
|||
Timber.e(it, "Error while opening profile settings from vault")
|
||||
}
|
||||
}
|
||||
is Command.ShowIntroduceVault -> {
|
||||
runCatching {
|
||||
findNavController().navigate(R.id.actionShowIntroduceVaultScreen)
|
||||
}.onFailure {
|
||||
Timber.e(it, "Error while opening introduce-vault-screen from vault")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,6 +96,11 @@ class VaultFragment : BaseComposeFragment() {
|
|||
// TODO Do nothing ?
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
vm.onResume()
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().vaultComponent.get().inject(this)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/galleryView"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomToolbar"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomToolbarСontainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/controlDivider2" />
|
||||
|
@ -89,7 +89,7 @@
|
|||
android:id="@+id/paginatorToolbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/default_toolbar_height"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomToolbar"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottomToolbarСontainer"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
|
|
@ -214,6 +214,9 @@
|
|||
<action
|
||||
android:id="@+id/actionCreateSpaceFromVault"
|
||||
app:destination="@id/createSpaceScreen" />
|
||||
<action
|
||||
android:id="@+id/actionShowIntroduceVaultScreen"
|
||||
app:destination="@id/introduceVaultScreen" />
|
||||
</fragment>
|
||||
|
||||
<dialog
|
||||
|
@ -225,6 +228,11 @@
|
|||
app:popUpToInclusive="false" />
|
||||
</dialog>
|
||||
|
||||
<dialog
|
||||
android:id="@+id/introduceVaultScreen"
|
||||
android:name="com.anytypeio.anytype.ui.vault.IntroduceVaultFragment"
|
||||
android:label="IntroduceVaultScreen"/>
|
||||
|
||||
<dialog
|
||||
android:id="@+id/spaceSettingsScreen"
|
||||
android:name="com.anytypeio.anytype.ui.settings.space.SpaceSettingsFragment"
|
||||
|
|
|
@ -3,5 +3,6 @@ package com.anytypeio.anytype.core_models.settings
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
|
||||
data class VaultSettings(
|
||||
val showIntroduceVault: Boolean,
|
||||
val orderOfSpaces: List<Id> = emptyList()
|
||||
)
|
|
@ -16,6 +16,7 @@ interface UserSettingsCache {
|
|||
suspend fun getVaultSettings(account: Account): VaultSettings
|
||||
suspend fun observeVaultSettings(account: Account): Flow<VaultSettings>
|
||||
suspend fun setVaultSpaceOrder(account: Account, order: List<Id>)
|
||||
suspend fun setVaultSettings(account: Account, settings: VaultSettings)
|
||||
|
||||
suspend fun setCurrentSpace(space: SpaceId)
|
||||
suspend fun getCurrentSpace(): SpaceId?
|
||||
|
|
|
@ -95,6 +95,10 @@ class UserSettingsDataRepository(private val cache: UserSettingsCache) : UserSet
|
|||
return cache.getVaultSettings(account)
|
||||
}
|
||||
|
||||
override suspend fun setVaultSettings(account: Account, settings: VaultSettings) {
|
||||
cache.setVaultSettings(account, settings)
|
||||
}
|
||||
|
||||
override suspend fun observeVaultSettings(account: Account): Flow<VaultSettings> {
|
||||
return cache.observeVaultSettings(account)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ interface UserSettingsRepository {
|
|||
suspend fun getVaultSettings(account: Account): VaultSettings
|
||||
suspend fun observeVaultSettings(account: Account): Flow<VaultSettings>
|
||||
suspend fun setVaultSpaceOrder(account: Account, order: List<Id>)
|
||||
suspend fun setVaultSettings(account: Account, settings: VaultSettings)
|
||||
|
||||
suspend fun setCurrentSpace(space: SpaceId)
|
||||
suspend fun getCurrentSpace(): SpaceId?
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.anytypeio.anytype.domain.vault
|
||||
|
||||
import com.anytypeio.anytype.core_models.settings.VaultSettings
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class GetVaultSettings @Inject constructor(
|
||||
private val settings: UserSettingsRepository,
|
||||
private val auth: AuthRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): ResultInteractor<Unit, VaultSettings>(dispatchers.io) {
|
||||
|
||||
override suspend fun doWork(params: Unit): VaultSettings {
|
||||
val acc = auth.getCurrentAccount()
|
||||
return settings.getVaultSettings(acc)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.anytypeio.anytype.domain.vault
|
||||
|
||||
import com.anytypeio.anytype.core_models.settings.VaultSettings
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.base.ResultInteractor
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
class SetVaultSettings @Inject constructor(
|
||||
private val settings: UserSettingsRepository,
|
||||
private val auth: AuthRepository,
|
||||
dispatchers: AppCoroutineDispatchers
|
||||
): ResultInteractor<VaultSettings, Unit>(dispatchers.io) {
|
||||
|
||||
override suspend fun doWork(params: VaultSettings): Unit {
|
||||
val acc = auth.getCurrentAccount()
|
||||
return settings.setVaultSettings(acc, params)
|
||||
}
|
||||
}
|
|
@ -396,11 +396,15 @@ class DefaultUserSettingsCache(
|
|||
return context.vaultPrefsStore
|
||||
.data
|
||||
.map { prefs ->
|
||||
val curr = prefs.preferences.getOrDefault(
|
||||
key = account.id,
|
||||
defaultValue = VaultPreference(
|
||||
showIntroduceVault = true
|
||||
)
|
||||
)
|
||||
VaultSettings(
|
||||
orderOfSpaces = prefs.preferences.getOrDefault(
|
||||
key = account.id,
|
||||
defaultValue = VaultPreference()
|
||||
).orderOfSpaces
|
||||
orderOfSpaces = curr.orderOfSpaces,
|
||||
showIntroduceVault = curr.showIntroduceVault
|
||||
)
|
||||
}
|
||||
.first()
|
||||
|
@ -410,11 +414,15 @@ class DefaultUserSettingsCache(
|
|||
return context.vaultPrefsStore
|
||||
.data
|
||||
.map { prefs ->
|
||||
val curr = prefs.preferences.getOrDefault(
|
||||
key = account.id,
|
||||
defaultValue = VaultPreference(
|
||||
showIntroduceVault = true
|
||||
)
|
||||
)
|
||||
VaultSettings(
|
||||
orderOfSpaces = prefs.preferences.getOrDefault(
|
||||
key = account.id,
|
||||
defaultValue = VaultPreference()
|
||||
).orderOfSpaces
|
||||
orderOfSpaces = curr.orderOfSpaces,
|
||||
showIntroduceVault = curr.showIntroduceVault
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +431,9 @@ class DefaultUserSettingsCache(
|
|||
context.vaultPrefsStore.updateData { existingPreferences ->
|
||||
val curr = existingPreferences.preferences.getOrDefault(
|
||||
key = account.id,
|
||||
defaultValue = VaultPreference()
|
||||
defaultValue = VaultPreference(
|
||||
showIntroduceVault = true
|
||||
)
|
||||
)
|
||||
existingPreferences.copy(
|
||||
preferences = existingPreferences.preferences + mapOf(
|
||||
|
@ -435,6 +445,19 @@ class DefaultUserSettingsCache(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun setVaultSettings(account: Account, settings: VaultSettings) {
|
||||
context.vaultPrefsStore.updateData { existingPreferences ->
|
||||
existingPreferences.copy(
|
||||
preferences = existingPreferences.preferences + mapOf(
|
||||
account.id to VaultPreference(
|
||||
orderOfSpaces = settings.orderOfSpaces,
|
||||
showIntroduceVault = settings.showIntroduceVault
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAllContentSort(space: SpaceId): Id {
|
||||
return context.spacePrefsStore
|
||||
.data
|
||||
|
|
|
@ -15,6 +15,7 @@ message VaultPreferences {
|
|||
|
||||
message VaultPreference {
|
||||
repeated string orderOfSpaces = 1;
|
||||
bool showIntroduceVault = 2;
|
||||
}
|
||||
|
||||
message SpacePreference {
|
||||
|
|
|
@ -9,9 +9,12 @@ import com.anytypeio.anytype.core_models.multiplayer.SpaceAccessType
|
|||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_models.restrictions.SpaceStatus
|
||||
import com.anytypeio.anytype.domain.base.fold
|
||||
import com.anytypeio.anytype.domain.base.onSuccess
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
|
||||
import com.anytypeio.anytype.domain.spaces.SaveCurrentSpace
|
||||
import com.anytypeio.anytype.domain.vault.GetVaultSettings
|
||||
import com.anytypeio.anytype.domain.vault.SetVaultSettings
|
||||
import com.anytypeio.anytype.domain.wallpaper.GetSpaceWallpapers
|
||||
import com.anytypeio.anytype.domain.workspace.SpaceManager
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
|
@ -31,6 +34,8 @@ class VaultViewModel(
|
|||
private val getSpaceWallpapers: GetSpaceWallpapers,
|
||||
private val spaceManager: SpaceManager,
|
||||
private val saveCurrentSpace: SaveCurrentSpace,
|
||||
private val getVaultSettings: GetVaultSettings,
|
||||
private val setVaultSettings: SetVaultSettings
|
||||
) : BaseViewModel() {
|
||||
|
||||
val spaces = MutableStateFlow<List<VaultSpaceView>>(emptyList())
|
||||
|
@ -109,6 +114,21 @@ class VaultViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
viewModelScope.launch {
|
||||
getVaultSettings.async(Unit).onSuccess { settings ->
|
||||
if (settings.showIntroduceVault) {
|
||||
commands.emit(Command.ShowIntroduceVault)
|
||||
setVaultSettings.async(
|
||||
params = settings.copy(
|
||||
showIntroduceVault = false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun proceedWithSavingCurrentSpace(targetSpace: String) {
|
||||
saveCurrentSpace.async(
|
||||
SaveCurrentSpace.Params(SpaceId(targetSpace))
|
||||
|
@ -128,6 +148,8 @@ class VaultViewModel(
|
|||
private val urlBuilder: UrlBuilder,
|
||||
private val spaceManager: SpaceManager,
|
||||
private val saveCurrentSpace: SaveCurrentSpace,
|
||||
private val getVaultSettings: GetVaultSettings,
|
||||
private val setVaultSettings: SetVaultSettings
|
||||
) : ViewModelProvider.Factory {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel> create(
|
||||
|
@ -137,7 +159,9 @@ class VaultViewModel(
|
|||
getSpaceWallpapers = getSpaceWallpapers,
|
||||
urlBuilder = urlBuilder,
|
||||
spaceManager = spaceManager,
|
||||
saveCurrentSpace = saveCurrentSpace
|
||||
saveCurrentSpace = saveCurrentSpace,
|
||||
getVaultSettings = getVaultSettings,
|
||||
setVaultSettings = setVaultSettings
|
||||
) as T
|
||||
}
|
||||
|
||||
|
@ -151,5 +175,6 @@ class VaultViewModel(
|
|||
data object EnterSpaceHomeScreen: Command()
|
||||
data object CreateNewSpace: Command()
|
||||
data class OpenProfileSettings(val space: SpaceId): Command()
|
||||
data object ShowIntroduceVault : Command()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue