diff --git a/app/build.gradle b/app/build.gradle index bc85ca885f..ed3b69ec43 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -171,6 +171,7 @@ dependencies { implementation project(':ui-settings') implementation project(':crash-reporting') implementation project(':payments') + implementation project(':gallery-experience') //Compile time dependencies kapt libs.daggerCompiler 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 371e84b9f3..3a199e90dd 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 @@ -60,6 +60,7 @@ import com.anytypeio.anytype.di.feature.ViewerFilterModule import com.anytypeio.anytype.di.feature.ViewerSortModule import com.anytypeio.anytype.di.feature.auth.DaggerDeletedAccountComponent import com.anytypeio.anytype.di.feature.cover.UnsplashModule +import com.anytypeio.anytype.di.feature.gallery.DaggerGalleryInstallationComponent import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent import com.anytypeio.anytype.di.feature.library.DaggerLibraryComponent import com.anytypeio.anytype.di.feature.multiplayer.DaggerRequestJoinSpaceComponent @@ -1075,6 +1076,10 @@ class ComponentManager( DaggerPaymentsComponent.factory().create(findComponentDependencies()) } + val galleryInstallationsComponent = Component { + DaggerGalleryInstallationComponent.factory().create(findComponentDependencies()) + } + class Component(private val builder: () -> T) { private var instance: T? = null diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt new file mode 100644 index 0000000000..a9e175b892 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/gallery/GalleryInstallationDi.kt @@ -0,0 +1,48 @@ +package com.anytypeio.anytype.di.feature.gallery + +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.gallery_experience.viewmodel.GalleryInstallationViewModelFactory +import com.anytypeio.anytype.ui.gallery.GalleryInstallationFragment +import dagger.Binds +import dagger.Component +import dagger.Module + +@Component( + dependencies = [GalleryInstallationComponentDependencies::class], + modules = [ + GalleryInstallationModule::class, + GalleryInstallationModule.Declarations::class + ] +) +@PerScreen +interface GalleryInstallationComponent { + + @Component.Factory + interface Factory { + fun create(dependencies: GalleryInstallationComponentDependencies): GalleryInstallationComponent + } + + fun inject(fragment: GalleryInstallationFragment) +} + +@Module +object GalleryInstallationModule { + + @Module + interface Declarations { + + @PerScreen + @Binds + fun bindViewModelFactory( + factory: GalleryInstallationViewModelFactory + ): ViewModelProvider.Factory + + } +} + +interface GalleryInstallationComponentDependencies : ComponentDependencies { + fun analytics(): Analytics +} \ 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 2b1919c64a..5e0dc3fea0 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 @@ -19,6 +19,7 @@ import com.anytypeio.anytype.di.feature.ObjectTypeChangeSubComponent import com.anytypeio.anytype.di.feature.PersonalizationSettingsSubComponent import com.anytypeio.anytype.di.feature.SplashDependencies import com.anytypeio.anytype.di.feature.auth.DeletedAccountDependencies +import com.anytypeio.anytype.di.feature.gallery.GalleryInstallationComponentDependencies import com.anytypeio.anytype.di.feature.home.HomeScreenDependencies import com.anytypeio.anytype.di.feature.library.LibraryDependencies import com.anytypeio.anytype.di.feature.multiplayer.RequestJoinSpaceDependencies @@ -112,7 +113,8 @@ interface MainComponent : ShareSpaceDependencies, SpaceJoinRequestDependencies, RequestJoinSpaceDependencies, - PaymentsComponentDependencies + PaymentsComponentDependencies, + GalleryInstallationComponentDependencies { fun inject(app: AndroidApplication) @@ -308,4 +310,9 @@ private abstract class ComponentDependenciesModule private constructor() { @IntoMap @ComponentDependenciesKey(RequestJoinSpaceDependencies::class) abstract fun provideRequestToJoinSpaceDependencies(component: MainComponent): ComponentDependencies + + @Binds + @IntoMap + @ComponentDependenciesKey(GalleryInstallationComponentDependencies::class) + abstract fun provideGalleryInstallationDependencies(component: MainComponent): ComponentDependencies } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/gallery/GalleryInstallationFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/gallery/GalleryInstallationFragment.kt new file mode 100644 index 0000000000..0a3b9a8573 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/ui/gallery/GalleryInstallationFragment.kt @@ -0,0 +1,119 @@ +package com.anytypeio.anytype.ui.gallery + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.fragment.app.viewModels +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.anytypeio.anytype.core_ui.common.ComposeDialogView +import com.anytypeio.anytype.core_utils.ext.subscribe +import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment +import com.anytypeio.anytype.di.common.componentManager +import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationNavigation +import com.anytypeio.anytype.gallery_experience.screens.GalleryInstallationScreen +import com.anytypeio.anytype.gallery_experience.screens.GalleryInstallationSpacesScreen +import com.anytypeio.anytype.gallery_experience.viewmodel.GalleryInstallationViewModel +import com.anytypeio.anytype.gallery_experience.viewmodel.GalleryInstallationViewModelFactory +import com.google.accompanist.navigation.material.BottomSheetNavigator +import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi +import com.google.accompanist.navigation.material.ModalBottomSheetLayout +import com.google.accompanist.navigation.material.bottomSheet +import com.google.accompanist.navigation.material.rememberBottomSheetNavigator +import javax.inject.Inject + +class GalleryInstallationFragment : BaseBottomSheetComposeFragment() { + + @Inject + lateinit var factory: GalleryInstallationViewModelFactory + private val vm by viewModels { factory } + private lateinit var navController: NavHostController + + @OptIn(ExperimentalMaterialNavigationApi::class) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return ComposeDialogView(context = requireContext(), dialog = requireDialog()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + MaterialTheme { + val bottomSheetNavigator = rememberBottomSheetNavigator() + navController = rememberNavController(bottomSheetNavigator) + SetupNavigation(bottomSheetNavigator, navController) + } + } + } + } + + override fun onStart() { + super.onStart() + jobs += subscribe(vm.command) { command -> + when (command) { + GalleryInstallationNavigation.Main -> navController.navigate( + GalleryInstallationNavigation.Main.route + ) + + GalleryInstallationNavigation.Dismiss -> navController.popBackStack() + else -> {} + } + } + } + + @OptIn(ExperimentalMaterialNavigationApi::class) + @Composable + private fun SetupNavigation( + bottomSheetNavigator: BottomSheetNavigator, + navController: NavHostController + ) { + ModalBottomSheetLayout(bottomSheetNavigator = bottomSheetNavigator) { + NavigationGraph(navController = navController) + } + } + + @OptIn(ExperimentalMaterialNavigationApi::class) + @Composable + private fun NavigationGraph(navController: NavHostController) { + NavHost( + navController = navController, + startDestination = GalleryInstallationNavigation.Main.route + ) { + composable(GalleryInstallationNavigation.Main.route) { + InitMainScreen() + } + bottomSheet(GalleryInstallationNavigation.Spaces.route) { + InitSpacesScreen() + } + } + } + + @Composable + private fun InitMainScreen() { + skipCollapsed() + expand() + GalleryInstallationScreen( + state = vm.mainState.collectAsStateWithLifecycle().value + ) + } + + @Composable + private fun InitSpacesScreen() { + GalleryInstallationSpacesScreen() + } + + override fun injectDependencies() { + componentManager().galleryInstallationsComponent.get().inject(this) + } + + override fun releaseDependencies() { + componentManager().galleryInstallationsComponent.release() + } +} \ No newline at end of file diff --git a/gallery-experience/build.gradle b/gallery-experience/build.gradle new file mode 100644 index 0000000000..d9f6397d91 --- /dev/null +++ b/gallery-experience/build.gradle @@ -0,0 +1,57 @@ +plugins { + id "com.android.library" + id "kotlin-android" +} + +android { + + def config = rootProject.extensions.getByName("ext") + + buildFeatures { + compose true + } + + composeOptions { + kotlinCompilerExtensionVersion libs.versions.composeKotlinCompilerVersion.get() + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlin { + jvmToolchain(17) + } + namespace 'com.anytypeio.anytype.galleryexperience' +} + +dependencies { + implementation project(':domain') + implementation project(':core-ui') + implementation project(':analytics') + implementation project(':core-models') + implementation project(':core-utils') + implementation project(':localization') + implementation project(':presentation') + implementation project(':library-emojifier') + + compileOnly libs.javaxInject + + implementation libs.lifecycleViewModel + implementation libs.lifecycleRuntime + + implementation libs.appcompat + implementation libs.compose + implementation libs.composeFoundation + implementation libs.composeToolingPreview + implementation libs.composeMaterial3 + + implementation libs.coilCompose + + debugImplementation libs.composeTooling + + implementation libs.timber + + testImplementation libs.junit + testImplementation libs.kotlinTest +} \ No newline at end of file diff --git a/gallery-experience/src/main/AndroidManifest.xml b/gallery-experience/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..227314eeb7 --- /dev/null +++ b/gallery-experience/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/models/GalleryInstallationState.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/models/GalleryInstallationState.kt new file mode 100644 index 0000000000..dbbe58116e --- /dev/null +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/models/GalleryInstallationState.kt @@ -0,0 +1,15 @@ +package com.anytypeio.anytype.gallery_experience.models + +sealed class GalleryInstallationState { + object Hidden : GalleryInstallationState() + object Loading : GalleryInstallationState() + object Success : GalleryInstallationState() +} + +sealed class GalleryInstallationNavigation(val route: String) { + object Main : GalleryInstallationNavigation("main") + object Spaces : GalleryInstallationNavigation("spaces") + object Success : GalleryInstallationNavigation("success") + object Error : GalleryInstallationNavigation("error") + object Dismiss : GalleryInstallationNavigation("") +} \ No newline at end of file diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationScreen.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationScreen.kt new file mode 100644 index 0000000000..b37cdf7b50 --- /dev/null +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationScreen.kt @@ -0,0 +1,16 @@ +package com.anytypeio.anytype.gallery_experience.screens + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationState + +@Composable +fun GalleryInstallationScreen(state: GalleryInstallationState) { +} + + +@Preview +@Composable +private fun GalleryInstallationScreenPreview() { + GalleryInstallationScreen(GalleryInstallationState.Success) +} \ No newline at end of file diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationSpacesScreen.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationSpacesScreen.kt new file mode 100644 index 0000000000..09d3c08ce0 --- /dev/null +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/screens/GalleryInstallationSpacesScreen.kt @@ -0,0 +1,14 @@ +package com.anytypeio.anytype.gallery_experience.screens + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview + +@Composable +fun GalleryInstallationSpacesScreen() { +} + +@Preview +@Composable +private fun GallerySpacesScreenPreview() { + GalleryInstallationSpacesScreen() +} \ No newline at end of file diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt new file mode 100644 index 0000000000..a332dc3866 --- /dev/null +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModel.kt @@ -0,0 +1,20 @@ +package com.anytypeio.anytype.gallery_experience.viewmodel + +import androidx.lifecycle.ViewModel +import com.anytypeio.anytype.analytics.base.Analytics +import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationNavigation +import com.anytypeio.anytype.gallery_experience.models.GalleryInstallationState +import kotlinx.coroutines.flow.MutableStateFlow +import timber.log.Timber + +class GalleryInstallationViewModel( + private val analytics: Analytics, +) : ViewModel() { + + val mainState = MutableStateFlow(GalleryInstallationState.Hidden) + val command = MutableStateFlow(null) + + init { + Timber.d("GalleryInstallationViewModel init") + } +} \ No newline at end of file diff --git a/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt new file mode 100644 index 0000000000..a484f859ac --- /dev/null +++ b/gallery-experience/src/main/java/com/anytypeio/anytype/gallery_experience/viewmodel/GalleryInstallationViewModelFactory.kt @@ -0,0 +1,17 @@ +package com.anytypeio.anytype.gallery_experience.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.anytypeio.anytype.analytics.base.Analytics +import javax.inject.Inject + +class GalleryInstallationViewModelFactory@Inject constructor( + private val analytics: Analytics, +) : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + return GalleryInstallationViewModel( + analytics = analytics, + ) as T + } +} \ No newline at end of file diff --git a/gallery-experience/src/main/res/values/strings.xml b/gallery-experience/src/main/res/values/strings.xml new file mode 100644 index 0000000000..e5f8fdc2aa --- /dev/null +++ b/gallery-experience/src/main/res/values/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index a4c5515f3a..dd2d9322e2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -59,3 +59,4 @@ include ':ui-settings' include ':crash-reporting' include ':localization' include ':payments' +include ':gallery-experience'