forked from MeloNX/MeloNX
initial work on multi driver selection
This commit is contained in:
parent
d6ba9ad8f5
commit
953559c71c
@ -31,6 +31,29 @@ class TitleUpdateViewModel(val titleId: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Add() {
|
fun Add() {
|
||||||
|
var callBack = storageHelper.onFileSelected
|
||||||
|
|
||||||
|
storageHelper.onFileSelected = { requestCode, files ->
|
||||||
|
run {
|
||||||
|
storageHelper.onFileSelected = callBack
|
||||||
|
if(requestCode == UpdateRequestCode)
|
||||||
|
{
|
||||||
|
var file = files.firstOrNull()
|
||||||
|
file?.apply {
|
||||||
|
var path = Helpers.getPath(storageHelper.storage.context, file.uri)
|
||||||
|
if(!path.isNullOrEmpty()){
|
||||||
|
data?.apply {
|
||||||
|
if(!paths.contains(path)) {
|
||||||
|
paths.add(path)
|
||||||
|
pathsState?.clear()
|
||||||
|
pathsState?.addAll(paths)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
storageHelper.openFilePicker(UpdateRequestCode)
|
storageHelper.openFilePicker(UpdateRequestCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,27 +109,6 @@ class TitleUpdateViewModel(val titleId: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
storageHelper = MainActivity.StorageHelper!!
|
storageHelper = MainActivity.StorageHelper!!
|
||||||
|
|
||||||
storageHelper.onFileSelected = { requestCode, files ->
|
|
||||||
run {
|
|
||||||
if(requestCode == UpdateRequestCode)
|
|
||||||
{
|
|
||||||
var file = files.firstOrNull()
|
|
||||||
file?.apply {
|
|
||||||
var path = Helpers.getPath(storageHelper.storage.context, file.uri)
|
|
||||||
if(!path.isNullOrEmpty()){
|
|
||||||
data?.apply {
|
|
||||||
if(!paths.contains(path)) {
|
|
||||||
paths.add(path)
|
|
||||||
pathsState?.clear()
|
|
||||||
pathsState?.addAll(paths)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,159 @@
|
|||||||
|
package org.ryujinx.android.viewmodels
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import com.anggrayudi.storage.file.extension
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import org.ryujinx.android.Helpers
|
||||||
|
import org.ryujinx.android.MainActivity
|
||||||
|
import java.io.File
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
|
class VulkanDriverViewModel(val activity: MainActivity) {
|
||||||
|
var selected: String = ""
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DriverRequestCode: Int = 1003
|
||||||
|
const val DriverFolder: String = "drivers"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAppPath() : String {
|
||||||
|
var appPath =
|
||||||
|
(MainActivity.AppPath ?: activity.getExternalFilesDir(null)?.absolutePath ?: "");
|
||||||
|
appPath += "/"
|
||||||
|
|
||||||
|
return appPath
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ensureDriverPath() : File {
|
||||||
|
var driverPath = getAppPath() + DriverFolder
|
||||||
|
|
||||||
|
var driverFolder = File(driverPath)
|
||||||
|
|
||||||
|
if(!driverFolder.exists())
|
||||||
|
driverFolder.mkdirs()
|
||||||
|
|
||||||
|
return driverFolder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAvailableDrivers() : MutableList<DriverMetadata> {
|
||||||
|
var driverFolder = ensureDriverPath()
|
||||||
|
|
||||||
|
var folders = driverFolder.walkTopDown()
|
||||||
|
|
||||||
|
var drivers = mutableListOf<DriverMetadata>()
|
||||||
|
|
||||||
|
var selectedDriverFile = File(driverFolder.absolutePath + "/selected");
|
||||||
|
if(selectedDriverFile.exists()){
|
||||||
|
selected = selectedDriverFile.readText()
|
||||||
|
|
||||||
|
if(!File(selected).exists()) {
|
||||||
|
selected = ""
|
||||||
|
saveSelected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var gson = Gson()
|
||||||
|
|
||||||
|
for (folder in folders){
|
||||||
|
if(folder.isDirectory() && folder.parent == driverFolder.absolutePath){
|
||||||
|
var meta = File(folder.absolutePath + "/meta.json")
|
||||||
|
|
||||||
|
if(meta.exists()){
|
||||||
|
var metadata = gson.fromJson(meta.readText(), DriverMetadata::class.java)
|
||||||
|
if(metadata.name.isNotEmpty()) {
|
||||||
|
var driver = folder.absolutePath + "/${metadata.libraryName}"
|
||||||
|
metadata.driverPath = driver
|
||||||
|
if (File(driver).exists())
|
||||||
|
drivers.add(metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return drivers
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveSelected() {
|
||||||
|
var driverFolder = ensureDriverPath()
|
||||||
|
|
||||||
|
var selectedDriverFile = File(driverFolder.absolutePath + "/selected")
|
||||||
|
selectedDriverFile.writeText(selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeSelected(){
|
||||||
|
if(selected.isNotEmpty()){
|
||||||
|
var sel = File(selected)
|
||||||
|
if(sel.exists()) {
|
||||||
|
var parent = sel.parentFile
|
||||||
|
parent.deleteRecursively()
|
||||||
|
}
|
||||||
|
selected = ""
|
||||||
|
|
||||||
|
saveSelected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(refresh: MutableState<Boolean>) {
|
||||||
|
activity.storageHelper?.apply {
|
||||||
|
|
||||||
|
var callBack = this.onFileSelected
|
||||||
|
|
||||||
|
onFileSelected = { requestCode, files ->
|
||||||
|
run {
|
||||||
|
onFileSelected = callBack
|
||||||
|
if(requestCode == DriverRequestCode)
|
||||||
|
{
|
||||||
|
var file = files.firstOrNull()
|
||||||
|
file?.apply {
|
||||||
|
var path = Helpers.getPath(storage.context, file.uri)
|
||||||
|
if(!path.isNullOrEmpty()){
|
||||||
|
var name = file.name?.removeSuffix("." + file.extension) ?: ""
|
||||||
|
var driverFolder = ensureDriverPath()
|
||||||
|
var extractionFolder = File(driverFolder.absolutePath + "/${name}")
|
||||||
|
extractionFolder.mkdirs()
|
||||||
|
ZipFile(path)?.use { zip ->
|
||||||
|
zip.entries().asSequence().forEach { entry ->
|
||||||
|
|
||||||
|
zip.getInputStream(entry).use { input ->
|
||||||
|
val filePath = extractionFolder.absolutePath + File.separator + entry.name
|
||||||
|
|
||||||
|
if (!entry.isDirectory) {
|
||||||
|
var length = input.available()
|
||||||
|
val bytesIn = ByteArray(length)
|
||||||
|
input.read(bytesIn)
|
||||||
|
File(filePath).writeBytes(bytesIn)
|
||||||
|
} else {
|
||||||
|
val dir = File(filePath)
|
||||||
|
dir.mkdir()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openFilePicker(DriverRequestCode,
|
||||||
|
filterMimeTypes = arrayOf("application/zip")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class DriverMetadata(
|
||||||
|
var schemaVersion : Int = 0,
|
||||||
|
var name : String = "",
|
||||||
|
var description : String = "",
|
||||||
|
var author : String = "",
|
||||||
|
var packageVersion : String = "",
|
||||||
|
var vendor : String = "",
|
||||||
|
var driverVersion : String = "",
|
||||||
|
var minApi : Int = 0,
|
||||||
|
var libraryName : String = "",
|
||||||
|
var driverPath : String = ""
|
||||||
|
)
|
@ -13,24 +13,34 @@ import androidx.compose.animation.expandVertically
|
|||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.shrinkVertically
|
import androidx.compose.animation.shrinkVertically
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.RadioButton
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Slider
|
import androidx.compose.material3.Slider
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@ -42,6 +52,7 @@ import androidx.compose.ui.draw.rotate
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import org.ryujinx.android.viewmodels.SettingsViewModel
|
import org.ryujinx.android.viewmodels.SettingsViewModel
|
||||||
|
import org.ryujinx.android.viewmodels.VulkanDriverViewModel
|
||||||
|
|
||||||
class SettingViews {
|
class SettingViews {
|
||||||
companion object {
|
companion object {
|
||||||
@ -273,6 +284,151 @@ class SettingViews {
|
|||||||
enableTextureRecompression.value = !enableTextureRecompression.value
|
enableTextureRecompression.value = !enableTextureRecompression.value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
/*Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
var isDriverSelectorOpen = remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
var driverViewModel = VulkanDriverViewModel(settingsViewModel.activity)
|
||||||
|
var isChanged = remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
var refresh = remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
var drivers = driverViewModel.getAvailableDrivers()
|
||||||
|
var selectedDriver = remember {
|
||||||
|
mutableStateOf(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(refresh.value) {
|
||||||
|
isChanged.value = true
|
||||||
|
refresh.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isDriverSelectorOpen.value){
|
||||||
|
AlertDialog(onDismissRequest = {
|
||||||
|
isDriverSelectorOpen.value = false
|
||||||
|
|
||||||
|
if(isChanged.value){
|
||||||
|
driverViewModel.saveSelected()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Column {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentWidth()
|
||||||
|
.wrapContentHeight(),
|
||||||
|
shape = MaterialTheme.shapes.large,
|
||||||
|
tonalElevation = AlertDialogDefaults.TonalElevation
|
||||||
|
) {
|
||||||
|
if (!isChanged.value) {
|
||||||
|
selectedDriver.value =
|
||||||
|
drivers.indexOfFirst { it.driverPath == driverViewModel.selected } + 1
|
||||||
|
isChanged.value = true
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
Column (modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(300.dp)) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
RadioButton(
|
||||||
|
selected = selectedDriver.value == 0 || driverViewModel.selected.isEmpty(),
|
||||||
|
onClick = {
|
||||||
|
selectedDriver.value = 0
|
||||||
|
isChanged.value = true
|
||||||
|
driverViewModel.selected = ""
|
||||||
|
})
|
||||||
|
Column {
|
||||||
|
Text(text = "Default",
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable {
|
||||||
|
selectedDriver.value = 0
|
||||||
|
isChanged.value = true
|
||||||
|
driverViewModel.selected =
|
||||||
|
""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var driverIndex = 1
|
||||||
|
for (driver in drivers) {
|
||||||
|
var ind = driverIndex
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
RadioButton(
|
||||||
|
selected = selectedDriver.value == ind,
|
||||||
|
onClick = {
|
||||||
|
selectedDriver.value = ind
|
||||||
|
isChanged.value = true
|
||||||
|
driverViewModel.selected =
|
||||||
|
driver.driverPath
|
||||||
|
})
|
||||||
|
Column {
|
||||||
|
Text(text = driver.libraryName,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable {
|
||||||
|
selectedDriver.value =
|
||||||
|
ind
|
||||||
|
isChanged.value =
|
||||||
|
true
|
||||||
|
driverViewModel.selected =
|
||||||
|
driver.driverPath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
driverIndex++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Button(onClick = {
|
||||||
|
driverViewModel.removeSelected()
|
||||||
|
refresh.value = true
|
||||||
|
}, modifier = Modifier.padding(8.dp)) {
|
||||||
|
Text(text = "Remove")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(onClick = {
|
||||||
|
driverViewModel.add(refresh)
|
||||||
|
refresh.value = true
|
||||||
|
}, modifier = Modifier.padding(8.dp)) {
|
||||||
|
Text(text = "Add")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
{
|
||||||
|
isChanged.value = false
|
||||||
|
isDriverSelectorOpen.value = !isDriverSelectorOpen.value
|
||||||
|
},
|
||||||
|
modifier = Modifier.align(Alignment.CenterVertically)
|
||||||
|
){
|
||||||
|
Text(text = "Drivers")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user