diff --git a/app/GiantExplorer/build.gradle.kts b/app/GiantExplorer/build.gradle.kts index 668e481..7a1a7f1 100644 --- a/app/GiantExplorer/build.gradle.kts +++ b/app/GiantExplorer/build.gradle.kts @@ -4,8 +4,7 @@ import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask buildscript { dependencies { val versionManager: String by project - val navVersion = "2.7.7" - classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$navVersion") + classpath(libs.navigation.safe.args.gradle.plugin) //jitpack 构建 classpath("com.github.storytellerF.common-ui-list:version-manager:$versionManager") //本地构建 @@ -13,14 +12,11 @@ buildscript { } } plugins { - val androidVersion = "8.3.1" - val kotlinVersion = "1.9.21" - val kspVersion = "1.9.21-1.0.15" - id("com.android.application") version androidVersion apply false - id("com.android.library") version androidVersion apply false - id("org.jetbrains.kotlin.android") version kotlinVersion apply false - id("org.jetbrains.kotlin.jvm") version kotlinVersion apply false - id("com.google.devtools.ksp") version kspVersion apply false + alias(libs.plugins.androidApplication) apply false + alias(libs.plugins.jetbrainsKotlinAndroid) apply false + alias(libs.plugins.ksp) apply false + id("com.starter.easylauncher") version "6.3.0" apply false + id("androidx.room") version "2.6.1" apply false id("io.gitlab.arturbosch.detekt") version "1.23.1" } diff --git a/app/GiantExplorer/giant-explorer/build.gradle.kts b/app/GiantExplorer/giant-explorer/build.gradle.kts index bf6e105..0b024ab 100644 --- a/app/GiantExplorer/giant-explorer/build.gradle.kts +++ b/app/GiantExplorer/giant-explorer/build.gradle.kts @@ -18,8 +18,8 @@ plugins { id("com.storyteller_f.version_manager") id("kotlin-kapt") id("com.google.devtools.ksp") - id("com.starter.easylauncher") version "6.2.0" - id("androidx.room") version "2.6.1" +// id("com.starter.easylauncher") + id("androidx.room") } android { @@ -52,7 +52,7 @@ android { dependencies { - implementation("androidx.constraintlayout:constraintlayout:${Versions.CONSTRAINTLAYOUT}") + implementation(libs.constraintlayout) networkDependency() workerDependency() @@ -60,30 +60,29 @@ dependencies { handleShun() implementation(project(":giant-explorer-plugin-core")) - implementation("com.j256.simplemagic:simplemagic:1.17") - implementation("com.github.bumptech.glide:glide:4.16.0") + implementation(libs.simplemagic) + implementation(libs.glide) - implementation("androidx.browser:browser:1.8.0") - implementation("androidx.webkit:webkit:1.10.0") - implementation("androidx.preference:preference-ktx:1.2.1") - implementation("androidx.window:window:1.2.0") + implementation(libs.browser) + implementation(libs.webkit) + implementation(libs.preference.ktx) + implementation(libs.window) - androidTestImplementation("androidx.room:room-testing:2.6.1") + androidTestImplementation(libs.room.testing) val liPluginModule = findProject(":li-plugin") if (liPluginModule != null) { implementation(liPluginModule) } - implementation("com.github.tony19:logback-android:3.0.0") + implementation(libs.logback.android) - val fileSystemVersion = "73769ee487" - implementation("com.github.storytellerF.AFS:file-system-remote:$fileSystemVersion") - implementation("com.github.storytellerF.AFS:file-system-ktx:$fileSystemVersion") - implementation("com.github.storytellerF.AFS:file-system:$fileSystemVersion") - implementation("com.github.storytellerF.AFS:file-system-root:$fileSystemVersion") - implementation("com.github.storytellerF.AFS:file-system-archive:$fileSystemVersion") - implementation("com.github.storytellerF.AFS:file-system-memory:$fileSystemVersion") - implementation("com.github.storytellerF.AFS:file-system-local:$fileSystemVersion") + implementation(libs.file.system.remote) + implementation(libs.file.system.ktx) + implementation(libs.file.system) + implementation(libs.file.system.root) + implementation(libs.file.system.archive) + implementation(libs.file.system.memory) + implementation(libs.file.system.local) constraints { listOf( @@ -97,12 +96,6 @@ dependencies { } baseApp() -android { - defaultConfig { - //fixme file-system-archive minSdk = 24 file-system-memory minSdk = 26 - minSdk = 26 - } -} implModule(":slim-ktx") constraintCommonUIListVersion(versionManager) configurations.all { diff --git a/app/GiantExplorer/giant-explorer/src/main/AndroidManifest.xml b/app/GiantExplorer/giant-explorer/src/main/AndroidManifest.xml index c64b0e0..dfc5719 100644 --- a/app/GiantExplorer/giant-explorer/src/main/AndroidManifest.xml +++ b/app/GiantExplorer/giant-explorer/src/main/AndroidManifest.xml @@ -2,11 +2,16 @@ + + - + + @@ -115,11 +120,13 @@ + android:exported="true" + android:permission="com.storyteller_f.giant_explorer.provider" /> + android:exported="true" + android:permission="com.storyteller_f.giant_explorer.provider" /> \ No newline at end of file diff --git a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileList.kt b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileList.kt index 40e8e6d..f5236c5 100644 --- a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileList.kt +++ b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileList.kt @@ -38,6 +38,7 @@ import com.storyteller_f.common_vm_ktx.combineDao import com.storyteller_f.common_vm_ktx.debounce import com.storyteller_f.common_vm_ktx.distinctUntilChangedBy import com.storyteller_f.common_vm_ktx.svm +import com.storyteller_f.common_vm_ktx.update import com.storyteller_f.common_vm_ktx.vm import com.storyteller_f.common_vm_ktx.wait5 import com.storyteller_f.file_system.instance.FileInstance @@ -94,7 +95,7 @@ class FileListObserver( ) where T : ViewModelStoreOwner, T : SavedStateRegistryOwner { val fileInstance: FileInstance? get() = session.fileInstance.value - val selected: List>? + val selected: List? get() = session.selected.value val fileListViewModel by owner.svm({}, scope) { handle, _ -> @@ -241,7 +242,7 @@ private val LiveData>.same @ItemHolder("file") class FileItemHolder( val file: FileModel, - val selected: List>, + val selected: List, variant: String ) : DataItemHolder(variant) { override fun areItemsTheSame(other: DataItemHolder) = @@ -273,9 +274,14 @@ class FileViewHolder(private val binding: ViewHolderFileBinding) : binding.fileName.text = file.name binding.fileIcon.fileIcon(file.item) val item = file.item - binding.root.isSelected = itemHolder.selected.valueContains( - Pair(itemHolder, 0) - ) == true + binding.root.isSelected = run { + val firstOrNull = itemHolder.selected.firstOrNull { + it.areItemsTheSame( + itemHolder + ) + } + firstOrNull != null + } == true binding.root.setBackgroundResource( if (file.item.isFile) R.drawable.background_file else R.drawable.background_folder ) @@ -466,31 +472,27 @@ private suspend fun fileModelBuilder( } /** - * 反选。pair 的first 作为key。 + * 反选。通过areItemsTheSame 比较,而不是equals + * @return 返回新的选中列表和上一次是否处于选中状态 */ -fun List>?.toggle( - pair: Pair -): Pair>, Boolean> { +fun List?.toggle( + holder: DataItemHolder +): Pair, Boolean> { val oldSelectedHolders = this ?: mutableListOf() val otherHolders = oldSelectedHolders.filter { - !it.first.areItemsTheSame(pair.first) + !it.areItemsTheSame(holder) } - val stateSelected = otherHolders.size == oldSelectedHolders.size - val selected = if (stateSelected) otherHolders + pair else otherHolders - return selected to stateSelected + val newState = otherHolders.size == oldSelectedHolders.size + val selected = if (newState) otherHolders + holder else otherHolders + return selected to newState } -fun List>.valueContains(pair: Pair): Boolean { - val firstOrNull = firstOrNull { - it.first.areItemsTheSame(pair.first) +fun MutableLiveData>.toggle(viewHolder: RecyclerView.ViewHolder) { + update { + val adapterViewHolder = viewHolder as AbstractViewHolder + val (selectedHolders, currentSelected) = + it.toggle(adapterViewHolder.itemHolder) + viewHolder.view.isSelected = currentSelected + selectedHolders } - return firstOrNull != null -} - -fun MutableLiveData>>.toggle(viewHolder: RecyclerView.ViewHolder) { - val adapterViewHolder = viewHolder as AbstractViewHolder - val (selectedHolders, currentSelected) = - value.toggle(adapterViewHolder.itemHolder to viewHolder.absoluteAdapterPosition) - viewHolder.view.isSelected = currentSelected - value = selectedHolders } diff --git a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileListFragment.kt b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileListFragment.kt index 3e2e82e..7cb18c4 100644 --- a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileListFragment.kt +++ b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/FileListFragment.kt @@ -9,6 +9,7 @@ import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.graphics.Rect import android.net.Uri +import android.os.Build import android.text.TextPaint import android.text.TextUtils import android.util.Log @@ -47,6 +48,7 @@ import com.storyteller_f.common_vm_ktx.pvm import com.storyteller_f.file_system.getFileInstance import com.storyteller_f.file_system.instance.FileCreatePolicy import com.storyteller_f.file_system.instance.FileInstance +import com.storyteller_f.file_system_archive.ArchiveFileInstanceFactory import com.storyteller_f.file_system_ktx.isDirectory import com.storyteller_f.giant_explorer.BuildConfig import com.storyteller_f.giant_explorer.R @@ -360,6 +362,9 @@ class FileListFragment : SimpleFragment(FragmentFileLis resolveInstalledPlugins(itemHolder, mimeTypeFromExtension, uri) resolveNoInstalledPlugins(mimeTypeFromExtension, fullPath, uri) resolveModulePlugin(key, uri, fullPath) + val isSupportArchiveFileInstance = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N + menu.findItem(R.id.preview_archive).isVisible = + isSupportArchiveFileInstance || itemHolder.file.item.extension == "zip" setOnMenuItemClickListener { item -> when (item.itemId) { @@ -368,12 +373,28 @@ class FileListFragment : SimpleFragment(FragmentFileLis R.id.copy_to -> moveOrCopy(false, itemHolder) R.id.copy_file -> copyFilePathToClipboard(itemHolder) R.id.properties -> showPropertiesDialog(uri) + R.id.preview_archive -> previewArchiveFile(uri) } true } }.show() } + private fun previewArchiveFile(uri: Uri) { + val context = context ?: return + scope.launch { + val fileInstance = getFileInstance(context, uri) ?: return@launch + val newUri = + ArchiveFileInstanceFactory().buildNestedFile(context, "/", fileInstance) + ?: return@launch + findNavController().navigate( + FileListFragmentDirections.actionFileListFragmentSelf( + newUri + ) + ) + } + } + private fun PopupMenu.resolveModulePlugin( key: String, uri: Uri, @@ -581,7 +602,7 @@ class FileListFragment : SimpleFragment(FragmentFileLis } private fun detectSelected(itemHolder: FileItemHolder) = - observer.selected?.map { pair -> (pair.first as FileItemHolder).file.item } ?: listOf( + observer.selected?.map { pair -> (pair as FileItemHolder).file.item } ?: listOf( itemHolder.file.item ) } diff --git a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/MainActivity.kt b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/MainActivity.kt index e8b0ea3..496563f 100644 --- a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/MainActivity.kt +++ b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/control/MainActivity.kt @@ -79,7 +79,7 @@ import java.lang.ref.WeakReference import java.util.Properties class FileExplorerSession(application: Application, uri: Uri) : AndroidViewModel(application) { - val selected = MutableLiveData>>() + val selected = MutableLiveData>() val fileInstance = MutableLiveData() init { @@ -387,8 +387,7 @@ class MainActivity : CommonActivity(), FileOperateService.FileOperateResultConta } override fun onServiceDisconnected(name: ComponentName?) { - // fixme 无法移除remote -// RootAccessFileInstance.registerLibSuRemote() + RootAccessFileInstance.removeLibSuRemote() } } diff --git a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/dialog/VolumeSpaceDialog.kt b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/dialog/VolumeSpaceDialog.kt index 3dc46c1..ba74643 100644 --- a/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/dialog/VolumeSpaceDialog.kt +++ b/app/GiantExplorer/giant-explorer/src/main/java/com/storyteller_f/giant_explorer/dialog/VolumeSpaceDialog.kt @@ -1,16 +1,20 @@ package com.storyteller_f.giant_explorer.dialog +import android.content.ContentResolver +import android.net.Uri import android.os.Build import android.os.storage.StorageVolume import androidx.annotation.RequiresApi import androidx.core.view.isVisible import com.storyteller_f.common_ui.SimpleDialogFragment import com.storyteller_f.common_ui.scope +import com.storyteller_f.file_system_local.LocalFileSystem import com.storyteller_f.file_system_local.getFree import com.storyteller_f.file_system_local.getSpace import com.storyteller_f.file_system_local.getStorageCompat import com.storyteller_f.file_system_local.getStorageVolume import com.storyteller_f.file_system_local.getTotal +import com.storyteller_f.file_system_local.requestFilePermission import com.storyteller_f.file_system_local.volumePathName import com.storyteller_f.giant_explorer.control.format1024 import com.storyteller_f.giant_explorer.databinding.DialogVolumeSpaceBinding @@ -30,6 +34,13 @@ class VolumeSpaceDialog : deployFile(binding, it) } } + val regularUri = Uri.Builder().scheme(ContentResolver.SCHEME_FILE) + .path(LocalFileSystem.ROOT_USER_EMULATED_PATH).build() + binding.managePermission.setOnClickListener { + scope.launch { + it.context.requestFilePermission(regularUri) + } + } } private fun deployFile( diff --git a/app/GiantExplorer/giant-explorer/src/main/res/layout/dialog_volume_space.xml b/app/GiantExplorer/giant-explorer/src/main/res/layout/dialog_volume_space.xml index ce71602..7a710e3 100644 --- a/app/GiantExplorer/giant-explorer/src/main/res/layout/dialog_volume_space.xml +++ b/app/GiantExplorer/giant-explorer/src/main/res/layout/dialog_volume_space.xml @@ -9,9 +9,18 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingHorizontal="40dp" + android:paddingHorizontal="20dp" android:paddingVertical="20dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + +