diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0eae0dc7..2b5b5272 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
-- Preserve modified date when unzip files ([#176])
+- File modification time is now preserved when compressing/decompressing files ([#176])
## [1.1.0] - 2025-05-21
diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml
index 21d2112b..753abbe9 100644
--- a/app/detekt-baseline.xml
+++ b/app/detekt-baseline.xml
@@ -9,7 +9,7 @@
ComplexCondition:MimeTypesActivity.kt$MimeTypesActivity$mimetype != "image" && mimetype != "video" && mimetype != "audio" && mimetype != "text" && !extraAudioMimeTypes.contains(fullMimetype) && !extraDocumentMimeTypes.contains(fullMimetype) && !archiveMimeTypes.contains(fullMimetype)
ComplexCondition:ReadTextActivity.kt$ReadTextActivity$requestCode == SELECT_SAVE_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null
CyclomaticComplexMethod:DecompressActivity.kt$DecompressActivity$private fun decompressTo(destination: String)
- CyclomaticComplexMethod:ItemsAdapter.kt$ItemsAdapter$@SuppressLint("NewApi") private fun compressPaths(sourcePaths: List<String>, targetPath: String, password: String? = null): Boolean
+ CyclomaticComplexMethod:ItemsAdapter.kt$ItemsAdapter$@SuppressLint("NewApi") private fun compressPaths( sourcePaths: List<String>, targetPath: String, password: String? = null ): Boolean
CyclomaticComplexMethod:ItemsAdapter.kt$ItemsAdapter$override fun actionItemPressed(id: Int)
CyclomaticComplexMethod:MainActivity.kt$MainActivity$private fun setupOptionsMenu()
CyclomaticComplexMethod:MimeTypesActivity.kt$MimeTypesActivity$private fun getProperFileDirItems(callback: (ArrayList<FileDirItem>) -> Unit)
@@ -58,32 +58,7 @@
MaxLineLength:FavoritesActivity.kt$FavoritesActivity$FilePickerDialog
MaxLineLength:FavoritesActivity.kt$FavoritesActivity$ManageFavoritesAdapter(this@FavoritesActivity, favorites, this@FavoritesActivity, manageFavoritesList) { }
MaxLineLength:FavoritesActivity.kt$FavoritesActivity$updateMaterialActivityViews(manageFavoritesCoordinator, manageFavoritesList, useTransparentNavigation = true, useTopSearchMenu = false)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$"${baseConfig.OTGTreeUri}/document/${baseConfig.OTGPartition}%3A${itemToLoad.substring(baseConfig.OTGPath.length).replace("/", "%2F")}"
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$(drawable as LayerDrawable).findDrawableByLayerId(R.id.shortcut_folder_background).applyColorFilter(appIconColor)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$File(path).listFiles()?.filter { if (shouldShowHidden) true else !it.name.startsWith('.') }
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$activity.getDocumentFile(path)?.listFiles()?.filter { if (shouldShowHidden) true else !it.name!!.startsWith(".") }
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$if
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NO_HISTORY
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$itemName?.text = if (textToHighlight.isEmpty()) fileName else fileName.highlightTextPart(textToHighlight, properPrimaryColor)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$itemSection?.text = if (textToHighlight.isEmpty()) listItem.mName else listItem.mName.highlightTextPart(textToHighlight, properPrimaryColor)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$name = if (base == currentPath) currentPath.getFilenameFromPath() else mainFilePath.relativizeWith(base)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$override fun getIsItemSelectable(position: Int)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$override fun onChange(position: Int)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$private
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$private fun getSelectedFileDirItems()
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$sourceFile.list()?.isEmpty() == true
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$val currPath = if (entry.isDirectory) path else "${path.getParentPath().trimEnd('/')}/${entry.fileName}"
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$val drawable = fileDrawables.getOrElse(fileName.substringAfterLast(".").lowercase(Locale.getDefault()), { fileDrawable })
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$val fileDirItem = FileDirItem(currPath, entry.fileName, entry.isDirectory, 0, entry.uncompressedSize)
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$val fileIcon = fileDrawables.getOrElse(path.substringAfterLast(".").lowercase(Locale.getDefault()), { fileDrawable })
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter$val paths = getSelectedFileDirItems().asSequence().filter { !it.isDirectory }.map { it.path }.toMutableList() as ArrayList<String>
MaxLineLength:ItemsAdapter.kt$ItemsAdapter$}
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter.Binding.ItemDirGrid$override
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter.Binding.ItemEmpty$override
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter.Binding.ItemFileDirList$override
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter.Binding.ItemFileDirList$return ItemFileDirListBindingAdapter(ItemFileDirListBinding.inflate(layoutInflater, viewGroup, attachToRoot))
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter.Binding.ItemFileGrid$override
- MaxLineLength:ItemsAdapter.kt$ItemsAdapter.Binding.ItemSection$override
MaxLineLength:ItemsFragment.kt$ItemsFragment$ItemsAdapter
MaxLineLength:ItemsFragment.kt$ItemsFragment$class
MaxLineLength:ItemsFragment.kt$ItemsFragment$context
@@ -107,7 +82,6 @@
MaxLineLength:MainActivity.kt$MainActivity$private fun getInactiveTabIndexes(activeIndex: Int)
MaxLineLength:MainActivity.kt$MainActivity$resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
MaxLineLength:MainActivity.kt$MainActivity$updateMaterialActivityViews(binding.mainCoordinator, null, useTransparentNavigation = false, useTopSearchMenu = true)
- MaxLineLength:MainActivity.kt$MainActivity$val isPickFileIntent = action == RingtoneManager.ACTION_RINGTONE_PICKER || action == Intent.ACTION_GET_CONTENT || action == Intent.ACTION_PICK
MaxLineLength:MainActivity.kt$MainActivity$val licenses = LICENSE_GLIDE or LICENSE_PATTERN or LICENSE_REPRINT or LICENSE_GESTURE_VIEWS or LICENSE_AUTOFITTEXTVIEW or LICENSE_ZIP4J
MaxLineLength:MimeTypesActivity.kt$MimeTypesActivity$!extraAudioMimeTypes.contains(fullMimetype)
MaxLineLength:MimeTypesActivity.kt$MimeTypesActivity$if
@@ -136,18 +110,17 @@
MaxLineLength:StorageFragment.kt$StorageFragment$val filtered = allDeviceListItems.filter { it.mName.contains(text, true) }.toMutableList() as ArrayList<ListItem>
MaxLineLength:StorageFragment.kt$StorageFragment$val mimeType = cursor.getStringValue(MediaStore.Files.FileColumns.MIME_TYPE)?.lowercase(Locale.getDefault())
MaxLineLength:StorageFragment.kt$StorageFragment$val storageStatsManager = context.getSystemService(AppCompatActivity.STORAGE_STATS_SERVICE) as StorageStatsManager
- MaxLineLength:ViewPagerAdapter.kt$ViewPagerAdapter$val isGetContentIntent = activity.intent.action == Intent.ACTION_GET_CONTENT || activity.intent.action == Intent.ACTION_PICK
NestedBlockDepth:DecompressActivity.kt$DecompressActivity$private fun decompressTo(destination: String)
- NestedBlockDepth:ItemsAdapter.kt$ItemsAdapter$@SuppressLint("NewApi") private fun compressPaths(sourcePaths: List<String>, targetPath: String, password: String? = null): Boolean
- NestedBlockDepth:ItemsAdapter.kt$ItemsAdapter$private fun decompressPaths(paths: List<String>, conflictResolutions: LinkedHashMap<String, Int>, callback: (success: Boolean) -> Unit)
+ NestedBlockDepth:ItemsAdapter.kt$ItemsAdapter$@SuppressLint("NewApi") private fun compressPaths( sourcePaths: List<String>, targetPath: String, password: String? = null ): Boolean
+ NestedBlockDepth:ItemsAdapter.kt$ItemsAdapter$private fun decompressPaths( paths: List<String>, conflictResolutions: LinkedHashMap<String, Int>, callback: (success: Boolean) -> Unit )
NestedBlockDepth:ItemsAdapter.kt$ItemsAdapter$private fun setupView(binding: ItemViewBinding, listItem: ListItem)
- NestedBlockDepth:ItemsAdapter.kt$ItemsAdapter$private fun tryDecompressingPaths(sourcePaths: List<String>, callback: (success: Boolean) -> Unit)
+ NestedBlockDepth:ItemsAdapter.kt$ItemsAdapter$private fun tryDecompressingPaths( sourcePaths: List<String>, callback: (success: Boolean) -> Unit )
NestedBlockDepth:ItemsFragment.kt$ItemsFragment$private fun getRegularItemsOf(path: String, callback: (originalPath: String, items: ArrayList<ListItem>) -> Unit)
NestedBlockDepth:ItemsFragment.kt$ItemsFragment$private fun searchFiles(text: String, path: String): ArrayList<ListItem>
NestedBlockDepth:RecentsFragment.kt$RecentsFragment$private fun getRecents(callback: (recents: ArrayList<ListItem>) -> Unit)
NestedBlockDepth:StorageFragment.kt$StorageFragment$override fun setupFragment(activity: SimpleActivity)
NestedBlockDepth:StorageFragment.kt$StorageFragment$private fun getAllFiles(volumeName: String): ArrayList<FileDirItem>
- ReturnCount:ItemsAdapter.kt$ItemsAdapter$@SuppressLint("NewApi") private fun compressPaths(sourcePaths: List<String>, targetPath: String, password: String? = null): Boolean
+ ReturnCount:ItemsAdapter.kt$ItemsAdapter$@SuppressLint("NewApi") private fun compressPaths( sourcePaths: List<String>, targetPath: String, password: String? = null ): Boolean
SwallowedException:ItemsAdapter.kt$ItemsAdapter$e: Exception
SwallowedException:MimeTypesActivity.kt$MimeTypesActivity$e: Exception
SwallowedException:StorageFragment.kt$StorageFragment$e: Exception
diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml
index 2b2184b5..e49ad51f 100644
--- a/app/lint-baseline.xml
+++ b/app/lint-baseline.xml
@@ -1,5 +1,5 @@
-
+
+ message="A newer version of Gradle than 8.13 is available: 8.14.3"
+ errorLine1="distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -107,7 +107,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -613,7 +613,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
@@ -624,7 +624,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
@@ -635,7 +635,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
@@ -646,7 +646,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
@@ -657,7 +657,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt
index 9b052b8c..67712316 100644
--- a/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt
+++ b/app/src/main/kotlin/org/fossify/filemanager/adapters/ItemsAdapter.kt
@@ -128,7 +128,8 @@ class ItemsAdapter(
private val swipeRefreshLayout: SwipeRefreshLayout?,
canHaveIndividualViewType: Boolean = true,
itemClick: (Any) -> Unit,
-) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), RecyclerViewFastScroller.OnPopupTextUpdate {
+) : MyRecyclerViewAdapter(activity, recyclerView, itemClick),
+ RecyclerViewFastScroller.OnPopupTextUpdate {
private lateinit var fileDrawable: Drawable
private lateinit var folderDrawable: Drawable
@@ -143,7 +144,9 @@ class ItemsAdapter(
private val config = activity.config
private val viewType = if (canHaveIndividualViewType) {
- config.getFolderViewType(listItems.firstOrNull { !it.isSectionTitle }?.mPath?.getParentPath() ?: "")
+ config.getFolderViewType(
+ path = listItems.firstOrNull { !it.isSectionTitle }?.mPath?.getParentPath().orEmpty()
+ )
} else {
config.viewType
}
@@ -169,7 +172,8 @@ class ItemsAdapter(
override fun prepareActionMode(menu: Menu) {
menu.apply {
- findItem(R.id.cab_decompress).isVisible = getSelectedFileDirItems().map { it.path }.any { it.isZipFile() }
+ findItem(R.id.cab_decompress).isVisible =
+ getSelectedFileDirItems().map { it.path }.any { it.isZipFile() }
findItem(R.id.cab_confirm_selection).isVisible = isPickMultipleIntent
findItem(R.id.cab_copy_path).isVisible = isOneItemSelected()
findItem(R.id.cab_open_with).isVisible = isOneFileSelected()
@@ -207,13 +211,21 @@ class ItemsAdapter(
}
}
- override fun getSelectableItemCount() = listItems.filter { !it.isSectionTitle && !it.isGridTypeDivider }.size
+ override fun getSelectableItemCount(): Int {
+ return listItems.filter { !it.isSectionTitle && !it.isGridTypeDivider }.size
+ }
- override fun getIsItemSelectable(position: Int) = !listItems[position].isSectionTitle && !listItems[position].isGridTypeDivider
+ override fun getIsItemSelectable(position: Int): Boolean {
+ return !listItems[position].isSectionTitle && !listItems[position].isGridTypeDivider
+ }
- override fun getItemSelectionKey(position: Int) = listItems.getOrNull(position)?.path?.hashCode()
+ override fun getItemSelectionKey(position: Int): Int? {
+ return listItems.getOrNull(position)?.path?.hashCode()
+ }
- override fun getItemKeyPosition(key: Int) = listItems.indexOfFirst { it.path.hashCode() == key }
+ override fun getItemKeyPosition(key: Int): Int {
+ return listItems.indexOfFirst { it.path.hashCode() == key }
+ }
override fun onActionModeCreated() {
swipeRefreshLayout?.isRefreshing = false
@@ -234,25 +246,37 @@ class ItemsAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- val binding = Binding.getByItemViewType(viewType, isListViewType).inflate(layoutInflater, parent, false)
+ val binding = Binding.getByItemViewType(viewType, isListViewType)
+ .inflate(layoutInflater, parent, false)
return createViewHolder(binding.root)
}
override fun onBindViewHolder(holder: MyRecyclerViewAdapter.ViewHolder, position: Int) {
val fileDirItem = listItems[position]
- holder.bindView(fileDirItem, true, !fileDirItem.isSectionTitle) { itemView, layoutPosition ->
+ holder.bindView(
+ any = fileDirItem,
+ allowSingleClick = true,
+ allowLongClick = !fileDirItem.isSectionTitle
+ ) { itemView, layoutPosition ->
val viewType = getItemViewType(position)
- setupView(Binding.getByItemViewType(viewType, isListViewType).bind(itemView), fileDirItem)
+ setupView(
+ binding = Binding.getByItemViewType(viewType, isListViewType).bind(itemView),
+ listItem = fileDirItem
+ )
}
bindViewHolder(holder)
}
override fun getItemCount() = listItems.size
- private fun getItemWithKey(key: Int): FileDirItem? = listItems.firstOrNull { it.path.hashCode() == key }
+ private fun getItemWithKey(key: Int): FileDirItem? {
+ return listItems.firstOrNull { it.path.hashCode() == key }
+ }
- private fun isOneFileSelected() = isOneItemSelected() && getItemWithKey(selectedKeys.first())?.isDirectory == false
+ private fun isOneFileSelected(): Boolean {
+ return isOneItemSelected() && getItemWithKey(selectedKeys.first())?.isDirectory == false
+ }
private fun checkHideBtnVisibility(menu: Menu) {
var hiddenCnt = 0
@@ -271,7 +295,10 @@ class ItemsAdapter(
private fun confirmSelection() {
if (selectedKeys.isNotEmpty()) {
- val paths = getSelectedFileDirItems().asSequence().filter { !it.isDirectory }.map { it.path }.toMutableList() as ArrayList
+ val paths = getSelectedFileDirItems()
+ .asSequence()
+ .filter { !it.isDirectory }.map { it.path }
+ .toMutableList() as ArrayList
if (paths.isEmpty()) {
finishActMode()
} else {
@@ -350,7 +377,11 @@ class ItemsAdapter(
getShortcutImage(path, drawable) {
val intent = Intent(activity, SplashActivity::class.java)
intent.action = Intent.ACTION_VIEW
- intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NO_HISTORY
+ intent.flags =
+ intent.flags or
+ Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_CLEAR_TASK or
+ Intent.FLAG_ACTIVITY_NO_HISTORY
intent.data = Uri.fromFile(File(path))
val shortcut = ShortcutInfo.Builder(activity, path)
@@ -366,7 +397,8 @@ class ItemsAdapter(
private fun getShortcutImage(path: String, drawable: Drawable, callback: () -> Unit) {
val appIconColor = baseConfig.appIconColor
- (drawable as LayerDrawable).findDrawableByLayerId(R.id.shortcut_folder_background).applyColorFilter(appIconColor)
+ (drawable as LayerDrawable).findDrawableByLayerId(R.id.shortcut_folder_background)
+ .applyColorFilter(appIconColor)
if (activity.getIsPathDirectory(path)) {
callback()
} else {
@@ -387,10 +419,15 @@ class ItemsAdapter(
try {
val bitmap = builder.get()
- drawable.findDrawableByLayerId(R.id.shortcut_folder_background).applyColorFilter(0)
+ drawable.findDrawableByLayerId(R.id.shortcut_folder_background)
+ .applyColorFilter(0)
drawable.setDrawableByLayerId(R.id.shortcut_folder_image, bitmap)
} catch (e: Exception) {
- val fileIcon = fileDrawables.getOrElse(path.substringAfterLast(".").lowercase(Locale.getDefault()), { fileDrawable })
+ val fileIcon = fileDrawables
+ .getOrElse(
+ key = path.substringAfterLast(".").lowercase(Locale.getDefault()),
+ defaultValue = { fileDrawable }
+ )
drawable.setDrawableByLayerId(R.id.shortcut_folder_image, fileIcon)
}
@@ -415,15 +452,19 @@ class ItemsAdapter(
}
activity.isPathOnOTG(path) -> {
- activity.getDocumentFile(path)?.listFiles()?.filter { if (shouldShowHidden) true else !it.name!!.startsWith(".") }?.forEach {
- addFileUris(it.uri.toString(), paths)
- }
+ activity.getDocumentFile(path)?.listFiles()
+ ?.filter { if (shouldShowHidden) true else !it.name!!.startsWith(".") }
+ ?.forEach {
+ addFileUris(it.uri.toString(), paths)
+ }
}
else -> {
- File(path).listFiles()?.filter { if (shouldShowHidden) true else !it.name.startsWith('.') }?.forEach {
- addFileUris(it.absolutePath, paths)
- }
+ File(path).listFiles()
+ ?.filter { if (shouldShowHidden) true else !it.name.startsWith('.') }
+ ?.forEach {
+ addFileUris(it.absolutePath, paths)
+ }
}
}
} else {
@@ -482,11 +523,21 @@ class ItemsAdapter(
if (activity.isPathOnRoot(it) || activity.isPathOnRoot(firstFile.path)) {
copyMoveRootItems(files, it, isCopyOperation)
} else {
- activity.copyMoveFilesTo(files, source, it, isCopyOperation, false, config.shouldShowHidden()) {
+ activity.copyMoveFilesTo(
+ fileDirItems = files,
+ source = source,
+ destination = it,
+ isCopyOperation = isCopyOperation,
+ copyPhotoVideoOnly = false,
+ copyHidden = config.shouldShowHidden()
+ ) {
if (!isCopyOperation) {
files.forEach { sourceFileDir ->
val sourcePath = sourceFileDir.path
- if (activity.isRestrictedSAFOnlyRoot(sourcePath) && activity.getDoesFilePathExist(sourcePath)) {
+ if (
+ activity.isRestrictedSAFOnlyRoot(sourcePath)
+ && activity.getDoesFilePathExist(sourcePath)
+ ) {
activity.deleteFile(sourceFileDir, true) {
listener?.refreshFragment()
activity.runOnUiThread {
@@ -495,8 +546,12 @@ class ItemsAdapter(
}
} else {
val sourceFile = File(sourcePath)
- if (activity.getDoesFilePathExist(source) && activity.getIsPathDirectory(source) &&
- sourceFile.list()?.isEmpty() == true && sourceFile.getProperSize(true) == 0L && sourceFile.getFileCount(true) == 0
+ if (
+ activity.getDoesFilePathExist(source)
+ && activity.getIsPathDirectory(source)
+ && sourceFile.list()?.isEmpty() == true
+ && sourceFile.getProperSize(true) == 0L
+ && sourceFile.getFileCount(true) == 0
) {
val sourceFolder = sourceFile.toFileDirItem(activity)
activity.deleteFile(sourceFolder, true) {
@@ -520,7 +575,11 @@ class ItemsAdapter(
}
}
- private fun copyMoveRootItems(files: ArrayList, destinationPath: String, isCopyOperation: Boolean) {
+ private fun copyMoveRootItems(
+ files: ArrayList,
+ destinationPath: String,
+ isCopyOperation: Boolean
+ ) {
activity.toast(R.string.copying)
ensureBackgroundThread {
val fileCnt = files.size
@@ -586,7 +645,11 @@ class ItemsAdapter(
return@handleSAFDialog
}
- val paths = getSelectedFileDirItems().asSequence().map { it.path }.filter { it.isZipFile() }.toList()
+ val paths = getSelectedFileDirItems()
+ .asSequence()
+ .map { it.path }
+ .filter { it.isZipFile() }
+ .toList()
ensureBackgroundThread {
tryDecompressingPaths(paths) { success ->
activity.runOnUiThread {
@@ -603,15 +666,28 @@ class ItemsAdapter(
}
}
- private fun tryDecompressingPaths(sourcePaths: List, callback: (success: Boolean) -> Unit) {
+ private fun tryDecompressingPaths(
+ sourcePaths: List,
+ callback: (success: Boolean) -> Unit
+ ) {
sourcePaths.forEach { path ->
ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path))).use { zipInputStream ->
try {
val fileDirItems = ArrayList()
var entry = zipInputStream.nextEntry
while (entry != null) {
- val currPath = if (entry.isDirectory) path else "${path.getParentPath().trimEnd('/')}/${entry.fileName}"
- val fileDirItem = FileDirItem(currPath, entry.fileName, entry.isDirectory, 0, entry.uncompressedSize)
+ val currPath = if (entry.isDirectory) {
+ path
+ } else {
+ "${path.getParentPath().trimEnd('/')}/${entry.fileName}"
+ }
+ val fileDirItem = FileDirItem(
+ path = currPath,
+ name = entry.fileName,
+ isDirectory = entry.isDirectory,
+ children = 0,
+ size = entry.uncompressedSize
+ )
fileDirItems.add(fileDirItem)
entry = zipInputStream.nextEntry
}
@@ -636,9 +712,14 @@ class ItemsAdapter(
}
}
- private fun decompressPaths(paths: List, conflictResolutions: LinkedHashMap, callback: (success: Boolean) -> Unit) {
+ private fun decompressPaths(
+ paths: List,
+ conflictResolutions: LinkedHashMap,
+ callback: (success: Boolean) -> Unit
+ ) {
paths.forEach { path ->
- val zipInputStream = ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path)))
+ val zipInputStream =
+ ZipInputStream(BufferedInputStream(activity.getFileInputStreamSync(path)))
zipInputStream.use {
try {
var entry = zipInputStream.nextEntry
@@ -651,7 +732,11 @@ class ItemsAdapter(
val resolution = getConflictResolution(conflictResolutions, newPath)
val doesPathExist = activity.getDoesFilePathExist(newPath)
if (doesPathExist && resolution == CONFLICT_OVERWRITE) {
- val fileDirItem = FileDirItem(newPath, newPath.getFilenameFromPath(), entry.isDirectory)
+ val fileDirItem = FileDirItem(
+ path = newPath,
+ name = newPath.getFilenameFromPath(),
+ isDirectory = entry.isDirectory
+ )
if (activity.getIsPathDirectory(path)) {
activity.deleteFolderBg(fileDirItem, false) {
if (it) {
@@ -684,10 +769,15 @@ class ItemsAdapter(
}
}
- private fun extractEntry(newPath: String, entry: LocalFileHeader, zipInputStream: ZipInputStream) {
+ private fun extractEntry(
+ newPath: String,
+ entry: LocalFileHeader,
+ zipInputStream: ZipInputStream
+ ) {
if (entry.isDirectory) {
if (!activity.createDirectorySync(newPath) && !activity.getDoesFilePathExist(newPath)) {
- val error = String.format(activity.getString(R.string.could_not_create_file), newPath)
+ val error =
+ String.format(activity.getString(R.string.could_not_create_file), newPath)
activity.showErrorToast(error)
}
} else {
@@ -699,7 +789,10 @@ class ItemsAdapter(
}
}
- private fun getConflictResolution(conflictResolutions: LinkedHashMap, path: String): Int {
+ private fun getConflictResolution(
+ conflictResolutions: LinkedHashMap,
+ path: String
+ ): Int {
return if (conflictResolutions.size == 1 && conflictResolutions.containsKey("")) {
conflictResolutions[""]!!
} else if (conflictResolutions.containsKey(path)) {
@@ -710,15 +803,21 @@ class ItemsAdapter(
}
@SuppressLint("NewApi")
- private fun compressPaths(sourcePaths: List, targetPath: String, password: String? = null): Boolean {
+ private fun compressPaths(
+ sourcePaths: List,
+ targetPath: String,
+ password: String? = null
+ ): Boolean {
val queue = LinkedList()
val fos = activity.getFileOutputStreamSync(targetPath, "application/zip") ?: return false
- val zout = password?.let { ZipOutputStream(fos, password.toCharArray()) } ?: ZipOutputStream(fos)
+ val zout =
+ password?.let { ZipOutputStream(fos, password.toCharArray()) } ?: ZipOutputStream(fos)
var res: Closeable = fos
- fun zipEntry(name: String) = ZipParameters().also {
+ fun zipEntry(name: String, lastModified: Long) = ZipParameters().also {
it.fileNameInZip = name
+ it.lastModifiedFileTime = lastModified
if (password != null) {
it.isEncryptFiles = true
it.encryptionMethod = EncryptionMethod.AES
@@ -734,9 +833,11 @@ class ItemsAdapter(
queue.push(mainFilePath)
if (activity.getIsPathDirectory(mainFilePath)) {
name = "${mainFilePath.getFilenameFromPath()}/"
+ val dirModified = File(mainFilePath).lastModified()
zout.putNextEntry(
ZipParameters().also {
it.fileNameInZip = name
+ it.lastModifiedFileTime = dirModified
}
)
}
@@ -751,9 +852,9 @@ class ItemsAdapter(
if (activity.getIsPathDirectory(file.path)) {
queue.push(file.path)
name = "${name.trimEnd('/')}/"
- zout.putNextEntry(zipEntry(name))
+ zout.putNextEntry(zipEntry(name, file.modified))
} else {
- zout.putNextEntry(zipEntry(name))
+ zout.putNextEntry(zipEntry(name, file.modified))
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
zout.closeEntry()
}
@@ -766,9 +867,9 @@ class ItemsAdapter(
if (activity.getIsPathDirectory(file.absolutePath)) {
queue.push(file.absolutePath)
name = "${name.trimEnd('/')}/"
- zout.putNextEntry(zipEntry(name))
+ zout.putNextEntry(zipEntry(name, file.lastModified()))
} else {
- zout.putNextEntry(zipEntry(name))
+ zout.putNextEntry(zipEntry(name, file.lastModified()))
activity.getFileInputStreamSync(file.path)!!.copyTo(zout)
zout.closeEntry()
}
@@ -776,8 +877,14 @@ class ItemsAdapter(
}
} else {
- name = if (base == currentPath) currentPath.getFilenameFromPath() else mainFilePath.relativizeWith(base)
- zout.putNextEntry(zipEntry(name))
+ name =
+ if (base == currentPath) {
+ currentPath.getFilenameFromPath()
+ } else {
+ mainFilePath.relativizeWith(base)
+ }
+ val fileModified = File(mainFilePath).lastModified()
+ zout.putNextEntry(zipEntry(name, fileModified))
activity.getFileInputStreamSync(mainFilePath)!!.copyTo(zout)
zout.closeEntry()
}
@@ -851,7 +958,11 @@ class ItemsAdapter(
private fun getFirstSelectedItemPath() = getSelectedFileDirItems().first().path
- private fun getSelectedFileDirItems() = listItems.filter { selectedKeys.contains(it.path.hashCode()) } as ArrayList
+ private fun getSelectedFileDirItems(): ArrayList {
+ return listItems.filter {
+ selectedKeys.contains(it.path.hashCode())
+ } as ArrayList
+ }
fun updateItems(newItems: ArrayList, highlightText: String = "") {
if (newItems.hashCode() != currentItemsHash) {
@@ -897,7 +1008,8 @@ class ItemsAdapter(
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing) {
- val icon = Binding.getByItemViewType(holder.itemViewType, isListViewType).bind(holder.itemView).itemIcon
+ val icon = Binding.getByItemViewType(holder.itemViewType, isListViewType)
+ .bind(holder.itemView).itemIcon
if (icon != null) {
Glide.with(activity).clear(icon)
}
@@ -909,16 +1021,35 @@ class ItemsAdapter(
binding.apply {
if (listItem.isSectionTitle) {
itemIcon?.setImageDrawable(folderDrawable)
- itemSection?.text = if (textToHighlight.isEmpty()) listItem.mName else listItem.mName.highlightTextPart(textToHighlight, properPrimaryColor)
+ itemSection?.text =
+ if (textToHighlight.isEmpty()) {
+ listItem.mName
+ } else {
+ listItem.mName.highlightTextPart(
+ textToHighlight = textToHighlight,
+ color = properPrimaryColor
+ )
+ }
itemSection?.setTextColor(textColor)
itemSection?.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
} else if (!listItem.isGridTypeDivider) {
root.setupViewBackground(activity)
itemFrame.isSelected = isSelected
val fileName = listItem.name
- itemName?.text = if (textToHighlight.isEmpty()) fileName else fileName.highlightTextPart(textToHighlight, properPrimaryColor)
+ itemName?.text =
+ if (textToHighlight.isEmpty()) {
+ fileName
+ } else {
+ fileName.highlightTextPart(
+ textToHighlight = textToHighlight,
+ color = properPrimaryColor
+ )
+ }
itemName?.setTextColor(textColor)
- itemName?.setTextSize(TypedValue.COMPLEX_UNIT_PX, if (isListViewType) fontSize else smallerFontSize)
+ itemName?.setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ if (isListViewType) fontSize else smallerFontSize
+ )
itemDetails?.setTextColor(textColor)
itemDetails?.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)
@@ -947,7 +1078,10 @@ class ItemsAdapter(
itemDate?.beVisible()
itemDate?.text = listItem.modified.formatDate(activity, dateFormat, timeFormat)
- val drawable = fileDrawables.getOrElse(fileName.substringAfterLast(".").lowercase(Locale.getDefault()), { fileDrawable })
+ val drawable = fileDrawables.getOrElse(
+ key = fileName.substringAfterLast(".").lowercase(Locale.getDefault()),
+ defaultValue = { fileDrawable }
+ )
val options = RequestOptions()
.signature(listItem.getKey())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
@@ -972,12 +1106,16 @@ class ItemsAdapter(
return activity.resources.getQuantityString(R.plurals.items, children, children)
}
- private fun getOTGPublicPath(itemToLoad: String) =
- "${baseConfig.OTGTreeUri}/document/${baseConfig.OTGPartition}%3A${itemToLoad.substring(baseConfig.OTGPath.length).replace("/", "%2F")}"
+ private fun getOTGPublicPath(itemToLoad: String): String {
+ return "${baseConfig.OTGTreeUri}/document/${baseConfig.OTGPartition}%3A${
+ itemToLoad.substring(baseConfig.OTGPath.length).replace("/", "%2F")
+ }"
+ }
private fun getImagePathToLoad(path: String): Any {
var itemToLoad = if (path.endsWith(".apk", true)) {
- val packageInfo = activity.packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES)
+ val packageInfo =
+ activity.packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES)
if (packageInfo != null) {
val appInfo = packageInfo.applicationInfo
appInfo.sourceDir = path
@@ -1000,13 +1138,16 @@ class ItemsAdapter(
}
fun initDrawables() {
- folderDrawable = resources.getColoredDrawableWithColor(R.drawable.ic_folder_vector, properPrimaryColor)
+ folderDrawable =
+ resources.getColoredDrawableWithColor(R.drawable.ic_folder_vector, properPrimaryColor)
folderDrawable.alpha = 180
fileDrawable = resources.getDrawable(R.drawable.ic_file_generic)
fileDrawables = getFilePlaceholderDrawables(activity)
}
- override fun onChange(position: Int) = listItems.getOrNull(position)?.getBubbleText(activity, dateFormat, timeFormat) ?: ""
+ override fun onChange(position: Int): String {
+ return listItems.getOrNull(position)?.getBubbleText(activity, dateFormat, timeFormat) ?: ""
+ }
private sealed interface Binding {
companion object {
@@ -1027,12 +1168,23 @@ class ItemsAdapter(
}
}
- fun inflate(layoutInflater: LayoutInflater, viewGroup: ViewGroup, attachToRoot: Boolean): ItemViewBinding
+ fun inflate(
+ layoutInflater: LayoutInflater,
+ viewGroup: ViewGroup,
+ attachToRoot: Boolean
+ ): ItemViewBinding
+
fun bind(view: View): ItemViewBinding
data object ItemSection : Binding {
- override fun inflate(layoutInflater: LayoutInflater, viewGroup: ViewGroup, attachToRoot: Boolean): ItemViewBinding {
- return ItemSectionBindingAdapter(ItemSectionBinding.inflate(layoutInflater, viewGroup, attachToRoot))
+ override fun inflate(
+ layoutInflater: LayoutInflater,
+ viewGroup: ViewGroup,
+ attachToRoot: Boolean
+ ): ItemViewBinding {
+ return ItemSectionBindingAdapter(
+ ItemSectionBinding.inflate(layoutInflater, viewGroup, attachToRoot)
+ )
}
override fun bind(view: View): ItemViewBinding {
@@ -1041,8 +1193,14 @@ class ItemsAdapter(
}
data object ItemEmpty : Binding {
- override fun inflate(layoutInflater: LayoutInflater, viewGroup: ViewGroup, attachToRoot: Boolean): ItemViewBinding {
- return ItemEmptyBindingAdapter(ItemEmptyBinding.inflate(layoutInflater, viewGroup, attachToRoot))
+ override fun inflate(
+ layoutInflater: LayoutInflater,
+ viewGroup: ViewGroup,
+ attachToRoot: Boolean
+ ): ItemViewBinding {
+ return ItemEmptyBindingAdapter(
+ ItemEmptyBinding.inflate(layoutInflater, viewGroup, attachToRoot)
+ )
}
override fun bind(view: View): ItemViewBinding {
@@ -1051,8 +1209,14 @@ class ItemsAdapter(
}
data object ItemFileDirList : Binding {
- override fun inflate(layoutInflater: LayoutInflater, viewGroup: ViewGroup, attachToRoot: Boolean): ItemViewBinding {
- return ItemFileDirListBindingAdapter(ItemFileDirListBinding.inflate(layoutInflater, viewGroup, attachToRoot))
+ override fun inflate(
+ layoutInflater: LayoutInflater,
+ viewGroup: ViewGroup,
+ attachToRoot: Boolean
+ ): ItemViewBinding {
+ return ItemFileDirListBindingAdapter(
+ ItemFileDirListBinding.inflate(layoutInflater, viewGroup, attachToRoot)
+ )
}
override fun bind(view: View): ItemViewBinding {
@@ -1061,8 +1225,14 @@ class ItemsAdapter(
}
data object ItemDirGrid : Binding {
- override fun inflate(layoutInflater: LayoutInflater, viewGroup: ViewGroup, attachToRoot: Boolean): ItemViewBinding {
- return ItemDirGridBindingAdapter(ItemDirGridBinding.inflate(layoutInflater, viewGroup, attachToRoot))
+ override fun inflate(
+ layoutInflater: LayoutInflater,
+ viewGroup: ViewGroup,
+ attachToRoot: Boolean
+ ): ItemViewBinding {
+ return ItemDirGridBindingAdapter(
+ ItemDirGridBinding.inflate(layoutInflater, viewGroup, attachToRoot)
+ )
}
override fun bind(view: View): ItemViewBinding {
@@ -1071,8 +1241,14 @@ class ItemsAdapter(
}
data object ItemFileGrid : Binding {
- override fun inflate(layoutInflater: LayoutInflater, viewGroup: ViewGroup, attachToRoot: Boolean): ItemViewBinding {
- return ItemFileGridBindingAdapter(ItemFileGridBinding.inflate(layoutInflater, viewGroup, attachToRoot))
+ override fun inflate(
+ layoutInflater: LayoutInflater,
+ viewGroup: ViewGroup,
+ attachToRoot: Boolean
+ ): ItemViewBinding {
+ return ItemFileGridBindingAdapter(
+ ItemFileGridBinding.inflate(layoutInflater, viewGroup, attachToRoot)
+ )
}
override fun bind(view: View): ItemViewBinding {
@@ -1114,7 +1290,9 @@ class ItemsAdapter(
override fun getRoot(): View = binding.root
}
- private class ItemFileDirListBindingAdapter(val binding: ItemFileDirListBinding) : ItemViewBinding {
+ private class ItemFileDirListBindingAdapter(
+ val binding: ItemFileDirListBinding
+ ) : ItemViewBinding {
override val itemFrame: FrameLayout = binding.itemFrame
override val itemName: TextView = binding.itemName
override val itemIcon: ImageView = binding.itemIcon