Skip to content

Commit

Permalink
Migrate to Decompose FileManager (#745)
Browse files Browse the repository at this point in the history
**Background**

Right now we have a lot of bugs for navigation

**Changes**

- Migrate file manager component to decompose 

**Test plan**

Try open filemanager
  • Loading branch information
LionZXY authored Dec 7, 2023
1 parent a6d5452 commit efc404e
Show file tree
Hide file tree
Showing 33 changed files with 531 additions and 257 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Changelog

# 1.6.8 - In progress

- [Refactor] Migrate file manager to decompose

# 1.6.7

Expand Down
1 change: 1 addition & 0 deletions components/core/ui/decompose/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
11 changes: 11 additions & 0 deletions components/core/ui/decompose/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id("flipper.android-compose")
}

android.namespace = "com.flipperdevices.ui.decompose"

dependencies {
implementation(libs.compose.ui)
implementation(libs.compose.foundation)
implementation(libs.lifecycle.viewmodel.ktx)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.flipperdevices.ui.decompose

import androidx.compose.runtime.Composable

interface DecomposeComponent {
@Composable
fun Render()
}
2 changes: 2 additions & 0 deletions components/core/ui/ktx/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ dependencies {
implementation(libs.coil.svg)
implementation(libs.compose.systemuicontroller)
implementation(libs.image.lottie)
implementation(libs.lifecycle.viewmodel.ktx)
implementation(libs.lifecycle.compose)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.flipperdevices.core.ui.ktx

import androidx.compose.runtime.Composable
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
inline fun <reified VM : ViewModel> viewModelWithFactory(
key: String,
crossinline factory: () -> VM
): VM {
return viewModel(
key = key,
factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return factory() as T
}
}
)
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.flipperdevices.filemanager.api.navigation

import com.flipperdevices.core.ui.navigation.AggregateFeatureEntry
import com.flipperdevices.core.ui.navigation.ComposableFeatureEntry
import com.flipperdevices.core.ui.navigation.FeatureScreenRootRoute

private const val DEFAULT_PATH = "/"

interface FileManagerEntry : AggregateFeatureEntry {
interface FileManagerEntry : ComposableFeatureEntry {
override val ROUTE: FeatureScreenRootRoute
get() = FeatureScreenRootRoute.FILE_MANAGER

fun fileManagerDestination(path: String = DEFAULT_PATH): String
fun fileManagerDestination(): String
}
8 changes: 3 additions & 5 deletions components/filemanager/impl/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
plugins {
id("flipper.android-compose")
id("flipper.anvil")
id("kotlin-parcelize")
id("kotlinx-serialization")
}

Expand All @@ -17,6 +16,7 @@ dependencies {
implementation(projects.components.core.ui.lifecycle)
implementation(projects.components.core.ui.res)
implementation(projects.components.core.ui.ktx)
implementation(projects.components.core.ui.decompose)
implementation(projects.components.core.share)

implementation(projects.components.bridge.service.api)
Expand All @@ -40,12 +40,10 @@ dependencies {
implementation(libs.compose.foundation)
implementation(libs.compose.material)
implementation(libs.compose.navigation)
implementation(libs.bundles.decompose)

implementation(libs.kotlin.coroutines)
implementation(libs.kotlin.immutable.collections)
implementation(libs.lifecycle.runtime.ktx)
implementation(libs.lifecycle.viewmodel.ktx)

implementation(libs.tangle.viewmodel.compose)
implementation(libs.tangle.viewmodel.api)
anvil(libs.tangle.viewmodel.compiler)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.flipperdevices.filemanager.impl.api

import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.value.Value
import com.flipperdevices.core.di.AppGraph
import com.flipperdevices.filemanager.impl.model.FileManagerNavigationConfig
import com.flipperdevices.ui.decompose.DecomposeComponent
import com.squareup.anvil.annotations.ContributesBinding
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject

interface FileManagerDecomposeComponent {
val stack: Value<ChildStack<*, DecomposeComponent>>

fun interface Factory {
operator fun invoke(
componentContext: ComponentContext,
): FileManagerDecomposeComponent
}
}

class FileManagerDecomposeComponentImpl @AssistedInject constructor(
@Assisted componentContext: ComponentContext,
private val fileManagerListingFactory: FileManagerListingComponent.Factory,
private val fileManagerUploadingFactory: FileManagerUploadingComponent.Factory,
private val fileManagerEditingFactory: FileManagerEditingComponent.Factory,
private val fileManagerDownloadFactory: FileManagerDownloadComponent.Factory
) : FileManagerDecomposeComponent, ComponentContext by componentContext {
private val navigation = StackNavigation<FileManagerNavigationConfig>()

override val stack: Value<ChildStack<*, DecomposeComponent>> = childStack(
source = navigation,
serializer = FileManagerNavigationConfig.serializer(),
initialConfiguration = FileManagerNavigationConfig.Screen("/"),
handleBackButton = true,
childFactory = ::child,
)

private fun child(
config: FileManagerNavigationConfig,
componentContext: ComponentContext
): DecomposeComponent = when (config) {
is FileManagerNavigationConfig.Screen -> fileManagerListingFactory(
componentContext,
config,
navigation
)

is FileManagerNavigationConfig.Uploading -> fileManagerUploadingFactory(
componentContext,
config,
navigation
)

is FileManagerNavigationConfig.Editing -> fileManagerEditingFactory(
componentContext,
config,
navigation
)
is FileManagerNavigationConfig.Download -> fileManagerDownloadFactory(
componentContext,
config,
navigation
)
}

@AssistedFactory
@ContributesBinding(AppGraph::class, FileManagerDecomposeComponent.Factory::class)
interface Factory : FileManagerDecomposeComponent.Factory {
override operator fun invoke(
componentContext: ComponentContext,
): FileManagerDecomposeComponentImpl
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.flipperdevices.filemanager.impl.api

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.pop
import com.flipperdevices.core.ui.ktx.viewModelWithFactory
import com.flipperdevices.filemanager.impl.composable.ComposableFileManagerDownloadScreen
import com.flipperdevices.filemanager.impl.model.FileManagerNavigationConfig
import com.flipperdevices.filemanager.impl.viewmodels.FileManagerViewModel
import com.flipperdevices.filemanager.impl.viewmodels.ShareViewModel
import com.flipperdevices.ui.decompose.DecomposeComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject

class FileManagerDownloadComponent @AssistedInject constructor(
private val fileManagerViewModelFactory: FileManagerViewModel.Factory,
private val shareModelFactory: ShareViewModel.Factory,
@Assisted componentContext: ComponentContext,
@Assisted val config: FileManagerNavigationConfig.Download,
@Assisted val navigation: StackNavigation<FileManagerNavigationConfig>
) : DecomposeComponent,
ComponentContext by componentContext {
@Composable
@Suppress("NonSkippableComposable")
override fun Render() {
val fileManagerViewModel = viewModelWithFactory(key = config.path) {
fileManagerViewModelFactory(config.path)
}
val shareViewModel = viewModelWithFactory(key = config.shareFile.toString()) {
shareModelFactory(config.shareFile)
}
val fileManagerState by fileManagerViewModel.getFileManagerState().collectAsState()
val shareState by shareViewModel.getShareState().collectAsState()
ComposableFileManagerDownloadScreen(
fileManagerState = fileManagerState,
shareState = shareState,
onBack = navigation::pop
)
}

@AssistedFactory
fun interface Factory {
operator fun invoke(
componentContext: ComponentContext,
config: FileManagerNavigationConfig.Download,
navigation: StackNavigation<FileManagerNavigationConfig>
): FileManagerDownloadComponent
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.flipperdevices.filemanager.impl.api

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.pop
import com.flipperdevices.core.ui.ktx.viewModelWithFactory
import com.flipperdevices.filemanager.impl.composable.ComposableFileManagerEditorScreen
import com.flipperdevices.filemanager.impl.model.FileManagerNavigationConfig
import com.flipperdevices.filemanager.impl.viewmodels.EditorViewModel
import com.flipperdevices.ui.decompose.DecomposeComponent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject

class FileManagerEditingComponent @AssistedInject constructor(
private val editorViewModelFactory: EditorViewModel.Factory,
@Assisted componentContext: ComponentContext,
@Assisted val config: FileManagerNavigationConfig.Editing,
@Assisted val navigation: StackNavigation<FileManagerNavigationConfig>
) : DecomposeComponent,
ComponentContext by componentContext {
@Composable
@Suppress("NonSkippableComposable")
override fun Render() {
val editorViewModel = viewModelWithFactory(key = config.shareFile.toString()) {
editorViewModelFactory(config.shareFile)
}
val editorState by editorViewModel.getEditorState().collectAsState()
ComposableFileManagerEditorScreen(
editorState = editorState,
onClickSaveButton = editorViewModel::onSaveFile,
onBack = navigation::pop
)
}

@AssistedFactory
fun interface Factory {
operator fun invoke(
componentContext: ComponentContext,
config: FileManagerNavigationConfig.Editing,
navigation: StackNavigation<FileManagerNavigationConfig>
): FileManagerEditingComponent
}
}
Loading

0 comments on commit efc404e

Please sign in to comment.