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

DROID-2916 App | Tech | Prepare staging release (#1666)

Co-authored-by: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com>
This commit is contained in:
Evgenii Kozlov 2024-10-22 12:17:11 +02:00
parent 14af7b40c1
commit b78e3e4d0d
203 changed files with 2606 additions and 1726 deletions

View file

@ -171,7 +171,7 @@ object EventsDictionary {
// Vault events
const val screenVault = "ScreenOnboarding"
const val screenVault = "ScreenVault"
// About-app screen

View file

@ -1,4 +1,4 @@
version.versionMajor=0
version.versionMinor=34
version.versionPatch=0
version.versionMinor=33
version.versionPatch=9
version.useDatedVersionName=false

View file

@ -376,9 +376,7 @@ open class EditorTestSetup {
getDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = repo,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
createObjectSet = CreateObjectSet(repo)
findObjectSetForType = FindObjectSetForType(repo)
@ -579,9 +577,8 @@ open class EditorTestSetup {
repo.stub {
onBlocking {
searchObjects(
filters = ObjectSearchConstants.filterTypes(
spaces = listOf(defaultSpace)
),
space = SpaceId(defaultSpace),
filters = ObjectSearchConstants.filterTypes(),
keys = ObjectSearchConstants.defaultKeysObjectType,
sorts = emptyList(),
limit = 0,

View file

@ -241,9 +241,7 @@ abstract class TestObjectSetSetup {
getDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = repo,
spaceManager = spaceManager,
dispatchers = dispatchers,
configStorage = configStorage
dispatchers = dispatchers
)
createDataViewObject = CreateDataViewObject(
repo = repo,
@ -378,6 +376,7 @@ abstract class TestObjectSetSetup {
repo.stub {
onBlocking {
searchObjectsWithSubscription(
space = any(),
subscription = any(),
filters = any(),
sorts = any(),

View file

@ -112,8 +112,7 @@ object AllContentModule {
): CreateObject = CreateObject(
repo = repo,
getDefaultObjectType = getDefaultObjectType,
dispatchers = dispatchers,
spaceManager = spaceManager
dispatchers = dispatchers
)
@JvmStatic
@ -128,9 +127,7 @@ object AllContentModule {
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic

View file

@ -42,8 +42,7 @@ object CreateObjectModule {
): CreateObject = CreateObject(
repo = repo,
getDefaultObjectType = getDefaultObjectType,
dispatchers = dispatchers,
spaceManager = spaceManager
dispatchers = dispatchers
)
@JvmStatic
@ -58,9 +57,7 @@ object CreateObjectModule {
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic
@ -81,6 +78,10 @@ object CreateObjectModule {
@Provides
@PerScreen
fun provideViewModelFactory(
createObject: CreateObject
): CreateObjectViewModel.Factory = CreateObjectViewModel.Factory(createObject = createObject)
createObject: CreateObject,
spaceManager: SpaceManager
): CreateObjectViewModel.Factory = CreateObjectViewModel.Factory(
createObject = createObject,
spaceManager = spaceManager
)
}

View file

@ -986,15 +986,11 @@ object EditorUseCaseModule {
fun provideGetDefaultPageType(
repo: UserSettingsRepository,
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
dispatchers: AppCoroutineDispatchers
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = repo,
blockRepository = blockRepository,
spaceManager = spaceManager,
dispatchers = dispatchers,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic
@ -1192,13 +1188,11 @@ object EditorUseCaseModule {
fun getCreateObject(
repo: BlockRepository,
getDefaultObjectType: GetDefaultObjectType,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager
dispatchers: AppCoroutineDispatchers
): CreateObject = CreateObject(
repo = repo,
getDefaultObjectType = getDefaultObjectType,
dispatchers = dispatchers,
spaceManager = spaceManager
dispatchers = dispatchers
)
@Module

View file

@ -307,13 +307,11 @@ object ObjectSetModule {
fun getCreateObject(
repo: BlockRepository,
getDefaultObjectType: GetDefaultObjectType,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager
dispatchers: AppCoroutineDispatchers
): CreateObject = CreateObject(
repo = repo,
getDefaultObjectType = getDefaultObjectType,
dispatchers = dispatchers,
spaceManager = spaceManager
dispatchers = dispatchers
)
@JvmStatic
@ -330,15 +328,11 @@ object ObjectSetModule {
fun provideGetDefaultPageType(
userSettingsRepository: UserSettingsRepository,
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
dispatchers: AppCoroutineDispatchers
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic

View file

@ -81,15 +81,11 @@ object ObjectTypeChangeModule {
fun provideGetDefaultPageType(
userSettingsRepository: UserSettingsRepository,
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
dispatchers: AppCoroutineDispatchers
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
}

View file

@ -41,14 +41,10 @@ object PersonalizationSettingsModule {
userSettingsRepository: UserSettingsRepository,
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic

View file

@ -120,14 +120,10 @@ object SplashModule {
userSettingsRepository: UserSettingsRepository,
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
spaceManager = spaceManager,
dispatchers = dispatchers,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic
@ -148,12 +144,10 @@ object SplashModule {
repo: BlockRepository,
getDefaultObjectType: GetDefaultObjectType,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager
): CreateObject = CreateObject(
repo = repo,
getDefaultObjectType = getDefaultObjectType,
dispatchers = dispatchers,
spaceManager = spaceManager
dispatchers = dispatchers
)
@JvmStatic

View file

@ -8,6 +8,7 @@ import com.anytypeio.anytype.data.auth.event.EventProcessImportRemoteChannel
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.workspace.EventProcessImportChannel
@ -85,4 +86,5 @@ interface GalleryInstallationComponentDependencies : ComponentDependencies {
fun urlBuilder(): UrlBuilder
fun userPermissionProvider(): UserPermissionProvider
fun eventProxy(): EventProxy
fun configStorage(): ConfigStorage
}

View file

@ -165,8 +165,7 @@ object HomeScreenModule {
): CreateObject = CreateObject(
repo = repo,
dispatchers = dispatchers,
getDefaultObjectType = getDefaultEditorType,
spaceManager = spaceManager
getDefaultObjectType = getDefaultEditorType
)
@JvmStatic
@ -175,15 +174,11 @@ object HomeScreenModule {
fun getDefaultPageType(
userSettingsRepository: UserSettingsRepository,
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
dispatchers: AppCoroutineDispatchers
) : GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic

View file

@ -147,12 +147,10 @@ object LibraryModule {
repo: BlockRepository,
getDefaultObjectType: GetDefaultObjectType,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
): CreateObject = CreateObject(
repo = repo,
getDefaultObjectType = getDefaultObjectType,
dispatchers = dispatchers,
spaceManager = spaceManager
dispatchers = dispatchers
)
@JvmStatic
@ -161,15 +159,11 @@ object LibraryModule {
fun provideGetDefaultPageType(
userSettingsRepository: UserSettingsRepository,
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
dispatchers: AppCoroutineDispatchers
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic

View file

@ -9,8 +9,10 @@ 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.ConfigStorage
import com.anytypeio.anytype.domain.config.TechSpaceProvider
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
@ -60,8 +62,10 @@ interface ShareSpaceDependencies : ComponentDependencies {
fun dispatchers(): AppCoroutineDispatchers
fun container(): StorelessSubscriptionContainer
fun config(): ConfigStorage
fun techSpaceProvider(): TechSpaceProvider
fun permissions(): UserPermissionProvider
fun analytics(): Analytics
fun analyticSpaceHelper(): AnalyticSpaceHelperDelegate
fun provideMembershipProvider(): MembershipProvider
fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer
}

View file

@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.networkmode.GetNetworkMode
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
@ -45,7 +46,6 @@ object ProfileModule {
@Provides
@PerScreen
fun provideViewModelFactory(
deleteAccount: DeleteAccount,
analytics: Analytics,
storelessSubscriptionContainer: StorelessSubscriptionContainer,
setObjectDetails: SetObjectDetails,
@ -53,9 +53,9 @@ object ProfileModule {
urlBuilder: UrlBuilder,
setDocumentImageIcon: SetDocumentImageIcon,
membershipProvider: MembershipProvider,
getNetworkMode: GetNetworkMode
getNetworkMode: GetNetworkMode,
profileSubscriptionManager: ProfileSubscriptionManager
): ProfileSettingsViewModel.Factory = ProfileSettingsViewModel.Factory(
deleteAccount = deleteAccount,
analytics = analytics,
container = storelessSubscriptionContainer,
setObjectDetails = setObjectDetails,
@ -63,7 +63,8 @@ object ProfileModule {
urlBuilder = urlBuilder,
setDocumentImageIcon = setDocumentImageIcon,
membershipProvider = membershipProvider,
getNetworkMode = getNetworkMode
getNetworkMode = getNetworkMode,
profileSubscriptionManager = profileSubscriptionManager
)
@Provides

View file

@ -19,6 +19,7 @@ import com.anytypeio.anytype.domain.multiplayer.ActiveSpaceMemberSubscriptionCon
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.payments.GetMembershipStatus
import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider
@ -119,4 +120,5 @@ interface SpaceSettingsDependencies : ComponentDependencies {
fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer
fun activeSpaceMemberSubscriptionContainer(): ActiveSpaceMemberSubscriptionContainer
fun analyticSpaceHelper(): AnalyticSpaceHelperDelegate
fun profileContainer(): ProfileSubscriptionManager
}

View file

@ -10,7 +10,9 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.navigation.DeepLinkToObjectDelegate
import com.anytypeio.anytype.presentation.vault.VaultViewModel
import com.anytypeio.anytype.ui.vault.VaultFragment
import dagger.Binds
@ -44,6 +46,12 @@ object VaultModule {
fun bindViewModelFactory(
factory: VaultViewModel.Factory
): ViewModelProvider.Factory
@PerScreen
@Binds
fun deepLinkToObjectDelegate(
default: DeepLinkToObjectDelegate.Default
) : DeepLinkToObjectDelegate
}
}
@ -55,5 +63,6 @@ interface VaultComponentDependencies : ComponentDependencies {
fun spaceViewSubscriptionContainer(): SpaceViewSubscriptionContainer
fun userSettingsRepository(): UserSettingsRepository
fun spaceManager(): SpaceManager
fun userPermissionProvider(): UserPermissionProvider
fun auth(): AuthRepository
}

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.config.Gateway
import com.anytypeio.anytype.domain.config.TechSpaceProvider
import com.anytypeio.anytype.domain.debugging.Logger
import dagger.Module
import dagger.Provides
@ -33,6 +34,13 @@ object ConfigModule {
@Singleton
fun provideConfigProvider(): ConfigStorage = ConfigStorage.CacheStorage()
@JvmStatic
@Provides
@Singleton
fun provideTechSpaceProvider(
configStorage: ConfigStorage
): TechSpaceProvider = configStorage
@JvmStatic
@Provides
@Singleton

View file

@ -19,6 +19,7 @@ import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.StoreOfRelations
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionContainer
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.ProfileSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionContainer
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
@ -43,12 +44,14 @@ object SubscriptionsModule {
repo: BlockRepository,
channel: SubscriptionEventChannel,
dispatchers: AppCoroutineDispatchers,
store: StoreOfRelations
store: StoreOfRelations,
logger: Logger
): RelationsSubscriptionContainer = RelationsSubscriptionContainer(
repo = repo,
channel = channel,
store = store,
dispatchers = dispatchers
dispatchers = dispatchers,
logger = logger
)
@JvmStatic
@ -58,12 +61,14 @@ object SubscriptionsModule {
repo: BlockRepository,
channel: SubscriptionEventChannel,
dispatchers: AppCoroutineDispatchers,
store: StoreOfObjectTypes
store: StoreOfObjectTypes,
logger: Logger
): ObjectTypesSubscriptionContainer = ObjectTypesSubscriptionContainer(
repo = repo,
channel = channel,
store = store,
dispatchers = dispatchers
dispatchers = dispatchers,
logger = logger
)
@JvmStatic
@ -81,7 +86,7 @@ object SubscriptionsModule {
@Singleton
fun relationsSubscriptionManager(
subscription: RelationsSubscriptionContainer,
spaceManager: SpaceManager
spaceManager: SpaceManager,
): RelationsSubscriptionManager = RelationsSubscriptionManager(
container = subscription,
spaceManager = spaceManager
@ -125,13 +130,15 @@ object SubscriptionsModule {
@Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope,
container: StorelessSubscriptionContainer,
repo: AuthRepository,
logger: Logger
logger: Logger,
spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
) : UserPermissionProvider = DefaultUserPermissionProvider(
dispatchers = dispatchers,
scope = scope,
container = container,
repo = repo,
logger = logger
logger = logger,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
)
@JvmStatic
@ -142,12 +149,33 @@ object SubscriptionsModule {
@Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope,
container: StorelessSubscriptionContainer,
awaitAccountStartManager: AwaitAccountStartManager,
logger: Logger
logger: Logger,
configStorage: ConfigStorage
) : SpaceViewSubscriptionContainer = SpaceViewSubscriptionContainer.Default(
dispatchers = dispatchers,
scope = scope,
container = container,
awaitAccountStart = awaitAccountStartManager,
logger = logger,
config = configStorage
)
@JvmStatic
@Provides
@Singleton
fun profileSubscriptionManager(
dispatchers: AppCoroutineDispatchers,
@Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope,
container: StorelessSubscriptionContainer,
awaitAccountStartManager: AwaitAccountStartManager,
configStorage: ConfigStorage,
logger: Logger
) : ProfileSubscriptionManager = ProfileSubscriptionManager.Default(
dispatchers = dispatchers,
scope = scope,
container = container,
awaitAccountStartManager = awaitAccountStartManager,
configStorage = configStorage,
logger = logger
)
@ -188,11 +216,13 @@ object SubscriptionsModule {
types: ObjectTypesSubscriptionManager,
relations: RelationsSubscriptionManager,
permissions: UserPermissionProvider,
isSpaceDeleted: SpaceDeletedStatusWatcher
isSpaceDeleted: SpaceDeletedStatusWatcher,
profileSubscriptionManager: ProfileSubscriptionManager
) : GlobalSubscriptionManager = GlobalSubscriptionManager.Default(
types = types,
relations = relations,
permissions = permissions,
isSpaceDeleted = isSpaceDeleted
isSpaceDeleted = isSpaceDeleted,
profile = profileSubscriptionManager
)
}

View file

@ -213,7 +213,7 @@ class AllContentFragment : BaseComposeFragment() {
is AllContentViewModel.Command.OpenTypeCreation -> {
runCatching {
navigation().openTypeCreationScreen(
name = command.name
name = ""
)
}.onFailure {
toast("Failed to open type creation screen")
@ -224,8 +224,8 @@ class AllContentFragment : BaseComposeFragment() {
is AllContentViewModel.Command.OpenRelationCreation -> {
runCatching {
navigation().openRelationCreationScreen(
id = command.id,
name = command.name,
id = "",
name = "",
space = command.space
)
}.onFailure {
@ -265,6 +265,7 @@ class AllContentFragment : BaseComposeFragment() {
uiTabsState = vm.uiTabsState.collectAsStateWithLifecycle().value,
uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value,
uiMenuState = vm.uiMenuState.collectAsStateWithLifecycle().value,
uiSnackbarState = vm.uiSnackbarState.collectAsStateWithLifecycle().value,
onSortClick = vm::onSortClicked,
onModeClick = vm::onAllContentModeClicked,
onItemClicked = vm::onItemClicked,
@ -273,7 +274,6 @@ class AllContentFragment : BaseComposeFragment() {
onUpdateLimitSearch = vm::updateLimit,
uiContentState = vm.uiContentState.collectAsStateWithLifecycle().value,
onTypeClicked = vm::onTypeClicked,
onHomeClicked = vm::onHomeClicked,
onGlobalSearchClicked = vm::onGlobalSearchClicked,
onAddDocClicked = vm::onAddDockClicked,
onCreateObjectLongClicked = {
@ -296,7 +296,10 @@ class AllContentFragment : BaseComposeFragment() {
Timber.e(it, "Error while opening space switcher from all-content screen")
}
},
onRelationClicked = vm::onRelationClicked
onRelationClicked = vm::onRelationClicked,
undoMoveToBin = vm::proceedWithUndoMoveToBin,
onDismissSnackbar = vm::proceedWithDismissSnackbar,
uiBottomMenu = vm.uiBottomMenu.collectAsStateWithLifecycle().value
)
}
}

View file

@ -15,7 +15,6 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -34,8 +33,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -45,9 +42,8 @@ import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_ui.extensions.throttledClick
import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults
import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationMenu
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.foundation.noRippleCombinedClickable
import com.anytypeio.anytype.core_ui.views.UXBody
import com.anytypeio.anytype.presentation.home.InteractionMode
import com.anytypeio.anytype.presentation.profile.ProfileIconView
@ -101,7 +97,8 @@ fun HomeScreen(
onSpaceShareIconClicked: (ObjectWrapper.SpaceView) -> Unit,
onSeeAllObjectsClicked: (WidgetView.Gallery) -> Unit,
onCreateObjectInsideWidget: (Id) -> Unit,
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit,
onBackLongClicked: () -> Unit
) {
Box(modifier = Modifier.fillMaxSize()) {
@ -160,13 +157,14 @@ fun HomeScreen(
enter = fadeIn() + slideInVertically { it },
exit = fadeOut() + slideOutVertically { it }
) {
HomeScreenBottomToolbar(
onSearchClicked = throttledClick(onSearchClicked),
onCreateNewObjectClicked = throttledClick(onCreateNewObjectClicked),
onBackClicked = throttledClick(onBackClicked),
onCreateNewObjectLongClicked = onCreateNewObjectLongClicked,
BottomNavigationMenu(
modifier = Modifier,
isReadOnlyAccess = mode is InteractionMode.ReadOnly
backClick = onBackClicked,
backLongClick = onBackLongClicked,
searchClick = onSearchClicked,
addDocClick = onCreateNewObjectClicked,
addDocLongClick = onCreateNewObjectLongClicked,
isOwnerOrEditor = mode !is InteractionMode.ReadOnly
)
}
}
@ -811,79 +809,4 @@ fun WidgetEditModeButton(
color = colorResource(id = R.color.text_white)
)
}
}
@Composable
fun HomeScreenBottomToolbar(
modifier: Modifier,
onSearchClicked: () -> Unit,
onCreateNewObjectClicked: () -> Unit,
onCreateNewObjectLongClicked: () -> Unit,
onBackClicked: () -> Unit,
isReadOnlyAccess: Boolean
) {
val haptic = LocalHapticFeedback.current
Row(
modifier = modifier
.height(BottomNavigationDefaults.Height)
.width(BottomNavigationDefaults.Width)
.background(
shape = RoundedCornerShape(16.dp),
color = colorResource(id = R.color.home_screen_toolbar_button)
)
) {
Box(
modifier = Modifier
.weight(1f)
.fillMaxSize()
.noRippleClickable { onBackClicked() }
) {
Image(
painter = painterResource(id = R.drawable.ic_nav_panel_back),
contentDescription = "Search icon",
modifier = Modifier.align(Alignment.Center)
)
}
Box(
modifier = Modifier
.weight(1f)
.alpha(if (isReadOnlyAccess) 0.2f else 1f)
.fillMaxSize()
.then(
if (isReadOnlyAccess)
Modifier.clickable {
// Do nothing.
}
else
Modifier.noRippleCombinedClickable(
onLongClicked = {
onCreateNewObjectLongClicked().also {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}
},
onClick = {
onCreateNewObjectClicked()
}
)
)
) {
Image(
painter = painterResource(id = R.drawable.ic_nav_panel_plus),
contentDescription = "Plus icon",
modifier = Modifier.align(Alignment.Center)
)
}
Box(
modifier = Modifier
.weight(1f)
.fillMaxSize()
.noRippleClickable { onSearchClicked() }
) {
Image(
painter = painterResource(id = R.drawable.ic_nav_panel_search),
contentDescription = "Search icon",
modifier = Modifier.align(Alignment.Center)
)
}
}
}

View file

@ -114,7 +114,8 @@ class HomeScreenFragment : BaseComposeFragment() {
onSpaceShareIconClicked = vm::onSpaceShareIconClicked,
onSeeAllObjectsClicked = vm::onSeeAllObjectsClicked,
onCreateObjectInsideWidget = vm::onCreateObjectInsideWidget,
onCreateDataViewObject = vm::onCreateDataViewObject
onCreateDataViewObject = vm::onCreateDataViewObject,
onBackLongClicked = vm::onBackLongClicked
)
if (featureToggles.enableDiscussionDemo) {
@ -367,6 +368,9 @@ class HomeScreenFragment : BaseComposeFragment() {
Timber.e(e, "Error while opening all content from widgets")
}
}
is Navigation.OpenSpaceSwitcher -> {
findNavController().navigate(R.id.actionOpenSpaceSwitcher)
}
}
}

View file

@ -31,7 +31,6 @@ import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -162,14 +161,10 @@ fun Menu(
backLongClick = {
onBackLongClicked()
},
homeClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Back) },
searchClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Search) },
addDocClick = { viewModel.eventStream(LibraryEvent.BottomMenu.CreateObject) },
onCreateObjectLongClicked = onCreateObjectLongClicked,
onProfileClicked = {
viewModel.eventStream(LibraryEvent.BottomMenu.OpenProfile)
},
profileIcon = viewModel.icon.collectAsState().value
addDocLongClick = onCreateObjectLongClicked,
isOwnerOrEditor = false
)
}

View file

@ -50,6 +50,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.nestedscroll.nestedScroll
@ -225,7 +226,7 @@ fun GlobalSearchScreen(
)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = colorResource(id = R.color.shape_transparent),
backgroundColor = Color.Transparent,
cursorColor = colorResource(id = R.color.cursor_color),
),
border = {},

View file

@ -39,8 +39,6 @@ import timber.log.Timber
class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
private val space: Id get() = arg(SPACE_ID_KEY)
@Inject
lateinit var factory: ProfileSettingsViewModel.Factory
@ -141,16 +139,6 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
}
}
private fun proceedWithAccountDeletion() {
vm.proceedWithAccountDeletion()
val dialog = DeleteAccountWarning()
dialog.onDeletionAccepted = {
dialog.dismiss()
vm.onDeleteAccountClicked()
}
dialog.show(childFragmentManager, null)
}
private fun proceedWithIconClick() {
permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, null)
}
@ -163,7 +151,7 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
if (uri != null) {
try {
val path = uri.parseImagePath(requireContext())
vm.onPickedImageFromDevice(path = path, space = space)
vm.onPickedImageFromDevice(path = path)
} catch (e: Exception) {
toast("Error while parsing path for cover image")
Timber.d(e, "Error while parsing path for cover image")

View file

@ -197,6 +197,14 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment() {
Command.NavigateToMembershipUpdate -> {
findNavController().navigate(R.id.membershipUpdateScreen)
}
is Command.ExitToVault -> {
runCatching {
findNavController()
.popBackStack(R.id.vaultScreen, false)
}.onFailure {
Timber.e(it, "Error while exiting to vault screen from space settings")
}
}
}
}
}

View file

@ -52,6 +52,7 @@ import coil.compose.rememberAsyncImagePainter
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_ui.features.SpaceIconView
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.views.BodyRegular
import com.anytypeio.anytype.core_ui.views.ButtonPrimary
@ -78,7 +79,7 @@ fun AddToAnytypeScreenUrlPreview() {
SpaceView(
obj = ObjectWrapper.SpaceView(map = mapOf("name" to "Space 1")),
isSelected = true,
icon = SpaceIconView.Gradient(from = "#FF0000", to = "#00FF00")
icon = SpaceIconView.Placeholder()
)
),
onSelectSpaceClicked = {},
@ -101,7 +102,7 @@ fun AddToAnytypeScreenNotePreview() {
SpaceView(
obj = ObjectWrapper.SpaceView(map = mapOf()),
isSelected = false,
icon = SpaceIconView.Gradient(from = "#FF0000", to = "#00FF00")
icon = SpaceIconView.Placeholder()
)
),
onSelectSpaceClicked = {},
@ -250,7 +251,7 @@ fun AddToAnytypeScreen(
)
} else {
CurrentSpaceSection(
name = stringResource(id = R.string.unknown),
name = stringResource(id = R.string.three_dots_text_placeholder),
spaces = spaces,
onSelectSpaceClicked = onSelectSpaceClicked
)
@ -527,11 +528,15 @@ private fun CurrentSpaceSection(
.padding(start = 20.dp, end = 20.dp, top = 6.dp, bottom = 14.dp),
verticalAlignment = Alignment.CenterVertically
) {
val hasIcon = icon is SpaceIconView.Gradient || icon is SpaceIconView.Image
val hasIcon = icon is SpaceIconView.Placeholder || icon is SpaceIconView.Image
if (icon != null && hasIcon) {
SmallSpaceIcon(
SpaceIconView(
icon = icon,
modifier = Modifier.padding(end = 8.dp)
modifier = Modifier.padding(end = 8.dp),
mainSize = 20.dp,
onSpaceIconClick = {
// Do nothing.
}
)
}
Text(
@ -614,22 +619,6 @@ private fun SmallSpaceIcon(
.clip(RoundedCornerShape(4.dp))
)
}
is SpaceIconView.Gradient -> {
val gradient = Brush.radialGradient(
colors = listOf(
Color(icon.from.toColorInt()),
Color(icon.to.toColorInt())
)
)
Box(
modifier = modifier
.size(size)
.clip(CircleShape)
.background(gradient)
)
}
else -> {
// Draw nothing.
}

View file

@ -94,9 +94,6 @@ fun CreateSpaceScreen(
Section(title = stringResource(id = R.string.type))
TypeOfSpace(spaceType = PRIVATE_SPACE_TYPE)
Divider()
Section(title = stringResource(id = R.string.create_space_start_with))
UseCase()
Divider()
Spacer(modifier = Modifier.height(78.dp))
}
CreateSpaceButton(

View file

@ -25,8 +25,6 @@ import javax.inject.Inject
class SelectSpaceFragment : BaseBottomSheetComposeFragment() {
private val exitHomeWhenSpaceIsSelected get() = argOrNull<Boolean>(EXIT_HOME_WHEN_SPACE_IS_SELECTED_KEY)
@Inject
lateinit var factory: SelectSpaceViewModel.Factory

View file

@ -162,9 +162,7 @@ private fun SelectSpaceSpaceItem(
icon = item.view.icon,
onSpaceIconClick = throttledClick(
onClick = { onSpaceClicked(item.view) }
),
gradientBackground = colorResource(id = R.color.default_gradient_background),
gradientCornerRadius = 4.dp
)
)
if (item.view.isShared) {
Image(

View file

@ -14,6 +14,7 @@ import com.anytypeio.anytype.BuildConfig
import com.anytypeio.anytype.R
import com.anytypeio.anytype.app.DefaultAppActionManager.Companion.ACTION_CREATE_NEW_TYPE_KEY
import com.anytypeio.anytype.core_utils.ext.gone
import com.anytypeio.anytype.core_utils.ext.orNull
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.BaseFragment
@ -27,7 +28,7 @@ import com.anytypeio.anytype.ui.editor.EditorFragment
import com.anytypeio.anytype.ui.home.HomeScreenFragment
import com.anytypeio.anytype.ui.onboarding.OnboardingFragment
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
import com.anytypeio.anytype.ui.widgets.collection.DefaultTheme
import com.anytypeio.anytype.ui.vault.VaultFragment
import javax.inject.Inject
import kotlinx.coroutines.launch
import timber.log.Timber
@ -71,26 +72,6 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>(R.layout.fragment_spl
}
}
}
launch {
vm.loadingState.collect { isLoading ->
when (isLoading) {
true -> {
binding.loadingContainer.setContent {
DefaultTheme {
PulsatingCircleScreen()
}
}
binding.logo.visibility = View.GONE
binding.loadingContainer.visibility = View.VISIBLE
}
false -> {
binding.logo.visibility = View.GONE
binding.loadingContainer.visibility = View.GONE
}
}
}
}
}
}
if (BuildConfig.DEBUG) {
@ -106,11 +87,11 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>(R.layout.fragment_spl
runCatching {
findNavController().navigate(
resId = R.id.actionOpenVaultFromSplash,
args = HomeScreenFragment.args(command.deeplink)
args = VaultFragment.args(deeplink = null)
)
findNavController().navigate(
R.id.actionOpenSpaceFromVault,
args = HomeScreenFragment.args(command.deeplink)
args = HomeScreenFragment.args(deeplink = command.deeplink)
)
}.onFailure {
Timber.e(it, "Error while navigating to widgets from splash")
@ -120,7 +101,7 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>(R.layout.fragment_spl
try {
findNavController().navigate(
resId = R.id.actionOpenVaultFromSplash,
args = HomeScreenFragment.args(command.deeplink)
args = HomeScreenFragment.args(deeplink = command.deeplink)
)
} catch (e: Exception) {
Timber.e(e, "Error while opening dashboard from splash screen")
@ -160,12 +141,12 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>(R.layout.fragment_spl
is SplashViewModel.Command.NavigateToAuthStart -> {
val intent = activity?.intent
val deepLink: String?
if (intent != null && intent.action == Intent.ACTION_VIEW) {
if (intent != null && (intent.action == Intent.ACTION_VIEW || intent.action == Intent.ACTION_SEND)) {
val data = intent.dataString
deepLink = if (data != null && DefaultDeepLinkResolver.isDeepLink(data)) {
data
} else {
null
intent.extras?.getString(Intent.EXTRA_TEXT)
}
} else {
deepLink = null
@ -178,7 +159,6 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>(R.layout.fragment_spl
putExtras(Bundle())
}
}
Timber.d("Deep link is empty: ${deepLink.isNullOrEmpty()}")
findNavController().navigate(
R.id.action_splashFragment_to_authStart,
args = OnboardingFragment.args(deepLink)
@ -191,9 +171,8 @@ class SplashFragment : BaseFragment<FragmentSplashBinding>(R.layout.fragment_spl
}
is SplashViewModel.Command.CheckAppStartIntent -> {
val intent = activity?.intent
Timber.d("Timber intent: $intent")
if (intent != null && intent.action == Intent.ACTION_VIEW) {
val data = intent.dataString
if (intent != null && (intent.action == Intent.ACTION_VIEW || intent.action == Intent.ACTION_SEND)) {
val data = intent.dataString.orNull() ?: intent.extras?.getString(Intent.EXTRA_TEXT)
if (data != null && DefaultDeepLinkResolver.isDeepLink(data)) {
// Clearing intent to only handle it once:
with(intent) {

View file

@ -130,7 +130,7 @@ fun IntroduceVaultScreen(
},
horizontalArrangement = Arrangement.Center
) {
repeat(3) { iteration ->
repeat(2) { iteration ->
val color = if (pagerState.currentPage == iteration)
colorResource(id = R.color.glyph_active)
else
@ -161,7 +161,8 @@ fun IntroduceVaultScreen(
.constrainAs(first) {
bottom.linkTo(btn.top)
},
textAlign = TextAlign.Center
textAlign = TextAlign.Center,
minLines = 3
)
ButtonSecondary(

View file

@ -12,14 +12,23 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavOptions
import androidx.navigation.fragment.findNavController
import com.anytypeio.anytype.BuildConfig.USE_EDGE_TO_EDGE
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_utils.ext.argOrNull
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
import com.anytypeio.anytype.core_utils.ui.BaseComposeFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.other.DefaultDeepLinkResolver
import com.anytypeio.anytype.presentation.vault.VaultViewModel
import com.anytypeio.anytype.presentation.vault.VaultViewModel.Navigation
import com.anytypeio.anytype.presentation.vault.VaultViewModel.Command
import com.anytypeio.anytype.ui.base.navigation
import com.anytypeio.anytype.ui.gallery.GalleryInstallationFragment
import com.anytypeio.anytype.ui.multiplayer.RequestJoinSpaceFragment
import com.anytypeio.anytype.ui.payments.MembershipFragment
import com.anytypeio.anytype.ui.settings.ProfileSettingsFragment
import com.anytypeio.anytype.ui.settings.typography
import javax.inject.Inject
@ -27,7 +36,7 @@ import timber.log.Timber
class VaultFragment : BaseComposeFragment() {
// TODO handle deeplink
private val deepLink: String? get() = argOrNull(DEEP_LINK_KEY)
@Inject
lateinit var factory: VaultViewModel.Factory
@ -51,14 +60,15 @@ class VaultFragment : BaseComposeFragment() {
)
}
LaunchedEffect(Unit) {
vm.commands.collect { command ->
proceedWithCommand(command)
}
vm.commands.collect { command -> proceed(command) }
}
LaunchedEffect(Unit) {
vm.navigation.collect { command -> proceed(command) }
}
}
}
private fun proceedWithCommand(command: Command) {
private fun proceed(command: Command) {
when (command) {
is Command.EnterSpaceHomeScreen -> {
runCatching {
@ -80,7 +90,7 @@ class VaultFragment : BaseComposeFragment() {
runCatching {
findNavController().navigate(
R.id.profileScreen,
bundleOf(ProfileSettingsFragment.SPACE_ID_KEY to command.space.id)
null
)
}.onFailure {
Timber.e(it, "Error while opening profile settings from vault")
@ -93,6 +103,57 @@ class VaultFragment : BaseComposeFragment() {
Timber.e(it, "Error while opening introduce-vault-screen from vault")
}
}
is Command.Deeplink.Invite -> {
findNavController().navigate(
R.id.requestJoinSpaceScreen,
RequestJoinSpaceFragment.args(link = command.link)
)
}
is Command.Deeplink.GalleryInstallation -> {
findNavController().navigate(
R.id.galleryInstallationScreen,
GalleryInstallationFragment.args(
deepLinkType = command.deepLinkType,
deepLinkSource = command.deepLinkSource
)
)
}
is Command.Deeplink.MembershipScreen -> {
findNavController().navigate(
R.id.paymentsScreen,
MembershipFragment.args(command.tierId),
NavOptions.Builder().setLaunchSingleTop(true).build()
)
}
is Command.Deeplink.DeepLinkToObjectNotWorking -> {
toast(
getString(R.string.multiplayer_deeplink_to_your_object_error)
)
}
}
}
private fun proceed(destination: Navigation) {
when (destination) {
is Navigation.OpenObject -> runCatching {
findNavController().navigate(R.id.actionOpenSpaceFromVault)
navigation().openDocument(
target = destination.ctx,
space = destination.space
)
}.onFailure {
Timber.e(it, "Error while opening object from vault")
}
is Navigation.OpenSet -> runCatching {
findNavController().navigate(R.id.actionOpenSpaceFromVault)
navigation().openObjectSet(
target = destination.ctx,
space = destination.space,
view = destination.view
)
}.onFailure {
Timber.e(it, "Error while opening set or collection from vault")
}
}
}
@ -106,7 +167,18 @@ class VaultFragment : BaseComposeFragment() {
override fun onResume() {
super.onResume()
vm.onResume()
proceedWithDeepLinks()
}
private fun proceedWithDeepLinks() {
val deepLinkFromFragmentArgs = deepLink
if (deepLinkFromFragmentArgs != null) {
Timber.d("Deeplink from fragment args")
vm.onResume(DefaultDeepLinkResolver.resolve(deepLinkFromFragmentArgs))
arguments?.putString(DEEP_LINK_KEY, null)
} else {
vm.onResume(null)
}
}
override fun injectDependencies() {
@ -118,8 +190,8 @@ class VaultFragment : BaseComposeFragment() {
}
companion object {
const val SHOW_MNEMONIC_KEY = "arg.vault-screen.show-mnemonic"
const val DEEP_LINK_KEY = "arg.vault-screen.deep-link"
private const val SHOW_MNEMONIC_KEY = "arg.vault-screen.show-mnemonic"
private const val DEEP_LINK_KEY = "arg.vault-screen.deep-link"
fun args(deeplink: String?) : Bundle = bundleOf(
DEEP_LINK_KEY to deeplink
)

View file

@ -148,6 +148,14 @@ fun VaultScreen(
Spacer(modifier = Modifier.height(40.dp))
}
}
if (spaceList.isEmpty()) {
item {
VaultSpaceAddCard(
onCreateSpaceClicked = onCreateSpaceClicked
)
Spacer(modifier = Modifier.height(40.dp))
}
}
}
}
}
@ -259,13 +267,10 @@ fun VaultSpaceCard(
onSpaceIconClick = {
onCardClicked()
},
gradientBackground = colorResource(id = R.color.default_gradient_background),
gradientCornerRadius = 4.dp,
mainSize = 64.dp,
modifier = Modifier
.padding(start = 16.dp)
.align(Alignment.CenterStart),
gradientSize = 48.dp
.align(Alignment.CenterStart)
)
Column(
modifier = Modifier

View file

@ -166,8 +166,7 @@ object CollectionModule {
): CreateObject = CreateObject(
repo = repo,
getDefaultObjectType = getDefaultObjectType,
dispatchers = dispatchers,
spaceManager = spaceManager
dispatchers = dispatchers
)
@JvmStatic
@ -178,13 +177,10 @@ object CollectionModule {
blockRepository: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager,
configStorage: ConfigStorage
): GetDefaultObjectType = GetDefaultObjectType(
userSettingsRepository = userSettingsRepository,
blockRepository = blockRepository,
dispatchers = dispatchers,
spaceManager = spaceManager,
configStorage = configStorage
dispatchers = dispatchers
)
@JvmStatic

View file

@ -50,7 +50,6 @@ import androidx.compose.material.Text
import androidx.compose.material.rememberBottomSheetScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -148,13 +147,11 @@ fun ScreenContent(
.padding(bottom = 20.dp)) {
BottomNavigationMenu(
backClick = { vm.onPrevClicked() },
homeClick = { vm.onHomeClicked() },
searchClick = onSearchClicked,
addDocClick = { vm.onAddClicked(null) },
onCreateObjectLongClicked = onCreateObjectLongClicked,
onProfileClicked = vm::onProfileClicked,
profileIcon = vm.icon.collectAsState().value,
backLongClick = vm::onBackLongClicked
addDocLongClick = onCreateObjectLongClicked,
backLongClick = vm::onBackLongClicked,
isOwnerOrEditor = uiState.isActionButtonVisible
)
}
}

View file

@ -87,9 +87,7 @@ fun SpaceWidgetCard(
SpaceIconView(
icon = icon,
onSpaceIconClick = { onClick() },
mainSize = 40.dp,
gradientSize = 24.dp,
gradientCornerRadius = 2.dp
mainSize = 40.dp
)
}
Text(

View file

@ -144,10 +144,11 @@
<FrameLayout
android:id="@+id/bottomToolbarContainer"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="@dimen/default_nav_panel_height"
android:layout_gravity="bottom"
android:background="@color/defaultCanvasColor"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="@dimen/dp_20"
android:background="@drawable/widget_main_bottom_toolbar_background"
android:clickable="true"
android:focusable="true"
android:visibility="invisible"
@ -155,10 +156,9 @@
tools:visibility="visible">
<com.anytypeio.anytype.core_ui.widgets.toolbar.MainBottomToolbar
android:id="@+id/bottomToolbar"
android:layout_width="@dimen/default_nav_panel_width"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@color/defaultCanvasColor"
android:clickable="true"
android:focusable="true"
android:visibility="visible"

View file

@ -132,15 +132,17 @@
<FrameLayout
android:id="@+id/bottomToolbarBox"
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="@dimen/default_nav_panel_height"
android:layout_marginBottom="@dimen/dp_20"
android:background="@drawable/widget_main_bottom_toolbar_background"
app:layout_constraintBottom_toTopOf="@+id/bottomPanel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible">
<com.anytypeio.anytype.core_ui.widgets.toolbar.MainBottomToolbar
android:id="@+id/bottomToolbar"
android:layout_width="@dimen/default_nav_panel_width"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
tools:visibility="visible" />

View file

@ -169,6 +169,9 @@
<action
android:id="@+id/action_open_all_content"
app:destination="@id/allContentScreen" />
<action
android:id="@+id/actionOpenSpaceSwitcher"
app:destination="@id/selectSpaceScreen"/>
</fragment>
<fragment

View file

@ -38,6 +38,8 @@ dependencies {
implementation libs.recyclerView
implementation libs.constraintLayout
implementation libs.glide
annotationProcessor libs.glideCompiler
implementation libs.glideCompose
implementation libs.shimmerLayout
implementation libs.timber
implementation libs.betterLinkMovement

View file

@ -9,6 +9,7 @@ import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
@ -90,3 +91,8 @@ fun Modifier.bouncingClickable(
onDoubleClick = onDoubleClick,
)
}
fun <T> SnapshotStateList<T>.swapList(newList: List<T>){
clear()
addAll(newList)
}

View file

@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
@ -32,13 +33,11 @@ import com.anytypeio.anytype.presentation.spaces.SpaceIconView
fun SpaceIconView(
modifier: Modifier = Modifier,
mainSize: Dp = 96.dp,
gradientSize: Dp = 64.dp,
gradientBackground: Color = colorResource(id = R.color.default_gradient_background),
gradientCornerRadius: Dp = 8.dp,
icon: SpaceIconView,
onSpaceIconClick: () -> Unit,
) {
val radius = when(mainSize) {
20.dp -> 4.dp
40.dp -> 5.dp
48.dp -> 6.dp
64.dp -> 8.dp
@ -47,6 +46,7 @@ fun SpaceIconView(
}
val fontSize = when(mainSize) {
20.dp -> 16.sp
40.dp -> 24.sp
48.dp -> 28.sp
64.dp -> 40.sp
@ -68,46 +68,28 @@ fun SpaceIconView(
}
)
}
is SpaceIconView.Gradient -> {
val gradient = Brush.radialGradient(
colors = listOf(
Color(icon.from.toColorInt()),
Color(icon.to.toColorInt())
)
)
Box(
modifier = modifier
.size(mainSize)
.clip(RoundedCornerShape(gradientCornerRadius))
.background(color = gradientBackground)
.noRippleClickable { onSpaceIconClick.invoke() }
) {
Box(
modifier = Modifier
.align(Alignment.Center)
.size(gradientSize)
.clip(CircleShape)
.background(gradient)
)
}
}
is SpaceIconView.Placeholder -> {
val color = when (icon.color) {
SystemColor.YELLOW -> colorResource(id = R.color.palette_system_yellow)
SystemColor.AMBER -> colorResource(id = R.color.palette_system_amber_100)
SystemColor.RED -> colorResource(id = R.color.palette_system_red)
SystemColor.PINK -> colorResource(id = R.color.palette_system_pink)
SystemColor.PURPLE -> colorResource(id = R.color.palette_system_purple)
SystemColor.BLUE -> colorResource(id = R.color.palette_system_blue)
SystemColor.SKY -> colorResource(id = R.color.palette_system_sky)
SystemColor.TEAL -> colorResource(id = R.color.palette_system_teal)
SystemColor.GREEN -> colorResource(id = R.color.palette_system_green)
}
Box(
modifier = modifier
.size(mainSize)
.background(
color = when (icon.color) {
SystemColor.YELLOW -> colorResource(id = R.color.palette_system_yellow)
SystemColor.AMBER -> colorResource(id = R.color.palette_system_amber_100)
SystemColor.RED -> colorResource(id = R.color.palette_system_red)
SystemColor.PINK -> colorResource(id = R.color.palette_system_pink)
SystemColor.PURPLE -> colorResource(id = R.color.palette_system_purple)
SystemColor.BLUE -> colorResource(id = R.color.palette_system_blue)
SystemColor.SKY -> colorResource(id = R.color.palette_system_sky)
SystemColor.TEAL -> colorResource(id = R.color.palette_system_teal)
SystemColor.GREEN -> colorResource(id = R.color.palette_system_green)
},
Brush.linearGradient(
colors = listOf(
color.copy(alpha = 0.5f),
color
)
),
shape = RoundedCornerShape(radius)
)
.clip(RoundedCornerShape(radius))
@ -125,7 +107,7 @@ fun SpaceIconView(
style = TextStyle(
fontSize = fontSize,
fontWeight = FontWeight(600),
color = colorResource(id = R.color.text_label_inversion),
color = colorResource(id = R.color.text_white),
)
)
}

View file

@ -9,7 +9,6 @@ import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType.Layout
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.databinding.ItemViewerGridRowBinding
import com.anytypeio.anytype.core_ui.extensions.drawable
@ -128,28 +127,7 @@ class ViewerGridAdapter(
private fun showIcon(row: Viewer.GridView.Row) {
binding.objectIcon.visible()
when (row.layout) {
Layout.TODO -> binding.objectIcon.setTask(row.isChecked)
Layout.BASIC, Layout.BOOKMARK, Layout.SET, Layout.COLLECTION -> {
if (!row.image.isNullOrEmpty() || !row.emoji.isNullOrEmpty()) {
if (!row.image.isNullOrEmpty()) {
binding.objectIcon.setRectangularImage(row.image)
} else {
binding.objectIcon.setEmoji(row.emoji)
}
} else {
binding.objectIcon.gone()
}
}
Layout.PROFILE -> {
if (!row.image.isNullOrEmpty()) {
binding.objectIcon.setCircularImage(row.image)
} else {
binding.objectIcon.setProfileInitials(row.name.orEmpty())
}
}
else -> binding.objectIcon.gone()
}
binding.objectIcon.setIcon(row.objectIcon)
}
fun bindObjectCells(row: Viewer.GridView.Row) {

View file

@ -55,7 +55,7 @@ class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), Dec
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
error.visible()
@ -63,10 +63,10 @@ class Bookmark(val binding: ItemBlockBookmarkBinding) : Media(binding.root), Dec
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
error.gone()

View file

@ -39,7 +39,7 @@ class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root), Decor
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
error.visible()
@ -48,10 +48,10 @@ class Picture(val binding: ItemBlockPictureBinding) : Media(binding.root), Decor
}
override fun onResourceReady(
resource: Drawable?,
model: Any?,
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
error.invisible()

View file

@ -438,23 +438,9 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
.into(image)
} ?: apply {
hasImage = false
if (item is BlockView.Title.Profile && item.spaceGradient != null) {
val gradient = item.spaceGradient
requireNotNull(gradient)
gradientView.visible()
gradientView.setContent {
RadialGradientComposeView(
modifier = Modifier,
from = gradient.from,
to = gradient.to,
size = 0.dp
)
}
} else {
gradientView.gone()
setIconText(item.text)
image.setImageDrawable(null)
}
gradientView.gone()
setIconText(item.text)
image.setImageDrawable(null)
}
}

View file

@ -140,9 +140,7 @@ fun SpaceListCardItem(
top.linkTo(parent.top, margin = 16.dp)
start.linkTo(parent.start, margin = 16.dp)
},
mainSize = 48.dp,
gradientSize = 32.dp,
gradientCornerRadius = 4.dp
mainSize = 48.dp
)
if (actions.isNotEmpty()) {

View file

@ -3,12 +3,12 @@ package com.anytypeio.anytype.core_ui.foundation.components
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
@ -28,29 +28,52 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.rememberAsyncImagePainter
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.common.DefaultPreviews
import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults.Height
import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults.Width
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.foundation.noRippleCombinedClickable
import com.anytypeio.anytype.presentation.profile.ProfileIconView
@DefaultPreviews
@Composable
private fun MyBottomNavigationMenu() {
BottomNavigationMenu(
backClick = {},
backLongClick = {},
searchClick = {},
addDocClick = {},
addDocLongClick = {},
isOwnerOrEditor = true
)
}
@DefaultPreviews
@Composable
private fun MyBottomViewerNavigationMenu() {
BottomNavigationMenu(
backClick = {},
backLongClick = {},
searchClick = {},
addDocClick = {},
addDocLongClick = {},
isOwnerOrEditor = false
)
}
@Composable
fun BottomNavigationMenu(
modifier: Modifier = Modifier,
backClick: () -> Unit = {},
backLongClick: () -> Unit = {},
homeClick: () -> Unit = {},
searchClick: () -> Unit = {},
addDocClick: () -> Unit = {},
onCreateObjectLongClicked: () -> Unit = {},
onProfileClicked: () -> Unit = {},
profileIcon: ProfileIconView = ProfileIconView.Loading
addDocLongClick: () -> Unit = {},
isOwnerOrEditor: Boolean
) {
Row(
modifier = modifier
.height(Height)
.width(Width)
.wrapContentWidth()
.background(
shape = RoundedCornerShape(16.dp),
color = colorResource(id = R.color.home_screen_toolbar_button)
@ -59,20 +82,27 @@ fun BottomNavigationMenu(
* Workaround for clicks through the bottom navigation menu.
*/
.noRippleClickable { },
horizontalArrangement = Arrangement.SpaceAround,
verticalAlignment = Alignment.CenterVertically
) {
MenuItem(
modifier = Modifier.width(72.dp).height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_back_button),
res = BottomNavigationItem.BACK.res,
onClick = backClick,
onLongClick = backLongClick
)
if (isOwnerOrEditor) {
MenuItem(
modifier = Modifier.width(72.dp).height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_create_button),
res = BottomNavigationItem.ADD_DOC.res,
onClick = addDocClick,
onLongClick = addDocLongClick
)
}
MenuItem(
res = BottomNavigationItem.ADD_DOC.res,
onClick = addDocClick,
onLongClick = onCreateObjectLongClicked
)
MenuItem(
modifier = Modifier.width(72.dp).height(52.dp),
contentDescription = stringResource(id = R.string.main_navigation_content_desc_search_button),
res = BottomNavigationItem.SEARCH.res,
onClick = searchClick
)
@ -81,15 +111,19 @@ fun BottomNavigationMenu(
@Composable
private fun MenuItem(
modifier: Modifier,
contentDescription: String,
@DrawableRes res: Int,
onClick: () -> Unit = {},
onLongClick: () -> Unit = {},
onLongClick: () -> Unit = {}
) {
val haptic = LocalHapticFeedback.current
Image(
painter = painterResource(id = res),
contentDescription = "",
modifier = Modifier.noRippleCombinedClickable(
contentDescription = contentDescription,
contentScale = ContentScale.Inside,
modifier = modifier
.noRippleCombinedClickable(
onClick = onClick,
onLongClicked = {
haptic.performHapticFeedback(
@ -106,7 +140,7 @@ private fun ProfileMenuItem(
icon: ProfileIconView,
onClick: () -> Unit = {}
) {
when(icon) {
when (icon) {
is ProfileIconView.Image -> {
Image(
painter = rememberAsyncImagePainter(
@ -121,6 +155,7 @@ private fun ProfileMenuItem(
.noRippleClickable { onClick() }
)
}
is ProfileIconView.Placeholder -> {
val name = icon.name
val nameFirstChar = if (name.isNullOrEmpty()) {
@ -145,6 +180,7 @@ private fun ProfileMenuItem(
)
}
}
else -> {
Box(
modifier = Modifier

View file

@ -5,10 +5,10 @@ import android.graphics.Color
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.core.view.marginStart
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.databinding.WidgetDvGridObjectBinding
import com.anytypeio.anytype.core_utils.ext.gone
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.presentation.objects.ObjectIcon
@ -24,11 +24,19 @@ class GridCellObjectItem @JvmOverloads constructor(
tvName.visible()
tvName.text = name
tvName.setTextColor(context.getColor(R.color.black))
objectIcon.setIcon(icon)
objectIcon.visible()
if (tvName.marginStart == 0) {
tvName.updateLayoutParams<LayoutParams> {
marginStart = resources.getDimension(R.dimen.dp_20).toInt()
when (icon) {
ObjectIcon.None -> {
objectIcon.gone()
tvName.updateLayoutParams<LayoutParams> {
marginStart = 0
}
}
else -> {
objectIcon.visible()
objectIcon.setIcon(icon)
tvName.updateLayoutParams<LayoutParams> {
marginStart = resources.getDimension(R.dimen.dp_20).toInt()
}
}
}
}

View file

@ -23,6 +23,9 @@ import com.anytypeio.anytype.core_ui.widgets.objectIcon.DeletedIconView
import com.anytypeio.anytype.core_ui.widgets.objectIcon.EmojiIconView
import com.anytypeio.anytype.core_ui.widgets.objectIcon.EmptyIconView
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
import com.bumptech.glide.integration.compose.GlideImage
import com.bumptech.glide.integration.compose.placeholder
@Composable
fun ListWidgetObjectIcon(
@ -46,7 +49,7 @@ fun ListWidgetObjectIcon(
EmojiIconView(icon = icon, backgroundSize = iconSize, modifier = modifier)
}
is ObjectIcon.Basic.Image -> {
DefaultObjectImageIcon(icon.hash, modifier, iconSize)
DefaultObjectImageIcon(icon.hash, modifier, iconSize, fallback = icon.emptyState)
}
is ObjectIcon.Bookmark -> {
DefaultObjectBookmarkIcon(icon.image, modifier, iconSize)
@ -106,19 +109,23 @@ fun DefaultTaskObjectIcon(
}
}
@OptIn(ExperimentalGlideComposeApi::class)
@Composable
fun DefaultObjectImageIcon(
url: Url,
modifier: Modifier,
iconSize: Dp
iconSize: Dp,
fallback: ObjectIcon.Empty
) {
Image(
painter = rememberAsyncImagePainter(model = url),
GlideImage(
model = url,
contentDescription = "Icon from URI",
contentScale = ContentScale.Crop,
modifier = modifier
.size(iconSize)
.clip(RoundedCornerShape(2.dp))
.clip(RoundedCornerShape(2.dp)),
failure = placeholder(resourceId = imageAsset(fallback)),
loading = placeholder(resourceId = R.drawable.ic_icon_loading)
)
}

View file

@ -171,7 +171,7 @@ class ObjectIconWidget @JvmOverloads constructor(
binding.ivImage.setImageResource(R.drawable.ic_non_existent_object)
}
fun setProfileInitials(
private fun setProfileInitials(
name: String
) {
with(binding) {
@ -188,7 +188,7 @@ class ObjectIconWidget @JvmOverloads constructor(
}
}
fun setEmoji(emoji: String?) {
private fun setEmoji(emoji: String?) {
if (!emoji.isNullOrBlank()) {
with(binding) {
ivCheckbox.invisible()
@ -233,7 +233,7 @@ class ObjectIconWidget @JvmOverloads constructor(
}
}
fun setCircularImage(image: Url?) {
private fun setCircularImage(image: Url?) {
if (!image.isNullOrBlank()) {
with(binding) {
ivCheckbox.invisible()
@ -259,7 +259,7 @@ class ObjectIconWidget @JvmOverloads constructor(
}
}
fun setRectangularImage(image: Url?) {
private fun setRectangularImage(image: Url?) {
if (!image.isNullOrBlank()) {
with(binding) {
ivCheckbox.invisible()
@ -297,7 +297,7 @@ class ObjectIconWidget @JvmOverloads constructor(
}
}
fun setTask(isChecked: Boolean?) {
private fun setTask(isChecked: Boolean?) {
with(binding) {
ivCheckbox.visible()
ivCheckbox.background = context.drawable(R.drawable.ic_data_view_grid_checkbox_selector)

View file

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="8dp"
android:height="13dp"
android:viewportWidth="8"
android:viewportHeight="13">
<path
android:pathData="M0.2929,1.288C0.6834,0.8975 1.3166,0.8975 1.7071,1.288L7.4142,6.9951L1.7071,12.7022C1.3166,13.0927 0.6834,13.0927 0.2929,12.7022C-0.0976,12.3117 -0.0976,11.6785 0.2929,11.288L4.5858,6.9951L0.2929,2.7022C-0.0976,2.3117 -0.0976,1.6785 0.2929,1.288Z"
android:fillColor="#DFDDD0"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="36dp"
android:height="36dp"
android:viewportWidth="36"
android:viewportHeight="36">
<group android:rotation="90"
android:pivotY="18"
android:pivotX="18">
<path
android:pathData="M18,18m-14,0a14,14 0,1 1,28 0a14,14 0,1 1,-28 0"
android:strokeWidth="4"
android:fillColor="#00000000">
<aapt:attr name="android:strokeColor">
<gradient
android:centerX="18"
android:centerY="18"
android:gradientRadius="16"
android:type="sweep">
<item android:offset="0" android:color="#00A7A7A7"/>
<item android:offset="1" android:color="#FFA7A7A7"/>
</gradient>
</aapt:attr>
</path>
</group>
</vector>

View file

@ -1,20 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M3.375,2L3.375,14H4.625L4.625,2H3.375Z"
android:fillColor="#FFBB2C" />
<path
android:pathData="M4,1.1162L7.4419,4.5581C7.686,4.8022 7.686,5.198 7.4419,5.442C7.1979,5.6861 6.8021,5.6861 6.5581,5.442L4,2.884L1.4419,5.442C1.1979,5.6861 0.8021,5.6861 0.5581,5.442C0.314,5.198 0.314,4.8022 0.5581,4.5581L4,1.1162Z"
android:fillColor="#FFBB2C"
android:fillType="evenOdd" />
<path
android:pathData="M11.375,14V2H12.625V14H11.375Z"
android:fillColor="#FFBB2C" />
<path
android:pathData="M12,14.8838L15.4419,11.4418C15.686,11.1978 15.686,10.802 15.4419,10.558C15.1979,10.3139 14.8021,10.3139 14.5581,10.558L12,13.116L9.4419,10.558C9.1979,10.3139 8.8021,10.3139 8.5581,10.558C8.314,10.802 8.314,11.1978 8.5581,11.4418L12,14.8838Z"
android:fillColor="#FFBB2C"
android:fillType="evenOdd" />
</vector>

View file

@ -1,14 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="8dp"
android:height="24dp"
android:viewportWidth="8"
android:viewportHeight="24">
<group>
<clip-path
android:pathData="M0,24l0,-24l8,-0l0,24z"/>
<path
android:pathData="M0.9597,18.0303C0.6668,17.7374 0.6668,17.2626 0.9597,16.9697L5.9293,12L0.9597,7.0303C0.6668,6.7374 0.6668,6.2626 0.9597,5.9697C1.2526,5.6768 1.7274,5.6768 2.0203,5.9697L8.0506,12L2.0203,18.0303C1.7274,18.3232 1.2526,18.3232 0.9597,18.0303Z"
android:fillColor="@color/text_tertiary"
android:fillType="evenOdd"/>
</group>
</vector>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="16dp"/>
<solid android:color="@color/background_primary"/>
</shape>

View file

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.anytypeio.anytype.core_ui.widgets.toolbar.MainBottomToolbar">
<FrameLayout
android:id="@+id/btnBack"
@ -11,9 +13,10 @@
<ImageView
android:id="@+id/icBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/main_bottom_toolbar_icon_width"
android:layout_height="@dimen/main_bottom_toolbar_icon_height"
android:layout_gravity="center"
android:scaleType="center"
android:contentDescription="@string/content_desc_back_button"
app:srcCompat="@drawable/ic_nav_panel_back" />
@ -28,9 +31,10 @@
<ImageView
android:id="@+id/icAddDoc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/main_bottom_toolbar_icon_width"
android:layout_height="@dimen/main_bottom_toolbar_icon_height"
android:layout_gravity="center"
android:scaleType="center"
android:contentDescription="@string/content_desc_add_doc_button"
app:srcCompat="@drawable/ic_nav_panel_plus" />
@ -46,10 +50,11 @@
<ImageView
android:id="@+id/icSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/main_bottom_toolbar_icon_width"
android:layout_height="@dimen/main_bottom_toolbar_icon_height"
android:layout_gravity="center"
android:contentDescription="@string/content_desc_search_button"
android:scaleType="center"
app:srcCompat="@drawable/ic_nav_panel_search" />
</FrameLayout>

View file

@ -23,6 +23,9 @@
<dimen name="default_toolbar_section_padding_start">16dp</dimen>
<dimen name="default_toolbar_section_padding_end">16dp</dimen>
<dimen name="main_bottom_toolbar_icon_width">72dp</dimen>
<dimen name="main_bottom_toolbar_icon_height">52dp</dimen>
<dimen name="default_toolbar_option_height">64dp</dimen>
<dimen name="default_toolbar_option_width">64dp</dimen>
<dimen name="default_toolbar_option_corner_radius">10dp</dimen>

View file

@ -1,5 +1,6 @@
package com.anytypeio.anytype.core_ui.features.dataview
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.sets.model.Viewer
import com.anytypeio.anytype.test_utils.MockDataFactory
import org.junit.Test
@ -13,7 +14,10 @@ class GridDiffUtilTest {
fun `showIcon changed - header payload exists`() {
val old = Viewer.GridView.Row(
id = MockDataFactory.randomUuid(),
showIcon = false
showIcon = false,
objectIcon = ObjectIcon.Basic.Image(
hash = MockDataFactory.randomUuid()
)
)
val new = old.copy(
showIcon = true
@ -30,7 +34,10 @@ class GridDiffUtilTest {
fun `nothing changed - payloads is empty`() {
val old = Viewer.GridView.Row(
id = MockDataFactory.randomUuid(),
showIcon = false
showIcon = false,
objectIcon = ObjectIcon.Basic.Image(
hash = MockDataFactory.randomUuid()
)
)
val new = old.copy()
val payload = ViewerGridAdapter.GridDiffUtil.getChangePayload(

View file

@ -44,6 +44,6 @@ interface UserSettingsCache {
suspend fun saveWidgetSession(session: WidgetSession)
suspend fun clear()
suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean>
suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean>?
suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean)
}

View file

@ -110,7 +110,7 @@ class UserSettingsDataRepository(private val cache: UserSettingsCache) : UserSet
)
}
override suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean> {
override suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean>? {
return cache.getAllContentSort(space)
}

View file

@ -378,6 +378,7 @@ class BlockDataRepository(
)
override suspend fun searchObjects(
space: SpaceId,
sorts: List<DVSort>,
filters: List<DVFilter>,
fulltext: String,
@ -385,6 +386,7 @@ class BlockDataRepository(
limit: Int,
keys: List<Id>
): List<Map<String, Any?>> = remote.searchObjects(
space = space,
sorts = sorts,
filters = filters,
fulltext = fulltext,
@ -398,6 +400,7 @@ class BlockDataRepository(
): List<Command.SearchWithMeta.Result> = remote.searchObjectWithMeta(command)
override suspend fun searchObjectsWithSubscription(
space: SpaceId,
subscription: Id,
sorts: List<DVSort>,
filters: List<DVFilter>,
@ -411,6 +414,7 @@ class BlockDataRepository(
noDepSubscription: Boolean?,
collection: Id?
): SearchResult = remote.searchObjectsWithSubscription(
space = space,
subscription = subscription,
sorts = sorts,
filters = filters,
@ -426,10 +430,12 @@ class BlockDataRepository(
)
override suspend fun searchObjectsByIdWithSubscription(
space: SpaceId,
subscription: Id,
ids: List<Id>,
keys: List<String>
): SearchResult = remote.searchObjectsByIdWithSubscription(
space = space,
subscription = subscription,
ids = ids,
keys = keys

View file

@ -148,6 +148,7 @@ interface BlockRemote {
): Payload
suspend fun searchObjects(
space: SpaceId,
sorts: List<DVSort>,
filters: List<DVFilter>,
fulltext: String,
@ -161,6 +162,7 @@ interface BlockRemote {
): List<Command.SearchWithMeta.Result>
suspend fun searchObjectsWithSubscription(
space: SpaceId,
subscription: Id,
sorts: List<DVSort>,
filters: List<DVFilter>,
@ -176,6 +178,7 @@ interface BlockRemote {
): SearchResult
suspend fun searchObjectsByIdWithSubscription(
space: SpaceId,
subscription: Id,
ids: List<Id>,
keys: List<String>

View file

@ -15,15 +15,22 @@ class RestoreAllContentState @Inject constructor(
override suspend fun doWork(params: Params): Response {
val res = settings.getAllContentSort(params.spaceId)
return Response(activeSort = res.first, isAsc = res.second)
return if (res == null) {
Response.Empty
} else {
Response.Success(activeSort = res.first, isAsc = res.second)
}
}
data class Params(
val spaceId: SpaceId
)
data class Response(
val activeSort: String?,
val isAsc: Boolean
)
sealed class Response {
data class Success(
val activeSort: String,
val isAsc: Boolean
) : Response()
data object Empty : Response()
}
}

View file

@ -26,6 +26,7 @@ class GetLastOpenedObject(
Response.Empty
} else {
val searchResults = blockRepo.searchObjects(
space = params.space,
limit = 1,
filters = listOf(
DVFilter(

View file

@ -3,6 +3,7 @@ package com.anytypeio.anytype.domain.auth.interactor
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.`object`.amend
import com.anytypeio.anytype.domain.`object`.unset
import com.anytypeio.anytype.domain.base.BaseUseCase
@ -66,6 +67,7 @@ class GetProfile(
): ObjectWrapper.Basic {
val config = provider.get()
val result = repo.searchObjectsByIdWithSubscription(
space = SpaceId(config.techSpace),
subscription = subscription,
ids = listOf(config.profile),
keys = keys
@ -80,6 +82,7 @@ class GetProfile(
override suspend fun run(params: Params) = safe {
val config = provider.get()
val result = repo.searchObjectsByIdWithSubscription(
space = SpaceId(config.techSpace),
subscription = params.subscription,
ids = listOf(config.profile),
keys = params.keys

View file

@ -20,13 +20,13 @@ import kotlinx.coroutines.Dispatchers
class LaunchAccount @Inject constructor(
private val repository: AuthRepository,
private val pathProvider: PathProvider,
private val context: CoroutineContext = Dispatchers.IO,
private val configStorage: ConfigStorage,
private val spaceManager: SpaceManager,
private val metricsProvider: MetricsProvider,
private val settings: UserSettingsRepository,
private val awaitAccountStartManager: AwaitAccountStartManager
) : BaseUseCase<Id, BaseUseCase.None>(context) {
private val awaitAccountStartManager: AwaitAccountStartManager,
context: CoroutineContext = Dispatchers.IO
) : BaseUseCase<Id, BaseUseCase.None>(context) {
override suspend fun run(params: None) = safe {
repository.setMetrics(
@ -53,8 +53,6 @@ class LaunchAccount @Inject constructor(
// Falling back to the default space
spaceManager.set(setup.config.space)
}
} else {
spaceManager.set(setup.config.space)
}
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
setup.config.analytics

View file

@ -56,8 +56,6 @@ class ResumeAccount @Inject constructor(
// Falling back to the default space
spaceManager.set(setup.config.space)
}
} else {
spaceManager.set(setup.config.space)
}
setup.account.id
}

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVFilterCondition
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.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -17,6 +18,8 @@ class EmptyBin(
) : ResultInteractor<Unit, List<Id>>(dispatchers.io) {
override suspend fun doWork(params: Unit) : List<Id> {
val archived = repo.searchObjects(
// TODO DROID-2916 Move space id to use case params
space = SpaceId(spaceManager.get()),
filters = listOf(
DVFilter(
relation = Relations.IS_ARCHIVED,
@ -34,9 +37,9 @@ class EmptyBin(
value = true
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = spaceManager.get()
relation = Relations.IS_HIDDEN_DISCOVERY,
condition = DVFilterCondition.NOT_EQUAL,
value = true
)
),
sorts = emptyList(),

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.ext.mapToObjectWrapperType
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -17,6 +18,7 @@ class GetObjectTypes @Inject constructor(
override suspend fun doWork(params: Params): List<ObjectWrapper.Type> {
val result = repo.searchObjects(
space = params.space,
keys = params.keys,
filters = params.filters,
sorts = params.sorts,
@ -28,6 +30,7 @@ class GetObjectTypes @Inject constructor(
}
data class Params(
val space: SpaceId,
val sorts: List<DVSort> = emptyList(),
val filters: List<DVFilter> = emptyList(),
val keys: List<Key> = emptyList(),

View file

@ -188,6 +188,7 @@ interface BlockRepository {
): Payload
suspend fun searchObjects(
space: SpaceId,
sorts: List<DVSort> = emptyList(),
filters: List<DVFilter> = emptyList(),
fulltext: String = "",
@ -201,6 +202,7 @@ interface BlockRepository {
): List<Command.SearchWithMeta.Result>
suspend fun searchObjectsWithSubscription(
space: SpaceId,
subscription: Id,
sorts: List<DVSort>,
filters: List<DVFilter>,
@ -216,6 +218,7 @@ interface BlockRepository {
): SearchResult
suspend fun searchObjectsByIdWithSubscription(
space: SpaceId,
subscription: Id,
ids: List<Id>,
keys: List<String>

View file

@ -1,9 +1,10 @@
package com.anytypeio.anytype.domain.config
import com.anytypeio.anytype.core_models.Config
import com.anytypeio.anytype.core_models.primitives.SpaceId
@Deprecated("Refactoring needed")
interface ConfigStorage {
interface ConfigStorage : TechSpaceProvider {
@Deprecated("Unsafe method. Use getOrNull() instead")
@Throws(IllegalStateException::class)
fun get(): Config
@ -26,5 +27,15 @@ interface ConfigStorage {
override fun clear() {
instance = null
}
override fun provide(): SpaceId? {
return instance?.let {
SpaceId(it.techSpace)
}
}
}
}
interface TechSpaceProvider {
fun provide(): SpaceId?
}

View file

@ -46,7 +46,7 @@ interface UserSettingsRepository {
suspend fun getWidgetSession() : WidgetSession
suspend fun saveWidgetSession(session: WidgetSession)
suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean>
suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean>?
suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean)
suspend fun clear()

View file

@ -16,7 +16,6 @@ import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.workspace.SpaceManager
import javax.inject.Inject
@ -24,18 +23,15 @@ import javax.inject.Inject
class GetDefaultObjectType @Inject constructor(
private val userSettingsRepository: UserSettingsRepository,
private val blockRepository: BlockRepository,
private val spaceManager: SpaceManager,
private val configStorage: ConfigStorage,
dispatchers: AppCoroutineDispatchers
) : ResultInteractor<Unit, GetDefaultObjectType.Response>(dispatchers.io) {
) : ResultInteractor<SpaceId, GetDefaultObjectType.Response>(dispatchers.io) {
override suspend fun doWork(params: Unit): Response {
val space = SpaceId(spaceManager.get())
val defaultType = userSettingsRepository.getDefaultObjectType(space)
override suspend fun doWork(params: SpaceId): Response {
val defaultType = userSettingsRepository.getDefaultObjectType(params)
if (defaultType != null) {
val item = searchObjectByIdAndSpaceId(
type = defaultType,
space = space
space = params
)
return if (item != null) {
val key = TypeKey(item.uniqueKey)
@ -47,18 +43,20 @@ class GetDefaultObjectType @Inject constructor(
defaultTemplate = item.defaultTemplateId
)
} else {
fetchDefaultType()
fetchDefaultType(params)
}
} else {
return fetchDefaultType()
return fetchDefaultType(params)
}
}
private suspend fun fetchDefaultType(): Response {
private suspend fun fetchDefaultType(space: SpaceId): Response {
val structs = blockRepository.searchObjects(
space = space,
limit = 1,
fulltext = NO_VALUE,
filters = buildList {
// TODO DROID-2916 might need to delete this filter
add(
DVFilter(
relation = Relations.UNIQUE_KEY,
@ -66,19 +64,6 @@ class GetDefaultObjectType @Inject constructor(
value = ObjectTypeUniqueKeys.NOTE
)
)
val space = spaceManager.get().ifEmpty {
// Fallback to default space.
configStorage.getOrNull()?.space
}
if (!space.isNullOrEmpty()) {
add(
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = space
)
)
}
},
offset = 0,
sorts = emptyList(),
@ -110,10 +95,11 @@ class GetDefaultObjectType @Inject constructor(
space: SpaceId
): ObjectWrapper.Type? {
val structs = blockRepository.searchObjects(
space = space,
limit = 1,
fulltext = NO_VALUE,
filters = buildList {
addAll(filterObjectTypeLibrary(space))
addAll(filterObjectTypeLibrary())
add(
DVFilter(
relation = Relations.ID,
@ -135,7 +121,7 @@ class GetDefaultObjectType @Inject constructor(
return structs.firstOrNull()?.mapToObjectWrapperType()
}
private fun filterObjectTypeLibrary(space: SpaceId) = listOf(
private fun filterObjectTypeLibrary() = listOf(
DVFilter(
relation = Relations.LAYOUT,
condition = DVFilterCondition.EQUAL,
@ -157,9 +143,9 @@ class GetDefaultObjectType @Inject constructor(
value = true
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = space.id
relation = Relations.IS_HIDDEN_DISCOVERY,
condition = DVFilterCondition.NOT_EQUAL,
value = true
),
DVFilter(
relation = Relations.RESTRICTIONS,
@ -168,9 +154,6 @@ class GetDefaultObjectType @Inject constructor(
)
)
/**
* TODO provide space to params
*/
data class Response(
val id: TypeId,
val type: TypeKey,

View file

@ -4,8 +4,10 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.primitives.SpaceId
data class StoreSearchParams(
val space: SpaceId,
val subscription: Id,
val sorts: List<DVSort> = emptyList(),
val filters: List<DVFilter> = emptyList(),
@ -17,6 +19,7 @@ data class StoreSearchParams(
)
data class StoreSearchByIdsParams(
val space: SpaceId,
val subscription: Id,
val keys: List<Key>,
val targets: List<Id>,

View file

@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.library.processors.EventUnsetProcessor
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
@ -62,6 +63,7 @@ interface StorelessSubscriptionContainer {
flow {
with(searchParams) {
val initial = repo.searchObjectsWithSubscription(
space = space,
subscription = subscription,
sorts = sorts,
filters = filters,
@ -82,11 +84,14 @@ interface StorelessSubscriptionContainer {
)
)
}
}.catch {
logger.logException(it, "Error in storeless subscription container")
}.flowOn(dispatchers.io)
override fun subscribe(searchParams: StoreSearchByIdsParams) = flow {
with(searchParams) {
val initial = repo.searchObjectsByIdWithSubscription(
space = space,
subscription = subscription,
ids = targets,
keys = keys
@ -100,7 +105,11 @@ interface StorelessSubscriptionContainer {
)
)
}
}.flowOn(dispatchers.io)
}.catch {
logger.logException(it, "Error in storeless subscription container")
}.flowOn(
context = dispatchers.io
)
private fun buildObjectsFlow(
subscription: Id,
@ -160,6 +169,7 @@ interface StorelessSubscriptionContainer {
return flow {
with(searchParams) {
val initial = repo.searchObjectsWithSubscription(
space = searchParams.space,
subscription = subscription,
sorts = sorts,
filters = filters,
@ -182,7 +192,11 @@ interface StorelessSubscriptionContainer {
)
)
}
}.flowOn(dispatchers.io)
}.catch {
logger.logException(it, "Error in storeless subscription container")
}.flowOn(
context = dispatchers.io
)
}
private fun buildObjectsFlow(

View file

@ -94,6 +94,7 @@ interface ActiveSpaceMemberSubscriptionContainer {
.flatMapLatest { config ->
container.subscribe(
StoreSearchParams(
space = SpaceId(config.space),
subscription = GLOBAL_SUBSCRIPTION,
filters = buildList {
add(
@ -103,13 +104,6 @@ interface ActiveSpaceMemberSubscriptionContainer {
condition = DVFilterCondition.EQUAL
)
)
add(
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = config.space
)
)
},
limit = 0,
keys = listOf(

View file

@ -24,6 +24,7 @@ class CheckIsUserSpaceMember @Inject constructor(
override suspend fun doWork(params: SpaceId): Boolean {
val account = auth.getCurrentAccountId()
val results = repo.searchObjects(
space = params,
limit = 0,
filters = buildList {
add(
@ -40,13 +41,6 @@ class CheckIsUserSpaceMember @Inject constructor(
condition = DVFilterCondition.EQUAL
)
)
add(
DVFilter(
relation = Relations.SPACE_ID,
value = params.id,
condition = DVFilterCondition.EQUAL
)
)
},
keys = listOf(
Relations.ID,

View file

@ -19,6 +19,9 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@ -54,6 +57,7 @@ interface UserPermissionProvider {
}
class DefaultUserPermissionProvider @Inject constructor(
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
private val container: StorelessSubscriptionContainer,
private val repo: AuthRepository,
private val dispatchers: AppCoroutineDispatchers,
@ -81,45 +85,57 @@ class DefaultUserPermissionProvider @Inject constructor(
clear()
jobs += scope.launch(dispatchers.io) {
val account = repo.getCurrentAccountId()
container.subscribe(
StoreSearchParams(
subscription = GLOBAL_SUBSCRIPTION,
filters = buildList {
add(
DVFilter(
relation = Relations.LAYOUT,
value = ObjectType.Layout.PARTICIPANT.code.toDouble(),
condition = DVFilterCondition.EQUAL
spaceViewSubscriptionContainer
.observe()
.map { spaceViews ->
spaceViews.mapNotNull { spaceView -> spaceView.targetSpaceId }
}
.distinctUntilChanged()
.flatMapLatest { spaces ->
val subscriptions = spaces.map { space ->
container.subscribe(
StoreSearchParams(
space = SpaceId(space),
subscription = "$GLOBAL_SUBSCRIPTION-$space",
filters = buildList {
add(
DVFilter(
relation = Relations.LAYOUT,
value = ObjectType.Layout.PARTICIPANT.code.toDouble(),
condition = DVFilterCondition.EQUAL
)
)
add(
DVFilter(
relation = Relations.IDENTITY,
value = account,
condition = DVFilterCondition.EQUAL
)
)
},
limit = 1,
keys = listOf(
Relations.ID,
Relations.SPACE_ID,
Relations.IDENTITY,
Relations.PARTICIPANT_PERMISSIONS
)
)
)
add(
DVFilter(
relation = Relations.IDENTITY,
value = account,
condition = DVFilterCondition.EQUAL
)
)
},
limit = NO_LIMIT,
keys = listOf(
Relations.ID,
Relations.SPACE_ID,
Relations.IDENTITY,
Relations.PARTICIPANT_PERMISSIONS
)
)
)
.catch { error ->
).map { results ->
results.map { ObjectWrapper.SpaceMember(it.map) }
}
}
combine(flows = subscriptions) { flow ->
flow.toList().flatten()
}
}.catch { error ->
logger.logException(
e = error,
msg = "Failed to subscribe to user-as-space-member-permissions"
)
}.collect {
members.value = it
}
.collect { results ->
members.value = results.map {
ObjectWrapper.SpaceMember(it.map)
}
}
}
}
@ -138,7 +154,11 @@ class DefaultUserPermissionProvider @Inject constructor(
override fun stop() {
clear()
scope.launch(dispatchers.io) {
container.unsubscribe(listOf(GLOBAL_SUBSCRIPTION))
val subscriptions = spaceViewSubscriptionContainer
.get()
.mapNotNull { it.targetSpaceId }
.map { space -> "$GLOBAL_SUBSCRIPTION-$space" }
container.unsubscribe(subscriptions)
}
}
@ -148,7 +168,6 @@ class DefaultUserPermissionProvider @Inject constructor(
companion object {
const val GLOBAL_SUBSCRIPTION = "subscription.global.user-as-space-member-permissions"
const val NO_LIMIT = 0
}
}

View file

@ -19,6 +19,7 @@ class GetSpaceMemberByIdentity @Inject constructor(
override suspend fun doWork(params: Params): ObjectWrapper.SpaceMember? {
val results = repo.searchObjects(
space = params.space,
limit = 0,
filters = buildList {
add(
@ -35,13 +36,6 @@ class GetSpaceMemberByIdentity @Inject constructor(
condition = DVFilterCondition.EQUAL
)
)
add(
DVFilter(
relation = Relations.SPACE_ID,
value = params.space.id,
condition = DVFilterCondition.EQUAL
)
)
},
keys = listOf(
Relations.ID,

View file

@ -17,6 +17,7 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_models.restrictions.SpaceStatus
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.library.StoreSearchParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
@ -46,7 +47,8 @@ interface SpaceViewSubscriptionContainer {
private val scope: CoroutineScope,
private val dispatchers: AppCoroutineDispatchers,
private val awaitAccountStart: AwaitAccountStartManager,
private val logger: Logger
private val logger: Logger,
private val config: ConfigStorage
) : SpaceViewSubscriptionContainer {
private val data = MutableStateFlow<List<ObjectWrapper.SpaceView>>(emptyList())
@ -90,68 +92,77 @@ interface SpaceViewSubscriptionContainer {
override fun start() {
jobs += scope.launch(dispatchers.io) {
container.subscribe(
StoreSearchParams(
subscription = GLOBAL_SUBSCRIPTION,
keys = listOf(
Relations.ID,
Relations.TARGET_SPACE_ID,
Relations.SPACE_ACCOUNT_STATUS,
Relations.SPACE_LOCAL_STATUS,
Relations.SPACE_ACCESS_TYPE,
Relations.SHARED_SPACES_LIMIT,
Relations.READERS_LIMIT,
Relations.WRITERS_LIMIT,
Relations.NAME,
Relations.CREATED_DATE,
Relations.CREATOR,
Relations.ICON_IMAGE,
Relations.ICON_OPTION,
val techSpace = config.getOrNull()?.techSpace
if (techSpace != null) {
proceedWithSubscription(techSpace)
} else {
logger.logException(IllegalStateException("Tech space was missing"))
}
}
}
private suspend fun proceedWithSubscription(techSpace: Id) {
container.subscribe(
StoreSearchParams(
space = SpaceId(techSpace),
subscription = GLOBAL_SUBSCRIPTION,
keys = listOf(
Relations.ID,
Relations.TARGET_SPACE_ID,
Relations.SPACE_ACCOUNT_STATUS,
Relations.SPACE_LOCAL_STATUS,
Relations.SPACE_ACCESS_TYPE,
Relations.SHARED_SPACES_LIMIT,
Relations.READERS_LIMIT,
Relations.WRITERS_LIMIT,
Relations.NAME,
Relations.CREATED_DATE,
Relations.CREATOR,
Relations.ICON_IMAGE,
Relations.ICON_OPTION,
),
filters = listOf(
DVFilter(
relation = Relations.LAYOUT,
value = ObjectType.Layout.SPACE_VIEW.code.toDouble(),
condition = DVFilterCondition.EQUAL
),
filters = listOf(
DVFilter(
relation = Relations.LAYOUT,
value = ObjectType.Layout.SPACE_VIEW.code.toDouble(),
condition = DVFilterCondition.EQUAL
),
DVFilter(
relation = Relations.SPACE_ACCOUNT_STATUS,
value = buildList {
add(SpaceStatus.SPACE_DELETED.code.toDouble())
},
condition = DVFilterCondition.NOT_IN
),
DVFilter(
relation = Relations.SPACE_LOCAL_STATUS,
value = buildList {
add(SpaceStatus.OK.code.toDouble())
add(SpaceStatus.UNKNOWN.code.toDouble())
},
condition = DVFilterCondition.IN
)
DVFilter(
relation = Relations.SPACE_ACCOUNT_STATUS,
value = buildList {
add(SpaceStatus.SPACE_DELETED.code.toDouble())
},
condition = DVFilterCondition.NOT_IN
),
sorts = listOf(
DVSort(
relationKey = Relations.LAST_OPENED_DATE,
type = DVSortType.DESC,
includeTime = true,
relationFormat = RelationFormat.DATE
)
DVFilter(
relation = Relations.SPACE_LOCAL_STATUS,
value = buildList {
add(SpaceStatus.OK.code.toDouble())
add(SpaceStatus.UNKNOWN.code.toDouble())
},
condition = DVFilterCondition.IN
)
),
sorts = listOf(
DVSort(
relationKey = Relations.LAST_OPENED_DATE,
type = DVSortType.DESC,
includeTime = true,
relationFormat = RelationFormat.DATE
)
)
).map { objects ->
objects.map { obj ->
ObjectWrapper.SpaceView(obj.map)
}
}.catch { error ->
logger.logException(
e = error,
msg = "Failed to subscribe to space-views"
)
)
).map { objects ->
objects.map { obj ->
ObjectWrapper.SpaceView(obj.map)
}
.collect {
data.value = it
}
}.catch { error ->
logger.logException(
e = error,
msg = "Failed to subscribe to space-views"
)
}.collect {
data.value = it
}
}
@ -168,6 +179,7 @@ interface SpaceViewSubscriptionContainer {
}
}
@Deprecated("To de deleted")
fun SpaceViewSubscriptionContainer.isSharingLimitReached(
spaceToUserPermissions: Flow<Map<Id, SpaceMemberPermissions>>
) : Flow<Pair<Boolean, Int>> {
@ -193,4 +205,19 @@ fun SpaceViewSubscriptionContainer.isSharingLimitReached(
val isLimitReached = limit == 0 || count >= limit
Pair(isLimitReached, limit)
}
}
}
fun SpaceViewSubscriptionContainer.sharedSpaceCount(
spaceToUserPermissions: Flow<Map<Id, SpaceMemberPermissions>>
) : Flow<Int> {
return combine(
observe(),
spaceToUserPermissions
) { spaceViews, permissions ->
spaceViews.count { spaceView ->
val permission = permissions[spaceView.targetSpaceId]
spaceView.spaceAccessType == SHARED && permission == OWNER
}
}
}

View file

@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -28,7 +29,8 @@ class FetchObject @Inject constructor(
)
},
limit = 1,
keys = params.keys
keys = params.keys,
space = params.space
)
return if (result.isNotEmpty() && result.first().isNotEmpty()) {
ObjectWrapper.Basic(result.first())
@ -38,6 +40,7 @@ class FetchObject @Inject constructor(
}
data class Params(
val space: SpaceId,
val obj: Id,
val keys: List<Key> = listOf(
Relations.ID,

View file

@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -53,6 +54,7 @@ class GetOptions(
)
}
repo.searchObjects(
space = SpaceId(params.space),
sorts = emptyList(),
filters = filters,
limit = 0,

View file

@ -12,7 +12,6 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.launch.GetDefaultObjectType
import com.anytypeio.anytype.domain.workspace.SpaceManager
import javax.inject.Inject
/**
@ -21,14 +20,14 @@ import javax.inject.Inject
class CreateObject @Inject constructor(
private val repo: BlockRepository,
private val getDefaultObjectType: GetDefaultObjectType,
private val spaceManager: SpaceManager,
dispatchers: AppCoroutineDispatchers
) : ResultInteractor<CreateObject.Param, CreateObject.Result>(dispatchers.io) {
override suspend fun doWork(params: Param): Result {
if (params.type == null) {
val defType = getDefaultObjectType.run(Unit)
val defType = getDefaultObjectType.run(params.space)
return createObject(
space = params.space,
typeKey = defType.type,
template = defType.defaultTemplate,
internalFlags = params.internalFlags,
@ -36,6 +35,7 @@ class CreateObject @Inject constructor(
)
} else {
return createObject(
space = params.space,
typeKey = params.type,
template = params.template,
internalFlags = params.internalFlags,
@ -45,16 +45,15 @@ class CreateObject @Inject constructor(
}
private suspend fun createObject(
space: SpaceId,
typeKey: TypeKey,
template: Id?,
internalFlags: List<InternalFlags>,
prefilled: Struct
): Result {
val spaceId = SpaceId(spaceManager.get())
val command = Command.CreateObject(
space = spaceId,
space = space,
typeKey = typeKey,
template = template,
prefilled = prefilled,
@ -72,10 +71,8 @@ class CreateObject @Inject constructor(
)
}
/**
* DROID-2341 TODO provide custom space to params?
*/
data class Param(
val space: SpaceId,
val type: TypeKey? = null,
val template: Id? = null,
val internalFlags: List<InternalFlags> = emptyList(),

View file

@ -45,6 +45,7 @@ class CreateObjectByTypeAndTemplate @Inject constructor(
private suspend fun searchObjectType(params: Param): ObjectWrapper.Type? {
try {
val struct = repo.searchObjects(
space = params.space,
limit = 1,
keys = params.keys,
sorts = params.sorts,
@ -65,16 +66,16 @@ class CreateObjectByTypeAndTemplate @Inject constructor(
value = true
),
DVFilter(
relation = Relations.IS_DELETED,
relation = Relations.IS_HIDDEN_DISCOVERY,
condition = DVFilterCondition.NOT_EQUAL,
value = true
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.IN,
value = listOf(params.space.id)
relation = Relations.IS_DELETED,
condition = DVFilterCondition.NOT_EQUAL,
value = true
)
),
)
)
return if (struct.isNotEmpty()) {
ObjectWrapper.Type(struct.first())

View file

@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -18,6 +19,7 @@ class GetRelations(
}
private suspend fun proceedWithUseCase(params: Params) = repo.searchObjects(
space = params.space,
keys = params.keys,
filters = params.filters,
sorts = params.sorts,
@ -29,6 +31,7 @@ class GetRelations(
}
data class Params(
val space: SpaceId,
val sorts: List<DVSort> = emptyList(),
val filters: List<DVFilter> = emptyList(),
val keys: List<Key> = emptyList(),

View file

@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.SearchResult
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.`object`.move
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.runCatchingL
@ -38,6 +39,7 @@ class DataViewSubscriptionContainer(
fun observe(params: Params): Flow<DataViewState> {
return flow {
val initial = repo.searchObjectsWithSubscription(
space = params.space,
subscription = params.subscription,
sorts = params.sorts.distinct(),
filters = params.filters.distinct(),
@ -183,6 +185,7 @@ class DataViewSubscriptionContainer(
}
data class Params(
val space: SpaceId,
val subscription: Id,
val sorts: List<DVSort>,
val filters: List<DVFilter>,

View file

@ -7,6 +7,7 @@ import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Subscription
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.`object`.move
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -26,6 +27,7 @@ class ObjectSearchSubscriptionContainer(
private fun subscribe(subscriptions: List<Id>) = channel.subscribe(subscriptions)
fun observe(
space: SpaceId,
subscription: Id,
sorts: List<DVSort> = emptyList(),
filters: List<DVFilter> = emptyList(),
@ -36,6 +38,7 @@ class ObjectSearchSubscriptionContainer(
): Flow<Subscription> {
return flow {
val initial = repo.searchObjectsWithSubscription(
space = space,
subscription = subscription,
sorts = sorts,
filters = filters,
@ -144,11 +147,13 @@ class ObjectSearchSubscriptionContainer(
}
fun observe(
space: SpaceId,
subscription: Id,
targets: List<Id>,
keys: List<Key>
): Flow<List<ObjectWrapper.Basic>> = flow {
val initial = repo.searchObjectsByIdWithSubscription(
space = space,
subscription = subscription,
ids = targets,
keys = keys
@ -157,10 +162,12 @@ class ObjectSearchSubscriptionContainer(
}
suspend fun get(
space: SpaceId,
subscription: Id,
targets: List<Id>,
keys: List<Key>
): List<ObjectWrapper.Basic> = repo.searchObjectsByIdWithSubscription(
space = space,
subscription = subscription,
ids = targets,
keys = keys

View file

@ -5,11 +5,14 @@ import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.`object`.move
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
@ -20,12 +23,14 @@ class ObjectTypesSubscriptionContainer(
private val repo: BlockRepository,
private val channel: SubscriptionEventChannel,
private val store: StoreOfObjectTypes,
private val dispatchers: AppCoroutineDispatchers
private val dispatchers: AppCoroutineDispatchers,
private val logger: Logger
) {
fun observe(params: Params): Flow<Index> {
return flow {
val initial = repo.searchObjectsWithSubscription(
space = params.space,
subscription = params.subscription,
sorts = params.sorts,
filters = params.filters,
@ -121,7 +126,11 @@ class ObjectTypesSubscriptionContainer(
)
}
)
}.flowOn(dispatchers.io)
}.catch {
logger.logException(it, "Error in object types container")
}.flowOn(
context = dispatchers.io
)
}
/**
@ -139,6 +148,7 @@ class ObjectTypesSubscriptionContainer(
}
data class Params(
val space: SpaceId,
val subscription: Id,
val sorts: List<DVSort>,
val filters: List<DVFilter>,

View file

@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscription
import com.anytypeio.anytype.domain.workspace.SpaceManager
import kotlinx.coroutines.CoroutineScope
@ -65,6 +66,7 @@ class ObjectTypesSubscriptionManager (
companion object {
fun buildParams(config: Config) =
ObjectTypesSubscriptionContainer.Params(
space = SpaceId(config.space),
subscription = ObjectTypesSubscriptionContainer.SUBSCRIPTION_ID,
filters = listOf(
DVFilter(

View file

@ -0,0 +1,89 @@
package com.anytypeio.anytype.domain.search
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscription
import javax.inject.Inject
import kotlin.math.log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
interface ProfileSubscriptionManager : GlobalSubscription {
fun observe(): Flow<ObjectWrapper.Basic>
fun onStart()
fun onStop()
class Default @Inject constructor(
private val scope: CoroutineScope,
private val configStorage: ConfigStorage,
private val awaitAccountStartManager: AwaitAccountStartManager,
private val container: StorelessSubscriptionContainer,
private val dispatchers: AppCoroutineDispatchers,
private val logger: Logger
) : ProfileSubscriptionManager {
private val state = MutableStateFlow<ObjectWrapper.Basic?>(null)
override fun observe(): Flow<ObjectWrapper.Basic> {
return state.mapNotNull { it }
}
override fun onStart() {
scope.launch {
awaitAccountStartManager
.state()
.mapNotNull { configStorage.getOrNull() }
.flatMapLatest { config ->
container.subscribe(
searchParams = StoreSearchByIdsParams(
subscription = GLOBAL_PROFILE_SUBSCRIPTION,
space = SpaceId(config.techSpace),
keys = listOf(
Relations.ID,
Relations.NAME,
Relations.ICON_EMOJI,
Relations.ICON_IMAGE,
Relations.ICON_OPTION,
Relations.SHARED_SPACES_LIMIT
),
targets = listOf(config.profile)
)
).map {
it.firstOrNull()
}
}
.flowOn(dispatchers.io)
.catch { logger.logException(it, "Error in ProfileSubscriptionManager") }
.collect {
state.value = it
}
}
}
override fun onStop() {
scope.launch(dispatchers.io) {
container.unsubscribe(listOf(GLOBAL_PROFILE_SUBSCRIPTION))
}
}
companion object {
const val GLOBAL_PROFILE_SUBSCRIPTION = "subscription.global.profile"
}
}
}

View file

@ -5,11 +5,14 @@ import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.`object`.move
import com.anytypeio.anytype.domain.objects.StoreOfRelations
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
@ -20,12 +23,14 @@ class RelationsSubscriptionContainer(
private val repo: BlockRepository,
private val channel: SubscriptionEventChannel,
private val store: StoreOfRelations,
private val dispatchers: AppCoroutineDispatchers
private val dispatchers: AppCoroutineDispatchers,
private val logger: Logger
) {
fun observe(params: Params): Flow<Index> {
return flow {
val initial = repo.searchObjectsWithSubscription(
space = params.space,
subscription = params.subscription,
sorts = params.sorts,
filters = params.filters,
@ -121,7 +126,11 @@ class RelationsSubscriptionContainer(
)
}
)
}.flowOn(dispatchers.io)
}.catch {
logger.logException(it, "Error in storeless subscription container")
}.flowOn(
context = dispatchers.io
)
}
@ -141,6 +150,7 @@ class RelationsSubscriptionContainer(
}
data class Params(
val space: SpaceId,
val subscription: Id,
val sorts: List<DVSort>,
val filters: List<DVFilter>,

View file

@ -6,6 +6,7 @@ import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Marketplace
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscription
import com.anytypeio.anytype.domain.workspace.SpaceManager
import javax.inject.Inject
@ -27,12 +28,9 @@ class RelationsSubscriptionManager @Inject constructor(
val pipeline get() = spaceManager.state().flatMapLatest { state ->
when(state) {
is SpaceManager.State.Space.Active -> {
// DROID-2916 TODO provide other spaces or add new subscription
val params = buildParams(
spaces = listOf(
state.config.space,
state.config.techSpace,
Marketplace.MARKETPLACE_SPACE_ID
)
space = SpaceId(state.config.space)
)
container.observe(params)
}
@ -69,7 +67,8 @@ class RelationsSubscriptionManager @Inject constructor(
}
companion object {
fun buildParams(spaces: List<Id>) = RelationsSubscriptionContainer.Params(
fun buildParams(space: SpaceId) = RelationsSubscriptionContainer.Params(
space = space,
subscription = RelationsSubscriptionContainer.SUBSCRIPTION_ID,
filters = listOf(
DVFilter(
@ -86,11 +85,6 @@ class RelationsSubscriptionManager @Inject constructor(
relation = Relations.IS_ARCHIVED,
condition = DVFilterCondition.NOT_EQUAL,
value = true
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.IN,
value = spaces
)
),
limit = 0,

View file

@ -4,6 +4,7 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import javax.inject.Inject
@ -14,6 +15,7 @@ class SearchObjects @Inject constructor(
override suspend fun run(params: Params) = safe {
repo.searchObjects(
space = params.space,
sorts = params.sorts,
filters = params.filters,
fulltext = params.fulltext,
@ -26,6 +28,7 @@ class SearchObjects @Inject constructor(
}
data class Params(
val space: SpaceId,
val sorts: List<DVSort> = emptyList(),
val filters: List<DVFilter> = emptyList(),
val fulltext: String = EMPTY_TEXT,

View file

@ -2,6 +2,7 @@ package com.anytypeio.anytype.domain.search
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.SearchResult
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.ResultatInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -11,6 +12,7 @@ class SearchObjectsByIdWithSubscription(
override suspend fun execute(params: Params): SearchResult {
return repo.searchObjectsByIdWithSubscription(
space = params.space,
subscription = params.subscription,
ids = params.ids,
keys = params.keys
@ -18,6 +20,7 @@ class SearchObjectsByIdWithSubscription(
}
class Params(
val space: SpaceId,
val subscription: Id,
val ids: List<Id>,
val keys: List<String>

View file

@ -1,6 +1,7 @@
package com.anytypeio.anytype.domain.sets
import com.anytypeio.anytype.core_models.*
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.sets.FindObjectSetForType.Params
@ -17,6 +18,7 @@ class FindObjectSetForType(
override suspend fun run(params: Params) = safe {
val results = repo.searchObjects(
space = params.space,
limit = 1,
filters = params.filters,
sorts = emptyList(),
@ -38,7 +40,11 @@ class FindObjectSetForType(
/**
* @property [type] object type id
*/
data class Params(val type: Id, val filters: List<DVFilter>)
data class Params(
val space: SpaceId,
val type: Id,
val filters: List<DVFilter>
)
sealed class Response {
/**

View file

@ -9,17 +9,21 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.config.ConfigStorage
import javax.inject.Inject
class GetSpaceView @Inject constructor(
private val repo: BlockRepository,
private val configStorage: ConfigStorage,
dispatchers: AppCoroutineDispatchers
): ResultInteractor<GetSpaceView.Params, ObjectWrapper.Basic?>(dispatchers.io) {
override suspend fun doWork(params: Params): ObjectWrapper.Basic? {
when(params) {
is Params.BySpaceViewId -> {
val techSpace = configStorage.getOrNull()?.techSpace ?: return null
val result = repo.searchObjects(
space = SpaceId(techSpace),
filters = buildList {
add(
DVFilter(
@ -39,6 +43,7 @@ class GetSpaceView @Inject constructor(
}
is Params.BySpaceId -> {
val result = repo.searchObjects(
space = params.space,
filters = buildList {
add(
DVFilter(

View file

@ -8,6 +8,7 @@ import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_models.restrictions.SpaceStatus
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
@ -17,9 +18,10 @@ import javax.inject.Inject
class GetSpaceViews @Inject constructor(
private val repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): ResultInteractor<Unit, List<ObjectWrapper.SpaceView>>(dispatchers.io) {
override suspend fun doWork(params: Unit): List<ObjectWrapper.SpaceView> {
): ResultInteractor<SpaceId, List<ObjectWrapper.SpaceView>>(dispatchers.io) {
override suspend fun doWork(params: SpaceId): List<ObjectWrapper.SpaceView> {
val result = repo.searchObjects(
space = params,
keys = listOf(
Relations.ID,
Relations.TARGET_SPACE_ID,

Some files were not shown because too many files have changed in this diff Show more