forked from MeloNX/MeloNX
android - adjust grid view design, remove bottom app bar
This commit is contained in:
parent
bc6e5de507
commit
9765f7a388
@ -11,8 +11,8 @@ android {
|
||||
applicationId "org.ryujinx.android"
|
||||
minSdk 30
|
||||
targetSdk 33
|
||||
versionCode 10004
|
||||
versionName '1.0.4'
|
||||
versionCode 10006
|
||||
versionName '1.0.6'
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
@ -6,9 +6,7 @@ import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.anggrayudi.storage.file.DocumentFileCompat
|
||||
import com.anggrayudi.storage.file.DocumentFileType
|
||||
import com.anggrayudi.storage.file.FileFullPath
|
||||
import com.anggrayudi.storage.file.extension
|
||||
import com.anggrayudi.storage.file.getAbsolutePath
|
||||
import com.anggrayudi.storage.file.search
|
||||
import org.ryujinx.android.MainActivity
|
||||
import kotlin.concurrent.thread
|
||||
@ -17,6 +15,7 @@ class HomeViewModel(
|
||||
val activity: MainActivity? = null,
|
||||
val mainViewModel: MainViewModel? = null
|
||||
) {
|
||||
private var savedFolder: String = ""
|
||||
private var isLoading: Boolean = false
|
||||
private var loadedCache: List<GameModel> = listOf()
|
||||
private var gameFolderPath: DocumentFile? = null
|
||||
@ -26,18 +25,8 @@ class HomeViewModel(
|
||||
init {
|
||||
if (activity != null) {
|
||||
sharedPref = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
activity.storageHelper!!.onFolderSelected = { requestCode, folder ->
|
||||
run {
|
||||
gameFolderPath = folder
|
||||
val p = folder.getAbsolutePath(activity!!)
|
||||
val editor = sharedPref?.edit()
|
||||
editor?.putString("gameFolder", p)
|
||||
editor?.apply()
|
||||
reloadGameList()
|
||||
}
|
||||
}
|
||||
|
||||
val savedFolder = sharedPref?.getString("gameFolder", "") ?: ""
|
||||
savedFolder = sharedPref?.getString("gameFolder", "") ?: ""
|
||||
|
||||
if (savedFolder.isNotEmpty()) {
|
||||
try {
|
||||
@ -56,16 +45,20 @@ class HomeViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun openGameFolder() {
|
||||
val path = sharedPref?.getString("gameFolder", "") ?: ""
|
||||
fun ensureReloadIfNecessary() {
|
||||
val oldFolder = savedFolder
|
||||
val savedFolder = sharedPref?.getString("gameFolder", "") ?: ""
|
||||
|
||||
if (path.isEmpty())
|
||||
activity?.storageHelper?.storage?.openFolderPicker()
|
||||
else
|
||||
activity?.storageHelper?.storage?.openFolderPicker(
|
||||
activity.storageHelper!!.storage.requestCodeFolderPicker,
|
||||
FileFullPath(activity, path)
|
||||
if(savedFolder.isNotEmpty() && savedFolder != oldFolder) {
|
||||
gameFolderPath = DocumentFileCompat.fromFullPath(
|
||||
mainViewModel?.activity!!,
|
||||
savedFolder,
|
||||
documentType = DocumentFileType.FOLDER,
|
||||
requiresWriteAccess = true
|
||||
)
|
||||
|
||||
reloadGameList()
|
||||
}
|
||||
}
|
||||
|
||||
fun reloadGameList() {
|
||||
|
@ -2,15 +2,28 @@ package org.ryujinx.android.viewmodels
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.anggrayudi.storage.file.FileFullPath
|
||||
import com.anggrayudi.storage.file.getAbsolutePath
|
||||
import org.ryujinx.android.MainActivity
|
||||
|
||||
class SettingsViewModel(var navController: NavHostController, val activity: MainActivity) {
|
||||
private var previousCallback: ((requestCode: Int, folder: DocumentFile) -> Unit)?
|
||||
private var sharedPref: SharedPreferences
|
||||
|
||||
init {
|
||||
sharedPref = getPreferences()
|
||||
previousCallback = activity.storageHelper!!.onFolderSelected
|
||||
activity.storageHelper!!.onFolderSelected = { requestCode, folder ->
|
||||
run {
|
||||
val p = folder.getAbsolutePath(activity!!)
|
||||
val editor = sharedPref?.edit()
|
||||
editor?.putString("gameFolder", p)
|
||||
editor?.apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPreferences() : SharedPreferences {
|
||||
@ -73,5 +86,20 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
||||
editor.putBoolean("isGrid", isGrid.value)
|
||||
|
||||
editor.apply()
|
||||
activity.storageHelper!!.onFolderSelected = previousCallback
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun openGameFolder() {
|
||||
val path = sharedPref?.getString("gameFolder", "") ?: ""
|
||||
|
||||
if (path.isEmpty())
|
||||
activity?.storageHelper?.storage?.openFolderPicker()
|
||||
else
|
||||
activity?.storageHelper?.storage?.openFolderPicker(
|
||||
activity.storageHelper!!.storage.requestCodeFolderPicker,
|
||||
FileFullPath(activity, path)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -33,18 +33,15 @@ import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.BottomAppBarDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SearchBar
|
||||
import androidx.compose.material3.SearchBarDefaults
|
||||
@ -55,6 +52,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
@ -75,7 +73,7 @@ import kotlin.math.roundToInt
|
||||
class HomeViews {
|
||||
companion object {
|
||||
const val ListImageSize = 150
|
||||
const val GridImageSize = 256
|
||||
const val GridImageSize = 300
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -88,6 +86,9 @@ class HomeViews {
|
||||
val openTitleUpdateDialog = remember { mutableStateOf(false) }
|
||||
val canClose = remember { mutableStateOf(true) }
|
||||
val openDlcDialog = remember { mutableStateOf(false) }
|
||||
val selectedModel = remember {
|
||||
mutableStateOf(viewModel.mainViewModel?.selected)
|
||||
}
|
||||
val query = remember {
|
||||
mutableStateOf("")
|
||||
}
|
||||
@ -161,138 +162,13 @@ class HomeViews {
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
BottomAppBar(
|
||||
actions = {
|
||||
if (showAppActions.value) {
|
||||
IconButton(onClick = {
|
||||
if (viewModel.mainViewModel?.selected != null) {
|
||||
thread {
|
||||
showLoading.value = true
|
||||
val success =
|
||||
viewModel.mainViewModel?.loadGame(viewModel.mainViewModel.selected!!)
|
||||
?: false
|
||||
if (success) {
|
||||
launchOnUiThread {
|
||||
viewModel.mainViewModel?.navigateToGame()
|
||||
}
|
||||
} else {
|
||||
viewModel.mainViewModel?.selected!!.close()
|
||||
}
|
||||
showLoading.value = false
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
org.ryujinx.android.Icons.playArrow(MaterialTheme.colorScheme.onSurface),
|
||||
contentDescription = "Run"
|
||||
)
|
||||
}
|
||||
val showAppMenu = remember { mutableStateOf(false) }
|
||||
Box {
|
||||
IconButton(onClick = {
|
||||
showAppMenu.value = true
|
||||
}) {
|
||||
Icon(
|
||||
Icons.Filled.Menu,
|
||||
contentDescription = "Menu"
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showAppMenu.value,
|
||||
onDismissRequest = { showAppMenu.value = false }) {
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Clear PPTC Cache")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
viewModel.mainViewModel?.clearPptcCache(
|
||||
viewModel.mainViewModel?.selected?.titleId ?: ""
|
||||
)
|
||||
})
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Purge Shader Cache")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
viewModel.mainViewModel?.purgeShaderCache(
|
||||
viewModel.mainViewModel?.selected?.titleId ?: ""
|
||||
)
|
||||
})
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Manage Updates")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
openTitleUpdateDialog.value = true
|
||||
})
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Manage DLC")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
openDlcDialog.value = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*\val showAppletMenu = remember { mutableStateOf(false) }
|
||||
Box {
|
||||
IconButton(onClick = {
|
||||
showAppletMenu.value = true
|
||||
}) {
|
||||
Icon(
|
||||
org.ryujinx.android.Icons.applets(MaterialTheme.colorScheme.onSurface),
|
||||
contentDescription = "Applets"
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showAppletMenu.value,
|
||||
onDismissRequest = { showAppletMenu.value = false }) {
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Launch Mii Editor")
|
||||
}, onClick = {
|
||||
showAppletMenu.value = false
|
||||
showLoading.value = true
|
||||
thread {
|
||||
val success =
|
||||
viewModel.mainViewModel?.loadMiiEditor() ?: false
|
||||
if (success) {
|
||||
launchOnUiThread {
|
||||
viewModel.mainViewModel?.navigateToGame()
|
||||
}
|
||||
} else
|
||||
viewModel.mainViewModel!!.isMiiEditorLaunched = false
|
||||
showLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}*/
|
||||
},
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
viewModel.openGameFolder()
|
||||
},
|
||||
containerColor = BottomAppBarDefaults.bottomAppBarFabColor,
|
||||
elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation()
|
||||
) {
|
||||
Icon(
|
||||
org.ryujinx.android.Icons.folderOpen(MaterialTheme.colorScheme.onSurface),
|
||||
contentDescription = "Open Folder"
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
) { contentPadding ->
|
||||
Box(modifier = Modifier.padding(contentPadding)) {
|
||||
val list = remember {
|
||||
viewModel.gameList
|
||||
}
|
||||
val selectedModel = remember {
|
||||
mutableStateOf(viewModel.mainViewModel?.selected)
|
||||
}
|
||||
var settings = QuickSettings(viewModel.activity!!)
|
||||
|
||||
if (settings.isGrid) {
|
||||
@ -301,13 +177,13 @@ class HomeViews {
|
||||
columns = GridCells.Adaptive(minSize = (size + 4).dp),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(4.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
items(list) {
|
||||
it.titleName?.apply {
|
||||
if (this.isNotEmpty() && (query.value.trim()
|
||||
.isEmpty() || this.lowercase(
|
||||
Locale.getDefault()
|
||||
)
|
||||
.isEmpty() || this.lowercase(Locale.getDefault())
|
||||
.contains(query.value))
|
||||
)
|
||||
GridGameItem(
|
||||
@ -335,7 +211,7 @@ class HomeViews {
|
||||
viewModel,
|
||||
showAppActions,
|
||||
showLoading,
|
||||
selectedModel
|
||||
selectedModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -405,6 +281,89 @@ class HomeViews {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showAppActions.value)
|
||||
ModalBottomSheet(
|
||||
content = {
|
||||
Row(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
if (showAppActions.value) {
|
||||
IconButton(onClick = {
|
||||
if (viewModel.mainViewModel?.selected != null) {
|
||||
thread {
|
||||
showLoading.value = true
|
||||
val success =
|
||||
viewModel.mainViewModel?.loadGame(viewModel.mainViewModel.selected!!)
|
||||
?: false
|
||||
if (success) {
|
||||
launchOnUiThread {
|
||||
viewModel.mainViewModel?.navigateToGame()
|
||||
}
|
||||
} else {
|
||||
viewModel.mainViewModel?.selected!!.close()
|
||||
}
|
||||
showLoading.value = false
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
org.ryujinx.android.Icons.playArrow(MaterialTheme.colorScheme.onSurface),
|
||||
contentDescription = "Run"
|
||||
)
|
||||
}
|
||||
val showAppMenu = remember { mutableStateOf(false) }
|
||||
Box {
|
||||
IconButton(onClick = {
|
||||
showAppMenu.value = true
|
||||
}) {
|
||||
Icon(
|
||||
Icons.Filled.Menu,
|
||||
contentDescription = "Menu"
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showAppMenu.value,
|
||||
onDismissRequest = { showAppMenu.value = false }) {
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Clear PPTC Cache")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
viewModel.mainViewModel?.clearPptcCache(
|
||||
viewModel.mainViewModel?.selected?.titleId ?: ""
|
||||
)
|
||||
})
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Purge Shader Cache")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
viewModel.mainViewModel?.purgeShaderCache(
|
||||
viewModel.mainViewModel?.selected?.titleId ?: ""
|
||||
)
|
||||
})
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Manage Updates")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
openTitleUpdateDialog.value = true
|
||||
})
|
||||
DropdownMenuItem(text = {
|
||||
Text(text = "Manage DLC")
|
||||
}, onClick = {
|
||||
showAppMenu.value = false
|
||||
openDlcDialog.value = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
showAppActions.value = false
|
||||
selectedModel.value = null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@ -548,7 +507,7 @@ class HomeViews {
|
||||
selectedModel.value = gameModel
|
||||
})
|
||||
) {
|
||||
Column {
|
||||
Column(modifier = Modifier.padding(4.dp)) {
|
||||
if (!gameModel.titleId.isNullOrEmpty() && gameModel.titleId != "0000000000000000") {
|
||||
if (gameModel.icon?.isNotEmpty() == true) {
|
||||
val pic = decoder.decode(gameModel.icon)
|
||||
@ -560,6 +519,7 @@ class HomeViews {
|
||||
modifier = Modifier
|
||||
.padding(0.dp)
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
} else NotAvailableIcon()
|
||||
} else NotAvailableIcon()
|
||||
@ -567,13 +527,15 @@ class HomeViews {
|
||||
text = gameModel.titleName ?: "N/A",
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.basicMarquee()
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
.basicMarquee()
|
||||
)
|
||||
Text(
|
||||
text = gameModel.developer ?: "N/A",
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.basicMarquee()
|
||||
modifier = Modifier.padding(vertical = 4.dp)
|
||||
.basicMarquee()
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -584,7 +546,7 @@ class HomeViews {
|
||||
val size = ListImageSize / Resources.getSystem().displayMetrics.density
|
||||
Icon(
|
||||
Icons.Filled.Add,
|
||||
contentDescription = "Options",
|
||||
contentDescription = "N/A",
|
||||
modifier = Modifier
|
||||
.padding(end = 8.dp)
|
||||
.width(size.roundToInt().dp)
|
||||
|
@ -167,6 +167,23 @@ class SettingViews {
|
||||
isGrid.value = !isGrid.value
|
||||
})
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Game Folder",
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
)
|
||||
Button(onClick = {
|
||||
settingsViewModel.openGameFolder()
|
||||
}) {
|
||||
Text(text = "Choose Folder")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ExpandableView(onCardArrowClick = { }, title = "System") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user