mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Feature | Reopen the last opened object or set on application start (#1851)
This commit is contained in:
parent
ecfe6baeaf
commit
ad421e3fe6
28 changed files with 356 additions and 26 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,5 +1,20 @@
|
|||
# Change log for Android @Anytype app.
|
||||
|
||||
## Version 0.3.3 (WIP)
|
||||
|
||||
### New features & enhancements 🚀
|
||||
|
||||
* App: Restoring the last opened object or the last opened set on application start (#1851)
|
||||
* App: Drafts without any history will be deleted after close (#1833)
|
||||
* Editor | Drag & drop (position above, below or inside) (#1848)
|
||||
* Sets | Grid as fallback view: views not supported on Android can be seen as grid (#1850)
|
||||
|
||||
### Design & UX 🔳
|
||||
|
||||
### Fixes & tech 🚒
|
||||
|
||||
|
||||
|
||||
## Version 0.3.2
|
||||
|
||||
### New features & enhancements 🚀
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.fragment.app.testing.launchFragmentInContainer
|
|||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.core_models.*
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateText
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.Gateway
|
||||
|
@ -46,6 +47,10 @@ abstract class TestObjectSetSetup {
|
|||
|
||||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var auth: AuthRepository
|
||||
|
||||
@Mock
|
||||
lateinit var gateway: Gateway
|
||||
@Mock
|
||||
|
@ -88,7 +93,7 @@ abstract class TestObjectSetSetup {
|
|||
|
||||
addDataViewRelation = AddNewRelationToDataView(repo)
|
||||
updateText = UpdateText(repo)
|
||||
openObjectSet = OpenObjectSet(repo)
|
||||
openObjectSet = OpenObjectSet(repo, auth)
|
||||
createDataViewRecord = CreateDataViewRecord(repo)
|
||||
updateDataViewRecord = UpdateDataViewRecord(repo)
|
||||
updateDataViewViewer = UpdateDataViewViewer(repo)
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.anytypeio.anytype.analytics.base.Analytics
|
|||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.domain.`object`.ObjectTypesProvider
|
||||
import com.anytypeio.anytype.domain.auth.interactor.GetProfile
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.block.interactor.Move
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.config.GetConfig
|
||||
|
@ -87,9 +88,11 @@ object HomeDashboardModule {
|
|||
@Provides
|
||||
@PerScreen
|
||||
fun provideOpenDashboardUseCase(
|
||||
repo: BlockRepository
|
||||
repo: BlockRepository,
|
||||
auth: AuthRepository
|
||||
): OpenDashboard = OpenDashboard(
|
||||
repo = repo
|
||||
repo = repo,
|
||||
auth = auth
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.anytypeio.anytype.di.feature.relations.RelationCreateFromScratchForOb
|
|||
import com.anytypeio.anytype.di.feature.relations.RelationCreateFromScratchForObjectSubComponent
|
||||
import com.anytypeio.anytype.domain.`object`.ObjectTypesProvider
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.block.UpdateDivider
|
||||
import com.anytypeio.anytype.domain.block.interactor.*
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
|
||||
|
@ -297,9 +298,11 @@ object EditorUseCaseModule {
|
|||
@Provides
|
||||
@PerScreen
|
||||
fun provideOpenPageUseCase(
|
||||
repo: BlockRepository
|
||||
repo: BlockRepository,
|
||||
auth: AuthRepository
|
||||
): OpenPage = OpenPage(
|
||||
repo = repo
|
||||
repo = repo,
|
||||
auth = auth
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.anytypeio.anytype.di.feature.sets.CreateFilterSubComponent
|
|||
import com.anytypeio.anytype.di.feature.sets.ModifyFilterSubComponent
|
||||
import com.anytypeio.anytype.di.feature.sets.SelectFilterRelationSubComponent
|
||||
import com.anytypeio.anytype.domain.`object`.UpdateDetail
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.block.interactor.UpdateText
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.dataview.interactor.*
|
||||
|
@ -118,7 +119,10 @@ object ObjectSetModule {
|
|||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun provideOpenObjectSetUseCase(repo: BlockRepository): OpenObjectSet = OpenObjectSet(repo)
|
||||
fun provideOpenObjectSetUseCase(
|
||||
repo: BlockRepository,
|
||||
auth: AuthRepository
|
||||
): OpenObjectSet = OpenObjectSet(repo = repo, auth = auth)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.anytypeio.anytype.analytics.base.Analytics
|
|||
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
|
||||
import com.anytypeio.anytype.domain.`object`.ObjectTypesProvider
|
||||
import com.anytypeio.anytype.domain.auth.interactor.CheckAuthorizationStatus
|
||||
import com.anytypeio.anytype.domain.auth.interactor.GetLastOpenedObject
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchAccount
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchWallet
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
|
@ -13,6 +14,7 @@ import com.anytypeio.anytype.domain.config.FlavourConfigProvider
|
|||
import com.anytypeio.anytype.domain.device.PathProvider
|
||||
import com.anytypeio.anytype.presentation.splash.SplashViewModelFactory
|
||||
import com.anytypeio.anytype.ui.splash.SplashFragment
|
||||
import com.squareup.wire.get
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
@ -47,13 +49,15 @@ object SplashModule {
|
|||
launchAccount: LaunchAccount,
|
||||
launchWallet: LaunchWallet,
|
||||
analytics: Analytics,
|
||||
storeObjectTypes: StoreObjectTypes
|
||||
storeObjectTypes: StoreObjectTypes,
|
||||
getLastOpenedObject: GetLastOpenedObject
|
||||
): SplashViewModelFactory = SplashViewModelFactory(
|
||||
checkAuthorizationStatus = checkAuthorizationStatus,
|
||||
launchAccount = launchAccount,
|
||||
launchWallet = launchWallet,
|
||||
analytics = analytics,
|
||||
storeObjectTypes = storeObjectTypes
|
||||
storeObjectTypes = storeObjectTypes,
|
||||
getLastOpenedObject = getLastOpenedObject
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
|
@ -97,4 +101,15 @@ object SplashModule {
|
|||
repo: BlockRepository,
|
||||
objectTypesProvider: ObjectTypesProvider
|
||||
) : StoreObjectTypes = StoreObjectTypes(repo, objectTypesProvider)
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@PerScreen
|
||||
fun getLastOpenedObject(
|
||||
repo: BlockRepository,
|
||||
auth: AuthRepository
|
||||
) : GetLastOpenedObject = GetLastOpenedObject(
|
||||
authRepo = auth,
|
||||
blockRepo = repo
|
||||
)
|
||||
}
|
|
@ -105,6 +105,20 @@ class Navigator : AppNavigation {
|
|||
)
|
||||
}
|
||||
|
||||
override fun launchObjectFromSplash(id: Id) {
|
||||
navController?.navigate(
|
||||
R.id.action_splashScreen_to_objectScreen,
|
||||
bundleOf(EditorFragment.ID_KEY to id),
|
||||
)
|
||||
}
|
||||
|
||||
override fun launchObjectSetFromSplash(id: Id) {
|
||||
navController?.navigate(
|
||||
R.id.action_splashScreen_to_objectSetScreen,
|
||||
bundleOf(ObjectSetFragment.CONTEXT_ID_KEY to id),
|
||||
)
|
||||
}
|
||||
|
||||
override fun openKeychainScreen() {
|
||||
navController?.navigate(R.id.action_open_keychain)
|
||||
}
|
||||
|
@ -149,11 +163,17 @@ class Navigator : AppNavigation {
|
|||
}
|
||||
|
||||
override fun exit() {
|
||||
navController?.popBackStack()
|
||||
val popped = navController?.popBackStack()
|
||||
if (popped == false) {
|
||||
navController?.navigate(R.id.desktopScreen)
|
||||
}
|
||||
}
|
||||
|
||||
override fun exitToDesktop() {
|
||||
navController?.popBackStack(R.id.desktopScreen, false)
|
||||
val popped = navController?.popBackStack(R.id.desktopScreen, false)
|
||||
if (popped == false) {
|
||||
navController?.navigate(R.id.desktopScreen)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openDebugSettings() {
|
||||
|
|
|
@ -42,6 +42,8 @@ abstract class NavigationFragment(
|
|||
is Command.OpenObjectSet -> navigation.openObjectSet(command.target)
|
||||
is Command.LaunchObjectSet -> navigation.launchObjectSet(command.target)
|
||||
is Command.LaunchDocument -> navigation.launchDocument(command.id)
|
||||
is Command.LaunchObjectFromSplash -> navigation.launchObjectFromSplash(command.target)
|
||||
is Command.LaunchObjectSetFromSplash -> navigation.launchObjectSetFromSplash(command.target)
|
||||
is Command.OpenDatabaseViewAddView -> navigation.openDatabaseViewAddView()
|
||||
is Command.OpenEditDatabase -> navigation.openEditDatabase()
|
||||
is Command.OpenKeychainScreen -> navigation.openKeychainScreen()
|
||||
|
|
|
@ -206,6 +206,24 @@
|
|||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:popUpTo="@+id/splashScreen"
|
||||
app:popUpToInclusive="true" />
|
||||
<action
|
||||
android:id="@+id/action_splashScreen_to_objectScreen"
|
||||
app:destination="@id/objectNavigation"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:popUpTo="@+id/main_navigation"
|
||||
app:popUpToInclusive="true" />
|
||||
<action
|
||||
android:id="@+id/action_splashScreen_to_objectSetScreen"
|
||||
app:destination="@id/dataViewNavigation"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:popUpTo="@+id/main_navigation"
|
||||
app:popUpToInclusive="true" />
|
||||
<action
|
||||
android:id="@+id/action_splashFragment_to_login_nav"
|
||||
app:destination="@id/login_nav"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.anytypeio.anytype.data.auth.repo
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.data.auth.model.AccountEntity
|
||||
|
||||
interface AuthCache {
|
||||
|
@ -16,4 +17,8 @@ interface AuthCache {
|
|||
suspend fun logout()
|
||||
suspend fun getAccounts(): List<AccountEntity>
|
||||
suspend fun setCurrentAccount(id: String)
|
||||
|
||||
suspend fun saveLastOpenedObject(id: Id)
|
||||
suspend fun getLastOpenedObject() : Id?
|
||||
suspend fun clearLastOpenedObject()
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package com.anytypeio.anytype.data.auth.repo
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.data.auth.model.AccountEntity
|
||||
import com.anytypeio.anytype.data.auth.model.FlavourConfigEntity
|
||||
import com.anytypeio.anytype.data.auth.model.WalletEntity
|
||||
|
@ -69,4 +71,8 @@ class AuthCacheDataStore(private val cache: AuthCache) : AuthDataStore {
|
|||
override suspend fun getVersion(): String {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override suspend fun saveLastOpenedObject(id: Id) { cache.saveLastOpenedObject(id) }
|
||||
override suspend fun getLastOpenedObject(): Id? = cache.getLastOpenedObject()
|
||||
override suspend fun clearLastOpenedObject() { cache.clearLastOpenedObject() }
|
||||
}
|
|
@ -7,6 +7,8 @@ import com.anytypeio.anytype.domain.auth.model.Account
|
|||
import com.anytypeio.anytype.domain.auth.model.Wallet
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.core_models.FlavourConfig
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class AuthDataRepository(
|
||||
|
@ -77,4 +79,8 @@ class AuthDataRepository(
|
|||
}
|
||||
|
||||
override suspend fun getVersion(): String = factory.remote.getVersion()
|
||||
|
||||
override suspend fun saveLastOpenedObjectId(id: Id) { factory.cache.saveLastOpenedObject(id) }
|
||||
override suspend fun getLastOpenedObjectId(): Id? = factory.cache.getLastOpenedObject()
|
||||
override suspend fun clearLastOpenedObject() { factory.cache.clearLastOpenedObject() }
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package com.anytypeio.anytype.data.auth.repo
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.data.auth.model.AccountEntity
|
||||
import com.anytypeio.anytype.data.auth.model.FlavourConfigEntity
|
||||
import com.anytypeio.anytype.data.auth.model.WalletEntity
|
||||
|
@ -33,4 +35,8 @@ interface AuthDataStore {
|
|||
suspend fun setCurrentAccount(id: String)
|
||||
|
||||
suspend fun getVersion(): String
|
||||
|
||||
suspend fun saveLastOpenedObject(id: Id)
|
||||
suspend fun getLastOpenedObject() : Id?
|
||||
suspend fun clearLastOpenedObject()
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package com.anytypeio.anytype.data.auth.repo
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.data.auth.model.AccountEntity
|
||||
import com.anytypeio.anytype.data.auth.model.WalletEntity
|
||||
|
||||
|
@ -71,4 +73,16 @@ class AuthRemoteDataStore(
|
|||
}
|
||||
|
||||
override suspend fun getVersion(): String = authRemote.getVersion()
|
||||
|
||||
override suspend fun saveLastOpenedObject(id: Id) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override suspend fun getLastOpenedObject(): Id? {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override suspend fun clearLastOpenedObject() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.anytypeio.anytype.domain.auth.interactor
|
||||
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
|
||||
/**
|
||||
* Use case for clearing last open object's id from user session.
|
||||
* @see GetLastOpenedObject
|
||||
* @see SaveLastOpenedObject
|
||||
*/
|
||||
class ClearLastOpenedObject(
|
||||
private val repo: AuthRepository
|
||||
) : BaseUseCase<Unit, BaseUseCase.None>() {
|
||||
override suspend fun run(params: None) = safe { repo.clearLastOpenedObject() }
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.anytypeio.anytype.domain.auth.interactor
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
||||
/**
|
||||
* Use case for fetching last open object's id for restoring user session.
|
||||
* @see SaveLastOpenedObject
|
||||
* @see ClearLastOpenedObject
|
||||
*/
|
||||
class GetLastOpenedObject(
|
||||
private val authRepo: AuthRepository,
|
||||
private val blockRepo: BlockRepository
|
||||
) : BaseUseCase<GetLastOpenedObject.Response, BaseUseCase.None>() {
|
||||
|
||||
override suspend fun run(params: None) = safe {
|
||||
val lastOpenObjectId = authRepo.getLastOpenedObjectId()
|
||||
if (lastOpenObjectId == null) {
|
||||
Response.Empty
|
||||
} else {
|
||||
val searchResults = blockRepo.searchObjects(
|
||||
offset = 0,
|
||||
limit = 1,
|
||||
sorts = emptyList(),
|
||||
filters = listOf(
|
||||
Block.Content.DataView.Filter(
|
||||
relationKey = Relations.ID,
|
||||
condition = Block.Content.DataView.Filter.Condition.EQUAL,
|
||||
operator = Block.Content.DataView.Filter.Operator.AND,
|
||||
value = lastOpenObjectId
|
||||
)
|
||||
),
|
||||
fulltext = ""
|
||||
)
|
||||
val wrappedObjects = searchResults.map { ObjectWrapper.Basic(it) }
|
||||
val lastOpenedObject = wrappedObjects.firstOrNull { it.id == lastOpenObjectId }
|
||||
if (lastOpenedObject != null) {
|
||||
Response.Success(lastOpenedObject)
|
||||
} else {
|
||||
Response.NotFound(lastOpenObjectId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Response {
|
||||
/**
|
||||
* There was no information about the last opened object.
|
||||
*/
|
||||
object Empty : Response()
|
||||
|
||||
/**
|
||||
* The last opened object could not be found. It might habe been deleted.
|
||||
*/
|
||||
data class NotFound(val id: Id) : Response()
|
||||
|
||||
/**
|
||||
* The last opened object has been found.
|
||||
*/
|
||||
data class Success(val obj: ObjectWrapper.Basic) : Response()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.anytypeio.anytype.domain.auth.interactor
|
||||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
|
||||
/**
|
||||
* Use case for saving last open object's id for restoring user session.
|
||||
* @see GetLastOpenedObject
|
||||
* @see ClearLastOpenedObject
|
||||
*/
|
||||
class SaveLastOpenedObject(
|
||||
private val repo: AuthRepository
|
||||
) : BaseUseCase<Unit, Id>() {
|
||||
override suspend fun run(params: Id) = safe { repo.saveLastOpenedObjectId(params) }
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.anytypeio.anytype.domain.auth.repo
|
|||
import com.anytypeio.anytype.domain.auth.model.Account
|
||||
import com.anytypeio.anytype.domain.auth.model.Wallet
|
||||
import com.anytypeio.anytype.core_models.FlavourConfig
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AuthRepository {
|
||||
|
@ -49,4 +51,8 @@ interface AuthRepository {
|
|||
suspend fun setCurrentAccount(id: String)
|
||||
|
||||
suspend fun getVersion(): String
|
||||
|
||||
suspend fun saveLastOpenedObjectId(id: Id)
|
||||
suspend fun getLastOpenedObjectId() : Id?
|
||||
suspend fun clearLastOpenedObject()
|
||||
}
|
|
@ -4,6 +4,7 @@ import com.anytypeio.anytype.domain.base.BaseUseCase
|
|||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
|
||||
/**
|
||||
* Use-case for opening a dashboard by sending a special request.
|
||||
|
@ -11,7 +12,8 @@ import com.anytypeio.anytype.core_models.Payload
|
|||
* @property repo
|
||||
*/
|
||||
class OpenDashboard(
|
||||
private val repo: BlockRepository
|
||||
private val repo: BlockRepository,
|
||||
private val auth: AuthRepository,
|
||||
) : BaseUseCase<Payload, OpenDashboard.Param?>() {
|
||||
|
||||
override suspend fun run(params: Param?) = try {
|
||||
|
@ -20,7 +22,9 @@ class OpenDashboard(
|
|||
contextId = params.contextId,
|
||||
id = params.id
|
||||
).let {
|
||||
Either.Right(it)
|
||||
Either.Right(it).also {
|
||||
auth.clearLastOpenedObject()
|
||||
}
|
||||
}
|
||||
else {
|
||||
repo.getConfig().let { config ->
|
||||
|
@ -28,7 +32,9 @@ class OpenDashboard(
|
|||
contextId = config.home,
|
||||
id = config.home
|
||||
).let {
|
||||
Either.Right(it)
|
||||
Either.Right(it).also {
|
||||
auth.clearLastOpenedObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,18 @@ import com.anytypeio.anytype.domain.base.BaseUseCase
|
|||
import com.anytypeio.anytype.domain.base.Result
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
|
||||
open class OpenPage(
|
||||
private val repo: BlockRepository
|
||||
private val repo: BlockRepository,
|
||||
private val auth: AuthRepository
|
||||
) : BaseUseCase<Result<Payload>, OpenPage.Params>() {
|
||||
|
||||
override suspend fun run(params: Params) = safe { repo.openPage(params.id) }
|
||||
override suspend fun run(params: Params) = safe {
|
||||
repo.openPage(params.id).also {
|
||||
auth.saveLastOpenedObjectId(params.id)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @property id page's id
|
||||
|
|
|
@ -2,9 +2,17 @@ package com.anytypeio.anytype.domain.sets
|
|||
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Payload
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
||||
class OpenObjectSet(private val repo: BlockRepository) : BaseUseCase<Payload, Id>() {
|
||||
override suspend fun run(params: Id) = safe { repo.openObjectSet(params) }
|
||||
class OpenObjectSet(
|
||||
private val repo: BlockRepository,
|
||||
private val auth: AuthRepository
|
||||
) : BaseUseCase<Payload, Id>() {
|
||||
override suspend fun run(params: Id) = safe {
|
||||
repo.openObjectSet(params).also {
|
||||
auth.saveLastOpenedObjectId(params)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
|||
import com.anytypeio.anytype.core_models.CoroutineTestRule
|
||||
import com.anytypeio.anytype.domain.common.MockDataFactory
|
||||
import com.anytypeio.anytype.core_models.Config
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.dashboard.interactor.OpenDashboard
|
||||
import com.nhaarman.mockitokotlin2.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
@ -23,12 +24,15 @@ class OpenDashboardTest {
|
|||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var auth: AuthRepository
|
||||
|
||||
private lateinit var usecase: OpenDashboard
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
usecase = OpenDashboard(repo = repo)
|
||||
usecase = OpenDashboard(repo = repo, auth = auth)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -74,6 +74,7 @@ class DefaultAuthCache(
|
|||
encryptedPrefs
|
||||
.edit()
|
||||
.remove(MNEMONIC_KEY)
|
||||
.remove(LAST_OPENED_OBJECT_KEY)
|
||||
.remove(CURRENT_ACCOUNT_ID_KEY)
|
||||
.apply()
|
||||
}
|
||||
|
@ -88,8 +89,21 @@ class DefaultAuthCache(
|
|||
encryptedPrefs.edit().putString(CURRENT_ACCOUNT_ID_KEY, id).apply()
|
||||
}
|
||||
|
||||
override suspend fun saveLastOpenedObject(id: String) {
|
||||
encryptedPrefs.edit().putString(LAST_OPENED_OBJECT_KEY, id).apply()
|
||||
}
|
||||
|
||||
override suspend fun getLastOpenedObject(): String? {
|
||||
return encryptedPrefs.getString(LAST_OPENED_OBJECT_KEY, null)
|
||||
}
|
||||
|
||||
override suspend fun clearLastOpenedObject() {
|
||||
encryptedPrefs.edit().remove(LAST_OPENED_OBJECT_KEY).apply()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MNEMONIC_KEY = "mnemonic"
|
||||
const val LAST_OPENED_OBJECT_KEY = "last_opened_object"
|
||||
const val CURRENT_ACCOUNT_ID_KEY = "current_account"
|
||||
}
|
||||
}
|
|
@ -134,7 +134,7 @@ class EditorViewModel(
|
|||
private val updateDetail: UpdateDetail,
|
||||
private val getCompatibleObjectTypes: GetCompatibleObjectTypes,
|
||||
private val objectTypesProvider: ObjectTypesProvider,
|
||||
private val searchObjects: SearchObjects
|
||||
private val searchObjects: SearchObjects,
|
||||
) : ViewStateViewModel<ViewState>(),
|
||||
SupportNavigation<EventWrapper<AppNavigation.Command>>,
|
||||
SupportCommand<Command>,
|
||||
|
|
|
@ -24,6 +24,8 @@ interface AppNavigation {
|
|||
fun openDocument(id: String, editorSettings: EditorSettings?)
|
||||
|
||||
fun launchDocument(id: String)
|
||||
fun launchObjectFromSplash(id: Id)
|
||||
fun launchObjectSetFromSplash(id: Id)
|
||||
fun launchObjectSet(id: Id)
|
||||
|
||||
fun startDesktopFromSplash()
|
||||
|
@ -65,6 +67,8 @@ interface AppNavigation {
|
|||
|
||||
data class OpenObject(val id: String, val editorSettings: EditorSettings? = null) : Command()
|
||||
data class LaunchDocument(val id: String) : Command()
|
||||
data class LaunchObjectFromSplash(val target: Id) : Command()
|
||||
data class LaunchObjectSetFromSplash(val target: Id) : Command()
|
||||
|
||||
object OpenProfile : Command()
|
||||
object OpenKeychainScreen : Command()
|
||||
|
|
|
@ -11,15 +11,18 @@ import com.anytypeio.anytype.analytics.base.sendEvent
|
|||
import com.anytypeio.anytype.analytics.base.updateUserProperties
|
||||
import com.anytypeio.anytype.analytics.props.Props
|
||||
import com.anytypeio.anytype.analytics.props.UserProperty
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_utils.common.EventWrapper
|
||||
import com.anytypeio.anytype.core_utils.ui.ViewState
|
||||
import com.anytypeio.anytype.domain.auth.interactor.CheckAuthorizationStatus
|
||||
import com.anytypeio.anytype.domain.auth.interactor.GetLastOpenedObject
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchAccount
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchWallet
|
||||
import com.anytypeio.anytype.domain.auth.model.AuthStatus
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.StoreObjectTypes
|
||||
import com.anytypeio.anytype.presentation.navigation.AppNavigation
|
||||
import com.anytypeio.anytype.presentation.objects.SupportedLayouts
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
|
@ -33,7 +36,8 @@ class SplashViewModel(
|
|||
private val checkAuthorizationStatus: CheckAuthorizationStatus,
|
||||
private val launchWallet: LaunchWallet,
|
||||
private val launchAccount: LaunchAccount,
|
||||
private val storeObjectTypes: StoreObjectTypes
|
||||
private val storeObjectTypes: StoreObjectTypes,
|
||||
private val getLastOpenedObject: GetLastOpenedObject
|
||||
) : ViewModel() {
|
||||
|
||||
val state = MutableLiveData<ViewState<Nothing>>()
|
||||
|
@ -106,9 +110,41 @@ class SplashViewModel(
|
|||
storeObjectTypes.invoke(Unit).process(
|
||||
failure = {
|
||||
Timber.e(it, "Error while store account object types")
|
||||
navigateToDashboard()
|
||||
handleNavigation()
|
||||
},
|
||||
success = { navigateToDashboard() }
|
||||
success = { handleNavigation() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleNavigation() {
|
||||
viewModelScope.launch {
|
||||
getLastOpenedObject(BaseUseCase.None).process(
|
||||
failure = { navigateToDashboard() },
|
||||
success = { response ->
|
||||
when(response) {
|
||||
is GetLastOpenedObject.Response.Success -> {
|
||||
if (SupportedLayouts.layouts.contains(response.obj.layout)) {
|
||||
if (response.obj.layout == ObjectType.Layout.SET) {
|
||||
navigation.postValue(
|
||||
EventWrapper(
|
||||
AppNavigation.Command.LaunchObjectSetFromSplash(response.obj.id)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
navigation.postValue(
|
||||
EventWrapper(
|
||||
AppNavigation.Command.LaunchObjectFromSplash(response.obj.id)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
navigateToDashboard()
|
||||
}
|
||||
}
|
||||
else -> navigateToDashboard()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.domain.auth.interactor.CheckAuthorizationStatus
|
||||
import com.anytypeio.anytype.domain.auth.interactor.GetLastOpenedObject
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchAccount
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchWallet
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.StoreObjectTypes
|
||||
|
@ -18,7 +19,8 @@ class SplashViewModelFactory(
|
|||
private val launchAccount: LaunchAccount,
|
||||
private val launchWallet: LaunchWallet,
|
||||
private val analytics: Analytics,
|
||||
private val storeObjectTypes: StoreObjectTypes
|
||||
private val storeObjectTypes: StoreObjectTypes,
|
||||
private val getLastOpenedObject: GetLastOpenedObject
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -28,6 +30,7 @@ class SplashViewModelFactory(
|
|||
launchAccount = launchAccount,
|
||||
launchWallet = launchWallet,
|
||||
analytics = analytics,
|
||||
storeObjectTypes = storeObjectTypes
|
||||
storeObjectTypes = storeObjectTypes,
|
||||
getLastOpenedObject = getLastOpenedObject
|
||||
) as T
|
||||
}
|
|
@ -6,9 +6,11 @@ import com.anytypeio.anytype.analytics.base.Analytics
|
|||
import com.anytypeio.anytype.core_utils.ui.ViewState
|
||||
import com.anytypeio.anytype.domain.`object`.ObjectTypesProvider
|
||||
import com.anytypeio.anytype.domain.auth.interactor.CheckAuthorizationStatus
|
||||
import com.anytypeio.anytype.domain.auth.interactor.GetLastOpenedObject
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchAccount
|
||||
import com.anytypeio.anytype.domain.auth.interactor.LaunchWallet
|
||||
import com.anytypeio.anytype.domain.auth.model.AuthStatus
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.block.interactor.sets.StoreObjectTypes
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
|
@ -46,10 +48,14 @@ class SplashViewModelTest {
|
|||
@Mock
|
||||
lateinit var repo: BlockRepository
|
||||
|
||||
@Mock
|
||||
lateinit var auth: AuthRepository
|
||||
|
||||
@Mock
|
||||
lateinit var objectTypesProvider: ObjectTypesProvider
|
||||
|
||||
lateinit var storeObjectTypes: StoreObjectTypes
|
||||
private lateinit var storeObjectTypes: StoreObjectTypes
|
||||
private lateinit var getLastOpenedObject: GetLastOpenedObject
|
||||
|
||||
lateinit var vm: SplashViewModel
|
||||
|
||||
|
@ -61,12 +67,17 @@ class SplashViewModelTest {
|
|||
repo = repo,
|
||||
objectTypesProvider = objectTypesProvider
|
||||
)
|
||||
getLastOpenedObject = GetLastOpenedObject(
|
||||
authRepo = auth,
|
||||
blockRepo = repo
|
||||
)
|
||||
vm = SplashViewModel(
|
||||
checkAuthorizationStatus = checkAuthorizationStatus,
|
||||
launchAccount = launchAccount,
|
||||
launchWallet = launchWallet,
|
||||
analytics = analytics,
|
||||
storeObjectTypes = storeObjectTypes
|
||||
storeObjectTypes = storeObjectTypes,
|
||||
getLastOpenedObject = getLastOpenedObject
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -79,6 +90,7 @@ class SplashViewModelTest {
|
|||
stubCheckAuthStatus(response)
|
||||
stubLaunchWallet()
|
||||
stubLaunchAccount()
|
||||
stubGetLastOpenedObject()
|
||||
|
||||
runBlocking {
|
||||
verify(checkAuthorizationStatus, times(0)).invoke(any(), any(), any())
|
||||
|
@ -96,6 +108,7 @@ class SplashViewModelTest {
|
|||
stubCheckAuthStatus(response)
|
||||
stubLaunchWallet()
|
||||
stubLaunchAccount()
|
||||
stubGetLastOpenedObject()
|
||||
|
||||
vm.onResume()
|
||||
|
||||
|
@ -114,6 +127,7 @@ class SplashViewModelTest {
|
|||
stubCheckAuthStatus(response)
|
||||
stubLaunchWallet()
|
||||
stubLaunchAccount()
|
||||
stubGetLastOpenedObject()
|
||||
|
||||
vm.onResume()
|
||||
|
||||
|
@ -132,6 +146,7 @@ class SplashViewModelTest {
|
|||
stubCheckAuthStatus(response)
|
||||
stubLaunchWallet()
|
||||
stubLaunchAccount()
|
||||
stubGetLastOpenedObject()
|
||||
|
||||
vm.onResume()
|
||||
|
||||
|
@ -172,6 +187,7 @@ class SplashViewModelTest {
|
|||
val response = Either.Right(status)
|
||||
|
||||
stubCheckAuthStatus(response)
|
||||
stubGetLastOpenedObject()
|
||||
|
||||
vm.onResume()
|
||||
|
||||
|
@ -229,4 +245,12 @@ class SplashViewModelTest {
|
|||
onBlocking { invoke(any()) } doReturn Either.Right("accountId")
|
||||
}
|
||||
}
|
||||
|
||||
private fun stubGetLastOpenedObject() {
|
||||
auth.stub {
|
||||
onBlocking {
|
||||
getLastOpenedObjectId()
|
||||
} doReturn null
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue