Add the basic framework to assign game folder

This commit is contained in:
Abandoned Cart 2023-04-21 11:50:36 -04:00
parent 35fb874a42
commit 3921099c53
7 changed files with 175 additions and 3 deletions

View File

@ -25,6 +25,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import emu.skyline.data.AppItem import emu.skyline.data.AppItem
import emu.skyline.data.AppItemTag import emu.skyline.data.AppItemTag
import emu.skyline.data.GameFolders
import emu.skyline.databinding.AppDialogBinding import emu.skyline.databinding.AppDialogBinding
import emu.skyline.loader.LoaderResult import emu.skyline.loader.LoaderResult
import emu.skyline.provider.DocumentsProvider import emu.skyline.provider.DocumentsProvider
@ -71,6 +72,14 @@ class AppDialog : BottomSheetDialogFragment() {
private val documentPicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) { private val documentPicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
it?.let { uri -> importSave(uri) } it?.let { uri -> importSave(uri) }
} }
private val directoryPicker = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
it?.let { uri ->
activity?.contentResolver?.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
activity?.contentResolver?.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
GameFolders.putDirectory(item.titleId ?: item.key(), uri.toString())
}
binding.gameFolderPath.text = GameFolders.getDirectoryPath(it)
}
/** /**
* This inflates the layout of the dialog after initial view creation * This inflates the layout of the dialog after initial view creation
@ -151,6 +160,18 @@ class AppDialog : BottomSheetDialogFragment() {
exportSave(saveFolderPath) exportSave(saveFolderPath)
} }
binding.gameFolderPath.text = GameFolders.getDirectoryPath(item.titleId ?: item.key())
binding.setFolder.setOnClickListener {
directoryPicker.launch(null)
}
binding.clearFolder.setOnClickListener {
GameFolders.removeDirectory(item.titleId ?: item.key())
(activity as? MainActivity)?.loadRoms(false)
binding.gameFolderPath.text = ""
}
binding.gameTitleId.setOnLongClickListener { binding.gameTitleId.setOnLongClickListener {
val clipboard = requireActivity().getSystemService(android.content.Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager val clipboard = requireActivity().getSystemService(android.content.Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
clipboard.setPrimaryClip(android.content.ClipData.newPlainText("Title ID", item.titleId)) clipboard.setPrimaryClip(android.content.ClipData.newPlainText("Title ID", item.titleId))

View File

@ -29,6 +29,7 @@ import dagger.hilt.android.AndroidEntryPoint
import emu.skyline.adapter.* import emu.skyline.adapter.*
import emu.skyline.data.AppItem import emu.skyline.data.AppItem
import emu.skyline.data.AppItemTag import emu.skyline.data.AppItemTag
import emu.skyline.data.GameFolders
import emu.skyline.databinding.MainActivityBinding import emu.skyline.databinding.MainActivityBinding
import emu.skyline.loader.AppEntry import emu.skyline.loader.AppEntry
import emu.skyline.loader.LoaderResult import emu.skyline.loader.LoaderResult
@ -215,7 +216,10 @@ class MainActivity : AppCompatActivity() {
private fun sortGameList(gameList : List<AppEntry>) : List<AppEntry> { private fun sortGameList(gameList : List<AppEntry>) : List<AppEntry> {
val sortedApps : MutableList<AppEntry> = mutableListOf() val sortedApps : MutableList<AppEntry> = mutableListOf()
gameList.forEach { entry -> sortedApps.add(entry) } gameList.forEach { entry ->
if (!appSettings.filterGameFolders || !GameFolders.hasDirectory(entry.uri))
sortedApps.add(entry)
}
when (appSettings.sortAppsBy) { when (appSettings.sortAppsBy) {
SortingOrder.AlphabeticalAsc.ordinal -> sortedApps.sortBy { it.name } SortingOrder.AlphabeticalAsc.ordinal -> sortedApps.sortBy { it.name }
SortingOrder.AlphabeticalDesc.ordinal -> sortedApps.sortByDescending { it.name } SortingOrder.AlphabeticalDesc.ordinal -> sortedApps.sortByDescending { it.name }
@ -258,7 +262,7 @@ class MainActivity : AppCompatActivity() {
AppDialog.newInstance(appItem).show(supportFragmentManager, "game") AppDialog.newInstance(appItem).show(supportFragmentManager, "game")
} }
private fun loadRoms(loadFromFile : Boolean) { fun loadRoms(loadFromFile : Boolean) {
if (!loadFromFile) { if (!loadFromFile) {
binding.romPlaceholder.isVisible = true binding.romPlaceholder.isVisible = true
binding.romPlaceholder.text = getString(R.string.searching_roms) binding.romPlaceholder.text = getString(R.string.searching_roms)

View File

@ -0,0 +1,78 @@
/*
* SPDX-License-Identifier: MPL-2.0
* Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/)
*/
package emu.skyline.data
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import androidx.preference.PreferenceManager
import emu.skyline.SkylineApplication
import org.json.JSONException
import org.json.JSONObject
import java.io.File
object GameFolders {
private val sharedPref : SharedPreferences = PreferenceManager.getDefaultSharedPreferences(SkylineApplication.instance)
private val directories : HashMap<String, String> = hashMapOf()
init {
try {
val jsonString = sharedPref.getString("game_folders", JSONObject().toString())
if (jsonString != null) {
val jsonObject = JSONObject(jsonString)
val keysItr = jsonObject.keys()
while (keysItr.hasNext()) {
val key = keysItr.next()
val value = jsonObject.getString(key)
directories[key] = value
}
}
} catch (e : JSONException) {
e.printStackTrace()
}
}
private fun saveMap(inputMap : Map<String?, String?>) {
val jsonObject = JSONObject(inputMap)
val jsonString = jsonObject.toString()
with (sharedPref.edit()) {
remove("game_folders")
putString("game_folders", jsonString)
apply()
}
}
fun removeDirectory(key: String) {
directories.remove(key)
saveMap(directories.toMap())
}
fun putDirectory(key: String, directory: String) {
directories[key] = directory
saveMap(directories.toMap())
}
private fun getDirectory(key: String) : String? {
return directories[key]
}
fun getDirectoryPath(key: String) : String {
val uri = getDirectory(key)
return uri?.let { Uri.parse(it).path.toString() } ?: ""
}
fun getDirectoryPath(uri: Uri?) : String {
return uri?.path ?: ""
}
fun hasDirectory(uri: Uri) : Boolean {
return directories.values.any { dlcPath ->
uri.path?.substringAfterLast(":")?.startsWith("${Uri.parse(dlcPath).path?.substringAfterLast(":")}${File.separator}") ?: false
}
}
}

