Skip to content

Commit 2f43437

Browse files
committed
v5.4.1
1 parent 25f7059 commit 2f43437

File tree

16 files changed

+193
-21
lines changed

16 files changed

+193
-21
lines changed

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ android {
1111
applicationId "com.wirelessalien.zipxtract"
1212
minSdk 24
1313
targetSdk 34
14-
versionCode 19
15-
versionName "5.4"
14+
versionCode 20
15+
versionName "5.4.1"
1616

1717
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1818
}

app/src/main/java/com/wirelessalien/zipxtract/fragment/ArchiveFragment.kt

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ import android.content.Intent
2727
import android.content.IntentFilter
2828
import android.content.SharedPreferences
2929
import android.icu.text.DateFormat
30+
import android.media.MediaScannerConnection
3031
import android.os.Bundle
32+
import android.os.Environment
3133
import android.os.Handler
3234
import android.os.Looper
3335
import android.provider.MediaStore
@@ -53,6 +55,7 @@ import androidx.lifecycle.Lifecycle
5355
import androidx.localbroadcastmanager.content.LocalBroadcastManager
5456
import androidx.recyclerview.widget.LinearLayoutManager
5557
import com.google.android.material.bottomsheet.BottomSheetDialog
58+
import com.google.android.material.chip.Chip
5659
import com.google.android.material.dialog.MaterialAlertDialogBuilder
5760
import com.google.android.material.progressindicator.LinearProgressIndicator
5861
import com.google.android.material.snackbar.Snackbar
@@ -253,16 +256,47 @@ class ArchiveFragment : Fragment(), FileAdapter.OnItemClickListener {
253256
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(extractionReceiver, filter)
254257

255258
extractProgressDialog()
256-
loadArchiveFiles()
259+
setupFilterChips()
260+
scanStorageAndLoadFiles()
257261
}
258262

