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