initial work on multi driver selection

This commit is contained in:
Emmanuel Hansen 2023-07-08 19:36:30 +00:00
parent d6ba9ad8f5
commit 953559c71c
3 changed files with 338 additions and 21 deletions

View File

@ -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)
}
}
}
}
}
}
}
} }
} }

View File

@ -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 = ""
)

View File

@ -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")
}
}
*/
} }
} }
} }