259-
private fun loadArchiveFiles() {
263+
private fun setupFilterChips() {
264+
val extensions = listOf("All", "zip", "rar", "7z", "tar", "gz", "bz2", "xz")
265+
val chipGroup = binding.chipGroupFilter
266+
chipGroup.isSingleSelection = true
267+
extensions.forEach { extension ->
268+
val chip = Chip(requireContext())
269+
chip.text = extension
270+
chip.isCheckable = true
271+
chip.isCheckedIconVisible = false
272+
chipGroup.addView(chip)
273+
274+
if (extension == "All") {
275+
chip.isChecked = true
276+
}
277+
}
278+
279+
chipGroup.setOnCheckedStateChangeListener { group, checkedIds ->
280+
if (checkedIds.isNotEmpty()) {
281+
val checkedChipId = checkedIds[0]
282+
val checkedChip = group.findViewById<Chip>(checkedChipId)
283+
val selectedExtension = if (checkedChip.text.toString() == "All") {
284+
null
285+
} else {
286+
checkedChip.text.toString()
287+
}
288+
loadArchiveFiles(selectedExtension)
289+
}
290+
}
291+
}
292+
293+
private fun loadArchiveFiles(extension: String?) {
260294
binding.shimmerViewContainer.startShimmer()
261295
binding.shimmerViewContainer.visibility = View.VISIBLE
262296
binding.recyclerView.visibility = View.GONE
263297

264298
CoroutineScope(Dispatchers.IO).launch {
265-
val archiveFiles = getArchiveFiles()
299+
val archiveFiles = getArchiveFiles(null, extension)
266300
withContext(Dispatchers.Main) {
267301
adapter.updateFilesAndFilter(archiveFiles)
268302
binding.shimmerViewContainer.stopShimmer()
@@ -305,34 +339,39 @@ class ArchiveFragment : Fragment(), FileAdapter.OnItemClickListener {
305339
}
306340

307341
private fun searchAllFiles(query: String?): Flow<List<File>> = flow {
308-
val results = getArchiveFiles(query)
342+
val results = getArchiveFiles(query, null)
309343
emit(results)
310344
}
311345

312-
private fun getArchiveFiles(query: String? = null): ArrayList<File> {
346+
private fun getArchiveFiles(query: String? = null, extension: String? = null): ArrayList<File> {
313347
val archiveFiles = ArrayList<File>()
314348
val uri = MediaStore.Files.getContentUri("external")
315349
val projection = arrayOf(
316350
MediaStore.Files.FileColumns.DATA,
317351
)
318352

319-
val extensionSelection = archiveExtensions.joinToString(" OR ") {
320-
"${MediaStore.Files.FileColumns.DATA} LIKE ?"
321-
}
322-
val extensionSelectionArgs = archiveExtensions.map { "%.$it" }
353+
val selectionParts = mutableListOf<String>()
354+
val selectionArgs = mutableListOf<String>()
323355

324-
val finalSelection: String
325-
val finalSelectionArgs: Array<String>
356+
if (extension != null) {
357+
selectionParts.add("${MediaStore.Files.FileColumns.DATA} LIKE ?")
358+
selectionArgs.add("%.$extension")
359+
} else {
360+
val extensionSelection = archiveExtensions.joinToString(" OR ") {
361+
"${MediaStore.Files.FileColumns.DATA} LIKE ?"
362+
}
363+
selectionParts.add("($extensionSelection)")
364+
selectionArgs.addAll(archiveExtensions.map { "%.$it" })
365+
}
326366

327367
if (!query.isNullOrBlank()) {
328-
finalSelection = "($extensionSelection) AND ${MediaStore.Files.FileColumns.DISPLAY_NAME} LIKE ?"
329-
val queryArg = "%$query%"
330-
finalSelectionArgs = (extensionSelectionArgs + queryArg).toTypedArray()
331-
} else {
332-
finalSelection = extensionSelection
333-
finalSelectionArgs = extensionSelectionArgs.toTypedArray()
368+
selectionParts.add("${MediaStore.Files.FileColumns.DISPLAY_NAME} LIKE ?")
369+
selectionArgs.add("%$query%")
334370
}
335371

372+
val finalSelection = selectionParts.joinToString(" AND ")
373+
val finalSelectionArgs = selectionArgs.toTypedArray()
374+
336375
val sortOrderColumn = when (sortBy) {
337376
SortBy.SORT_BY_NAME -> MediaStore.Files.FileColumns.DISPLAY_NAME
338377
SortBy.SORT_BY_SIZE -> MediaStore.Files.FileColumns.SIZE
@@ -376,14 +415,26 @@ class ArchiveFragment : Fragment(), FileAdapter.OnItemClickListener {
376415
return archiveFiles
377416
}
378417

418+
private fun scanStorageAndLoadFiles() {
419+
binding.shimmerViewContainer.startShimmer()
420+
binding.shimmerViewContainer.visibility = View.VISIBLE
421+
binding.recyclerView.visibility = View.GONE
422+
val externalStoragePath = Environment.getExternalStorageDirectory().absolutePath
423+
MediaScannerConnection.scanFile(requireContext(), arrayOf(externalStoragePath), null) { _, _ ->
424+
activity?.runOnUiThread {
425+
loadArchiveFiles(null)
426+
}
427+
}
428+
}
429+
379430
private fun updateAdapterWithFullList() {
380431
if (!isSearchActive) {
381432
binding.shimmerViewContainer.startShimmer()
382433
binding.shimmerViewContainer.visibility = View.VISIBLE
383434
binding.recyclerView.visibility = View.GONE
384435

385436
CoroutineScope(Dispatchers.IO).launch {
386-
val archiveFiles = getArchiveFiles()
437+
val archiveFiles = getArchiveFiles(null, null)
387438
withContext(Dispatchers.Main) {
388439
adapter.updateFilesAndFilter(archiveFiles)
389440
binding.shimmerViewContainer.stopShimmer()

app/src/main/java/com/wirelessalien/zipxtract/service/Archive7zService.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
2222
import android.app.NotificationManager
2323
import android.app.Service
2424
import android.content.Intent
25+
import android.media.MediaScannerConnection
2526
import android.os.Build
2627
import android.os.Environment
2728
import android.os.IBinder
@@ -213,6 +214,7 @@ class Archive7zService : Service() {
213214
outArchive.close()
214215
stopForegroundService()
215216
showCompletionNotification()
217+
scanForNewFile(sevenZFile)
216218
sendLocalBroadcast(Intent(ACTION_ARCHIVE_COMPLETE).putExtra(EXTRA_DIR_PATH, sevenZFile.parent))
217219
}
218220
} catch (e: SevenZipException) {
@@ -272,4 +274,8 @@ class Archive7zService : Service() {
272274
val notificationManager = getSystemService(NotificationManager::class.java)
273275
notificationManager.cancel(NOTIFICATION_ID)
274276
}
277+
278+
private fun scanForNewFile(file: File) {
279+
MediaScannerConnection.scanFile(this, arrayOf(file.absolutePath), null, null)
280+
}
275281
}

app/src/main/java/com/wirelessalien/zipxtract/service/ArchiveSplitZipService.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
2222
import android.app.NotificationManager
2323
import android.app.Service
2424
import android.content.Intent
25+
import android.media.MediaScannerConnection
2526
import android.os.Build
2627
import android.os.Environment
2728
import android.os.IBinder
@@ -250,6 +251,7 @@ class ArchiveSplitZipService : Service() {
250251

251252
if (progressMonitor.result == ProgressMonitor.Result.SUCCESS) {
252253
showCompletionNotification()
254+
scanForNewFiles(outputFile.parentFile ?: Environment.getExternalStorageDirectory())
253255
sendLocalBroadcast(Intent(ACTION_ARCHIVE_COMPLETE).putExtra(EXTRA_DIR_PATH, outputFile.parent))
254256
} else {
255257
showErrorNotification(getString(R.string.zip_creation_failed))
@@ -313,4 +315,12 @@ class ArchiveSplitZipService : Service() {
313315
val notificationManager = getSystemService(NotificationManager::class.java)
314316
notificationManager.cancel(NOTIFICATION_ID)
315317
}
318+
319+
private fun scanForNewFiles(directory: File) {
320+
val files = directory.listFiles()
321+
if (files != null) {
322+
val paths = files.map { it.absolutePath }.toTypedArray()
323+
MediaScannerConnection.scanFile(this, paths, null, null)
324+
}
325+
}
316326
}

app/src/main/java/com/wirelessalien/zipxtract/service/ArchiveTarService.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
2222
import android.app.NotificationManager
2323
import android.app.Service
2424
import android.content.Intent
25+
import android.media.MediaScannerConnection
2526
import android.os.Build
2627
import android.os.Environment
2728
import android.os.IBinder
@@ -223,6 +224,7 @@ class ArchiveTarService : Service() {
223224
}
224225
stopForegroundService()
225226
showCompletionNotification()
227+
scanForNewFile(finalTarFile)
226228
sendLocalBroadcast(Intent(ACTION_ARCHIVE_COMPLETE).putExtra(EXTRA_DIR_PATH, finalTarFile.parent))
227229

228230
} catch (e: SevenZipException) {
@@ -333,4 +335,8 @@ class ArchiveTarService : Service() {
333335
val notificationManager = getSystemService(NotificationManager::class.java)
334336
notificationManager.cancel(NOTIFICATION_ID)
335337
}
338+
339+
private fun scanForNewFile(file: File) {
340+
MediaScannerConnection.scanFile(this, arrayOf(file.absolutePath), null, null)
341+
}
336342
}

app/src/main/java/com/wirelessalien/zipxtract/service/ArchiveZipService.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
2222
import android.app.NotificationManager
2323
import android.app.Service
2424
import android.content.Intent
25+
import android.media.MediaScannerConnection
2526
import android.os.Build
2627
import android.os.Environment
2728
import android.os.IBinder
@@ -254,6 +255,7 @@ class ArchiveZipService : Service() {
254255

255256
if (progressMonitor.result == ProgressMonitor.Result.SUCCESS) {
256257
showCompletionNotification()
258+
scanForNewFile(outputFile)
257259
sendLocalBroadcast(Intent(ACTION_ARCHIVE_COMPLETE).putExtra(EXTRA_DIR_PATH, outputFile.parent))
258260
} else {
259261
showErrorNotification(progressMonitor.result.toString())
@@ -317,4 +319,8 @@ class ArchiveZipService : Service() {
317319
val notificationManager = getSystemService(NotificationManager::class.java)
318320
notificationManager.cancel(NOTIFICATION_ID)
319321
}
322+
323+
private fun scanForNewFile(file: File) {
324+
MediaScannerConnection.scanFile(this, arrayOf(file.absolutePath), null, null)
325+
}
320326
}

app/src/main/java/com/wirelessalien/zipxtract/service/CompressCsArchiveService.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
2222
import android.app.NotificationManager
2323
import android.app.Service
2424
import android.content.Intent
25+
import android.media.MediaScannerConnection
2526
import android.os.Build
2627
import android.os.Environment
2728
import android.os.IBinder
@@ -203,6 +204,7 @@ class CompressCsArchiveService : Service() {
203204
inStream.close()
204205

205206
showCompletionNotification()
207+
scanForNewFile(outputFile)
206208
sendLocalBroadcast(Intent(ACTION_ARCHIVE_COMPLETE).putExtra(EXTRA_DIR_PATH, outputFile.parent))
207209

208210
} catch (e: CompressorException) {
@@ -285,6 +287,7 @@ class CompressCsArchiveService : Service() {
285287
compressor.close()
286288

287289
showCompletionNotification()
290+
scanForNewFile(outputFile)
288291
sendLocalBroadcast(Intent(ACTION_ARCHIVE_COMPLETE).putExtra(EXTRA_DIR_PATH, outputFile.parent))
289292

290293
} catch (e: Exception) {
@@ -334,4 +337,8 @@ class CompressCsArchiveService : Service() {
334337
val notificationManager = getSystemService(NotificationManager::class.java)
335338
notificationManager.cancel(NOTIFICATION_ID)
336339
}
340+
341+
private fun scanForNewFile(file: File) {
342+
MediaScannerConnection.scanFile(this, arrayOf(file.absolutePath), null, null)
343+
}
337344
}

app/src/main/java/com/wirelessalien/zipxtract/service/CopyMoveService.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
2222
import android.app.NotificationManager
2323
import android.app.Service
2424
import android.content.Intent
25+
import android.media.MediaScannerConnection
2526
import android.os.Build
2627
import android.os.IBinder
2728
import androidx.core.app.NotificationCompat
@@ -76,13 +77,16 @@ class CopyMoveService : Service() {
7677

7778
fun copyMoveFile(file: File, destination: File) {
7879
if (file.isDirectory) {
80+
destination.mkdirs()
7981
file.listFiles()?.forEach { copyMoveFile(it, File(destination, it.name)) }
8082
} else {
8183
if (isCopyAction) {
8284
file.copyTo(destination, overwrite = true)
8385
} else {
86+
MediaScannerConnection.scanFile(this, arrayOf(file.absolutePath), null, null)
8487
file.moveTo(destination, overwrite = true)
8588
}
89+
MediaScannerConnection.scanFile(this, arrayOf(destination.absolutePath), null, null)
8690
processedFilesCount++
8791
updateNotification(processedFilesCount, totalFilesCount, isCopyAction)
8892
}

app/src/main/java/com/wirelessalien/zipxtract/service/DeleteFilesService.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.NotificationChannel
2222
import android.app.NotificationManager
2323
import android.app.Service
2424
import android.content.Intent
25+
import android.media.MediaScannerConnection
2526
import android.os.Build
2627
import android.os.IBinder
2728
import androidx.core.app.NotificationCompat
@@ -57,8 +58,10 @@ class DeleteFilesService : Service() {
5758
private fun deleteFiles(files: List<File>) {
5859
val totalFilesCount = countTotalFiles(files)
5960
var deletedFilesCount = 0
61+
val parentDirs = mutableSetOf<String>()
6062

6163
fun deleteFile(file: File) {
64+
file.parentFile?.absolutePath?.let { parentDirs.add(it) }
6265
if (file.isDirectory) {
6366
file.listFiles()?.forEach { deleteFile(it) }
6467
}
@@ -71,6 +74,10 @@ class DeleteFilesService : Service() {
7174
deleteFile(file)
7275
}
7376

77+
if (parentDirs.isNotEmpty()) {
78+
MediaScannerConnection.scanFile(this, parentDirs.toTypedArray(), null, null)
79+
}
80+
7481
stopForegroundService()
7582
stopSelf()
7683
}

0 commit comments

Comments
 (0)