Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ android {
applicationId = "co.adityarajput.fileflow"
minSdk = 29
targetSdk = 36
versionCode = 4
versionName = "1.2.0"
versionCode = 5
versionName = "1.3.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/co/adityarajput/fileflow/utils/Files.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package co.adityarajput.fileflow.utils

import android.content.Context
import android.os.Build
import android.os.Environment
import android.os.storage.StorageManager
import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import co.adityarajput.fileflow.data.models.Rule
Expand Down Expand Up @@ -205,3 +208,43 @@ fun String.getGetDirectoryFromUri() =

fun Context.findRulesToBeMigrated(rules: List<Rule>) =
rules.filter { File.fromPath(this, it.action.src) == null }

fun Context.getAllStorages(): List<IOFile> {
val storages = mutableListOf<IOFile>()

try {
getExternalFilesDirs(null).forEach {
var storage = it
var dir = it
while (dir.parentFile != null) {
dir = dir.parentFile!!
if (dir.canRead())
storage = dir
}
storages.add(storage)
}
} catch (e: Exception) {
Logger.e("Files", "Couldn't extract storages from external app directories", e)
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
(getSystemService(Context.STORAGE_SERVICE) as StorageManager).getStorageVolumes()
.forEach {
if (it.directory != null && it.directory!!.canRead()) {
storages.add(it.directory!!)
}
}
} catch (e: Exception) {
Logger.e("Files", "Couldn't extract storages from StorageManager", e)
}
}

Logger.d("Files", "Found storages: ${storages.joinToString { it.absolutePath }}")

return storages.distinct().apply {
val primaryStorage = Environment.getExternalStorageDirectory()
storages.remove(primaryStorage)
storages.add(0, primaryStorage)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package co.adityarajput.fileflow.views.components

import android.os.Environment
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
Expand All @@ -21,14 +20,19 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import co.adityarajput.fileflow.R
import co.adityarajput.fileflow.utils.getAllStorages
import co.adityarajput.fileflow.viewmodels.UpsertRuleViewModel

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FolderPickerBottomSheet(viewModel: UpsertRuleViewModel) {
val context = LocalContext.current
val hideSheet = { viewModel.folderPickerState = null }
var currentDir by remember { mutableStateOf(Environment.getExternalStorageDirectory()) }

val storages = remember { context.getAllStorages() }
var currentStorage by remember { mutableIntStateOf(0) }

var currentDir by remember { mutableStateOf(storages[0]) }
val items = remember(currentDir) {
currentDir.listFiles()?.sortedBy { it.name.lowercase() }?.sortedBy { it.isFile }.orEmpty()
}
Expand All @@ -54,12 +58,31 @@ fun FolderPickerBottomSheet(viewModel: UpsertRuleViewModel) {
.padding(dimensionResource(R.dimen.padding_medium)),
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)),
) {
if (currentDir in storages) {
item {
Row(
Modifier
.fillMaxWidth()
.clickable {
currentStorage = (currentStorage + 1) % storages.size
currentDir = storages[currentStorage]
},
Arrangement.spacedBy(dimensionResource(R.dimen.padding_small)),
) {
Icon(
painterResource(R.drawable.folder_switch),
stringResource(R.string.storage_switch),
)
Text(stringResource(R.string.storage_switch))
}
}
}
if (currentDir.parentFile?.canRead() ?: false) {
item {
Row(
Modifier
.fillMaxWidth()
.clickable { currentDir = currentDir.parentFile },
.clickable { currentDir = currentDir.parentFile!! },
Arrangement.spacedBy(dimensionResource(R.dimen.padding_small)),
) {
Icon(
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/folder_switch.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M360,776Q279,744 226.5,675.5Q174,607 163,520L244,520Q253,573 283,617Q313,661 360,688L360,776ZM500,880Q475,880 457.5,862.5Q440,845 440,820L440,580Q440,555 457.5,537.5Q475,520 500,520L588,520Q603,520 616.5,527Q630,534 638,547L660,580L820,580Q845,580 862.5,597.5Q880,615 880,640L880,820Q880,845 862.5,862.5Q845,880 820,880L500,880ZM140,440Q115,440 97.5,422.5Q80,405 80,380L80,140Q80,115 97.5,97.5Q115,80 140,80L228,80Q243,80 256.5,87Q270,94 278,107L300,140L460,140Q485,140 502.5,157.5Q520,175 520,200L520,380Q520,405 502.5,422.5Q485,440 460,440L140,440ZM720,480Q720,415 688,359.5Q656,304 600,272L600,184Q691,221 745.5,301.5Q800,382 800,480L720,480ZM520,800L800,800Q800,800 800,800Q800,800 800,800L800,660Q800,660 800,660Q800,660 800,660L617,660L577,600Q577,600 577,600Q577,600 577,600L520,600Q520,600 520,600Q520,600 520,600L520,800Q520,800 520,800Q520,800 520,800ZM160,360L440,360Q440,360 440,360Q440,360 440,360L440,220Q440,220 440,220Q440,220 440,220L257,220L217,160Q217,160 217,160Q217,160 217,160L160,160Q160,160 160,160Q160,160 160,160L160,360Q160,360 160,360Q160,360 160,360ZM520,800Q520,800 520,800Q520,800 520,800L520,600Q520,600 520,600Q520,600 520,600L520,600Q520,600 520,600Q520,600 520,600L520,660L520,660Q520,660 520,660Q520,660 520,660L520,800Q520,800 520,800Q520,800 520,800ZM160,360Q160,360 160,360Q160,360 160,360L160,160Q160,160 160,160Q160,160 160,160L160,160Q160,160 160,160Q160,160 160,160L160,220L160,220Q160,220 160,220Q160,220 160,220L160,360Q160,360 160,360Q160,360 160,360Z" />
</vector>
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<resources>
<string name="app_name" translatable="false">FileFlow</string>
<string name="app_name_launcher" translatable="false">FileFlow</string>
<string name="app_version" translatable="false">1.2.0</string>
<string name="app_version" translatable="false">1.3.0</string>

<!-- region AboutScreen -->
<string name="about">About</string>
Expand Down Expand Up @@ -124,6 +124,7 @@
<string name="delete_stale_phrase">Delete if unmodified for a while</string>
<!-- endregion -->
<!-- region FolderPickerBottomSheet -->
<string name="storage_switch">Switch storage</string>
<string name="parent_directory">Back</string>
<string name="empty_folder">(Empty)</string>
<string name="folder">Folder</string>
Expand Down
3 changes: 3 additions & 0 deletions metadata/en-US/changelogs/5.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
• feat: Add a special reference for UUID replacement (check project wiki for details)
• feat: Provide "don't rename" template shortcut in supporting text
• feat: Support secondary storage(s) in folder picker
Loading