forked from MeloNX/MeloNX
Cleanup RyujinxAndroid
This commit is contained in:
parent
300b23cf9b
commit
979db1def3
@ -37,4 +37,4 @@
|
|||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -6,40 +6,26 @@ import android.view.KeyEvent
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.GraphicsLayerScope
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleCoroutineScope
|
import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import androidx.lifecycle.flowWithLifecycle
|
|
||||||
import com.swordfish.radialgamepad.library.RadialGamePad
|
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||||
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||||
import com.swordfish.radialgamepad.library.config.CrossConfig
|
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||||
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
||||||
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
||||||
import com.swordfish.radialgamepad.library.config.RadialGamePadConfig
|
import com.swordfish.radialgamepad.library.config.RadialGamePadConfig
|
||||||
import com.swordfish.radialgamepad.library.config.RadialGamePadTheme
|
|
||||||
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
||||||
import com.swordfish.radialgamepad.library.event.Event
|
import com.swordfish.radialgamepad.library.event.Event
|
||||||
import com.swordfish.radialgamepad.library.event.GestureType
|
|
||||||
import com.swordfish.radialgamepad.library.haptics.HapticConfig
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.flowOn
|
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
import kotlinx.coroutines.flow.onCompletion
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.flow.subscribe
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
typealias GamePad = RadialGamePad
|
typealias GamePad = RadialGamePad
|
||||||
@ -56,7 +42,7 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
|
|||||||
return this.isVisible
|
return this.isVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -80,22 +66,22 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
|
|||||||
|
|
||||||
lifecycleScope.apply {
|
lifecycleScope.apply {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
var events = merge(leftGamePad.events(),rightGamePad.events())
|
val events = merge(leftGamePad.events(),rightGamePad.events())
|
||||||
.shareIn(lifecycleScope, SharingStarted.Lazily)
|
.shareIn(lifecycleScope, SharingStarted.Lazily)
|
||||||
|
|
||||||
events.safeCollect {
|
events.safeCollect {
|
||||||
handleEvent(it)
|
handleEvent(it)
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Create(context: Context) : View
|
private fun Create(context: Context) : View
|
||||||
{
|
{
|
||||||
var inflator = LayoutInflater.from(context);
|
val inflator = LayoutInflater.from(context)
|
||||||
var view = inflator.inflate(R.layout.game_layout, null)
|
val view = inflator.inflate(R.layout.game_layout, null)
|
||||||
view.findViewById<FrameLayout>(R.id.leftcontainer)!!.addView(leftGamePad);
|
view.findViewById<FrameLayout>(R.id.leftcontainer)!!.addView(leftGamePad)
|
||||||
view.findViewById<FrameLayout>(R.id.rightcontainer)!!.addView(rightGamePad);
|
view.findViewById<FrameLayout>(R.id.rightcontainer)!!.addView(rightGamePad)
|
||||||
|
|
||||||
controllerView = view
|
controllerView = view
|
||||||
|
|
||||||
@ -120,51 +106,43 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
|
|||||||
if(controllerId == -1)
|
if(controllerId == -1)
|
||||||
controllerId = ryujinxNative.inputConnectGamepad(0)
|
controllerId = ryujinxNative.inputConnectGamepad(0)
|
||||||
|
|
||||||
controllerId?.apply {
|
controllerId.apply {
|
||||||
when (ev) {
|
when (ev) {
|
||||||
is Event.Button -> {
|
is Event.Button -> {
|
||||||
var action = ev.action
|
val action = ev.action
|
||||||
when (action) {
|
when (action) {
|
||||||
KeyEvent.ACTION_UP -> {
|
KeyEvent.ACTION_UP -> {
|
||||||
ryujinxNative.inputSetButtonReleased(ev.id, this)
|
ryujinxNative.inputSetButtonReleased(ev.id, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyEvent.ACTION_DOWN -> {
|
KeyEvent.ACTION_DOWN -> {
|
||||||
ryujinxNative.inputSetButtonPressed(ev.id, this)
|
ryujinxNative.inputSetButtonPressed(ev.id, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is Event.Direction -> {
|
is Event.Direction -> {
|
||||||
var direction = ev.id
|
val direction = ev.id
|
||||||
|
|
||||||
when(direction) {
|
when(direction) {
|
||||||
GamePadButtonInputId.DpadUp.ordinal -> {
|
GamePadButtonInputId.DpadUp.ordinal -> {
|
||||||
if (ev.xAxis > 0)
|
if (ev.xAxis > 0) {
|
||||||
{
|
|
||||||
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
}
|
} else if (ev.xAxis < 0) {
|
||||||
else if (ev.xAxis < 0)
|
|
||||||
{
|
|
||||||
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
}
|
}
|
||||||
if (ev.yAxis < 0)
|
if (ev.yAxis < 0) {
|
||||||
{
|
|
||||||
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
}
|
} else if (ev.yAxis > 0) {
|
||||||
else if (ev.yAxis > 0)
|
|
||||||
{
|
|
||||||
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
ryujinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
ryujinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
}
|
}
|
||||||
@ -173,6 +151,7 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
|
|||||||
GamePadButtonInputId.LeftStick.ordinal -> {
|
GamePadButtonInputId.LeftStick.ordinal -> {
|
||||||
ryujinxNative.inputSetStickAxis(1, ev.xAxis, -ev.yAxis ,this)
|
ryujinxNative.inputSetStickAxis(1, ev.xAxis, -ev.yAxis ,this)
|
||||||
}
|
}
|
||||||
|
|
||||||
GamePadButtonInputId.RightStick.ordinal -> {
|
GamePadButtonInputId.RightStick.ordinal -> {
|
||||||
ryujinxNative.inputSetStickAxis(2, ev.xAxis, -ev.yAxis ,this)
|
ryujinxNative.inputSetStickAxis(2, ev.xAxis, -ev.yAxis ,this)
|
||||||
}
|
}
|
||||||
@ -193,7 +172,7 @@ suspend fun <T> Flow<T>.safeCollect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateConfig(isLeft: Boolean): GamePadConfig {
|
private fun generateConfig(isLeft: Boolean): GamePadConfig {
|
||||||
var distance = 0.05f
|
val distance = 0.05f
|
||||||
|
|
||||||
if (isLeft) {
|
if (isLeft) {
|
||||||
return GamePadConfig(
|
return GamePadConfig(
|
||||||
|
@ -2,14 +2,12 @@ package org.ryujinx.android
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.SurfaceHolder
|
import android.view.SurfaceHolder
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
import org.ryujinx.android.viewmodels.GameModel
|
import org.ryujinx.android.viewmodels.GameModel
|
||||||
import org.ryujinx.android.viewmodels.MainViewModel
|
import org.ryujinx.android.viewmodels.MainViewModel
|
||||||
import org.ryujinx.android.viewmodels.QuickSettings
|
import org.ryujinx.android.viewmodels.QuickSettings
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class GameHost(context: Context?, val controller: GameController, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
|
class GameHost(context: Context?, val controller: GameController, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
|
||||||
private var _renderingThreadWatcher: Thread? = null
|
private var _renderingThreadWatcher: Thread? = null
|
||||||
@ -37,19 +35,19 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||||
var isStarted = _isStarted;
|
val isStarted = _isStarted
|
||||||
|
|
||||||
start(holder)
|
start(holder)
|
||||||
|
|
||||||
if(isStarted && (_width != width || _height != height))
|
if(isStarted && (_width != width || _height != height))
|
||||||
{
|
{
|
||||||
var nativeHelpers = NativeHelpers()
|
val nativeHelpers = NativeHelpers()
|
||||||
var window = nativeHelpers.getNativeWindow(holder.surface);
|
val window = nativeHelpers.getNativeWindow(holder.surface)
|
||||||
_nativeRyujinx.graphicsSetSurface(window);
|
_nativeRyujinx.graphicsSetSurface(window)
|
||||||
}
|
}
|
||||||
|
|
||||||
_width = width;
|
_width = width
|
||||||
_height = height;
|
_height = height
|
||||||
|
|
||||||
if(_isStarted)
|
if(_isStarted)
|
||||||
{
|
{
|
||||||
@ -61,15 +59,15 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun start(surfaceHolder: SurfaceHolder) : Unit {
|
private fun start(surfaceHolder: SurfaceHolder) {
|
||||||
var game = gameModel ?: return
|
val game = gameModel ?: return
|
||||||
var path = game.getPath() ?: return
|
val path = game.getPath() ?: return
|
||||||
if (_isStarted)
|
if (_isStarted)
|
||||||
return
|
return
|
||||||
|
|
||||||
var surface = surfaceHolder.surface;
|
var surface = surfaceHolder.surface
|
||||||
|
|
||||||
var settings = QuickSettings(mainViewModel.activity)
|
val settings = QuickSettings(mainViewModel.activity)
|
||||||
|
|
||||||
var success = _nativeRyujinx.graphicsInitialize(GraphicsConfiguration().apply {
|
var success = _nativeRyujinx.graphicsInitialize(GraphicsConfiguration().apply {
|
||||||
EnableShaderCache = settings.enableShaderCache
|
EnableShaderCache = settings.enableShaderCache
|
||||||
@ -78,14 +76,14 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
var nativeHelpers = NativeHelpers()
|
val nativeHelpers = NativeHelpers()
|
||||||
var window = nativeHelpers.getNativeWindow(surfaceHolder.surface);
|
val window = nativeHelpers.getNativeWindow(surfaceHolder.surface)
|
||||||
nativeInterop = NativeGraphicsInterop()
|
nativeInterop = NativeGraphicsInterop()
|
||||||
nativeInterop!!.VkRequiredExtensions = arrayOf(
|
nativeInterop!!.VkRequiredExtensions = arrayOf(
|
||||||
"VK_KHR_surface", "VK_KHR_android_surface"
|
"VK_KHR_surface", "VK_KHR_android_surface"
|
||||||
);
|
)
|
||||||
nativeInterop!!.VkCreateSurface = nativeHelpers.getCreateSurfacePtr()
|
nativeInterop!!.VkCreateSurface = nativeHelpers.getCreateSurfacePtr()
|
||||||
nativeInterop!!.SurfaceHandle = window;
|
nativeInterop!!.SurfaceHandle = window
|
||||||
|
|
||||||
success = _nativeRyujinx.graphicsInitializeRenderer(
|
success = _nativeRyujinx.graphicsInitializeRenderer(
|
||||||
nativeInterop!!.VkRequiredExtensions!!,
|
nativeInterop!!.VkRequiredExtensions!!,
|
||||||
@ -104,7 +102,7 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
|
|||||||
false,
|
false,
|
||||||
"UTC",
|
"UTC",
|
||||||
settings.ignoreMissingServices
|
settings.ignoreMissingServices
|
||||||
);
|
)
|
||||||
|
|
||||||
success = _nativeRyujinx.deviceLoad(path)
|
success = _nativeRyujinx.deviceLoad(path)
|
||||||
|
|
||||||
@ -124,12 +122,12 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
|
|||||||
_nativeRyujinx.graphicsRendererSetSize(
|
_nativeRyujinx.graphicsRendererSetSize(
|
||||||
surfaceHolder.surfaceFrame.width(),
|
surfaceHolder.surfaceFrame.width(),
|
||||||
surfaceHolder.surfaceFrame.height()
|
surfaceHolder.surfaceFrame.height()
|
||||||
);
|
)
|
||||||
|
|
||||||
_guestThread = thread(start = true) {
|
_guestThread = thread(start = true) {
|
||||||
runGame()
|
runGame()
|
||||||
}
|
}
|
||||||
_isStarted = success;
|
_isStarted = success
|
||||||
|
|
||||||
_updateThread = thread(start = true) {
|
_updateThread = thread(start = true) {
|
||||||
var c = 0
|
var c = 0
|
||||||
@ -145,20 +143,20 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runGame() : Unit{
|
private fun runGame() {
|
||||||
// RenderingThreadWatcher
|
// RenderingThreadWatcher
|
||||||
_renderingThreadWatcher = thread(start = true) {
|
_renderingThreadWatcher = thread(start = true) {
|
||||||
var threadId = 0L;
|
var threadId = 0L
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
mainViewModel.performanceManager?.enable()
|
mainViewModel.performanceManager?.enable()
|
||||||
while (_isStarted) {
|
while (_isStarted) {
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
var newthreadId = mainViewModel.activity.getRenderingThreadId()
|
val newthreadId = mainViewModel.activity.getRenderingThreadId()
|
||||||
|
|
||||||
if (threadId != newthreadId) {
|
if (threadId != newthreadId) {
|
||||||
mainViewModel.performanceManager?.closeCurrentRenderingSession()
|
mainViewModel.performanceManager?.closeCurrentRenderingSession()
|
||||||
}
|
}
|
||||||
threadId = newthreadId;
|
threadId = newthreadId
|
||||||
if (threadId != 0L) {
|
if (threadId != 0L) {
|
||||||
mainViewModel.performanceManager?.initializeRenderingSession(threadId)
|
mainViewModel.performanceManager?.initializeRenderingSession(threadId)
|
||||||
}
|
}
|
||||||
|
@ -34,12 +34,16 @@ class Helpers {
|
|||||||
val split = docId.split(":".toRegex()).toTypedArray()
|
val split = docId.split(":".toRegex()).toTypedArray()
|
||||||
val type = split[0]
|
val type = split[0]
|
||||||
var contentUri: Uri? = null
|
var contentUri: Uri? = null
|
||||||
if ("image" == type) {
|
when (type) {
|
||||||
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
"image" -> {
|
||||||
} else if ("video" == type) {
|
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||||
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
}
|
||||||
} else if ("audio" == type) {
|
"video" -> {
|
||||||
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
|
||||||
|
}
|
||||||
|
"audio" -> {
|
||||||
|
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val selection = "_id=?"
|
val selection = "_id=?"
|
||||||
val selectionArgs = arrayOf(split[1])
|
val selectionArgs = arrayOf(split[1])
|
||||||
@ -58,13 +62,13 @@ class Helpers {
|
|||||||
val column = "_data"
|
val column = "_data"
|
||||||
val projection = arrayOf(column)
|
val projection = arrayOf(column)
|
||||||
try {
|
try {
|
||||||
cursor = uri?.let { context.getContentResolver().query(it, projection, selection, selectionArgs,null) }
|
cursor = uri?.let { context.contentResolver.query(it, projection, selection, selectionArgs,null) }
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
val column_index: Int = cursor.getColumnIndexOrThrow(column)
|
val column_index: Int = cursor.getColumnIndexOrThrow(column)
|
||||||
return cursor.getString(column_index)
|
return cursor.getString(column_index)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null) cursor.close()
|
cursor?.close()
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.ryujinx.android
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.media.AudioDeviceInfo
|
import android.media.AudioDeviceInfo
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
@ -25,23 +24,19 @@ import androidx.core.view.WindowInsetsCompat
|
|||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import com.anggrayudi.storage.SimpleStorageHelper
|
import com.anggrayudi.storage.SimpleStorageHelper
|
||||||
import org.ryujinx.android.ui.theme.RyujinxAndroidTheme
|
import org.ryujinx.android.ui.theme.RyujinxAndroidTheme
|
||||||
import org.ryujinx.android.viewmodels.HomeViewModel
|
|
||||||
import org.ryujinx.android.viewmodels.MainViewModel
|
import org.ryujinx.android.viewmodels.MainViewModel
|
||||||
import org.ryujinx.android.views.HomeViews
|
import org.ryujinx.android.views.HomeViews
|
||||||
import org.ryujinx.android.views.MainView
|
import org.ryujinx.android.views.MainView
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
var physicalControllerManager: PhysicalControllerManager
|
var physicalControllerManager: PhysicalControllerManager = PhysicalControllerManager(this)
|
||||||
private var _isInit: Boolean = false
|
private var _isInit: Boolean = false
|
||||||
var storageHelper: SimpleStorageHelper? = null
|
var storageHelper: SimpleStorageHelper? = null
|
||||||
companion object {
|
companion object {
|
||||||
var mainViewModel: MainViewModel? = null
|
var mainViewModel: MainViewModel? = null
|
||||||
var AppPath : String?
|
var AppPath : String = ""
|
||||||
var StorageHelper: SimpleStorageHelper? = null
|
var StorageHelper: SimpleStorageHelper? = null
|
||||||
init {
|
|
||||||
AppPath = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun updateRenderSessionPerformance(gameTime : Long)
|
fun updateRenderSessionPerformance(gameTime : Long)
|
||||||
@ -56,7 +51,6 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
physicalControllerManager = PhysicalControllerManager(this)
|
|
||||||
storageHelper = SimpleStorageHelper(this)
|
storageHelper = SimpleStorageHelper(this)
|
||||||
StorageHelper = storageHelper
|
StorageHelper = storageHelper
|
||||||
System.loadLibrary("ryujinxjni")
|
System.loadLibrary("ryujinxjni")
|
||||||
@ -66,29 +60,28 @@ class MainActivity : ComponentActivity() {
|
|||||||
external fun getRenderingThreadId() : Long
|
external fun getRenderingThreadId() : Long
|
||||||
external fun initVm()
|
external fun initVm()
|
||||||
|
|
||||||
fun setFullScreen() :Unit {
|
fun setFullScreen() {
|
||||||
requestedOrientation =
|
requestedOrientation =
|
||||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||||
|
|
||||||
var insets = WindowCompat.getInsetsController(window, window.decorView)
|
val insets = WindowCompat.getInsetsController(window, window.decorView)
|
||||||
|
|
||||||
insets?.apply {
|
insets.apply {
|
||||||
insets.hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
|
insets.hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
|
||||||
insets.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
insets.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAudioDevice () : Int {
|
private fun getAudioDevice () : Int {
|
||||||
var audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
|
||||||
var devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
|
|
||||||
|
|
||||||
|
val devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
|
||||||
|
|
||||||
return if (devices.isEmpty())
|
return if (devices.isEmpty())
|
||||||
0
|
0
|
||||||
else {
|
else {
|
||||||
var speaker = devices.find { it.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER }
|
val speaker = devices.find { it.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER }
|
||||||
var earPiece = devices.find { it.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES || it.type == AudioDeviceInfo.TYPE_WIRED_HEADSET }
|
val earPiece = devices.find { it.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES || it.type == AudioDeviceInfo.TYPE_WIRED_HEADSET }
|
||||||
if(earPiece != null)
|
if(earPiece != null)
|
||||||
return earPiece.id
|
return earPiece.id
|
||||||
if(speaker != null)
|
if(speaker != null)
|
||||||
@ -112,17 +105,23 @@ class MainActivity : ComponentActivity() {
|
|||||||
return super.dispatchGenericMotionEvent(ev)
|
return super.dispatchGenericMotionEvent(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initialize() : Unit
|
private fun initialize() {
|
||||||
{
|
if (_isInit)
|
||||||
if(_isInit)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
var appPath: String = AppPath ?: return
|
val appPath: String = AppPath
|
||||||
var success = RyujinxNative().initialize(appPath, false)
|
val success = RyujinxNative().initialize(appPath, false)
|
||||||
_isInit = success
|
_isInit = success
|
||||||
}
|
}
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if(
|
||||||
|
!Environment.isExternalStorageManager()
|
||||||
|
) {
|
||||||
|
storageHelper?.storage?.requestFullStorageAccess()
|
||||||
|
}
|
||||||
|
|
||||||
AppPath = this.getExternalFilesDir(null)!!.absolutePath
|
AppPath = this.getExternalFilesDir(null)!!.absolutePath
|
||||||
|
|
||||||
initialize()
|
initialize()
|
||||||
@ -130,14 +129,6 @@ class MainActivity : ComponentActivity() {
|
|||||||
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
WindowCompat.setDecorFitsSystemWindows(window,false)
|
WindowCompat.setDecorFitsSystemWindows(window,false)
|
||||||
|
|
||||||
if(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
!Environment.isExternalStorageManager()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
storageHelper?.storage?.requestFullStorageAccess()
|
|
||||||
}
|
|
||||||
mainViewModel = MainViewModel(this)
|
mainViewModel = MainViewModel(this)
|
||||||
|
|
||||||
mainViewModel?.apply {
|
mainViewModel?.apply {
|
||||||
|
@ -14,7 +14,7 @@ class PerformanceManager(val performanceHintManager: PerformanceHintManager) {
|
|||||||
if(!_isEnabled || renderingSession != null)
|
if(!_isEnabled || renderingSession != null)
|
||||||
return
|
return
|
||||||
|
|
||||||
var threads = IntArray(1)
|
val threads = IntArray(1)
|
||||||
threads[0] = threadId.toInt()
|
threads[0] = threadId.toInt()
|
||||||
renderingSession = performanceHintManager.createHintSession(threads, DEFAULT_TARGET_NS)
|
renderingSession = performanceHintManager.createHintSession(threads, DEFAULT_TARGET_NS)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ class PhysicalControllerManager(val activity: MainActivity) {
|
|||||||
|
|
||||||
fun onKeyEvent(event: KeyEvent) : Boolean{
|
fun onKeyEvent(event: KeyEvent) : Boolean{
|
||||||
if(controllerId != -1) {
|
if(controllerId != -1) {
|
||||||
var id = GetGamePadButtonInputId(event.keyCode)
|
val id = GetGamePadButtonInputId(event.keyCode)
|
||||||
|
|
||||||
if(id != GamePadButtonInputId.None) {
|
if(id != GamePadButtonInputId.None) {
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
@ -21,7 +21,7 @@ class PhysicalControllerManager(val activity: MainActivity) {
|
|||||||
ryujinxNative.inputSetButtonPressed(id.ordinal, controllerId)
|
ryujinxNative.inputSetButtonPressed(id.ordinal, controllerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,10 +31,10 @@ class PhysicalControllerManager(val activity: MainActivity) {
|
|||||||
fun onMotionEvent(ev: MotionEvent) {
|
fun onMotionEvent(ev: MotionEvent) {
|
||||||
if(controllerId != -1) {
|
if(controllerId != -1) {
|
||||||
if(ev.action == MotionEvent.ACTION_MOVE) {
|
if(ev.action == MotionEvent.ACTION_MOVE) {
|
||||||
var leftStickX = ev.getAxisValue(MotionEvent.AXIS_X);
|
val leftStickX = ev.getAxisValue(MotionEvent.AXIS_X)
|
||||||
var leftStickY = ev.getAxisValue(MotionEvent.AXIS_Y);
|
val leftStickY = ev.getAxisValue(MotionEvent.AXIS_Y)
|
||||||
var rightStickX = ev.getAxisValue(MotionEvent.AXIS_Z);
|
val rightStickX = ev.getAxisValue(MotionEvent.AXIS_Z)
|
||||||
var rightStickY = ev.getAxisValue(MotionEvent.AXIS_RZ);
|
val rightStickY = ev.getAxisValue(MotionEvent.AXIS_RZ)
|
||||||
ryujinxNative.inputSetStickAxis(1, leftStickX, -leftStickY ,controllerId)
|
ryujinxNative.inputSetStickAxis(1, leftStickX, -leftStickY ,controllerId)
|
||||||
ryujinxNative.inputSetStickAxis(2, rightStickX, -rightStickY ,controllerId)
|
ryujinxNative.inputSetStickAxis(2, rightStickX, -rightStickY ,controllerId)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package org.ryujinx.android
|
package org.ryujinx.android
|
||||||
|
|
||||||
import android.view.Surface
|
|
||||||
import org.ryujinx.android.viewmodels.GameInfo
|
import org.ryujinx.android.viewmodels.GameInfo
|
||||||
import java.io.FileDescriptor
|
|
||||||
|
|
||||||
|
@Suppress("KotlinJniMissingFunction")
|
||||||
class RyujinxNative {
|
class RyujinxNative {
|
||||||
|
|
||||||
external fun initialize(appPath: String, enableDebugLogs : Boolean): Boolean
|
external fun initialize(appPath: String, enableDebugLogs : Boolean): Boolean
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package org.ryujinx.android.viewmodels
|
package org.ryujinx.android.viewmodels
|
||||||
|
|
||||||
import android.R.string
|
|
||||||
import android.content.ContentResolver
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.ParcelFileDescriptor
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.anggrayudi.storage.file.extension
|
import com.anggrayudi.storage.file.extension
|
||||||
import org.ryujinx.android.Helpers
|
import org.ryujinx.android.Helpers
|
||||||
@ -22,8 +19,8 @@ class GameModel(var file: DocumentFile, val context: Context) {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
fileName = file.name
|
fileName = file.name
|
||||||
var absPath = getPath()
|
val absPath = getPath()
|
||||||
var gameInfo = RyujinxNative().deviceGetGameInfoFromPath(absPath ?: "")
|
val gameInfo = RyujinxNative().deviceGetGameInfoFromPath(absPath ?: "")
|
||||||
|
|
||||||
fileSize = gameInfo.FileSize
|
fileSize = gameInfo.FileSize
|
||||||
titleId = gameInfo.TitleId
|
titleId = gameInfo.TitleId
|
||||||
@ -37,7 +34,7 @@ class GameModel(var file: DocumentFile, val context: Context) {
|
|||||||
var uri = file.uri
|
var uri = file.uri
|
||||||
if (uri.scheme != "file")
|
if (uri.scheme != "file")
|
||||||
uri = Uri.parse("file://" + Helpers.getPath(context, file.uri))
|
uri = Uri.parse("file://" + Helpers.getPath(context, file.uri))
|
||||||
return uri.path;
|
return uri.path
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getIsXci() : Boolean {
|
fun getIsXci() : Boolean {
|
||||||
|
@ -8,7 +8,6 @@ import com.anggrayudi.storage.file.DocumentFileCompat
|
|||||||
import com.anggrayudi.storage.file.DocumentFileType
|
import com.anggrayudi.storage.file.DocumentFileType
|
||||||
import com.anggrayudi.storage.file.FileFullPath
|
import com.anggrayudi.storage.file.FileFullPath
|
||||||
import com.anggrayudi.storage.file.extension
|
import com.anggrayudi.storage.file.extension
|
||||||
import com.anggrayudi.storage.file.fullName
|
|
||||||
import com.anggrayudi.storage.file.getAbsolutePath
|
import com.anggrayudi.storage.file.getAbsolutePath
|
||||||
import com.anggrayudi.storage.file.search
|
import com.anggrayudi.storage.file.search
|
||||||
import org.ryujinx.android.MainActivity
|
import org.ryujinx.android.MainActivity
|
||||||
@ -20,7 +19,7 @@ class HomeViewModel(
|
|||||||
private var gameList: SnapshotStateList<GameModel>? = null
|
private var gameList: SnapshotStateList<GameModel>? = null
|
||||||
private var loadedCache: List<GameModel> = listOf()
|
private var loadedCache: List<GameModel> = listOf()
|
||||||
private var gameFolderPath: DocumentFile? = null
|
private var gameFolderPath: DocumentFile? = null
|
||||||
private var sharedPref: SharedPreferences? = null;
|
private var sharedPref: SharedPreferences? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (activity != null) {
|
if (activity != null) {
|
||||||
@ -28,15 +27,15 @@ class HomeViewModel(
|
|||||||
activity.storageHelper!!.onFolderSelected = { requestCode, folder ->
|
activity.storageHelper!!.onFolderSelected = { requestCode, folder ->
|
||||||
run {
|
run {
|
||||||
gameFolderPath = folder
|
gameFolderPath = folder
|
||||||
var p = folder.getAbsolutePath(activity!!)
|
val p = folder.getAbsolutePath(activity!!)
|
||||||
var editor = sharedPref?.edit()
|
val editor = sharedPref?.edit()
|
||||||
editor?.putString("gameFolder", p);
|
editor?.putString("gameFolder", p)
|
||||||
editor?.apply()
|
editor?.apply()
|
||||||
reloadGameList()
|
reloadGameList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var savedFolder = sharedPref?.getString("gameFolder", "") ?: ""
|
val savedFolder = sharedPref?.getString("gameFolder", "") ?: ""
|
||||||
|
|
||||||
if (savedFolder.isNotEmpty()) {
|
if (savedFolder.isNotEmpty()) {
|
||||||
try {
|
try {
|
||||||
@ -56,26 +55,26 @@ class HomeViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun openGameFolder() {
|
fun openGameFolder() {
|
||||||
var path = sharedPref?.getString("gameFolder", "") ?: ""
|
val path = sharedPref?.getString("gameFolder", "") ?: ""
|
||||||
|
|
||||||
if (path.isNullOrEmpty())
|
if (path.isEmpty())
|
||||||
activity?.storageHelper?.storage?.openFolderPicker();
|
activity?.storageHelper?.storage?.openFolderPicker()
|
||||||
else
|
else
|
||||||
activity?.storageHelper?.storage?.openFolderPicker(
|
activity?.storageHelper?.storage?.openFolderPicker(
|
||||||
activity!!.storageHelper!!.storage.requestCodeFolderPicker,
|
activity.storageHelper!!.storage.requestCodeFolderPicker,
|
||||||
FileFullPath(activity, path)
|
FileFullPath(activity, path)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reloadGameList() {
|
fun reloadGameList() {
|
||||||
var storage = activity?.storageHelper ?: return
|
var storage = activity?.storageHelper ?: return
|
||||||
var folder = gameFolderPath ?: return
|
val folder = gameFolderPath ?: return
|
||||||
|
|
||||||
var files = mutableListOf<GameModel>()
|
val files = mutableListOf<GameModel>()
|
||||||
|
|
||||||
for (file in folder.search(false, DocumentFileType.FILE)) {
|
for (file in folder.search(false, DocumentFileType.FILE)) {
|
||||||
if (file.extension == "xci" || file.extension == "nsp")
|
if (file.extension == "xci" || file.extension == "nsp")
|
||||||
activity?.let {
|
activity.let {
|
||||||
files.add(GameModel(file, it))
|
files.add(GameModel(file, it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,7 +90,7 @@ class HomeViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setViewList(list: SnapshotStateList<GameModel>) {
|
fun setViewList(list: SnapshotStateList<GameModel>) {
|
||||||
gameList = list;
|
gameList = list
|
||||||
applyFilter()
|
applyFilter()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,14 +23,14 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
var hintService =
|
val hintService =
|
||||||
activity.getSystemService(Context.PERFORMANCE_HINT_SERVICE) as PerformanceHintManager
|
activity.getSystemService(Context.PERFORMANCE_HINT_SERVICE) as PerformanceHintManager
|
||||||
performanceManager = PerformanceManager(hintService)
|
performanceManager = PerformanceManager(hintService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadGame(game:GameModel) {
|
fun loadGame(game:GameModel) {
|
||||||
var controller = navController?: return;
|
val controller = navController?: return
|
||||||
activity.setFullScreen()
|
activity.setFullScreen()
|
||||||
GameHost.gameModel = game
|
GameHost.gameModel = game
|
||||||
controller.navigate("game")
|
controller.navigate("game")
|
||||||
|
@ -55,18 +55,18 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
|||||||
resScale: MutableState<Float>,
|
resScale: MutableState<Float>,
|
||||||
useVirtualController: MutableState<Boolean>
|
useVirtualController: MutableState<Boolean>
|
||||||
){
|
){
|
||||||
var editor = sharedPref.edit()
|
val editor = sharedPref.edit()
|
||||||
|
|
||||||
editor.putBoolean("isHostMapped", isHostMapped?.value ?: true)
|
editor.putBoolean("isHostMapped", isHostMapped.value)
|
||||||
editor.putBoolean("useNce", useNce?.value ?: true)
|
editor.putBoolean("useNce", useNce.value)
|
||||||
editor.putBoolean("enableVsync", enableVsync?.value ?: true)
|
editor.putBoolean("enableVsync", enableVsync.value)
|
||||||
editor.putBoolean("enableDocked", enableDocked?.value ?: true)
|
editor.putBoolean("enableDocked", enableDocked.value)
|
||||||
editor.putBoolean("enablePtc", enablePtc?.value ?: true)
|
editor.putBoolean("enablePtc", enablePtc.value)
|
||||||
editor.putBoolean("ignoreMissingServices", ignoreMissingServices?.value ?: false)
|
editor.putBoolean("ignoreMissingServices", ignoreMissingServices.value)
|
||||||
editor.putBoolean("enableShaderCache", enableShaderCache?.value ?: true)
|
editor.putBoolean("enableShaderCache", enableShaderCache.value)
|
||||||
editor.putBoolean("enableTextureRecompression", enableTextureRecompression?.value ?: false)
|
editor.putBoolean("enableTextureRecompression", enableTextureRecompression.value)
|
||||||
editor.putFloat("resScale", resScale?.value ?: 1f)
|
editor.putFloat("resScale", resScale.value)
|
||||||
editor.putBoolean("useVirtualController", useVirtualController?.value ?: true)
|
editor.putBoolean("useVirtualController", useVirtualController.value)
|
||||||
|
|
||||||
editor.apply()
|
editor.apply()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.ryujinx.android.viewmodels
|
package org.ryujinx.android.viewmodels
|
||||||
|
|
||||||
import androidx.appcompat.widget.ThemedSpinnerAdapter.Helper
|
|
||||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
import androidx.compose.ui.text.intl.Locale
|
import androidx.compose.ui.text.intl.Locale
|
||||||
import androidx.compose.ui.text.toLowerCase
|
import androidx.compose.ui.text.toLowerCase
|
||||||
@ -24,23 +23,23 @@ class TitleUpdateViewModel(val titleId: String) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
data?.paths?.apply {
|
data?.paths?.apply {
|
||||||
removeAt(index - 1);
|
removeAt(index - 1)
|
||||||
pathsState?.clear()
|
pathsState?.clear()
|
||||||
pathsState?.addAll(this)
|
pathsState?.addAll(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Add() {
|
fun Add() {
|
||||||
var callBack = storageHelper.onFileSelected
|
val callBack = storageHelper.onFileSelected
|
||||||
|
|
||||||
storageHelper.onFileSelected = { requestCode, files ->
|
storageHelper.onFileSelected = { requestCode, files ->
|
||||||
run {
|
run {
|
||||||
storageHelper.onFileSelected = callBack
|
storageHelper.onFileSelected = callBack
|
||||||
if(requestCode == UpdateRequestCode)
|
if(requestCode == UpdateRequestCode)
|
||||||
{
|
{
|
||||||
var file = files.firstOrNull()
|
val file = files.firstOrNull()
|
||||||
file?.apply {
|
file?.apply {
|
||||||
var path = Helpers.getPath(storageHelper.storage.context, file.uri)
|
val path = Helpers.getPath(storageHelper.storage.context, file.uri)
|
||||||
if(!path.isNullOrEmpty()){
|
if(!path.isNullOrEmpty()){
|
||||||
data?.apply {
|
data?.apply {
|
||||||
if(!paths.contains(path)) {
|
if(!paths.contains(path)) {
|
||||||
@ -62,20 +61,19 @@ class TitleUpdateViewModel(val titleId: String) {
|
|||||||
this.selected = ""
|
this.selected = ""
|
||||||
if(paths.isNotEmpty() && index > 0)
|
if(paths.isNotEmpty() && index > 0)
|
||||||
{
|
{
|
||||||
var ind = max(index - 1, paths.count() - 1)
|
val ind = max(index - 1, paths.count() - 1)
|
||||||
this.selected = paths[ind]
|
this.selected = paths[ind]
|
||||||
}
|
}
|
||||||
var gson = Gson()
|
val gson = Gson()
|
||||||
var json = gson.toJson(this)
|
val json = gson.toJson(this)
|
||||||
jsonPath = (MainActivity.AppPath
|
jsonPath = MainActivity.AppPath + "/games/" + titleId.toLowerCase(Locale.current)
|
||||||
?: "") + "/games/" + titleId.toLowerCase(Locale.current)
|
|
||||||
File(jsonPath).mkdirs()
|
File(jsonPath).mkdirs()
|
||||||
File(jsonPath + "/updates.json").writeText(json)
|
File("$jsonPath/updates.json").writeText(json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setPaths(paths: SnapshotStateList<String>) {
|
fun setPaths(paths: SnapshotStateList<String>) {
|
||||||
pathsState = paths;
|
pathsState = paths
|
||||||
data?.apply {
|
data?.apply {
|
||||||
pathsState?.clear()
|
pathsState?.clear()
|
||||||
pathsState?.addAll(this.paths)
|
pathsState?.addAll(this.paths)
|
||||||
@ -86,16 +84,15 @@ class TitleUpdateViewModel(val titleId: String) {
|
|||||||
private var jsonPath: String
|
private var jsonPath: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
jsonPath = (MainActivity.AppPath
|
jsonPath = MainActivity.AppPath + "/games/" + titleId.toLowerCase(Locale.current) + "/updates.json"
|
||||||
?: "") + "/games/" + titleId.toLowerCase(Locale.current) + "/updates.json"
|
|
||||||
|
|
||||||
data = TitleUpdateMetadata()
|
data = TitleUpdateMetadata()
|
||||||
if (File(jsonPath).exists()) {
|
if (File(jsonPath).exists()) {
|
||||||
var gson = Gson()
|
val gson = Gson()
|
||||||
data = gson.fromJson(File(jsonPath).readText(), TitleUpdateMetadata::class.java)
|
data = gson.fromJson(File(jsonPath).readText(), TitleUpdateMetadata::class.java)
|
||||||
|
|
||||||
data?.apply {
|
data?.apply {
|
||||||
var existingPaths = mutableListOf<String>()
|
val existingPaths = mutableListOf<String>()
|
||||||
for (path in paths) {
|
for (path in paths) {
|
||||||
if (File(path).exists()) {
|
if (File(path).exists()) {
|
||||||
existingPaths.add(path)
|
existingPaths.add(path)
|
||||||
|
@ -12,22 +12,22 @@ class VulkanDriverViewModel(val activity: MainActivity) {
|
|||||||
var selected: String = ""
|
var selected: String = ""
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val DriverRequestCode: Int = 1003
|
const val DriverRequestCode: Int = 1003
|
||||||
const val DriverFolder: String = "drivers"
|
const val DriverFolder: String = "drivers"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAppPath() : String {
|
private fun getAppPath() : String {
|
||||||
var appPath =
|
var appPath =
|
||||||
(MainActivity.AppPath ?: activity.getExternalFilesDir(null)?.absolutePath ?: "");
|
MainActivity.AppPath
|
||||||
appPath += "/"
|
appPath += "/"
|
||||||
|
|
||||||
return appPath
|
return appPath
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ensureDriverPath() : File {
|
fun ensureDriverPath() : File {
|
||||||
var driverPath = getAppPath() + DriverFolder
|
val driverPath = getAppPath() + DriverFolder
|
||||||
|
|
||||||
var driverFolder = File(driverPath)
|
val driverFolder = File(driverPath)
|
||||||
|
|
||||||
if(!driverFolder.exists())
|
if(!driverFolder.exists())
|
||||||
driverFolder.mkdirs()
|
driverFolder.mkdirs()
|
||||||
@ -36,13 +36,13 @@ class VulkanDriverViewModel(val activity: MainActivity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getAvailableDrivers() : MutableList<DriverMetadata> {
|
fun getAvailableDrivers() : MutableList<DriverMetadata> {
|
||||||
var driverFolder = ensureDriverPath()
|
val driverFolder = ensureDriverPath()
|
||||||
|
|
||||||
var folders = driverFolder.walkTopDown()
|
val folders = driverFolder.walkTopDown()
|
||||||
|
|
||||||
var drivers = mutableListOf<DriverMetadata>()
|
val drivers = mutableListOf<DriverMetadata>()
|
||||||
|
|
||||||
var selectedDriverFile = File(driverFolder.absolutePath + "/selected");
|
val selectedDriverFile = File(driverFolder.absolutePath + "/selected")
|
||||||
if(selectedDriverFile.exists()){
|
if(selectedDriverFile.exists()){
|
||||||
selected = selectedDriverFile.readText()
|
selected = selectedDriverFile.readText()
|
||||||
|
|
||||||
@ -52,16 +52,16 @@ class VulkanDriverViewModel(val activity: MainActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var gson = Gson()
|
val gson = Gson()
|
||||||
|
|
||||||
for (folder in folders){
|
for (folder in folders){
|
||||||
if(folder.isDirectory() && folder.parent == driverFolder.absolutePath){
|
if(folder.isDirectory() && folder.parent == driverFolder.absolutePath){
|
||||||
var meta = File(folder.absolutePath + "/meta.json")
|
val meta = File(folder.absolutePath + "/meta.json")
|
||||||
|
|
||||||
if(meta.exists()){
|
if(meta.exists()){
|
||||||
var metadata = gson.fromJson(meta.readText(), DriverMetadata::class.java)
|
val metadata = gson.fromJson(meta.readText(), DriverMetadata::class.java)
|
||||||
if(metadata.name.isNotEmpty()) {
|
if(metadata.name.isNotEmpty()) {
|
||||||
var driver = folder.absolutePath + "/${metadata.libraryName}"
|
val driver = folder.absolutePath + "/${metadata.libraryName}"
|
||||||
metadata.driverPath = driver
|
metadata.driverPath = driver
|
||||||
if (File(driver).exists())
|
if (File(driver).exists())
|
||||||
drivers.add(metadata)
|
drivers.add(metadata)
|
||||||
@ -74,18 +74,17 @@ class VulkanDriverViewModel(val activity: MainActivity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun saveSelected() {
|
fun saveSelected() {
|
||||||
var driverFolder = ensureDriverPath()
|
val driverFolder = ensureDriverPath()
|
||||||
|
|
||||||
var selectedDriverFile = File(driverFolder.absolutePath + "/selected")
|
val selectedDriverFile = File(driverFolder.absolutePath + "/selected")
|
||||||
selectedDriverFile.writeText(selected)
|
selectedDriverFile.writeText(selected)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeSelected(){
|
fun removeSelected(){
|
||||||
if(selected.isNotEmpty()){
|
if(selected.isNotEmpty()){
|
||||||
var sel = File(selected)
|
val sel = File(selected)
|
||||||
if(sel.exists()) {
|
if(sel.exists()) {
|
||||||
var parent = sel.parentFile
|
sel.parentFile?.deleteRecursively()
|
||||||
parent.deleteRecursively()
|
|
||||||
}
|
}
|
||||||
selected = ""
|
selected = ""
|
||||||
|
|
||||||
@ -96,20 +95,20 @@ class VulkanDriverViewModel(val activity: MainActivity) {
|
|||||||
fun add(refresh: MutableState<Boolean>) {
|
fun add(refresh: MutableState<Boolean>) {
|
||||||
activity.storageHelper?.apply {
|
activity.storageHelper?.apply {
|
||||||
|
|
||||||
var callBack = this.onFileSelected
|
val callBack = this.onFileSelected
|
||||||
|
|
||||||
onFileSelected = { requestCode, files ->
|
onFileSelected = { requestCode, files ->
|
||||||
run {
|
run {
|
||||||
onFileSelected = callBack
|
onFileSelected = callBack
|
||||||
if(requestCode == DriverRequestCode)
|
if(requestCode == DriverRequestCode)
|
||||||
{
|
{
|
||||||
var file = files.firstOrNull()
|
val file = files.firstOrNull()
|
||||||
file?.apply {
|
file?.apply {
|
||||||
var path = Helpers.getPath(storage.context, file.uri)
|
val path = Helpers.getPath(storage.context, file.uri)
|
||||||
if(!path.isNullOrEmpty()){
|
if(!path.isNullOrEmpty()){
|
||||||
var name = file.name?.removeSuffix("." + file.extension) ?: ""
|
val name = file.name?.removeSuffix("." + file.extension) ?: ""
|
||||||
var driverFolder = ensureDriverPath()
|
val driverFolder = ensureDriverPath()
|
||||||
var extractionFolder = File(driverFolder.absolutePath + "/${name}")
|
val extractionFolder = File(driverFolder.absolutePath + "/${name}")
|
||||||
extractionFolder.mkdirs()
|
extractionFolder.mkdirs()
|
||||||
ZipFile(path)?.use { zip ->
|
ZipFile(path)?.use { zip ->
|
||||||
zip.entries().asSequence().forEach { entry ->
|
zip.entries().asSequence().forEach { entry ->
|
||||||
@ -118,7 +117,7 @@ class VulkanDriverViewModel(val activity: MainActivity) {
|
|||||||
val filePath = extractionFolder.absolutePath + File.separator + entry.name
|
val filePath = extractionFolder.absolutePath + File.separator + entry.name
|
||||||
|
|
||||||
if (!entry.isDirectory) {
|
if (!entry.isDirectory) {
|
||||||
var length = input.available()
|
val length = input.available()
|
||||||
val bytesIn = ByteArray(length)
|
val bytesIn = ByteArray(length)
|
||||||
input.read(bytesIn)
|
input.read(bytesIn)
|
||||||
File(filePath).writeBytes(bytesIn)
|
File(filePath).writeBytes(bytesIn)
|
||||||
|
@ -12,8 +12,6 @@ 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.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeContentPadding
|
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
@ -56,12 +54,9 @@ import androidx.compose.ui.layout.onSizeChanged
|
|||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.IntOffset
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.DialogWindowProvider
|
import androidx.compose.ui.window.DialogWindowProvider
|
||||||
import androidx.compose.ui.window.Popup
|
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import org.ryujinx.android.MainActivity
|
import org.ryujinx.android.MainActivity
|
||||||
@ -78,11 +73,11 @@ class HomeViews {
|
|||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainTopBar(navController: NavHostController) {
|
fun MainTopBar(navController: NavHostController) {
|
||||||
var topBarSize = remember {
|
val topBarSize = remember {
|
||||||
mutableStateOf(0)
|
mutableStateOf(0)
|
||||||
}
|
}
|
||||||
Column {
|
Column {
|
||||||
var showOptionsPopup = remember {
|
val showOptionsPopup = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@ -116,7 +111,7 @@ class HomeViews {
|
|||||||
actions = {
|
actions = {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
showOptionsPopup.value = true;
|
showOptionsPopup.value = true
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
@ -171,7 +166,7 @@ class HomeViews {
|
|||||||
fun Home(viewModel: HomeViewModel = HomeViewModel(), navController: NavHostController? = null) {
|
fun Home(viewModel: HomeViewModel = HomeViewModel(), navController: NavHostController? = null) {
|
||||||
val sheetState = rememberModalBottomSheetState()
|
val sheetState = rememberModalBottomSheetState()
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
var showBottomSheet = remember { mutableStateOf(false) }
|
val showBottomSheet = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
@ -195,7 +190,7 @@ class HomeViews {
|
|||||||
|
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
Box(modifier = Modifier.padding(contentPadding)) {
|
Box(modifier = Modifier.padding(contentPadding)) {
|
||||||
var list = remember {
|
val list = remember {
|
||||||
mutableStateListOf<GameModel>()
|
mutableStateListOf<GameModel>()
|
||||||
}
|
}
|
||||||
viewModel.setViewList(list)
|
viewModel.setViewList(list)
|
||||||
@ -227,8 +222,8 @@ class HomeViews {
|
|||||||
shape = MaterialTheme.shapes.large,
|
shape = MaterialTheme.shapes.large,
|
||||||
tonalElevation = AlertDialogDefaults.TonalElevation
|
tonalElevation = AlertDialogDefaults.TonalElevation
|
||||||
) {
|
) {
|
||||||
var titleId = viewModel.mainViewModel?.selected?.titleId ?: ""
|
val titleId = viewModel.mainViewModel?.selected?.titleId ?: ""
|
||||||
var name = viewModel.mainViewModel?.selected?.titleName ?: ""
|
val name = viewModel.mainViewModel?.selected?.titleName ?: ""
|
||||||
TitleUpdateViews.Main(titleId, name, openDialog)
|
TitleUpdateViews.Main(titleId, name, openDialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +262,7 @@ class HomeViews {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun GameItem(gameModel: GameModel, viewModel: HomeViewModel, showSheet : MutableState<Boolean>) {
|
fun GameItem(gameModel: GameModel, viewModel: HomeViewModel, showSheet : MutableState<Boolean>) {
|
||||||
Card(shape = MaterialTheme.shapes.medium,
|
Card(shape = MaterialTheme.shapes.medium,
|
||||||
@ -291,8 +286,8 @@ class HomeViews {
|
|||||||
Row {
|
Row {
|
||||||
if(!gameModel.titleId.isNullOrEmpty() && gameModel.titleId != "0000000000000000")
|
if(!gameModel.titleId.isNullOrEmpty() && gameModel.titleId != "0000000000000000")
|
||||||
{
|
{
|
||||||
var iconSource = MainActivity.AppPath + "/iconCache/" + gameModel.iconCache
|
val iconSource = MainActivity.AppPath + "/iconCache/" + gameModel.iconCache
|
||||||
var imageFile = File(iconSource)
|
val imageFile = File(iconSource)
|
||||||
if(imageFile.exists()) {
|
if(imageFile.exists()) {
|
||||||
val size = ImageSize / Resources.getSystem().displayMetrics.density
|
val size = ImageSize / Resources.getSystem().displayMetrics.density
|
||||||
AsyncImage(model = imageFile,
|
AsyncImage(model = imageFile,
|
||||||
@ -320,7 +315,7 @@ class HomeViews {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NotAvailableIcon() {
|
fun NotAvailableIcon() {
|
||||||
var size = ImageSize / Resources.getSystem().displayMetrics.density
|
val size = ImageSize / Resources.getSystem().displayMetrics.density
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Filled.Add,
|
Icons.Filled.Add,
|
||||||
contentDescription = "Options",
|
contentDescription = "Options",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.ryujinx.android.views
|
package org.ryujinx.android.views
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@ -73,7 +72,7 @@ class MainView {
|
|||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
GameStats(mainViewModel)
|
GameStats(mainViewModel)
|
||||||
|
|
||||||
var ryujinxNative = RyujinxNative()
|
val ryujinxNative = RyujinxNative()
|
||||||
|
|
||||||
// touch surface
|
// touch surface
|
||||||
Surface(color = Color.Transparent, modifier = Modifier
|
Surface(color = Color.Transparent, modifier = Modifier
|
||||||
@ -82,32 +81,36 @@ class MainView {
|
|||||||
.pointerInput(Unit) {
|
.pointerInput(Unit) {
|
||||||
awaitPointerEventScope {
|
awaitPointerEventScope {
|
||||||
while (true) {
|
while (true) {
|
||||||
Thread.sleep(2);
|
Thread.sleep(2)
|
||||||
val event = awaitPointerEvent()
|
val event = awaitPointerEvent()
|
||||||
|
|
||||||
if(controller.isVisible)
|
if(controller.isVisible)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var change = event
|
val change = event
|
||||||
.component1()
|
.component1()
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
change?.apply {
|
change?.apply {
|
||||||
var position = this.position
|
val position = this.position
|
||||||
|
|
||||||
if (event.type == PointerEventType.Press) {
|
when (event.type) {
|
||||||
ryujinxNative.inputSetTouchPoint(
|
PointerEventType.Press -> {
|
||||||
position.x.roundToInt(),
|
ryujinxNative.inputSetTouchPoint(
|
||||||
position.y.roundToInt()
|
position.x.roundToInt(),
|
||||||
)
|
position.y.roundToInt()
|
||||||
} else if (event.type == PointerEventType.Release) {
|
)
|
||||||
ryujinxNative.inputReleaseTouchPoint()
|
}
|
||||||
|
PointerEventType.Release -> {
|
||||||
|
ryujinxNative.inputReleaseTouchPoint()
|
||||||
|
|
||||||
} else if (event.type == PointerEventType.Move) {
|
}
|
||||||
ryujinxNative.inputSetTouchPoint(
|
PointerEventType.Move -> {
|
||||||
position.x.roundToInt(),
|
ryujinxNative.inputSetTouchPoint(
|
||||||
position.y.roundToInt()
|
position.x.roundToInt(),
|
||||||
)
|
position.y.roundToInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,7 +131,7 @@ class MainView {
|
|||||||
}
|
}
|
||||||
@Composable
|
@Composable
|
||||||
fun rememberVideogameAsset(): ImageVector {
|
fun rememberVideogameAsset(): ImageVector {
|
||||||
var primaryColor = MaterialTheme.colorScheme.primary
|
val primaryColor = MaterialTheme.colorScheme.primary
|
||||||
return remember {
|
return remember {
|
||||||
ImageVector.Builder(
|
ImageVector.Builder(
|
||||||
name = "videogame_asset",
|
name = "videogame_asset",
|
||||||
@ -224,20 +227,20 @@ class MainView {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GameStats(mainViewModel: MainViewModel){
|
fun GameStats(mainViewModel: MainViewModel){
|
||||||
var fifo = remember {
|
val fifo = remember {
|
||||||
mutableStateOf(0.0)
|
mutableStateOf(0.0)
|
||||||
}
|
}
|
||||||
var gameFps = remember {
|
val gameFps = remember {
|
||||||
mutableStateOf(0.0)
|
mutableStateOf(0.0)
|
||||||
}
|
}
|
||||||
var gameTime = remember {
|
val gameTime = remember {
|
||||||
mutableStateOf(0.0)
|
mutableStateOf(0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface(modifier = Modifier.padding(16.dp),
|
Surface(modifier = Modifier.padding(16.dp),
|
||||||
color = MaterialTheme.colorScheme.surface.copy(0.4f)) {
|
color = MaterialTheme.colorScheme.surface.copy(0.4f)) {
|
||||||
Column {
|
Column {
|
||||||
var gameTimeVal = 0.0;
|
var gameTimeVal = 0.0
|
||||||
if (!gameTime.value.isInfinite())
|
if (!gameTime.value.isInfinite())
|
||||||
gameTimeVal = gameTime.value
|
gameTimeVal = gameTime.value
|
||||||
Text(text = "${String.format("%.3f", fifo.value)} %")
|
Text(text = "${String.format("%.3f", fifo.value)} %")
|
||||||
|
@ -13,36 +13,24 @@ 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.safeContentPadding
|
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
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
|
||||||
@ -54,7 +42,6 @@ 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 {
|
||||||
@ -63,38 +50,38 @@ class SettingViews {
|
|||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Main(settingsViewModel: SettingsViewModel) {
|
fun Main(settingsViewModel: SettingsViewModel) {
|
||||||
var loaded = remember {
|
val loaded = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isHostMapped = remember {
|
val isHostMapped = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var useNce = remember {
|
val useNce = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var enableVsync = remember {
|
val enableVsync = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var enableDocked = remember {
|
val enableDocked = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var enablePtc = remember {
|
val enablePtc = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var ignoreMissingServices = remember {
|
val ignoreMissingServices = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var enableShaderCache = remember {
|
val enableShaderCache = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var enableTextureRecompression = remember {
|
val enableTextureRecompression = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
var resScale = remember {
|
val resScale = remember {
|
||||||
mutableStateOf(1f)
|
mutableStateOf(1f)
|
||||||
}
|
}
|
||||||
var useVirtualController = remember {
|
val useVirtualController = remember {
|
||||||
mutableStateOf(true)
|
mutableStateOf(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,8 +457,8 @@ class SettingViews {
|
|||||||
title: String,
|
title: String,
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
var expanded = false
|
val expanded = false
|
||||||
var mutableExpanded = remember {
|
val mutableExpanded = remember {
|
||||||
mutableStateOf(expanded)
|
mutableStateOf(expanded)
|
||||||
}
|
}
|
||||||
val transitionState = remember {
|
val transitionState = remember {
|
||||||
|
@ -3,11 +3,9 @@ package org.ryujinx.android.views
|
|||||||
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.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
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.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
@ -35,7 +33,7 @@ class TitleUpdateViews {
|
|||||||
fun Main(titleId: String, name: String, openDialog: MutableState<Boolean>) {
|
fun Main(titleId: String, name: String, openDialog: MutableState<Boolean>) {
|
||||||
val viewModel = TitleUpdateViewModel(titleId)
|
val viewModel = TitleUpdateViewModel(titleId)
|
||||||
|
|
||||||
var selected = remember { mutableStateOf(0) }
|
val selected = remember { mutableStateOf(0) }
|
||||||
viewModel.data?.apply {
|
viewModel.data?.apply {
|
||||||
selected.value = paths.indexOf(this.selected) + 1
|
selected.value = paths.indexOf(this.selected) + 1
|
||||||
}
|
}
|
||||||
@ -67,14 +65,14 @@ class TitleUpdateViews {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var paths = remember {
|
val paths = remember {
|
||||||
mutableStateListOf<String>()
|
mutableStateListOf<String>()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.setPaths(paths)
|
viewModel.setPaths(paths)
|
||||||
var index = 1
|
var index = 1
|
||||||
for (path in paths) {
|
for (path in paths) {
|
||||||
var i = index
|
val i = index
|
||||||
Row(modifier = Modifier.padding(8.dp)) {
|
Row(modifier = Modifier.padding(8.dp)) {
|
||||||
RadioButton(
|
RadioButton(
|
||||||
selected = (selected.value == i),
|
selected = (selected.value == i),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user