mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-11-02 15:53:55 +01:00
Issue 5811: folder deletion for api < 29.
This commit is contained in:
parent
1725304cce
commit
ec9e3d1b36
2 changed files with 349 additions and 30 deletions
|
|
@ -0,0 +1,212 @@
|
||||||
|
package fr.free.nrw.commons.customselector.helper
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.RecoverableSecurityException
|
||||||
|
import android.content.ContentUris
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.IntentSender
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import fr.free.nrw.commons.R
|
||||||
|
import fr.free.nrw.commons.utils.PermissionUtils
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object FolderDeletionHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main function to confirm and delete a folder.
|
||||||
|
*/
|
||||||
|
fun confirmAndDeleteFolder(context: Context, folder: File, onDeletionComplete: (Boolean) -> Unit) {
|
||||||
|
val itemCount = countItemsInFolder(folder)
|
||||||
|
val folderPath = folder.absolutePath
|
||||||
|
|
||||||
|
// Show confirmation dialog
|
||||||
|
AlertDialog.Builder(context)
|
||||||
|
.setTitle("Confirm Deletion")
|
||||||
|
.setMessage("Are you sure you want to delete the folder?\n\nPath: $folderPath\nItems: $itemCount")
|
||||||
|
.setPositiveButton("Delete") { _, _ ->
|
||||||
|
// Proceed with deletion if user confirms
|
||||||
|
val success = deleteFolder(context, folder)
|
||||||
|
onDeletionComplete(success)
|
||||||
|
}
|
||||||
|
.setNegativeButton("Cancel") { dialog, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
onDeletionComplete(false) // Return false if the user cancels
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the folder based on the Android version.
|
||||||
|
*/
|
||||||
|
private fun deleteFolder(context: Context, folder: File): Boolean {
|
||||||
|
return when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> deleteFolderScopedStorage(context, folder)
|
||||||
|
Build.VERSION.SDK_INT == Build.VERSION_CODES.Q -> deleteFolderMediaStore(context, folder)
|
||||||
|
else -> deleteFolderLegacy(folder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of items in the folder, including subfolders.
|
||||||
|
*/
|
||||||
|
private fun countItemsInFolder(folder: File): Int {
|
||||||
|
return folder.listFiles()?.size ?: 0
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Deletes a folder using the Scoped Storage API for Android 11 (API level 30) and above.
|
||||||
|
*/
|
||||||
|
private fun deleteFolderScopedStorage(context: Context, folder: File): Boolean {
|
||||||
|
Timber.tag("FolderAction").d("Deleting folder using Scoped Storage API")
|
||||||
|
|
||||||
|
// Implement deletion with Scoped Storage; fallback to recursive delete
|
||||||
|
return folder.deleteRecursively().also {
|
||||||
|
if (!it) {
|
||||||
|
Timber.tag("FolderAction").e("Failed to delete folder with Scoped Storage API")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a folder using the MediaStore API for Android 10 (API level 29).
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Deletes a folder using the MediaStore API for Android 10 (API level 29).
|
||||||
|
*/
|
||||||
|
fun deleteFolderMediaStore(context: Context, folder: File): Boolean {
|
||||||
|
Timber.tag("FolderAction").d("Deleting folder using MediaStore API on Android 10")
|
||||||
|
|
||||||
|
val contentResolver = context.contentResolver
|
||||||
|
val folderPath = folder.absolutePath
|
||||||
|
var deletionSuccessful = true
|
||||||
|
|
||||||
|
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||||
|
val selection = "${MediaStore.Images.Media.DATA} LIKE ?"
|
||||||
|
val selectionArgs = arrayOf("$folderPath/%")
|
||||||
|
|
||||||
|
contentResolver.query(uri, arrayOf(MediaStore.Images.Media._ID), selection, selectionArgs, null)?.use { cursor ->
|
||||||
|
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
|
||||||
|
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
val id = cursor.getLong(idColumn)
|
||||||
|
val imageUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val rowsDeleted = contentResolver.delete(imageUri, null, null)
|
||||||
|
if (rowsDeleted <= 0) {
|
||||||
|
Timber.tag("FolderAction").e("Failed to delete image with URI: $imageUri")
|
||||||
|
deletionSuccessful = false
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Handle RecoverableSecurityException only for API 29 and above
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && e is RecoverableSecurityException) {
|
||||||
|
handleRecoverableSecurityException(context, e)
|
||||||
|
deletionSuccessful = false
|
||||||
|
} else {
|
||||||
|
Timber.tag("FolderAction").e("Error deleting file: ${e.message}")
|
||||||
|
deletionSuccessful = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return deletionSuccessful
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the RecoverableSecurityException for deletion requests requiring user confirmation.
|
||||||
|
*/
|
||||||
|
private fun handleRecoverableSecurityException(context: Context, e: RecoverableSecurityException) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
try {
|
||||||
|
val intentSender = e.userAction.actionIntent.intentSender
|
||||||
|
(context as? Activity)?.startIntentSenderForResult(
|
||||||
|
intentSender,
|
||||||
|
2,
|
||||||
|
null, 0, 0, 0
|
||||||
|
)
|
||||||
|
} catch (ex: IntentSender.SendIntentException) {
|
||||||
|
Timber.tag("FolderAction").e("Error sending intent for deletion: ${ex.message}")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Timber.tag("FolderAction").e("RecoverableSecurityException requires API 29 or higher")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles deletion for devices running Android 9 (API level 28) and below.
|
||||||
|
*/
|
||||||
|
private fun deleteFolderLegacy(folder: File): Boolean {
|
||||||
|
return folder.deleteRecursively().also {
|
||||||
|
if (it) {
|
||||||
|
Timber.tag("FolderAction").d("Folder deleted successfully")
|
||||||
|
} else {
|
||||||
|
Timber.tag("FolderAction").e("Failed to delete folder")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the path of the folder with the specified ID from the MediaStore.
|
||||||
|
*/
|
||||||
|
fun getFolderPath(context: Context, folderId: Long): String? {
|
||||||
|
val projection = arrayOf(MediaStore.Images.Media.DATA)
|
||||||
|
val selection = "${MediaStore.Images.Media.BUCKET_ID} = ?"
|
||||||
|
val selectionArgs = arrayOf(folderId.toString())
|
||||||
|
|
||||||
|
context.contentResolver.query(
|
||||||
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||||
|
projection,
|
||||||
|
selection,
|
||||||
|
selectionArgs,
|
||||||
|
null
|
||||||
|
)?.use { cursor ->
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
val fullPath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
|
||||||
|
return File(fullPath).parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timber.tag("FolderDeletion").d("Path is null for folder ID: $folderId")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun printCurrentPermissions(context: Context) {
|
||||||
|
val permissions = mutableListOf(
|
||||||
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||||
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
permissions.add(Manifest.permission.READ_MEDIA_IMAGES)
|
||||||
|
permissions.add(Manifest.permission.ACCESS_MEDIA_LOCATION)
|
||||||
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
permissions.add(Manifest.permission.ACCESS_MEDIA_LOCATION)
|
||||||
|
} else {
|
||||||
|
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (permission in permissions) {
|
||||||
|
val status = if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
"GRANTED"
|
||||||
|
} else {
|
||||||
|
"DENIED"
|
||||||
|
}
|
||||||
|
Timber.tag("PermissionsStatus").d("$permission: $status")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3,11 +3,14 @@ package fr.free.nrw.commons.customselector.ui.selector
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.provider.Settings
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
|
@ -16,6 +19,7 @@ import android.widget.TextView
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
|
@ -42,11 +46,17 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import com.karumi.dexter.Dexter
|
||||||
|
import com.karumi.dexter.MultiplePermissionsReport
|
||||||
|
import com.karumi.dexter.PermissionToken
|
||||||
|
import com.karumi.dexter.listener.PermissionRequest
|
||||||
|
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
|
||||||
import fr.free.nrw.commons.R
|
import fr.free.nrw.commons.R
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatus
|
||||||
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
import fr.free.nrw.commons.customselector.database.NotForUploadStatusDao
|
||||||
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants
|
||||||
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants.SHOULD_REFRESH
|
import fr.free.nrw.commons.customselector.helper.CustomSelectorConstants.SHOULD_REFRESH
|
||||||
|
import fr.free.nrw.commons.customselector.helper.FolderDeletionHelper
|
||||||
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
import fr.free.nrw.commons.customselector.listeners.FolderClickListener
|
||||||
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
import fr.free.nrw.commons.customselector.listeners.ImageSelectListener
|
||||||
import fr.free.nrw.commons.customselector.model.Image
|
import fr.free.nrw.commons.customselector.model.Image
|
||||||
|
|
@ -58,6 +68,7 @@ import fr.free.nrw.commons.media.ZoomableActivity
|
||||||
import fr.free.nrw.commons.theme.BaseActivity
|
import fr.free.nrw.commons.theme.BaseActivity
|
||||||
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
import fr.free.nrw.commons.upload.FileUtilsWrapper
|
||||||
import fr.free.nrw.commons.utils.CustomSelectorUtils
|
import fr.free.nrw.commons.utils.CustomSelectorUtils
|
||||||
|
import fr.free.nrw.commons.utils.PermissionUtils
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
@ -254,6 +265,16 @@ class CustomSelectorActivity :
|
||||||
val shouldRefresh = data.getBooleanExtra(SHOULD_REFRESH, false)
|
val shouldRefresh = data.getBooleanExtra(SHOULD_REFRESH, false)
|
||||||
imageFragment?.passSelectedImages(selectedImages, shouldRefresh)
|
imageFragment?.passSelectedImages(selectedImages, shouldRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestCode == 2) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
Timber.tag("FolderAction").d("User confirmed deletion")
|
||||||
|
// Retry deletion or refresh UI if needed
|
||||||
|
} else {
|
||||||
|
Timber.tag("FolderAction").e("User denied deletion request")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -439,10 +460,12 @@ class CustomSelectorActivity :
|
||||||
limitError.setOnClickListener { displayUploadLimitWarning() }
|
limitError.setOnClickListener { displayUploadLimitWarning() }
|
||||||
|
|
||||||
val overflowMenu: ImageButton = findViewById(R.id.menu_overflow)
|
val overflowMenu: ImageButton = findViewById(R.id.menu_overflow)
|
||||||
overflowMenu.visibility = if (showOverflowMenu) View.VISIBLE else View.INVISIBLE
|
if(defaultKvStore.getBoolean("displayDeletionButton")) {
|
||||||
|
overflowMenu.visibility = if (showOverflowMenu) View.VISIBLE else View.INVISIBLE
|
||||||
// Set up popup menu when overflow menu is clicked
|
overflowMenu.setOnClickListener { showPopupMenu(overflowMenu) }
|
||||||
overflowMenu.setOnClickListener { showPopupMenu(overflowMenu) }
|
}else{
|
||||||
|
overflowMenu.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,7 +477,7 @@ class CustomSelectorActivity :
|
||||||
popupMenu.setOnMenuItemClickListener { item ->
|
popupMenu.setOnMenuItemClickListener { item ->
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_delete_folder -> {
|
R.id.action_delete_folder -> {
|
||||||
deleteFolder() // Call the delete folder logic here
|
deleteFolderWithPermissions()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else -> false
|
else -> false
|
||||||
|
|
@ -463,37 +486,121 @@ class CustomSelectorActivity :
|
||||||
popupMenu.show()
|
popupMenu.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deleteFolder() {
|
/**
|
||||||
Timber.tag("FolderAction").d("Delete folder action triggered")
|
* Triggers folder deletion after permission checks.
|
||||||
|
*/
|
||||||
|
private fun deleteFolderWithPermissions() {
|
||||||
// Run on UI thread to ensure dialog shows correctly
|
val permissions = PermissionUtils.PERMISSIONS_STORAGE
|
||||||
runOnUiThread {
|
if (PermissionUtils.hasPermission(this, permissions)) {
|
||||||
val builder = AlertDialog.Builder(this)
|
deleteFolderByApiVersion()
|
||||||
builder.setTitle("Delete Folder")
|
} else {
|
||||||
builder.setMessage("Are you sure you want to delete this folder?")
|
requestPermissionsIfNeeded()
|
||||||
|
|
||||||
// Set the positive button to confirm deletion
|
|
||||||
builder.setPositiveButton("Delete") { dialog, _ ->
|
|
||||||
// Perform folder deletion here
|
|
||||||
Timber.tag("FolderAction").d("Folder deleted")
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the negative button to cancel
|
|
||||||
builder.setNegativeButton("Cancel") { dialog, _ ->
|
|
||||||
Timber.tag("FolderAction").d("Delete action cancelled")
|
|
||||||
dialog.dismiss() // Dismiss the dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the AlertDialog
|
|
||||||
builder.create().show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks and requests necessary permissions using Dexter library.
|
||||||
|
*/
|
||||||
|
private fun requestPermissionsIfNeeded() {
|
||||||
|
val permissions = PermissionUtils.PERMISSIONS_STORAGE
|
||||||
|
|
||||||
|
Dexter.withActivity(this)
|
||||||
|
.withPermissions(*permissions)
|
||||||
|
.withListener(object : MultiplePermissionsListener {
|
||||||
|
override fun onPermissionsChecked(report: MultiplePermissionsReport) {
|
||||||
|
if (report.areAllPermissionsGranted()) {
|
||||||
|
deleteFolderByApiVersion()
|
||||||
|
} else if (report.isAnyPermissionPermanentlyDenied) {
|
||||||
|
showSettingsDialog()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
this@CustomSelectorActivity,
|
||||||
|
"Permissions required to delete folder.",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPermissionRationaleShouldBeShown(
|
||||||
|
permissions: List<PermissionRequest>,
|
||||||
|
token: PermissionToken
|
||||||
|
) {
|
||||||
|
token.continuePermissionRequest()
|
||||||
|
}
|
||||||
|
}).check()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Show a dialog directing the user to settings if permissions are permanently denied.
|
||||||
|
*/
|
||||||
|
private fun showSettingsDialog() {
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle("Need Permissions")
|
||||||
|
.setMessage("This app needs storage permissions to delete folders. You can grant them in app settings.")
|
||||||
|
.setPositiveButton("Go to Settings") { _, _ ->
|
||||||
|
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||||
|
intent.data = Uri.fromParts("package", packageName, null)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
.setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes folder based on Android API version.
|
||||||
|
*/
|
||||||
|
private fun deleteFolderByApiVersion() {
|
||||||
|
val folderPath = FolderDeletionHelper.getFolderPath(this, bucketId)
|
||||||
|
if (folderPath != null) {
|
||||||
|
val folder = File(folderPath)
|
||||||
|
|
||||||
|
if (folder.exists() && folder.isDirectory) {
|
||||||
|
FolderDeletionHelper.confirmAndDeleteFolder(this, folder) { success ->
|
||||||
|
if (success) {
|
||||||
|
Toast.makeText(this, "Folder deleted", Toast.LENGTH_SHORT).show()
|
||||||
|
Timber.tag("FolderAction").d("Folder deleted successfully")
|
||||||
|
|
||||||
|
reloadFolderList()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Failed to delete folder", Toast.LENGTH_SHORT).show()
|
||||||
|
Timber.tag("FolderAction").e("Failed to delete folder")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Folder not found", Toast.LENGTH_SHORT).show()
|
||||||
|
Timber.tag("FolderAction").e("Folder not found")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Folder path not found", Toast.LENGTH_SHORT).show()
|
||||||
|
Timber.tag("FolderDeletion").e("Failed to retrieve folder path for bucket ID: $bucketId")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reloadFolderList() {
|
||||||
|
// Clear any saved state for the last open folder
|
||||||
|
prefs.edit()
|
||||||
|
.remove(FOLDER_ID)
|
||||||
|
.remove(FOLDER_NAME)
|
||||||
|
.apply()
|
||||||
|
|
||||||
|
supportFragmentManager.popBackStack(null, androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
||||||
|
supportFragmentManager
|
||||||
|
.beginTransaction()
|
||||||
|
.replace(R.id.fragment_container, FolderFragment.newInstance())
|
||||||
|
.commit()
|
||||||
|
|
||||||
|
// Reset the toolbar and other flags
|
||||||
|
|
||||||
|
isImageFragmentOpen = false
|
||||||
|
showOverflowMenu = false
|
||||||
|
fetchData()
|
||||||
|
setUpToolbar()
|
||||||
|
changeTitle(getString(R.string.custom_selector_title), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
* override on folder click,
|
* override on folder click,
|
||||||
* change the toolbar title on folder click, make overflow menu visible
|
* change the toolbar title on folder click, make overflow menu visible
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue