diff --git a/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt b/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt index 08c030e337..b43477637a 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt +++ b/app/src/main/java/fr/free/nrw/commons/utils/DownloadUtils.kt @@ -10,12 +10,20 @@ import fr.free.nrw.commons.Media import fr.free.nrw.commons.R import timber.log.Timber +/** + * Utility class for managing media file downloads. + * This class provides a function to start downloading media files to the local SD card/storage. + * The downloaded file can then be opened in the Gallery or other apps. + */ object DownloadUtils { + /** - * Start the media file downloading to the local SD card/storage. The file can then be opened in - * Gallery or other apps. + * Initiates the downloading of a media file to the device's external storage. + * This method will check for storage permissions before attempting to download the file. + * If permissions are granted, the file will be saved to the device's Downloads folder. * - * @param m Media file to download + * @param activity Activity context to perform permission checks and display messages + * @param m Media object representing the file to download */ @JvmStatic fun downloadMedia( @@ -25,13 +33,17 @@ object DownloadUtils { val imageUrl = m.imageUrl var fileName = m.filename if (imageUrl == null || fileName == null || activity == null) { - Timber.d("Skipping download media as either imageUrl $imageUrl or filename $fileName activity is null") + // Log if any required parameter is null and exit + Timber.d("Skipping download media as either imageUrl $imageUrl or filename $fileName or activity is null") return } - // Strip 'File:' from beginning of filename, we really shouldn't store it + + // Strip 'File:' from beginning of filename to ensure it is stored correctly fileName = fileName.substringAfter("File:") val imageUri = Uri.parse(imageUrl) - val req = + + // Prepare a DownloadManager.Request object with the media's URI and other configurations + val req = try { DownloadManager.Request(imageUri).apply { setTitle(m.displayTitle) setDescription(activity.getString(R.string.app_name)) @@ -39,29 +51,43 @@ object DownloadUtils { allowScanningByMediaScanner() setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) } + } catch (e: SecurityException) { + // Catch SecurityException if storage permission is missing, show a message, and exit + Toast.makeText(activity, "no permission", Toast.LENGTH_SHORT).show() + return + } + + // Check for storage permissions and perform the download action if granted PermissionUtils.checkPermissionsAndPerformAction( activity, - { enqueueRequest(activity, req) }, { - Toast - .makeText( - activity, - R.string.download_failed_we_cannot_download_the_file_without_storage_permission, - Toast.LENGTH_SHORT, - ).show() + if (activity != null) enqueueRequest(activity, req) // Ensure activity is not null before proceeding }, - R.string.storage_permission, - R.string.write_storage_permission_rationale, - *PermissionUtils.PERMISSIONS_STORAGE, + { + // Show a message if permissions are denied and download cannot proceed + Toast.makeText( + activity, + R.string.download_failed_we_cannot_download_the_file_without_storage_permission, + Toast.LENGTH_SHORT, + ).show() + }, + R.string.storage_permission, // Title for permission rationale + R.string.write_storage_permission_rationale, // Message for permission rationale + *PermissionUtils.PERMISSIONS_STORAGE, // Permissions to request ) } + /** + * Enqueues the download request with the system's DownloadManager. + * + * @param activity Activity context for accessing the system's DownloadManager + * @param req DownloadManager.Request configured with the download details + */ private fun enqueueRequest( activity: Activity, req: DownloadManager.Request, ) { - val systemService = - activity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + val systemService = activity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager systemService?.enqueue(req) } } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java index 3144679720..e78916b3c7 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/StringSortingUtils.java @@ -50,15 +50,23 @@ private static double calculateSimilarity(String str1, String str2) { * @return Number of characters the strings differ by */ private static int levenshteinDistance(String str1, String str2) { - if (str1.equals(str2)) return 0; - if (str1.length() == 0) return str2.length(); - if (str2.length() == 0) return str1.length(); + if (str1.equals(str2)) { + return 0; + } + if (str1.length() == 0) { + return str2.length(); + } + if (str2.length() == 0) { + return str1.length(); + } int[] cost = new int[str1.length() + 1]; int[] newcost = new int[str1.length() + 1]; // initial cost of skipping prefix in str1 - for (int i = 0; i < cost.length; i++) cost[i] = i; + for (int i = 0; i < cost.length; i++) { + cost[i] = i; + } // transformation cost for each letter in str2 for (int j = 1; j <= str2.length(); j++) {