View File

@ -24,6 +24,7 @@ class AppSettings @Inject constructor(@ApplicationContext private val context :
var useMaterialYou by sharedPreferences(context, false) var useMaterialYou by sharedPreferences(context, false)
var layoutType by sharedPreferences(context, 1) var layoutType by sharedPreferences(context, 1)
var sortAppsBy by sharedPreferences(context, 0) var sortAppsBy by sharedPreferences(context, 0)
var filterGameFolders by sharedPreferences(context, false)
var selectAction by sharedPreferences(context, false) var selectAction by sharedPreferences(context, false)
// Input // Input

View File

@ -148,7 +148,6 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
app:alignItems="center" app:alignItems="center"
app:flexWrap="nowrap" app:flexWrap="nowrap"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/save_management" app:layout_constraintTop_toBottomOf="@+id/save_management"
@ -185,5 +184,62 @@
app:iconGravity="textStart" /> app:iconGravity="textStart" />
</com.google.android.flexbox.FlexboxLayout> </com.google.android.flexbox.FlexboxLayout>
<TextView
android:id="@+id/game_folder"
style="?attr/textAppearanceLabelLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/game_folder"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/flexboxSaves" />
<TextView
android:id="@+id/game_folder_path"
style="?attr/textAppearanceLabelSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/game_folder" />
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/flexboxGameFolder"
style="@style/ThemeOverlay.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:alignItems="center"
app:flexWrap="nowrap"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/game_folder_path"
app:layout_constraintVertical_bias="1">
<com.google.android.material.button.MaterialButton
android:id="@+id/set_folder"
style="@style/Widget.Material3.Button.TonalButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/set_game_folder"
android:text="@string/set_game_folder"
app:icon="@drawable/ic_add" />
<com.google.android.material.button.MaterialButton
android:id="@+id/clear_folder"
style="@style/Widget.Material3.Button.TonalButton.Icon"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:contentDescription="@string/clear_game_folder"
android:tooltipText="@string/clear_game_folder"
app:icon="@drawable/ic_delete" />
</com.google.android.flexbox.FlexboxLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout> </LinearLayout>

View File

@ -24,6 +24,9 @@
<string name="delete_save">Delete save</string> <string name="delete_save">Delete save</string>
<string name="import_save">Import</string> <string name="import_save">Import</string>
<string name="export_save">Export</string> <string name="export_save">Export</string>
<string name="game_folder">DLC / Update Folder</string>
<string name="set_game_folder">Set Folder</string>
<string name="clear_game_folder">Clear Folder</string>
<string name="searching_roms">Searching for ROMs</string> <string name="searching_roms">Searching for ROMs</string>
<string name="invalid_file">Invalid file</string> <string name="invalid_file">Invalid file</string>
<string name="missing_title_key">Missing title key</string> <string name="missing_title_key">Missing title key</string>
@ -56,6 +59,9 @@
<string name="app_language_default">Use System Default</string> <string name="app_language_default">Use System Default</string>
<string name="layout_type">Game Display Layout</string> <string name="layout_type">Game Display Layout</string>
<string name="sort_apps_by">Games Sorting Order</string> <string name="sort_apps_by">Games Sorting Order</string>
<string name="filter_game_folders">Hide DLC / Update Folders</string>
<string name="filter_game_folders_desc_off">Show files in folders assigned to individual games</string>
<string name="filter_game_folders_desc_on">Hide files in folders assigned to individual games</string>
<string name="select_action">Always Show Game Information</string> <string name="select_action">Always Show Game Information</string>
<string name="select_action_desc_on">Game information will be shown on clicking a game</string> <string name="select_action_desc_on">Game information will be shown on clicking a game</string>
<string name="select_action_desc_off">Game information will only be shown on long-clicking a game</string> <string name="select_action_desc_off">Game information will only be shown on long-clicking a game</string>

View File

@ -51,6 +51,12 @@
app:refreshRequired="true" app:refreshRequired="true"
app:title="@string/sort_apps_by" app:title="@string/sort_apps_by"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<emu.skyline.preference.RefreshSwitchPreferenceCompat
android:defaultValue="false"
android:summaryOff="@string/filter_game_folders_desc_off"
android:summaryOn="@string/filter_game_folders_desc_on"
app:key="filter_game_folders"
app:title="@string/filter_game_folders" />
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:defaultValue="false" android:defaultValue="false"
android:summaryOff="@string/select_action_desc_off" android:summaryOff="@string/select_action_desc_off"