diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e251f5f8f..c2489a4f4c 100644
--- a/CHANGELOG.md
+++ b/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 🚀
diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt
index 98eee51e45..dac73de521 100644
--- a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt
+++ b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt
@@ -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)
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/DashboardDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/DashboardDi.kt
index 6dce89596f..204f357d5b 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/DashboardDi.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/DashboardDi.kt
@@ -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
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt
index dd1012431d..d2a7020327 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/EditorDI.kt
@@ -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
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt
index 1fd422433e..13e412807c 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectSetDI.kt
@@ -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
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt
index ffaf9e08f7..81f977d720 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt
@@ -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
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt
index cffa3e94d2..b36b881637 100644
--- a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt
+++ b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt
@@ -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() {
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationFragment.kt
index cd51cf5da1..d493d554f4 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationFragment.kt
@@ -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()
diff --git a/app/src/main/res/navigation/graph.xml b/app/src/main/res/navigation/graph.xml
index b0e16943ea..e5627803a0 100644
--- a/app/src/main/res/navigation/graph.xml
+++ b/app/src/main/res/navigation/graph.xml
@@ -206,6 +206,24 @@
app:popExitAnim="@anim/nav_default_pop_exit_anim"
app:popUpTo="@+id/splashScreen"
app:popUpToInclusive="true" />
+
+
suspend fun setCurrentAccount(id: String)
+
+ suspend fun saveLastOpenedObject(id: Id)
+ suspend fun getLastOpenedObject() : Id?
+ suspend fun clearLastOpenedObject()
}
\ No newline at end of file
diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt
index 8d9b1cabb8..4a1f74ab5f 100644
--- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt
+++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthCacheDataStore.kt
@@ -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() }
}
\ No newline at end of file
diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt
index 56660cf57d..0e4d5c47b7 100644
--- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt
+++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataRepository.kt
@@ -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() }
}
\ No newline at end of file
diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt
index eb55126f3a..c649066aaa 100644
--- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt
+++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthDataStore.kt
@@ -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()
}
\ No newline at end of file
diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt
index 6900aa3a50..29f8be1df1 100644
--- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt
+++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/AuthRemoteDataStore.kt
@@ -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()
+ }
}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/ClearLastOpenedObject.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/ClearLastOpenedObject.kt
new file mode 100644
index 0000000000..dd6b8c3eec
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/ClearLastOpenedObject.kt
@@ -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() {
+ override suspend fun run(params: None) = safe { repo.clearLastOpenedObject() }
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetLastOpenedObject.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetLastOpenedObject.kt
new file mode 100644
index 0000000000..c6d1a2f4c5
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/GetLastOpenedObject.kt
@@ -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() {
+
+ 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()
+ }
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/SaveLastOpenedObject.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/SaveLastOpenedObject.kt
new file mode 100644
index 0000000000..fedd9a25ef
--- /dev/null
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/interactor/SaveLastOpenedObject.kt
@@ -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() {
+ override suspend fun run(params: Id) = safe { repo.saveLastOpenedObjectId(params) }
+}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt
index 94bb839247..4e5f34ae8c 100644
--- a/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/auth/repo/AuthRepository.kt
@@ -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()
}
\ No newline at end of file
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/dashboard/interactor/OpenDashboard.kt b/domain/src/main/java/com/anytypeio/anytype/domain/dashboard/interactor/OpenDashboard.kt
index 84d6273e69..ef61064b0a 100644
--- a/domain/src/main/java/com/anytypeio/anytype/domain/dashboard/interactor/OpenDashboard.kt
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/dashboard/interactor/OpenDashboard.kt
@@ -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() {
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()
+ }
}
}
}
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/page/OpenPage.kt b/domain/src/main/java/com/anytypeio/anytype/domain/page/OpenPage.kt
index 13b5b241d9..8bd1811728 100644
--- a/domain/src/main/java/com/anytypeio/anytype/domain/page/OpenPage.kt
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/page/OpenPage.kt
@@ -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, 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
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/sets/OpenObjectSet.kt b/domain/src/main/java/com/anytypeio/anytype/domain/sets/OpenObjectSet.kt
index 8c7a03f85b..4d31990b93 100644
--- a/domain/src/main/java/com/anytypeio/anytype/domain/sets/OpenObjectSet.kt
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/sets/OpenObjectSet.kt
@@ -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() {
- override suspend fun run(params: Id) = safe { repo.openObjectSet(params) }
+class OpenObjectSet(
+ private val repo: BlockRepository,
+ private val auth: AuthRepository
+) : BaseUseCase() {
+ override suspend fun run(params: Id) = safe {
+ repo.openObjectSet(params).also {
+ auth.saveLastOpenedObjectId(params)
+ }
+ }
}
\ No newline at end of file
diff --git a/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/OpenDashboardTest.kt b/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/OpenDashboardTest.kt
index a1d305d4a5..af9f0728df 100644
--- a/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/OpenDashboardTest.kt
+++ b/domain/src/test/java/com/anytypeio/anytype/domain/dashboard/OpenDashboardTest.kt
@@ -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
diff --git a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultAuthCache.kt b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultAuthCache.kt
index 0760fa0745..7dd8478455 100644
--- a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultAuthCache.kt
+++ b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultAuthCache.kt
@@ -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"
}
}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt
index 0172f6f64f..844887295f 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt
@@ -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(),
SupportNavigation>,
SupportCommand,
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt
index d7f36b37b4..89daecb5a3 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt
@@ -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()
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt
index 7c40720d5e..80dd010960 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModel.kt
@@ -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>()
@@ -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()
+ }
+ }
)
}
}
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModelFactory.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModelFactory.kt
index 1fa0daf099..eac0009538 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModelFactory.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/splash/SplashViewModelFactory.kt
@@ -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
}
\ No newline at end of file
diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/splash/SplashViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/splash/SplashViewModelTest.kt
index a785c5cd56..438a9d7148 100644
--- a/presentation/src/test/java/com/anytypeio/anytype/presentation/splash/SplashViewModelTest.kt
+++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/splash/SplashViewModelTest.kt
@@ -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
+ }
+ }
}
\ No newline at end of file