diff --git a/app/build.gradle b/app/build.gradle index 99aeb538c7..8d00f0b706 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -169,7 +169,7 @@ dependencies { implementation project(':library-page-icon-picker-widget') implementation project(':library-emojifier') implementation project(':analytics') - implementation project(':ui-settings') + implementation project(':feature-ui-settings') implementation project(':crash-reporting') implementation project(':payments') implementation project(':feature-chats') diff --git a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt index 6e352eff2e..73319f70e3 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt @@ -66,6 +66,7 @@ import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingStartComponen import com.anytypeio.anytype.di.feature.onboarding.login.DaggerOnboardingMnemonicLoginComponent import com.anytypeio.anytype.di.feature.onboarding.signup.DaggerOnboardingMnemonicComponent import com.anytypeio.anytype.di.feature.onboarding.signup.DaggerOnboardingSoulCreationComponent +import com.anytypeio.anytype.di.feature.participant.DaggerParticipantComponent import com.anytypeio.anytype.di.feature.relations.DaggerRelationCreateFromLibraryComponent import com.anytypeio.anytype.di.feature.relations.DaggerRelationEditComponent import com.anytypeio.anytype.di.feature.relations.LimitObjectTypeModule @@ -115,6 +116,7 @@ import com.anytypeio.anytype.presentation.multiplayer.RequestJoinSpaceViewModel import com.anytypeio.anytype.presentation.multiplayer.ShareSpaceViewModel import com.anytypeio.anytype.presentation.multiplayer.SpaceJoinRequestViewModel import com.anytypeio.anytype.presentation.objects.SelectObjectTypeViewModel +import com.anytypeio.anytype.presentation.profile.ParticipantViewModel import com.anytypeio.anytype.presentation.relations.RelationAddViewModelBase import com.anytypeio.anytype.presentation.relations.RelationListViewModel import com.anytypeio.anytype.presentation.relations.option.CreateOrEditOptionViewModel @@ -343,6 +345,12 @@ class ComponentManager( .create(params, findComponentDependencies()) } + val participantScreenComponent = ComponentWithParams { params: ParticipantViewModel.VmParams -> + DaggerParticipantComponent + .factory() + .create(params, findComponentDependencies()) + } + val dateObjectComponent = ComponentWithParams { params: DateObjectVmParams -> DaggerDateObjectComponent .factory() diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/participant/ParticipantDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/participant/ParticipantDi.kt new file mode 100644 index 0000000000..16fa483753 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/participant/ParticipantDi.kt @@ -0,0 +1,112 @@ +package com.anytypeio.anytype.di.feature.participant + +import androidx.lifecycle.ViewModelProvider +import com.anytypeio.anytype.analytics.base.Analytics +import com.anytypeio.anytype.core_utils.di.scope.PerScreen +import com.anytypeio.anytype.di.common.ComponentDependencies +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +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.debugging.Logger +import com.anytypeio.anytype.domain.icon.SetDocumentImageIcon +import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer +import com.anytypeio.anytype.domain.misc.LocaleProvider +import com.anytypeio.anytype.domain.misc.UrlBuilder +import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider +import com.anytypeio.anytype.domain.`object`.SetObjectDetails +import com.anytypeio.anytype.domain.primitives.FieldParser +import com.anytypeio.anytype.domain.search.SubscriptionEventChannel +import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate +import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider +import com.anytypeio.anytype.presentation.profile.ParticipantViewModel +import com.anytypeio.anytype.ui.profile.ParticipantFragment +import dagger.Binds +import dagger.BindsInstance +import dagger.Component +import dagger.Module +import dagger.Provides + +@Component( + dependencies = [ParticipantComponentDependencies::class], + modules = [ + ParticipantModule::class, + ParticipantModule.Declarations::class + ] +) +@PerScreen +interface ParticipantComponent { + + @Component.Factory + interface Factory { + fun create( + @BindsInstance vmParams: ParticipantViewModel.VmParams, + dependencies: ParticipantComponentDependencies + ): ParticipantComponent + } + + fun inject(fragment: ParticipantFragment) + +} + +@Module +object ParticipantModule { + + @JvmStatic + @Provides + @PerScreen + fun provideSetObjectDetails( + repo: BlockRepository, + dispatchers: AppCoroutineDispatchers + ): SetObjectDetails = SetObjectDetails( + repo, + dispatchers + ) + + @JvmStatic + @Provides + @PerScreen + fun provideSetDocumentImageIconUseCase( + repo: BlockRepository + ): SetDocumentImageIcon = SetDocumentImageIcon(repo) + + @JvmStatic + @Provides + @PerScreen + fun provideStoreLessSubscriptionContainer( + repo: BlockRepository, + channel: SubscriptionEventChannel, + dispatchers: AppCoroutineDispatchers, + logger: Logger + ): StorelessSubscriptionContainer = StorelessSubscriptionContainer.Impl( + repo = repo, + channel = channel, + dispatchers = dispatchers, + logger = logger + ) + + @Module + interface Declarations { + @PerScreen + @Binds + fun bindViewModelFactory( + factory: ParticipantViewModel.Factory + ): ViewModelProvider.Factory + } +} + +interface ParticipantComponentDependencies : ComponentDependencies { + fun blockRepository(): BlockRepository + fun analytics(): Analytics + fun urlBuilder(): UrlBuilder + fun dispatchers(): AppCoroutineDispatchers + fun analyticsHelper(): AnalyticSpaceHelperDelegate + fun userSettingsRepository(): UserSettingsRepository + fun logger(): Logger + fun localeProvider(): LocaleProvider + fun userPermissionProvider(): UserPermissionProvider + fun fieldsProvider(): FieldParser + fun provideMembershipProvider(): MembershipProvider + fun subEventChannel(): SubscriptionEventChannel + fun provideConfigStorage(): ConfigStorage +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt index c53f97d979..d8e7fc314a 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt @@ -37,6 +37,7 @@ import com.anytypeio.anytype.di.feature.onboarding.OnboardingStartDependencies import com.anytypeio.anytype.di.feature.onboarding.login.OnboardingMnemonicLoginDependencies import com.anytypeio.anytype.di.feature.onboarding.signup.OnboardingMnemonicDependencies import com.anytypeio.anytype.di.feature.onboarding.signup.OnboardingSoulCreationDependencies +import com.anytypeio.anytype.di.feature.participant.ParticipantComponentDependencies import com.anytypeio.anytype.di.feature.relations.RelationCreateFromLibraryDependencies import com.anytypeio.anytype.di.feature.relations.RelationEditDependencies import com.anytypeio.anytype.di.feature.search.GlobalSearchDependencies @@ -139,7 +140,8 @@ interface MainComponent : MoveToDependencies, DateObjectDependencies, SelectChatReactionDependencies, - ChatReactionDependencies + ChatReactionDependencies, + ParticipantComponentDependencies { fun inject(app: AndroidApplication) @@ -400,4 +402,9 @@ abstract class ComponentDependenciesModule { @IntoMap @ComponentDependenciesKey(ChatReactionDependencies::class) abstract fun provideChatReactionDependencies(component: MainComponent): ComponentDependencies + + @Binds + @IntoMap + @ComponentDependenciesKey(ParticipantComponentDependencies::class) + abstract fun provideParticipantComponentDependencies(component: MainComponent): ComponentDependencies } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt index 50c62c5ba2..d207cf0ee8 100644 --- a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt +++ b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt @@ -16,6 +16,7 @@ import com.anytypeio.anytype.ui.date.DateObjectFragment import com.anytypeio.anytype.ui.editor.EditorFragment import com.anytypeio.anytype.ui.editor.EditorModalFragment import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment +import com.anytypeio.anytype.ui.profile.ParticipantFragment import com.anytypeio.anytype.ui.relations.RelationCreateFromScratchForObjectFragment import com.anytypeio.anytype.ui.relations.RelationEditFragment import com.anytypeio.anytype.ui.search.GlobalSearchFragment @@ -342,4 +343,17 @@ class Navigator : AppNavigation { space = space) ) } + + override fun openParticipantObject( + objectId: Id, + space: Id + ) { + navController?.navigate( + resId = R.id.participantScreen, + args = ParticipantFragment.args( + objectId = objectId, + space = space + ) + ) + } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt index 32209d4b71..286d25106e 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt @@ -38,6 +38,7 @@ import com.anytypeio.anytype.ui.base.navigation import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment import com.anytypeio.anytype.ui.objects.creation.ObjectTypeSelectionFragment import com.anytypeio.anytype.ui.objects.types.pickers.ObjectTypeSelectionListener +import com.anytypeio.anytype.ui.profile.ParticipantFragment import com.anytypeio.anytype.ui.relations.REQUEST_KEY_MODIFY_RELATION import com.anytypeio.anytype.ui.relations.REQUEST_KEY_UNINSTALL_RELATION import com.anytypeio.anytype.ui.relations.REQUEST_UNINSTALL_RELATION_ARG_ID @@ -278,6 +279,20 @@ class AllContentFragment : BaseComposeFragment(), ObjectTypeSelectionListener { Timber.e(e, "Error while opening date object from All Objects screen") } } + + is AllContentViewModel.Command.NavigateToParticipant -> { + runCatching { + findNavController().navigate( + R.id.participantScreen, + ParticipantFragment.args( + objectId = command.objectId, + space = command.space + ) + ) + }.onFailure { + Timber.w("Error while opening participant screen") + } + } } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt index da85d2805d..12ff5d5360 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt @@ -62,6 +62,10 @@ class NavigationRouter( objectId = command.objectId, space = command.space ) + is AppNavigation.Command.OpenParticipant -> navigation.openParticipantObject( + objectId = command.objectId, + space = command.space + ) else -> Timber.d("Nav command ignored: $command") } } catch (e: Exception) { diff --git a/app/src/main/java/com/anytypeio/anytype/ui/date/DateObjectFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/date/DateObjectFragment.kt index 727f1d5db0..4d9798c56c 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/date/DateObjectFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/date/DateObjectFragment.kt @@ -39,6 +39,7 @@ import com.anytypeio.anytype.feature_date.viewmodel.DateObjectVmParams import com.anytypeio.anytype.ui.base.navigation import com.anytypeio.anytype.ui.objects.creation.ObjectTypeSelectionFragment import com.anytypeio.anytype.ui.objects.types.pickers.ObjectTypeSelectionListener +import com.anytypeio.anytype.ui.profile.ParticipantFragment import com.anytypeio.anytype.ui.search.GlobalSearchFragment import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi import com.google.accompanist.navigation.material.rememberBottomSheetNavigator @@ -163,6 +164,19 @@ class DateObjectFragment : BaseComposeFragment(), ObjectTypeSelectionListener { val dialog = ObjectTypeSelectionFragment.new(space = space) dialog.show(childFragmentManager, null) } + is DateObjectCommand.NavigateToParticipant -> { + runCatching { + findNavController().navigate( + R.id.participantScreen, + ParticipantFragment.args( + objectId = effect.objectId, + space = effect.space.id + ) + ) + }.onFailure { + Timber.w("Error while opening participant screen") + } + } } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt index 94c28ca5f6..dfbad9466e 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt @@ -57,6 +57,9 @@ import com.anytypeio.anytype.ui.objects.types.pickers.ObjectTypeSelectionListene import com.anytypeio.anytype.ui.objects.types.pickers.WidgetObjectTypeListener import com.anytypeio.anytype.ui.objects.types.pickers.WidgetSourceTypeListener import com.anytypeio.anytype.ui.payments.MembershipFragment +import com.anytypeio.anytype.ui.profile.ParticipantFragment +import com.anytypeio.anytype.ui.search.GlobalSearchScreen +import com.anytypeio.anytype.ui.sets.ObjectSetFragment import com.anytypeio.anytype.ui.settings.space.SpaceSettingsFragment import com.anytypeio.anytype.ui.settings.typography import com.anytypeio.anytype.ui.widgets.SelectWidgetSourceFragment @@ -446,6 +449,16 @@ class HomeScreenFragment : BaseComposeFragment(), Timber.e(e, "Error while opening date object from widgets") } } + is Navigation.OpenParticipant -> { + runCatching { + navigation().openParticipantObject( + objectId = destination.objectId, + space = destination.space + ) + }.onFailure { e -> + Timber.e(e, "Error while opening participant from widgets") + } + } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt b/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt index 47d2e3438b..c408e98060 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt @@ -60,6 +60,7 @@ import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment import com.anytypeio.anytype.ui.multiplayer.SpaceJoinRequestFragment import com.anytypeio.anytype.ui.notifications.NotificationsFragment import com.anytypeio.anytype.ui.payments.MembershipFragment +import com.anytypeio.anytype.ui.profile.ParticipantFragment import com.anytypeio.anytype.ui.sets.ObjectSetFragment import com.anytypeio.anytype.ui.sharing.SharingFragment import com.anytypeio.anytype.ui_settings.appearance.ThemeApplicator @@ -209,6 +210,19 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr Timber.e(it, "Error while data view navigation") } } + is OpenObjectNavigation.OpenParticipant -> { + runCatching { + findNavController(R.id.fragment).navigate( + R.id.participantScreen, + ParticipantFragment.args( + objectId = dest.target, + space = dest.space + ) + ) + }.onFailure { + Timber.w("Error while opening participant screen") + } + } is OpenObjectNavigation.OpenEditor -> { runCatching { findNavController(R.id.fragment).navigate( @@ -234,7 +248,7 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr OpenObjectNavigation.NonValidObject -> { toast(getString(R.string.error_non_valid_object)) } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { runCatching { findNavController(R.id.fragment).navigate( R.id.dateObjectScreen, diff --git a/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareSpaceFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareSpaceFragment.kt index b4f1c16b17..1f378f67b2 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareSpaceFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/multiplayer/ShareSpaceFragment.kt @@ -26,6 +26,7 @@ import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment import com.anytypeio.anytype.di.common.componentManager import com.anytypeio.anytype.presentation.multiplayer.ShareSpaceViewModel import com.anytypeio.anytype.presentation.multiplayer.ShareSpaceViewModel.Command +import com.anytypeio.anytype.ui.profile.ParticipantFragment import com.anytypeio.anytype.ui.settings.typography import javax.inject.Inject import timber.log.Timber @@ -69,7 +70,8 @@ class ShareSpaceFragment : BaseBottomSheetComposeFragment() { onDeleteLinkClicked = vm::onDeleteLinkClicked, incentiveState = vm.showIncentive.collectAsStateWithLifecycle().value, onIncentiveClicked = vm::onIncentiveClicked, - isLoadingInProgress = vm.isLoadingInProgress.collectAsStateWithLifecycle().value + isLoadingInProgress = vm.isLoadingInProgress.collectAsStateWithLifecycle().value, + onMemberClicked = vm::onMemberClicked ) } LaunchedEffect(Unit) { @@ -215,6 +217,19 @@ class ShareSpaceFragment : BaseBottomSheetComposeFragment() { } } } + is Command.OpenParticipantObject -> { + runCatching { + findNavController().navigate( + R.id.participantScreen, + ParticipantFragment.args( + space = command.space.id, + objectId = command.objectId + ) + ) + }.onFailure { + Timber.e(it, "Error while navigation: $command") + } + } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/profile/ParticipantFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/profile/ParticipantFragment.kt new file mode 100644 index 0000000000..e3f9fec804 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/ui/profile/ParticipantFragment.kt @@ -0,0 +1,102 @@ +package com.anytypeio.anytype.ui.profile + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.LaunchedEffect +import androidx.core.os.bundleOf +import androidx.fragment.app.viewModels +import androidx.fragment.compose.content +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.fragment.findNavController +import com.anytypeio.anytype.R +import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.primitives.SpaceId +import com.anytypeio.anytype.core_ui.features.profile.ParticipantScreen +import com.anytypeio.anytype.core_utils.ext.argString +import com.anytypeio.anytype.core_utils.ext.toast +import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment +import com.anytypeio.anytype.di.common.componentManager +import com.anytypeio.anytype.presentation.profile.ParticipantViewModel +import javax.inject.Inject +import timber.log.Timber + +class ParticipantFragment: BaseBottomSheetComposeFragment() { + + @Inject + lateinit var factory: ParticipantViewModel.Factory + + private val vm by viewModels { factory } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ) = content { + MaterialTheme { + ParticipantScreen( + uiState = vm.uiState.collectAsStateWithLifecycle().value, + onEvent = vm::onEvent + ) + LaunchedEffect(Unit) { + vm.commands.collect { command -> + proceedWithCommand(command) + } + } + } + } + + private fun proceedWithCommand(command: ParticipantViewModel.Command) { + when (command) { + ParticipantViewModel.Command.Dismiss -> { + findNavController().popBackStack() + } + is ParticipantViewModel.Command.Toast.Error -> { + toast(command.msg) + } + ParticipantViewModel.Command.OpenSettingsProfile -> { + runCatching { + findNavController().navigate( + R.id.profileSettingsScreen, + null + ) + }.onFailure { + Timber.w("Error while opening participant screen") + } + } + } + } + + override fun onStart() { + super.onStart() + vm.onStart() + } + + override fun onStop() { + super.onStop() + vm.onStop() + } + + override fun injectDependencies() { + val vmParams = ParticipantViewModel.VmParams( + objectId = argString(ARG_OBJECT_ID), + space = SpaceId(argString(ARG_SPACE)) + ) + componentManager().participantScreenComponent.get(vmParams).inject(this) + } + + override fun releaseDependencies() { + componentManager().participantScreenComponent.release() + } + + companion object ProfileScreenNavigation { + const val ARG_SPACE = "arg.participant.screen.space" + const val ARG_OBJECT_ID = "arg.participant.screen.object_id" + + fun args(space: Id, objectId: Id) = bundleOf( + ARG_SPACE to space, + ARG_OBJECT_ID to objectId + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchFragment.kt index 47691922ac..08deaee247 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/search/GlobalSearchFragment.kt @@ -27,6 +27,7 @@ import com.anytypeio.anytype.presentation.home.OpenObjectNavigation import com.anytypeio.anytype.presentation.search.GlobalSearchViewModel import com.anytypeio.anytype.ui.date.DateObjectFragment import com.anytypeio.anytype.ui.editor.EditorFragment +import com.anytypeio.anytype.ui.profile.ParticipantFragment import com.anytypeio.anytype.ui.sets.ObjectSetFragment import com.anytypeio.anytype.ui.settings.typography import javax.inject.Inject @@ -92,6 +93,19 @@ class GlobalSearchFragment : BaseBottomSheetComposeFragment() { ) ) } + is OpenObjectNavigation.OpenParticipant -> { + runCatching { + findNavController().navigate( + R.id.participantScreen, + ParticipantFragment.args( + objectId = nav.target, + space = nav.space + ) + ) + }.onFailure { + Timber.w("Error while opening participant screen") + } + } is OpenObjectNavigation.OpenChat -> { findNavController().navigate( R.id.chatScreen, @@ -104,7 +118,7 @@ class GlobalSearchFragment : BaseBottomSheetComposeFragment() { OpenObjectNavigation.NonValidObject -> { toast(getString(R.string.error_non_valid_object)) } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { runCatching { findNavController().navigate( R.id.dateObjectScreen, diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/RemoteFilesManageFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/RemoteFilesManageFragment.kt index dd6d3d3d28..d70e129000 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/settings/RemoteFilesManageFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/RemoteFilesManageFragment.kt @@ -110,6 +110,9 @@ class RemoteFilesManageFragment : BaseBottomSheetComposeFragment() { is CollectionViewModel.Command.OpenShareScreen -> { // Do nothing } + is CollectionViewModel.Command.OpenParticipant -> { + // Do nothing + } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt index 2db12c8629..1ca33220e6 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt @@ -109,7 +109,7 @@ class VaultFragment : BaseComposeFragment() { is Command.OpenProfileSettings -> { runCatching { findNavController().navigate( - R.id.profileScreen, + R.id.profileSettingsScreen, null ) }.onFailure { @@ -192,6 +192,18 @@ class VaultFragment : BaseComposeFragment() { Timber.e(e, "Error while opening date object from widgets") } } + + is Navigation.OpenParticipant -> { + runCatching { + findNavController().navigate(R.id.actionOpenSpaceFromVault) + navigation().openParticipantObject( + objectId = destination.ctx, + space = destination.space + ) + }.onFailure { e -> + Timber.e(e, "Error while opening participant object from widgets") + } + } } } diff --git a/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionFragment.kt index 6e869b3b3a..ddc473a142 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/widgets/collection/CollectionFragment.kt @@ -142,6 +142,17 @@ class CollectionFragment : BaseComposeFragment(), ObjectTypeSelectionListener { Timber.e(it, "Error while opening share screen") } } + + is Command.OpenParticipant -> { + runCatching { + navigation().openParticipantObject( + objectId = command.target, + space = command.space + ) + }.onFailure { e -> + Timber.e(e, "Error while opening participant object from Collection screen") + } + } } } diff --git a/app/src/main/res/navigation/graph.xml b/app/src/main/res/navigation/graph.xml index 313c18b2a9..e5089aa9ec 100644 --- a/app/src/main/res/navigation/graph.xml +++ b/app/src/main/res/navigation/graph.xml @@ -176,6 +176,11 @@ android:name="com.anytypeio.anytype.ui.chats.ChatReactionFragment" android:label="Chat reaction" /> + + diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/ShareSpaceScreen.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/ShareSpaceScreen.kt index 9b767bb0d8..eafc72e889 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/ShareSpaceScreen.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/multiplayer/ShareSpaceScreen.kt @@ -76,6 +76,7 @@ import com.anytypeio.anytype.core_ui.foundation.Dragger import com.anytypeio.anytype.core_ui.foundation.Section import com.anytypeio.anytype.core_ui.foundation.Toolbar import com.anytypeio.anytype.core_ui.foundation.noRippleClickable +import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable import com.anytypeio.anytype.core_ui.views.BodyRegular import com.anytypeio.anytype.core_ui.views.ButtonSecondary import com.anytypeio.anytype.core_ui.views.ButtonSize @@ -111,7 +112,8 @@ fun ShareSpaceScreen( onMoreInfoClicked: () -> Unit, onShareQrCodeClicked: () -> Unit, onDeleteLinkClicked: () -> Unit, - onIncentiveClicked: () -> Unit + onIncentiveClicked: () -> Unit, + onMemberClicked: (ObjectWrapper.SpaceMember) -> Unit ) { val nestedScrollInteropConnection = rememberNestedScrollInteropConnection() Box( @@ -237,7 +239,8 @@ fun ShareSpaceScreen( icon = member.icon, canEditEnabled = member.canEditEnabled, canReadEnabled = member.canReadEnabled, - isUser = member.isUser + isUser = member.isUser, + onMemberClicked = onMemberClicked ) } @@ -403,6 +406,7 @@ private fun SpaceMember( config: ShareSpaceMemberView.Config.Member, onCanEditClicked: () -> Unit, onCanViewClicked: () -> Unit, + onMemberClicked: (ObjectWrapper.SpaceMember) -> Unit, onRemoveMemberClicked: () -> Unit, canEditEnabled: Boolean, canReadEnabled: Boolean @@ -412,6 +416,7 @@ private fun SpaceMember( modifier = Modifier .height(72.dp) .fillMaxWidth() + .noRippleThrottledClickable{ onMemberClicked(member) } ) { Spacer(modifier = Modifier.width(16.dp)) SpaceMemberIcon( @@ -838,7 +843,8 @@ fun ShareSpaceScreenPreview() { spaceAccessType = null, incentiveState = ShareSpaceViewModel.ShareSpaceIncentiveState.VisibleSpaceReaders, onIncentiveClicked = {}, - isLoadingInProgress = false + isLoadingInProgress = false, + onMemberClicked = {} ) } @@ -860,7 +866,8 @@ private fun SpaceOwnerMemberPreview() { isCurrentUserOwner = true, canEditEnabled = true, canReadEnabled = true, - isUser = true + isUser = true, + onMemberClicked = {} ) } @@ -882,7 +889,8 @@ private fun SpaceEditorMemberPreview() { isCurrentUserOwner = true, canReadEnabled = true, canEditEnabled = true, - isUser = true + isUser = true, + onMemberClicked = {} ) } @@ -904,6 +912,7 @@ private fun SpaceMemberLongNamePreview() { isCurrentUserOwner = true, canReadEnabled = true, canEditEnabled = true, - isUser = true + isUser = true, + onMemberClicked = {} ) } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/profile/ParticipantScreen.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/profile/ParticipantScreen.kt new file mode 100644 index 0000000000..259568b724 --- /dev/null +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/features/profile/ParticipantScreen.kt @@ -0,0 +1,230 @@ +package com.anytypeio.anytype.core_ui.features.profile + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Text +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.rememberModalBottomSheetState +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.layout.ContentScale +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.anytypeio.anytype.core_ui.R +import com.anytypeio.anytype.core_ui.common.DefaultPreviews +import com.anytypeio.anytype.core_ui.foundation.Dragger +import com.anytypeio.anytype.core_ui.foundation.noRippleClickable +import com.anytypeio.anytype.core_ui.views.AvatarTitle +import com.anytypeio.anytype.core_ui.views.ButtonSecondary +import com.anytypeio.anytype.core_ui.views.ButtonSize +import com.anytypeio.anytype.core_ui.views.Caption1Regular +import com.anytypeio.anytype.core_ui.views.HeadlineHeading +import com.anytypeio.anytype.core_ui.views.PreviewTitle2Regular +import com.anytypeio.anytype.presentation.profile.ParticipantEvent +import com.anytypeio.anytype.presentation.profile.ParticipantViewModel.UiParticipantScreenState +import com.anytypeio.anytype.presentation.profile.ProfileIconView +import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi +import com.bumptech.glide.integration.compose.GlideImage + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ParticipantScreen( + uiState: UiParticipantScreenState, + onEvent: (ParticipantEvent) -> Unit +) { + + val bottomSheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = true + ) + + ModalBottomSheet( + modifier = Modifier + .fillMaxWidth() + .padding(start = 12.dp, end = 12.dp, bottom = 32.dp), + dragHandle = { + Column { + Spacer(modifier = Modifier.height(6.dp)) + Dragger() + Spacer(modifier = Modifier.height(6.dp)) + } + }, + scrimColor = colorResource(id = R.color.modal_screen_outside_background), + containerColor = colorResource(id = R.color.background_secondary), + shape = RoundedCornerShape(20.dp), + sheetState = bottomSheetState, + onDismissRequest = { + onEvent(ParticipantEvent.OnDismiss) + }, + content = { + if (uiState is UiParticipantScreenState.Data) { + val (spacer, iconSize) = if (uiState.description.isNullOrBlank()) { + 68.dp to 184.dp + } else { + 48.dp to 128.dp + } + Spacer(modifier = Modifier.height(spacer)) + ImageBlock( + modifier = Modifier + .size(iconSize) + .align(Alignment.CenterHorizontally), + name = uiState.name, + icon = uiState.icon, + ) { } + Spacer(modifier = Modifier.height(12.dp)) + Title( + modifier = Modifier.align(Alignment.CenterHorizontally), + name = uiState.name + ) + Spacer(modifier = Modifier.height(4.dp)) + if (uiState.identity != null) { + AnyIdentity( + modifier = Modifier + .padding(horizontal = 32.dp) + .align(Alignment.CenterHorizontally), + identity = uiState.identity!! + ) + Spacer(modifier = Modifier.height(4.dp)) + } + if (!uiState.description.isNullOrBlank()) { + Description( + modifier = Modifier + .padding(horizontal = 32.dp) + .align(Alignment.CenterHorizontally), + description = uiState.description!! + ) + } + if (uiState.isOwner) { + ButtonSecondary( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp) + .padding(top = 16.dp) + .align(Alignment.CenterHorizontally), + text = stringResource(R.string.profile_view_edit_button), + size = ButtonSize.LargeSecondary, + onClick = { onEvent(ParticipantEvent.OnButtonClick) } + ) + } else { + Spacer( + modifier = Modifier + .height(64.dp) + .background(color = colorResource(R.color.palette_dark_teal)) + ) + } + } + }, + ) +} + +@OptIn(ExperimentalGlideComposeApi::class) +@Composable +private fun ImageBlock( + modifier: Modifier, + name: String, + icon: ProfileIconView, + fontSize: TextUnit = 24.sp, + onProfileIconClick: () -> Unit +) { + when (icon) { + is ProfileIconView.Image -> { + GlideImage( + model = icon.url, + contentDescription = "Custom image profile", + contentScale = ContentScale.Crop, + modifier = modifier + .clip(shape = CircleShape) + .noRippleClickable { + onProfileIconClick.invoke() + } + ) + } + + else -> { + val nameFirstChar = if (name.isEmpty()) { + stringResource(id = R.string.account_default_name) + } else { + name.first().uppercaseChar().toString() + } + Box( + modifier = modifier + .clip(CircleShape) + .background(colorResource(id = R.color.shape_tertiary)) + .noRippleClickable { + onProfileIconClick.invoke() + } + ) { + Text( + text = nameFirstChar, + style = AvatarTitle.copy( + color = colorResource(id = R.color.glyph_active), + fontSize = fontSize + ), + modifier = Modifier.align(Alignment.Center) + ) + } + } + } +} + +@Composable +private fun Title(modifier: Modifier, name: String) { + Text( + modifier = modifier, + text = name, + style = HeadlineHeading, + color = colorResource(id = R.color.text_primary), + maxLines = 3 + ) +} + +@Composable +private fun AnyIdentity(modifier: Modifier, identity: String) { + Text( + modifier = modifier, + text = identity, + style = Caption1Regular, + color = colorResource(id = R.color.text_secondary), + maxLines = 2, + textAlign = TextAlign.Center + ) +} + +@Composable +private fun Description(modifier: Modifier, description: String) { + Text( + modifier = modifier, + text = description, + style = PreviewTitle2Regular, + color = colorResource(id = R.color.text_primary), + textAlign = TextAlign.Center + ) +} + +@DefaultPreviews +@Composable +fun ParticipantScreenPreview() { + ParticipantScreen( + uiState = UiParticipantScreenState.Data( + name = "Ivanov Konstantin", + icon = ProfileIconView.Emoji(""), + description = "some desc", + isOwner = true + ), + onEvent = {} + ) +} \ No newline at end of file diff --git a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt index c465846354..f0f7bbcc1a 100644 --- a/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt +++ b/feature-all-content/src/main/java/com/anytypeio/anytype/feature_allcontent/presentation/AllContentViewModel.kt @@ -697,6 +697,15 @@ class AllContentViewModel( ) } + is OpenObjectNavigation.OpenParticipant -> { + commands.emit( + NavigateToParticipant( + objectId = navigation.target, + space = navigation.space + ) + ) + } + is OpenObjectNavigation.OpenEditor -> { commands.emit( Command.NavigateToEditor( @@ -721,7 +730,7 @@ class AllContentViewModel( OpenObjectNavigation.NonValidObject -> { Timber.e("Object id is missing") } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { commands.emit( NavigateToEditor( id = navigation.target, @@ -1007,6 +1016,7 @@ class AllContentViewModel( data class NavigateToEditor(val id: Id, val space: Id) : Command() data class NavigateToSetOrCollection(val id: Id, val space: Id) : Command() data class NavigateToBin(val space: Id) : Command() + data class NavigateToParticipant(val objectId: Id, val space: Id) : Command() data class NavigateToDateObject(val objectId: Id, val space: Id) : Command() sealed class SendToast: Command() { data class Error(val message: String) : SendToast() diff --git a/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectCommand.kt b/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectCommand.kt index 5803bb59c1..ebf8f689ae 100644 --- a/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectCommand.kt +++ b/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectCommand.kt @@ -8,6 +8,7 @@ sealed class DateObjectCommand { data class NavigateToEditor(val id: Id, val space: SpaceId) : DateObjectCommand() data class NavigateToSetOrCollection(val id: Id, val space: SpaceId) : DateObjectCommand() data class NavigateToDateObject(val objectId: Id, val space: SpaceId) : DateObjectCommand() + data class NavigateToParticipant(val objectId: Id, val space: SpaceId) : DateObjectCommand() data object TypeSelectionScreen : DateObjectCommand() data object ExitToSpaceWidgets : DateObjectCommand() sealed class SendToast : DateObjectCommand() { diff --git a/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectViewModel.kt b/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectViewModel.kt index 7bba68faf7..1aa2efd99c 100644 --- a/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectViewModel.kt +++ b/feature-date/src/main/java/com/anytypeio/anytype/feature_date/viewmodel/DateObjectViewModel.kt @@ -631,6 +631,15 @@ class DateObjectViewModel( ) } + is OpenObjectNavigation.OpenParticipant -> { + effects.emit( + DateObjectCommand.NavigateToParticipant( + objectId = navigation.target, + space = SpaceId(navigation.space) + ) + ) + } + is OpenObjectNavigation.OpenEditor -> { effects.emit( DateObjectCommand.NavigateToEditor( @@ -658,7 +667,7 @@ class DateObjectViewModel( Timber.e("Object id is missing") } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { effects.emit( DateObjectCommand.NavigateToEditor( id = navigation.target, diff --git a/ui-settings/build.gradle b/feature-ui-settings/build.gradle similarity index 100% rename from ui-settings/build.gradle rename to feature-ui-settings/build.gradle diff --git a/ui-settings/src/main/AndroidManifest.xml b/feature-ui-settings/src/main/AndroidManifest.xml similarity index 100% rename from ui-settings/src/main/AndroidManifest.xml rename to feature-ui-settings/src/main/AndroidManifest.xml diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppScreen.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppScreen.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppScreen.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppScreen.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppViewModel.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppViewModel.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppViewModel.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/about/AboutAppViewModel.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/LogoutWarningViewModel.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/LogoutWarningViewModel.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/LogoutWarningViewModel.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/LogoutWarningViewModel.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileScreen.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/account/ProfileSettingsViewModel.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceScreen.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceScreen.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceScreen.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceScreen.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceViewModel.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceViewModel.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceViewModel.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/AppearanceViewModel.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/ThemeApplicator.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/ThemeApplicator.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/ThemeApplicator.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/appearance/ThemeApplicator.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/fstorage/FilesStorageScreen.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/MainSettingScreen.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/Views.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/Views.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/Views.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/main/Views.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SegmentLine.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SegmentLine.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SegmentLine.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SegmentLine.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/Settings.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/Settings.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/Settings.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/Settings.kt diff --git a/ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SpaceStorageScreen.kt b/feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SpaceStorageScreen.kt similarity index 100% rename from ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SpaceStorageScreen.kt rename to feature-ui-settings/src/main/java/com/anytypeio/anytype/ui_settings/space/SpaceStorageScreen.kt diff --git a/ui-settings/src/main/res/drawable/ic_about.xml b/feature-ui-settings/src/main/res/drawable/ic_about.xml similarity index 100% rename from ui-settings/src/main/res/drawable/ic_about.xml rename to feature-ui-settings/src/main/res/drawable/ic_about.xml diff --git a/ui-settings/src/main/res/drawable/ic_appearance.xml b/feature-ui-settings/src/main/res/drawable/ic_appearance.xml similarity index 100% rename from ui-settings/src/main/res/drawable/ic_appearance.xml rename to feature-ui-settings/src/main/res/drawable/ic_appearance.xml diff --git a/ui-settings/src/main/res/drawable/ic_debug.xml b/feature-ui-settings/src/main/res/drawable/ic_debug.xml similarity index 100% rename from ui-settings/src/main/res/drawable/ic_debug.xml rename to feature-ui-settings/src/main/res/drawable/ic_debug.xml diff --git a/ui-settings/src/main/res/drawable/ic_file_storage.xml b/feature-ui-settings/src/main/res/drawable/ic_file_storage.xml similarity index 100% rename from ui-settings/src/main/res/drawable/ic_file_storage.xml rename to feature-ui-settings/src/main/res/drawable/ic_file_storage.xml diff --git a/ui-settings/src/main/res/drawable/ic_keychain_phrase.xml b/feature-ui-settings/src/main/res/drawable/ic_keychain_phrase.xml similarity index 100% rename from ui-settings/src/main/res/drawable/ic_keychain_phrase.xml rename to feature-ui-settings/src/main/res/drawable/ic_keychain_phrase.xml diff --git a/ui-settings/src/main/res/drawable/ic_personalization.xml b/feature-ui-settings/src/main/res/drawable/ic_personalization.xml similarity index 100% rename from ui-settings/src/main/res/drawable/ic_personalization.xml rename to feature-ui-settings/src/main/res/drawable/ic_personalization.xml diff --git a/ui-settings/src/main/res/values/strings.xml b/feature-ui-settings/src/main/res/values/strings.xml similarity index 100% rename from ui-settings/src/main/res/values/strings.xml rename to feature-ui-settings/src/main/res/values/strings.xml diff --git a/localization/src/main/res/values/strings.xml b/localization/src/main/res/values/strings.xml index 75d4add7e3..f1f9aa17ee 100644 --- a/localization/src/main/res/values/strings.xml +++ b/localization/src/main/res/values/strings.xml @@ -1421,6 +1421,7 @@ 1. Tap the Space widget to access settings 2. Open Share section 3. Generate an invite link and share it + Edit Profile %1$d member diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt index f485902d9b..293d37878c 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt @@ -3226,8 +3226,7 @@ class EditorViewModel( ObjectType.Layout.BASIC, ObjectType.Layout.NOTE, ObjectType.Layout.TODO, - ObjectType.Layout.BOOKMARK, - ObjectType.Layout.PARTICIPANT -> { + ObjectType.Layout.BOOKMARK -> { proceedWithOpeningObject(target = target) } in SupportedLayouts.fileLayouts -> { @@ -3260,6 +3259,16 @@ class EditorViewModel( ) ) } + ObjectType.Layout.PARTICIPANT -> { + navigate( + EventWrapper( + OpenParticipant( + objectId = target, + space = vmParams.space.id + ) + ) + ) + } else -> { sendToast("Cannot open object with layout: ${wrapper.layout}") } @@ -4438,6 +4447,16 @@ class EditorViewModel( ) ) } + is OpenObjectNavigation.OpenParticipant -> { + navigate( + EventWrapper( + AppNavigation.Command.OpenParticipant( + objectId = navigation.target, + space = navigation.space + ) + ) + ) + } is OpenObjectNavigation.OpenEditor -> { navigate( EventWrapper( @@ -4457,7 +4476,7 @@ class EditorViewModel( OpenObjectNavigation.NonValidObject -> { sendToast("Object id is missing") } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { navigate( EventWrapper( OpenDateObject( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt index ee8054b155..09571fb512 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt @@ -1436,7 +1436,7 @@ class HomeScreenViewModel( OpenObjectNavigation.NonValidObject -> { sendToast("Object id is missing") } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { navigate( destination = Navigation.OpenDateObject( ctx = navigation.target, @@ -1444,6 +1444,14 @@ class HomeScreenViewModel( ) ) } + is OpenObjectNavigation.OpenParticipant -> { + navigate( + Navigation.OpenParticipant( + objectId = navigation.target, + space = navigation.space + ) + ) + } } } @@ -2169,6 +2177,7 @@ class HomeScreenViewModel( data object OpenSpaceSwitcher: Navigation() data class OpenAllContent(val space: Id) : Navigation() data class OpenDateObject(val ctx: Id, val space: Id) : Navigation() + data class OpenParticipant(val objectId: Id, val space: Id) : Navigation() } class Factory @Inject constructor( @@ -2402,7 +2411,8 @@ sealed class OpenObjectNavigation { data class UnexpectedLayoutError(val layout: ObjectType.Layout?): OpenObjectNavigation() data object NonValidObject: OpenObjectNavigation() data class OpenChat(val target: Id, val space: Id): OpenObjectNavigation() - data class OpenDataObject(val target: Id, val space: Id): OpenObjectNavigation() + data class OpenDateObject(val target: Id, val space: Id): OpenObjectNavigation() + data class OpenParticipant(val target: Id, val space: Id): OpenObjectNavigation() } fun ObjectWrapper.Basic.navigation() : OpenObjectNavigation { @@ -2411,8 +2421,7 @@ fun ObjectWrapper.Basic.navigation() : OpenObjectNavigation { ObjectType.Layout.BASIC, ObjectType.Layout.NOTE, ObjectType.Layout.TODO, - ObjectType.Layout.BOOKMARK, - ObjectType.Layout.PARTICIPANT -> { + ObjectType.Layout.BOOKMARK -> { OpenObjectNavigation.OpenEditor( target = id, space = requireNotNull(spaceId) @@ -2452,7 +2461,13 @@ fun ObjectWrapper.Basic.navigation() : OpenObjectNavigation { ) } ObjectType.Layout.DATE -> { - OpenObjectNavigation.OpenDataObject( + OpenObjectNavigation.OpenDateObject( + target = id, + space = requireNotNull(spaceId) + ) + } + ObjectType.Layout.PARTICIPANT -> { + OpenObjectNavigation.OpenParticipant( target = id, space = requireNotNull(spaceId) ) @@ -2471,8 +2486,7 @@ fun ObjectType.Layout.navigation( ObjectType.Layout.BASIC, ObjectType.Layout.NOTE, ObjectType.Layout.TODO, - ObjectType.Layout.BOOKMARK, - ObjectType.Layout.PARTICIPANT -> { + ObjectType.Layout.BOOKMARK -> { OpenObjectNavigation.OpenEditor( target = target, space = space @@ -2504,7 +2518,13 @@ fun ObjectType.Layout.navigation( ) } ObjectType.Layout.DATE -> { - OpenObjectNavigation.OpenDataObject( + OpenObjectNavigation.OpenDateObject( + target = target, + space = space + ) + } + ObjectType.Layout.PARTICIPANT -> { + OpenObjectNavigation.OpenParticipant( target = target, space = space ) diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt index 30cde6a4ec..27ba485717 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/multiplayer/ShareSpaceViewModel.kt @@ -465,6 +465,17 @@ class ShareSpaceViewModel( } } + fun onMemberClicked(member: ObjectWrapper.SpaceMember) { + viewModelScope.launch { + commands.emit( + Command.OpenParticipantObject( + objectId = member.id, + space = vmParams.space + ) + ) + } + } + fun onIncentiveClicked() { val activeTier = (_activeTier.value as? ActiveTierState.Success) ?: return val isPossibleToUpgrade = activeTier.tierId.isPossibleToUpgradeNumberOfSpaceMembers() @@ -599,6 +610,7 @@ class ShareSpaceViewModel( data object Dismiss : Command() data object ShowMembershipScreen : Command() data object ShowMembershipUpgradeScreen : Command() + data class OpenParticipantObject(val objectId: Id, val space: SpaceId) : Command() } sealed class ShareSpaceIncentiveState { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt index 6f4351a3c3..38d3a22b39 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/navigation/AppNavigation.kt @@ -37,6 +37,11 @@ interface AppNavigation { space: Id ) + fun openParticipantObject( + objectId: Id, + space: Id + ) + fun launchDocument(target: String, space: Id) fun launchCollections(subscription: Subscription, space: Id) fun launchObjectSet(target: Id, space: Id) @@ -103,6 +108,11 @@ interface AppNavigation { val space: Id ) : Command() + data class OpenParticipant( + val objectId: Id, + val space: Id + ): Command() + data class LaunchObjectSet(val target: Id, val space: Id) : Command() object OpenUpdateAppScreen : Command() diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ParticipantEvent.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ParticipantEvent.kt new file mode 100644 index 0000000000..9a8a46cd22 --- /dev/null +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ParticipantEvent.kt @@ -0,0 +1,6 @@ +package com.anytypeio.anytype.presentation.profile + +sealed class ParticipantEvent{ + data object OnDismiss: ParticipantEvent() + data object OnButtonClick: ParticipantEvent() +} \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ParticipantViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ParticipantViewModel.kt new file mode 100644 index 0000000000..89eea3a509 --- /dev/null +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ParticipantViewModel.kt @@ -0,0 +1,172 @@ +package com.anytypeio.anytype.presentation.profile + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import com.anytypeio.anytype.analytics.base.Analytics +import com.anytypeio.anytype.analytics.base.EventsDictionary +import com.anytypeio.anytype.analytics.base.sendEvent +import com.anytypeio.anytype.core_models.Id +import com.anytypeio.anytype.core_models.Relations +import com.anytypeio.anytype.core_models.membership.MembershipStatus +import com.anytypeio.anytype.core_models.primitives.SpaceId +import com.anytypeio.anytype.domain.config.ConfigStorage +import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams +import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer +import com.anytypeio.anytype.domain.misc.UrlBuilder +import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider +import com.anytypeio.anytype.domain.primitives.FieldParser +import com.anytypeio.anytype.presentation.membership.provider.MembershipProvider +import com.anytypeio.anytype.presentation.search.ObjectSearchConstants +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch + +class ParticipantViewModel( + private val vmParams: VmParams, + private val analytics: Analytics, + private val urlBuilder: UrlBuilder, + private val membershipProvider: MembershipProvider, + private val subscriptionContainer: StorelessSubscriptionContainer, + private val fieldsParser: FieldParser, + private val userPermissionProvider: UserPermissionProvider, + private val configStorage: ConfigStorage +) : ViewModel() { + + val uiState = MutableStateFlow(UiParticipantScreenState.Idle) + + val membershipStatusState = MutableStateFlow(null) + val commands = MutableSharedFlow(0) + + private val permission = MutableStateFlow(userPermissionProvider.get(vmParams.space)) + + init { + proceedWithObservingPermissions() + viewModelScope.launch { + analytics.sendEvent( + eventName = EventsDictionary.screenSettingsAccount + ) + } + viewModelScope.launch { + membershipProvider.status().collect { status -> + membershipStatusState.value = status + } + } + } + + fun onStart() { + viewModelScope.launch { + val params = StoreSearchByIdsParams( + space = vmParams.space, + subscription = "$SUB_ID-${vmParams.objectId}", + targets = listOf(vmParams.objectId), + keys = ObjectSearchConstants.spaceMemberKeys + ) + subscriptionContainer.subscribe(params) + .collect { participant -> + if (participant.isNotEmpty()) { + val obj = participant.first() + val identityProfileLink = obj.getSingleValue(Relations.IDENTITY_PROFILE_LINK) + uiState.value = UiParticipantScreenState.Data( + name = fieldsParser.getObjectName(obj), + icon = obj.profileIcon(urlBuilder), + isOwner = configStorage.getOrNull()?.profile == identityProfileLink, + identity = obj.getSingleValue(Relations.IDENTITY), + description = if (obj.description?.isBlank() == true) { + null + } else { + obj.description + } + ) + } + } + } + } + + private fun proceedWithObservingPermissions() { + viewModelScope.launch { + userPermissionProvider + .observe(space = vmParams.space) + .collect { result -> + permission.value = result + } + } + } + + fun onStop() { + viewModelScope.launch{ + subscriptionContainer.unsubscribe(listOf("$SUB_ID-${vmParams.objectId}")) + } + } + + fun onEvent(event: ParticipantEvent) { + when (event) { + ParticipantEvent.OnDismiss -> { + viewModelScope.launch { + commands.emit(Command.Dismiss) + } + } + + ParticipantEvent.OnButtonClick -> { + viewModelScope.launch { + commands.emit(Command.OpenSettingsProfile) + } + } + } + } + + sealed class UiParticipantScreenState { + data object Idle : UiParticipantScreenState() + class Data( + val name: String, + val icon: ProfileIconView, + val description: String? = null, + val identity: String? = null, + val isOwner: Boolean + ) : UiParticipantScreenState() + } + + data class VmParams( + val objectId: Id, + val space: SpaceId + ) + + sealed class Command { + sealed class Toast : Command() { + data class Error(val msg: String) : Toast() + } + + data object Dismiss : Command() + data object OpenSettingsProfile : Command() + } + + companion object { + const val SUB_ID = "Participant-subscription" + } + + class Factory @Inject constructor( + private val vmParams: VmParams, + private val analytics: Analytics, + private val urlBuilder: UrlBuilder, + private val membershipProvider: MembershipProvider, + private val subscriptionContainer: StorelessSubscriptionContainer, + private val fieldsParser: FieldParser, + private val userPermissionProvider: UserPermissionProvider, + private val configStorage: ConfigStorage + ) : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + return ParticipantViewModel( + vmParams = vmParams, + analytics = analytics, + urlBuilder = urlBuilder, + membershipProvider = membershipProvider, + subscriptionContainer = subscriptionContainer, + fieldsParser = fieldsParser, + userPermissionProvider = userPermissionProvider, + configStorage = configStorage + ) as T + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ProfileView.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ProfileView.kt deleted file mode 100644 index b0a14a1a6d..0000000000 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/profile/ProfileView.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.anytypeio.anytype.presentation.profile - -import com.anytypeio.anytype.core_models.Url - -data class ProfileView( - val name: String, - val avatar: Url? = null, -) \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt index ee651d2020..d9b162cbca 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchConstants.kt @@ -1276,7 +1276,9 @@ object ObjectSearchConstants { Relations.SPACE_ID, Relations.TARGET_SPACE_ID, Relations.IDENTITY, + Relations.IDENTITY_PROFILE_LINK, Relations.NAME, + Relations.DESCRIPTION, Relations.ICON_IMAGE, Relations.PARTICIPANT_STATUS, Relations.PARTICIPANT_PERMISSIONS, @@ -1301,29 +1303,6 @@ object ObjectSearchConstants { ) //region SPACE VIEW - - fun getSpaceViewSearchParams( - techSpaceId: Id, - subscription: String, - targetSpaceId: Id - ): StoreSearchParams { - return StoreSearchParams( - space = SpaceId(techSpaceId), - subscription = subscription, - keys = spaceViewKeys, - limit = 1, - filters = buildList { - add( - DVFilter( - relation = Relations.TARGET_SPACE_ID, - value = targetSpaceId, - condition = DVFilterCondition.EQUAL - ) - ) - } - ) - } - fun getSpaceMembersSearchParams( subscription: String, space: SpaceId, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt index adb216d28a..220c7c7c08 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/search/ObjectSearchViewModel.kt @@ -169,8 +169,7 @@ open class ObjectSearchViewModel( ObjectType.Layout.NOTE, ObjectType.Layout.FILE, ObjectType.Layout.IMAGE, - ObjectType.Layout.BOOKMARK, - ObjectType.Layout.PARTICIPANT -> { + ObjectType.Layout.BOOKMARK -> { val obj = objects .value .getOrNull() @@ -184,6 +183,20 @@ open class ObjectSearchViewModel( ) ) } + ObjectType.Layout.PARTICIPANT -> { + val obj = objects + .value + .getOrNull() + ?.find { obj -> obj.id == view.id } + navigate( + EventWrapper( + AppNavigation.Command.OpenParticipant( + objectId = target, + space = requireNotNull(obj?.spaceId) + ) + ) + ) + } ObjectType.Layout.PROFILE -> { val obj = objects .value diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt index fd1dfdf7f7..445c00507a 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt @@ -1468,11 +1468,20 @@ class ObjectSetViewModel( ObjectType.Layout.VIDEO, ObjectType.Layout.AUDIO, ObjectType.Layout.PDF, - ObjectType.Layout.BOOKMARK, - ObjectType.Layout.PARTICIPANT -> proceedWithOpeningObject( + ObjectType.Layout.BOOKMARK -> proceedWithOpeningObject( target = target, space = space ) + ObjectType.Layout.PARTICIPANT -> { + navigate( + EventWrapper( + AppNavigation.Command.OpenParticipant( + objectId = target, + space = space + ) + ) + ) + } ObjectType.Layout.PROFILE -> proceedWithOpeningObject( target = identityProfileLink ?: target, space = space diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt index 09b10859ca..c328ab488e 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/vault/VaultViewModel.kt @@ -37,6 +37,7 @@ import com.anytypeio.anytype.presentation.navigation.NavigationViewModel import com.anytypeio.anytype.presentation.spaces.SpaceGradientProvider import com.anytypeio.anytype.presentation.spaces.SpaceIconView import com.anytypeio.anytype.presentation.spaces.spaceIcon +import com.anytypeio.anytype.presentation.vault.VaultViewModel.Navigation.* import javax.inject.Inject import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow @@ -281,7 +282,7 @@ class VaultViewModel( when(navigation) { is OpenObjectNavigation.OpenDataView -> { navigate( - Navigation.OpenSet( + OpenSet( ctx = navigation.target, space = navigation.space, view = null @@ -290,7 +291,7 @@ class VaultViewModel( } is OpenObjectNavigation.OpenEditor -> { navigate( - Navigation.OpenObject( + OpenObject( ctx = navigation.target, space = navigation.space ) @@ -298,7 +299,7 @@ class VaultViewModel( } is OpenObjectNavigation.OpenChat -> { navigate( - Navigation.OpenChat( + OpenChat( ctx = navigation.target, space = navigation.space ) @@ -310,9 +311,17 @@ class VaultViewModel( OpenObjectNavigation.NonValidObject -> { sendToast("Object id is missing") } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { navigate( - Navigation.OpenDateObject( + OpenDateObject( + ctx = navigation.target, + space = navigation.space + ) + ) + } + is OpenObjectNavigation.OpenParticipant -> { + navigate( + OpenParticipant( ctx = navigation.target, space = navigation.space ) @@ -385,6 +394,7 @@ class VaultViewModel( data class OpenObject(val ctx: Id, val space: Id) : Navigation() data class OpenSet(val ctx: Id, val space: Id, val view: Id?) : Navigation() data class OpenDateObject(val ctx: Id, val space: Id) : Navigation() + data class OpenParticipant(val ctx: Id, val space: Id) : Navigation() } companion object { diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt index 53e88e6888..d2909059c9 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/CollectionViewModel.kt @@ -435,7 +435,6 @@ class CollectionViewModel( val target = view.id when (view.layout) { ObjectType.Layout.PROFILE, - ObjectType.Layout.PARTICIPANT, ObjectType.Layout.BASIC, ObjectType.Layout.TODO, ObjectType.Layout.NOTE, @@ -457,6 +456,14 @@ class CollectionViewModel( ) ) } + ObjectType.Layout.PARTICIPANT -> { + commands.emit( + Command.OpenParticipant( + target = target, + space = view.space + ) + ) + } else -> { Timber.e("Unexpected layout: ${view.layout}") } @@ -934,7 +941,7 @@ class CollectionViewModel( OpenObjectNavigation.NonValidObject -> { toasts.emit("Object id is missing") } - is OpenObjectNavigation.OpenDataObject -> { + is OpenObjectNavigation.OpenDateObject -> { commands.emit( OpenDateObject( target = navigation.target, @@ -942,6 +949,14 @@ class CollectionViewModel( ) ) } + is OpenObjectNavigation.OpenParticipant -> { + commands.emit( + OpenParticipant( + target = navigation.target, + space = navigation.space + ) + ) + } } } @@ -1046,6 +1061,7 @@ class CollectionViewModel( data class LaunchObjectSet(val target: Id, val space: Id) : Command() data class OpenChat(val target: Id, val space: Id) : Command() data class OpenDateObject(val target: Id, val space: Id) : Command() + data class OpenParticipant(val target: Id, val space: Id) : Command() data class OpenShareScreen(val space: SpaceId) : Command() data object ToDesktop : Command() diff --git a/settings.gradle b/settings.gradle index e86afd0262..d5aa4aa027 100644 --- a/settings.gradle +++ b/settings.gradle @@ -59,7 +59,7 @@ include ':app', ':libs', ':feature-date' -include ':ui-settings' +include ':feature-ui-settings' include ':crash-reporting' include ':localization' include ':payments'