Skip to content

Commit

Permalink
Feature/filemanager (#962)
Browse files Browse the repository at this point in the history
**Background**

New FileManager sample with some implemented features

**Changes**

- Add new FileManager listing
- Add new FileManager uploading
- Add new FileManager file/folder creation

**Test plan**

- Open BridgeConnectionSample
- Open FileManager
  • Loading branch information
makeevrserg authored Oct 8, 2024
1 parent abce7be commit 18a214e
Show file tree
Hide file tree
Showing 98 changed files with 5,542 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Attention: don't forget to add the flag for F-Droid before release
- [Feature] Add new icons for remote-controls
- [Feature] Add experimental option to enable remote controls
- [Feature] Better information during synchronization
- [Feature] New File Manager listing and uploading
- [Refactor] Load RemoteControls from flipper, emulating animation
- [Refactor] Update to Kotlin 2.0
- [Refactor] Replace Ktorfit with Ktor requests in remote-controls
Expand Down
2 changes: 2 additions & 0 deletions components/archive/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ dependencies {
implementation(projects.components.bridge.service.api)
implementation(projects.components.bridge.api)

implementation(projects.components.filemngr.main.api)

implementation(libs.annotations)
implementation(libs.appcompat)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ArchiveDecomposeComponentImpl @AssistedInject constructor(
): DecomposeComponent = when (config) {
ArchiveNavigationConfig.ArchiveObject -> archiveScreenFactory(
componentContext = componentContext,
navigation = navigation
navigation = navigation,
)

is ArchiveNavigationConfig.OpenCategory -> openCategoryFactory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class ArchiveScreenDecomposeComponentImpl @AssistedInject constructor(
fun interface Factory {
operator fun invoke(
componentContext: ComponentContext,
navigation: StackNavigation<ArchiveNavigationConfig>
navigation: StackNavigation<ArchiveNavigationConfig>,
): ArchiveScreenDecomposeComponentImpl
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.flipperdevices.archive.impl.composable.filemanager

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
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.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.flipperdevices.archive.impl.R
import com.flipperdevices.core.ui.ktx.clickableRipple
import com.flipperdevices.core.ui.theme.FlipperThemeInternal
import com.flipperdevices.core.ui.theme.LocalPallet
import com.flipperdevices.core.ui.theme.LocalPalletV2
import com.flipperdevices.core.ui.theme.LocalTypography
import com.flipperdevices.core.ui.res.R as DesignSystem

@Composable
fun FileManagerCard(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Card(modifier = modifier) {
Column(
modifier = Modifier
.clip(RoundedCornerShape(12.dp))
.clickableRipple(onClick = onClick)
.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
) {
Row(
horizontalArrangement = Arrangement.spacedBy(15.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(
if (MaterialTheme.colors.isLight) {
R.drawable.ic_file_dark
} else {
R.drawable.ic_file_light
}
),
contentDescription = null,
tint = Color.Unspecified
)
Text(
text = stringResource(R.string.archive_card_file_manager_title),
style = LocalTypography.current.buttonB16,
color = LocalPalletV2.current.text.title.primary
)
}

Icon(
painter = painterResource(DesignSystem.drawable.ic_forward),
contentDescription = null,
tint = LocalPallet.current.iconTint30
)
}
Text(
text = stringResource(R.string.archive_card_file_manager_desc),
style = LocalTypography.current.bodyR14,
color = LocalPalletV2.current.text.caption.secondary
)
}
}
}

@Preview
@Composable
private fun FileManagerCardPreview() {
FlipperThemeInternal {
FileManagerCard(onClick = {})
}
}
41 changes: 41 additions & 0 deletions components/archive/impl/src/main/res/drawable/ic_file_dark.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:viewportWidth="30"
android:viewportHeight="30">
<group>
<clip-path
android:pathData="M4,1h23v28h-23z"/>
<group>
<clip-path
android:pathData="M27,29H4V1H19V3H6V27H25V9H27V29Z"/>
<path
android:pathData="M4,29H2V31H4V29ZM27,29V31H29V29H27ZM27,9H29V7H27V9ZM19,1H21V-1H19V1ZM4,1V-1H2V1H4ZM19,3V5H21V3H19ZM6,3V1H4V3H6ZM6,27H4V29H6V27ZM25,27V29H27V27H25ZM25,9V7H23V9H25ZM4,31H27V27H4V31ZM29,29V9H25V29H29ZM19,-1H4V3H19V-1ZM2,1V29H6V1H2ZM17,1V3H21V1H17ZM19,1H6V5H19V1ZM4,3V27H8V3H4ZM6,29H25V25H6V29ZM27,27V9H23V27H27ZM25,11H27V7H25V11Z"
android:fillColor="#000000"/>
</group>
<path
android:pathData="M19,3h2v2h-2z"
android:fillColor="#000000"/>
<path
android:pathData="M17,3h4v8h-4z"
android:fillColor="#000000"/>
<path
android:pathData="M21,5h2v2h-2z"
android:fillColor="#000000"/>
<path
android:pathData="M23,7h2v2h-2z"
android:fillColor="#000000"/>
<path
android:pathData="M17,7h8v4h-8z"
android:fillColor="#000000"/>
<path
android:pathData="M10,14h11v2h-11z"
android:fillColor="#000000"/>
<path
android:pathData="M10,18h11v2h-11z"
android:fillColor="#000000"/>
<path
android:pathData="M10,22h11v2h-11z"
android:fillColor="#000000"/>
</group>
</vector>
41 changes: 41 additions & 0 deletions components/archive/impl/src/main/res/drawable/ic_file_light.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:viewportWidth="30"
android:viewportHeight="30">
<group>
<clip-path
android:pathData="M4,1h23v28h-23z"/>
<group>
<clip-path
android:pathData="M27,29H4V1H19V3H6V27H25V9H27V29Z"/>
<path
android:pathData="M4,29H2V31H4V29ZM27,29V31H29V29H27ZM27,9H29V7H27V9ZM19,1H21V-1H19V1ZM4,1V-1H2V1H4ZM19,3V5H21V3H19ZM6,3V1H4V3H6ZM6,27H4V29H6V27ZM25,27V29H27V27H25ZM25,9V7H23V9H25ZM4,31H27V27H4V31ZM29,29V9H25V29H29ZM19,-1H4V3H19V-1ZM2,1V29H6V1H2ZM17,1V3H21V1H17ZM19,1H6V5H19V1ZM4,3V27H8V3H4ZM6,29H25V25H6V29ZM27,27V9H23V27H27ZM25,11H27V7H25V11Z"
android:fillColor="#FFFFFF"/>
</group>
<path
android:pathData="M19,3h2v2h-2z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M17,3h4v8h-4z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M21,5h2v2h-2z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M23,7h2v2h-2z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M17,7h8v4h-8z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M10,14h11v2h-11z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M10,18h11v2h-11z"
android:fillColor="#FFFFFF"/>
<path
android:pathData="M10,22h11v2h-11z"
android:fillColor="#FFFFFF"/>
</group>
</vector>
2 changes: 2 additions & 0 deletions components/archive/impl/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@
<string name="archive_preparing">Preparing sync: getting files from flipper</string>
<string name="archive_favorites">Syncing favorite keys…</string>
<string name="archive_hashes">Preparing sync: %s</string>
<string name="archive_card_file_manager_title">File Manager</string>
<string name="archive_card_file_manager_desc">Manage files and assets on your Flipper Zero</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.flipperdevices.core.progress.copyWithProgress
import com.flipperdevices.protobuf.Main
import com.flipperdevices.protobuf.storage.MkdirRequest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.plus
import kotlinx.coroutines.withContext
import okio.FileSystem
import okio.Path
Expand Down
7 changes: 7 additions & 0 deletions components/bridge/connection/sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ dependencies {
implementation(projects.components.bridge.api)
implementation(projects.components.bridge.connection.pbutils)

implementation(projects.components.filemngr.main.api)
implementation(projects.components.filemngr.main.impl)
implementation(projects.components.filemngr.listing.api)
implementation(projects.components.filemngr.listing.impl)
implementation(projects.components.filemngr.upload.api)
implementation(projects.components.filemngr.upload.impl)

implementation(projects.components.newfilemanager.api)
implementation(projects.components.newfilemanager.impl)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import com.flipperdevices.bridge.connection.screens.device.ConnectionDeviceScree
import com.flipperdevices.bridge.connection.screens.models.ConnectionRootConfig
import com.flipperdevices.bridge.connection.screens.nopermission.ConnectionNoPermissionDecomposeComponent
import com.flipperdevices.bridge.connection.screens.search.ConnectionSearchDecomposeComponent
import com.flipperdevices.newfilemanager.api.navigation.FileManagerDecomposeComponent
import com.flipperdevices.ui.decompose.CompositeDecomposeComponent
import com.flipperdevices.ui.decompose.DecomposeComponent
import dagger.assisted.Assisted
Expand All @@ -25,7 +24,8 @@ class ConnectionRootDecomposeComponent @AssistedInject constructor(
private val context: Context,
private val searchDecomposeFactory: ConnectionSearchDecomposeComponent.Factory,
private val connectionDeviceScreenDecomposeComponentFactory: ConnectionDeviceScreenDecomposeComponent.Factory,
private val fileManagerComponentFactory: FileManagerDecomposeComponent.Factory
private val fileManagerComponentFactory:
com.flipperdevices.filemanager.main.api.FileManagerDecomposeComponent.Factory
) : CompositeDecomposeComponent<ConnectionRootConfig>(), ComponentContext by componentContext {
override val stack: Value<ChildStack<ConnectionRootConfig, DecomposeComponent>> = childStack(
source = navigation,
Expand Down
13 changes: 13 additions & 0 deletions components/core/preference/src/commonMain/proto/settings.proto
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ enum SelectedCatalogSort {
NAME_ASC = 5;
}

enum FileManagerOrientation {
LIST = 0;
GRID = 1;
}

enum FileManagerSort {
DEFAULT = 0;
SIZE = 1;
}

message Settings {
reserved 7; // Already unused tags
reserved 12; // Already unused first_synchronization_passed
Expand Down Expand Up @@ -61,4 +71,7 @@ message Settings {
bool notification_topic_update_enabled = 27;
bool notification_dialog_shown = 28;
bool show_remote_controls = 29;
FileManagerOrientation file_manager_orientation = 30;
FileManagerSort file_manager_sort = 31;
bool show_hidden_files_on_flipper = 32;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ class FlipperMultiChoiceDialogModel private constructor(

fun setTitle(@StringRes textId: Int): Builder {
titleComposable = {
Text(
text = stringResource(textId),
style = LocalTypography.current.bodySSB14,
textAlign = TextAlign.Center,
color = LocalPallet.current.text100
)
ComposableTitle(stringResource(textId))
}
return this
}

fun setTitle(text: String): Builder {
titleComposable = {
ComposableTitle(text)
}
return this
}
Expand Down Expand Up @@ -68,6 +70,16 @@ class FlipperMultiChoiceDialogModel private constructor(
return this
}

@Composable
private fun ComposableTitle(text: String) {
Text(
text = text,
style = LocalTypography.current.bodySSB14,
textAlign = TextAlign.Center,
color = LocalPallet.current.text100
)
}

@Composable
private fun ComposableDescription(text: AnnotatedString) {
Text(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fun ComposableCatalogTabScreen(
.map { categoriesErrorLoadState -> categoriesErrorLoadState.throwable.toFapHubError() }
}.collectAsState(initial = null)

val refreshAll = {
val refreshAll: () -> Unit = {
fapsListViewModel.refreshManifest()
fapsList.refresh()
categoriesViewModel.onRefresh()
Expand Down
15 changes: 15 additions & 0 deletions components/filemngr/listing/api/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id("flipper.multiplatform")
id("flipper.multiplatform-dependencies")
}

android.namespace = "com.flipperdevices.filemanager.listing.api"

commonDependencies {
implementation(projects.components.core.ui.decompose)

implementation(libs.compose.ui)
implementation(libs.decompose)

implementation(libs.okio)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.flipperdevices.filemanager.listing.api

import com.arkivanov.decompose.ComponentContext
import com.flipperdevices.ui.decompose.DecomposeOnBackParameter
import com.flipperdevices.ui.decompose.ScreenDecomposeComponent
import okio.Path

abstract class FilesDecomposeComponent(
componentContext: ComponentContext
) : ScreenDecomposeComponent(componentContext) {
fun interface Factory {
operator fun invoke(
componentContext: ComponentContext,
onBack: DecomposeOnBackParameter,
path: Path,
onPathChanged: (Path) -> Unit,
onUploadClick: () -> Unit
): FilesDecomposeComponent
}
}
Loading

0 comments on commit 18a214e

Please sign in to comment.