From ca3d896900b3d6850d2b80dd5daf0880fb9dbc86 Mon Sep 17 00:00:00 2001 From: Simonx22 Date: Sun, 26 Apr 2026 12:44:24 -0400 Subject: [PATCH] Android: Convert FileBrowserHelper to Kotlin --- .../dolphinemu/utils/FileBrowserHelper.java | 175 ------------------ .../dolphinemu/utils/FileBrowserHelper.kt | 160 ++++++++++++++++ 2 files changed, 160 insertions(+), 175 deletions(-) delete mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.kt diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java deleted file mode 100644 index f52a70216f..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -package org.dolphinemu.dolphinemu.utils; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Environment; - -import androidx.annotation.Nullable; -import androidx.fragment.app.FragmentActivity; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.nononsenseapps.filepicker.FilePickerActivity; -import com.nononsenseapps.filepicker.Utils; - -import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.activities.CustomFilePickerActivity; -import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public final class FileBrowserHelper -{ - public static final HashSet GAME_EXTENSIONS = new HashSet<>(Arrays.asList( - "gcm", "tgc", "bin", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "nfs", "wad", "dol", - "elf", "json")); - - public static final HashSet GAME_LIKE_EXTENSIONS = new HashSet<>(GAME_EXTENSIONS); - - static - { - GAME_LIKE_EXTENSIONS.add("dff"); - } - - public static final HashSet GBA_ROM_EXTENSIONS = new HashSet<>(Arrays.asList( - "gba", "gbc", "gb", "agb", "mb", "rom", "bin")); - - public static final HashSet BIN_EXTENSION = new HashSet<>(Collections.singletonList( - "bin")); - - public static final HashSet RAW_EXTENSION = new HashSet<>(Collections.singletonList( - "raw")); - - public static final HashSet WAD_EXTENSION = new HashSet<>(Collections.singletonList( - "wad")); - - public static Intent createDirectoryPickerIntent(FragmentActivity activity, - HashSet extensions) - { - Intent i = new Intent(activity, CustomFilePickerActivity.class); - - i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); - i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false); - i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR); - i.putExtra(FilePickerActivity.EXTRA_START_PATH, - Environment.getExternalStorageDirectory().getPath()); - i.putExtra(CustomFilePickerActivity.EXTRA_EXTENSIONS, extensions); - - return i; - } - - @Nullable - public static String getSelectedPath(Intent result) - { - // Use the provided utility method to parse the result - List files = Utils.getSelectedFilesFromResult(result); - if (!files.isEmpty()) - { - File file = Utils.getFileForUri(files.get(0)); - return file.getAbsolutePath(); - } - - return null; - } - - public static boolean isPathEmptyOrValid(StringSetting path) - { - return isPathEmptyOrValid(path.getString()); - } - - /** - * Returns true if at least one of the following applies: - * - * 1. The input is empty. - * 2. The input is something which is not a content URI. - * 3. The input is a content URI that points to a file that exists and we're allowed to access. - */ - public static boolean isPathEmptyOrValid(String path) - { - return !ContentHandler.isContentUri(path) || ContentHandler.exists(path); - } - - public static void runAfterExtensionCheck(Context context, Uri uri, Set validExtensions, - Runnable runnable) - { - String extension = null; - - String path = uri.getLastPathSegment(); - if (path != null) - extension = getExtension(new File(path).getName(), false); - - if (extension == null) - extension = getExtension(ContentHandler.getDisplayName(uri), false); - - if (extension != null && validExtensions.contains(extension)) - { - runnable.run(); - return; - } - - String message; - if (extension == null) - { - message = context.getString(R.string.no_file_extension); - } - else - { - int messageId = validExtensions.size() == 1 ? - R.string.wrong_file_extension_single : R.string.wrong_file_extension_multiple; - - message = context.getString(messageId, extension, - setToSortedDelimitedString(validExtensions)); - } - - new MaterialAlertDialogBuilder(context) - .setMessage(message) - .setPositiveButton(R.string.yes, (dialogInterface, i) -> runnable.run()) - .setNegativeButton(R.string.no, null) - .setCancelable(false) - .show(); - } - - @Nullable - public static String getExtension(@Nullable String fileName, boolean includeDot) - { - if (fileName == null) - return null; - - int dotIndex = fileName.lastIndexOf("."); - if (dotIndex == -1) - return null; - return fileName.substring(dotIndex + (includeDot ? 0 : 1)); - } - - public static String setToSortedDelimitedString(Set set) - { - ArrayList list = new ArrayList<>(set); - Collections.sort(list); - return join(", ", list); - } - - // TODO: Replace this with String.join once we can use Java 8 - private static String join(CharSequence delimiter, Iterable elements) - { - StringBuilder sb = new StringBuilder(); - - boolean first = true; - for (CharSequence element : elements) - { - if (!first) - sb.append(delimiter); - first = false; - sb.append(element); - } - - return sb.toString(); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.kt new file mode 100644 index 0000000000..74f07901cb --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.kt @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.utils + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Environment +import androidx.fragment.app.FragmentActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.nononsenseapps.filepicker.FilePickerActivity +import com.nononsenseapps.filepicker.Utils +import org.dolphinemu.dolphinemu.R +import org.dolphinemu.dolphinemu.activities.CustomFilePickerActivity +import org.dolphinemu.dolphinemu.features.settings.model.StringSetting +import java.io.File + +object FileBrowserHelper { + @JvmField + val GAME_EXTENSIONS: HashSet = hashSetOf( + "gcm", + "tgc", + "bin", + "iso", + "ciso", + "gcz", + "wbfs", + "wia", + "rvz", + "nfs", + "wad", + "dol", + "elf", + "json" + ) + + @JvmField + val GAME_LIKE_EXTENSIONS: HashSet = HashSet(GAME_EXTENSIONS).apply { + add("dff") + } + + @JvmField + val GBA_ROM_EXTENSIONS: HashSet = hashSetOf( + "gba", "gbc", "gb", "agb", "mb", "rom", "bin" + ) + + @JvmField + val BIN_EXTENSION: HashSet = hashSetOf("bin") + + @JvmField + val RAW_EXTENSION: HashSet = hashSetOf("raw") + + @JvmField + val WAD_EXTENSION: HashSet = hashSetOf("wad") + + @JvmStatic + fun createDirectoryPickerIntent( + activity: FragmentActivity, extensions: HashSet + ): Intent { + val intent = Intent(activity, CustomFilePickerActivity::class.java) + + intent.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false) + intent.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false) + intent.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR) + intent.putExtra( + FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().path + ) + intent.putExtra(CustomFilePickerActivity.EXTRA_EXTENSIONS, extensions) + + return intent + } + + @JvmStatic + fun getSelectedPath(result: Intent): String? { + // Use the provided utility method to parse the result + val files = Utils.getSelectedFilesFromResult(result) + if (files.isNotEmpty()) { + val file = Utils.getFileForUri(files[0]) + return file.absolutePath + } + + return null + } + + @JvmStatic + fun isPathEmptyOrValid(path: StringSetting): Boolean { + return isPathEmptyOrValid(path.string) + } + + /** + * Returns true if at least one of the following applies: + * + * 1. The input is empty. + * 2. The input is something which is not a content URI. + * 3. The input is a content URI that points to a file that exists and we're allowed to access. + */ + @JvmStatic + fun isPathEmptyOrValid(path: String): Boolean { + return !ContentHandler.isContentUri(path) || ContentHandler.exists(path) + } + + @JvmStatic + fun runAfterExtensionCheck( + context: Context, uri: Uri, validExtensions: Set, runnable: Runnable + ) { + var extension: String? = null + + val path = uri.lastPathSegment + if (path != null) { + extension = getExtension(File(path).name, false) + } + + if (extension == null) { + extension = getExtension(ContentHandler.getDisplayName(uri), false) + } + + if (extension != null && validExtensions.contains(extension)) { + runnable.run() + return + } + + val message = if (extension == null) { + context.getString(R.string.no_file_extension) + } else { + val messageId = if (validExtensions.size == 1) { + R.string.wrong_file_extension_single + } else { + R.string.wrong_file_extension_multiple + } + + context.getString( + messageId, extension, setToSortedDelimitedString(validExtensions) + ) + } + + MaterialAlertDialogBuilder(context).setMessage(message) + .setPositiveButton(R.string.yes) { _, _ -> runnable.run() } + .setNegativeButton(R.string.no, null).setCancelable(false).show() + } + + @JvmStatic + fun getExtension(fileName: String?, includeDot: Boolean): String? { + if (fileName == null) { + return null + } + + val dotIndex = fileName.lastIndexOf(".") + if (dotIndex == -1) { + return null + } + return fileName.substring(dotIndex + if (includeDot) 0 else 1) + } + + @JvmStatic + fun setToSortedDelimitedString(set: Set): String { + val list = ArrayList(set) + list.sort() + return list.joinToString(", ") + } +}