forked from MeloNX/MeloNX
add closing emulation(starting a new one is still broken), disabled audio
This commit is contained in:
parent
a050e5c6c0
commit
2999275ed2
@ -72,7 +72,9 @@ namespace LibRyujinx
|
|||||||
|
|
||||||
var init = Initialize(path, enableDebugLogs);
|
var init = Initialize(path, enableDebugLogs);
|
||||||
|
|
||||||
AudioDriver = new OboeHardwareDeviceDriver();
|
// AudioDriver = new OboeHardwareDeviceDriver();
|
||||||
|
|
||||||
|
_surfaceEvent?.Set();
|
||||||
|
|
||||||
_surfaceEvent = new ManualResetEvent(false);
|
_surfaceEvent = new ManualResetEvent(false);
|
||||||
|
|
||||||
@ -151,6 +153,18 @@ namespace LibRyujinx
|
|||||||
return LoadApplication(path);
|
return LoadApplication(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceSignalEmulationClose")]
|
||||||
|
public static void JniSignalEmulationCloseNative(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||||
|
{
|
||||||
|
SignalEmulationClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceCloseEmulation")]
|
||||||
|
public static void JniCloseEmulationNative(JEnvRef jEnv, JObjectLocalRef jObj)
|
||||||
|
{
|
||||||
|
CloseEmulation();
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoadDescriptor")]
|
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoadDescriptor")]
|
||||||
public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
|
public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
|
using Ryujinx.Input.HLE;
|
||||||
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@ -168,5 +170,41 @@ namespace LibRyujinx
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SignalEmulationClose()
|
||||||
|
{
|
||||||
|
_isStopped = true;
|
||||||
|
_isActive = false;
|
||||||
|
|
||||||
|
debug_break(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CloseEmulation()
|
||||||
|
{
|
||||||
|
if (SwitchDevice == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_npadManager?.Dispose();
|
||||||
|
_npadManager = null;
|
||||||
|
|
||||||
|
_touchScreenManager?.Dispose();
|
||||||
|
_touchScreenManager = null;
|
||||||
|
|
||||||
|
SwitchDevice?.InputManager?.Dispose();
|
||||||
|
SwitchDevice.InputManager = null;
|
||||||
|
_inputManager = null;
|
||||||
|
|
||||||
|
|
||||||
|
_surfaceEvent?.Set();
|
||||||
|
|
||||||
|
if (Renderer != null)
|
||||||
|
{
|
||||||
|
_gpuDoneEvent.WaitOne();
|
||||||
|
_gpuDoneEvent.Dispose();
|
||||||
|
_gpuDoneEvent = null;
|
||||||
|
SwitchDevice?.DisposeContext();
|
||||||
|
Renderer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using LibRyujinx.Shared;
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.Graphics.Vulkan;
|
using Ryujinx.Graphics.Vulkan;
|
||||||
@ -21,6 +22,7 @@ namespace LibRyujinx
|
|||||||
private static CancellationTokenSource _gpuCancellationTokenSource;
|
private static CancellationTokenSource _gpuCancellationTokenSource;
|
||||||
private static SwapBuffersCallback? _swapBuffersCallback;
|
private static SwapBuffersCallback? _swapBuffersCallback;
|
||||||
private static NativeGraphicsInterop _nativeGraphicsInterop;
|
private static NativeGraphicsInterop _nativeGraphicsInterop;
|
||||||
|
private static ManualResetEvent _gpuDoneEvent;
|
||||||
|
|
||||||
public delegate void SwapBuffersCallback();
|
public delegate void SwapBuffersCallback();
|
||||||
public delegate IntPtr GetProcAddress(string name);
|
public delegate IntPtr GetProcAddress(string name);
|
||||||
@ -146,12 +148,14 @@ namespace LibRyujinx
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var device = SwitchDevice!.EmulationContext!;
|
var device = SwitchDevice!.EmulationContext!;
|
||||||
|
_gpuDoneEvent = new ManualResetEvent(true);
|
||||||
|
|
||||||
device.Gpu.Renderer.Initialize(GraphicsDebugLevel.None);
|
device.Gpu.Renderer.Initialize(GraphicsDebugLevel.None);
|
||||||
_gpuCancellationTokenSource = new CancellationTokenSource();
|
_gpuCancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
device.Gpu.Renderer.RunLoop(() =>
|
device.Gpu.Renderer.RunLoop(() =>
|
||||||
{
|
{
|
||||||
|
_gpuDoneEvent.Reset();
|
||||||
device.Gpu.SetGpuThread();
|
device.Gpu.SetGpuThread();
|
||||||
device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
||||||
Translator.IsReadyForTranslation.Set();
|
Translator.IsReadyForTranslation.Set();
|
||||||
@ -162,9 +166,11 @@ namespace LibRyujinx
|
|||||||
{
|
{
|
||||||
if (_isStopped)
|
if (_isStopped)
|
||||||
{
|
{
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_break(1);
|
||||||
|
|
||||||
if (Ryujinx.Common.SystemInfo.SystemInfo.IsBionic)
|
if (Ryujinx.Common.SystemInfo.SystemInfo.IsBionic)
|
||||||
{
|
{
|
||||||
setRenderingThread();
|
setRenderingThread();
|
||||||
@ -182,6 +188,13 @@ namespace LibRyujinx
|
|||||||
device.PresentFrame(() => _swapBuffersCallback?.Invoke());
|
device.PresentFrame(() => _swapBuffersCallback?.Invoke());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device.Gpu.Renderer is ThreadedRenderer threaded)
|
||||||
|
{
|
||||||
|
threaded.FlushThreadedCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
_gpuDoneEvent.Set();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ namespace LibRyujinx
|
|||||||
private static VirtualTouchScreenDriver? _touchScreenDriver;
|
private static VirtualTouchScreenDriver? _touchScreenDriver;
|
||||||
private static TouchScreenManager? _touchScreenManager;
|
private static TouchScreenManager? _touchScreenManager;
|
||||||
private static InputManager? _inputManager;
|
private static InputManager? _inputManager;
|
||||||
private static NpadManager _npadManager;
|
private static NpadManager? _npadManager;
|
||||||
private static InputConfig[] _configs;
|
private static InputConfig[] _configs;
|
||||||
|
|
||||||
public static void InitializeInput(int width, int height)
|
public static void InitializeInput(int width, int height)
|
||||||
|
@ -641,7 +641,9 @@ namespace LibRyujinx
|
|||||||
internal void DisposeContext()
|
internal void DisposeContext()
|
||||||
{
|
{
|
||||||
EmulationContext?.Dispose();
|
EmulationContext?.Dispose();
|
||||||
|
EmulationContext?.DisposeGpu();
|
||||||
EmulationContext = null;
|
EmulationContext = null;
|
||||||
|
LibRyujinx.Renderer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,5 +222,6 @@ Java_org_ryujinx_android_NativeHelpers_loadDriver(JNIEnv *env, jobject thiz,
|
|||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
void debug_break(int code){
|
void debug_break(int code){
|
||||||
|
if(code >= 3)
|
||||||
int r = 0;
|
int r = 0;
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ import java.io.File
|
|||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
|
class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
|
||||||
|
private var _isClosed: Boolean = false
|
||||||
private var _renderingThreadWatcher: Thread? = null
|
private var _renderingThreadWatcher: Thread? = null
|
||||||
private var _height: Int = 0
|
private var _height: Int = 0
|
||||||
private var _width: Int = 0
|
private var _width: Int = 0
|
||||||
@ -21,14 +22,9 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
|
|||||||
private var _isInit: Boolean = false
|
private var _isInit: Boolean = false
|
||||||
private var _isStarted: Boolean = false
|
private var _isStarted: Boolean = false
|
||||||
private var _nativeWindow: Long = 0
|
private var _nativeWindow: Long = 0
|
||||||
private var _nativeHelper: NativeHelpers = NativeHelpers()
|
|
||||||
|
|
||||||
private var _nativeRyujinx: RyujinxNative = RyujinxNative()
|
private var _nativeRyujinx: RyujinxNative = RyujinxNative()
|
||||||
|
|
||||||
companion object {
|
|
||||||
var gameModel: GameModel? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
holder.addCallback(this)
|
holder.addCallback(this)
|
||||||
}
|
}
|
||||||
@ -37,6 +33,8 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||||
|
if(_isClosed)
|
||||||
|
return
|
||||||
start(holder)
|
start(holder)
|
||||||
|
|
||||||
if(_width != width || _height != height)
|
if(_width != width || _height != height)
|
||||||
@ -59,8 +57,17 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun start(surfaceHolder: SurfaceHolder) {
|
fun close(){
|
||||||
|
_isClosed = true
|
||||||
|
_isInit = false
|
||||||
|
_isStarted = false
|
||||||
|
|
||||||
|
_updateThread?.join()
|
||||||
|
_renderingThreadWatcher?.join()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun start(surfaceHolder: SurfaceHolder) {
|
||||||
|
mainViewModel.gameHost = this
|
||||||
if(_isStarted)
|
if(_isStarted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -119,6 +126,7 @@ class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceVie
|
|||||||
mainViewModel.performanceManager?.initializeRenderingSession(threadId)
|
mainViewModel.performanceManager?.initializeRenderingSession(threadId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mainViewModel.performanceManager?.closeCurrentRenderingSession()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_nativeRyujinx.graphicsRendererRunLoop()
|
_nativeRyujinx.graphicsRendererRunLoop()
|
||||||
|
@ -12,6 +12,7 @@ import android.view.KeyEvent
|
|||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.addCallback
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -62,15 +63,22 @@ class MainActivity : ComponentActivity() {
|
|||||||
external fun getRenderingThreadId() : Long
|
external fun getRenderingThreadId() : Long
|
||||||
external fun initVm()
|
external fun initVm()
|
||||||
|
|
||||||
fun setFullScreen() {
|
fun setFullScreen(fullscreen: Boolean) {
|
||||||
requestedOrientation =
|
requestedOrientation =
|
||||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
if (fullscreen) ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
||||||
|
|
||||||
val 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())
|
if (fullscreen) {
|
||||||
insets.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
insets.hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insets.systemBarsBehavior =
|
||||||
|
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
} else {
|
||||||
|
insets.show(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
|
||||||
|
insets.systemBarsBehavior =
|
||||||
|
WindowInsetsControllerCompat.BEHAVIOR_DEFAULT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +103,8 @@ class MainActivity : ComponentActivity() {
|
|||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
|
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
|
||||||
event?.apply {
|
event?.apply {
|
||||||
return physicalControllerManager.onKeyEvent(this)
|
if(physicalControllerManager.onKeyEvent(this))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return super.dispatchKeyEvent(event)
|
return super.dispatchKeyEvent(event)
|
||||||
}
|
}
|
||||||
|
@ -48,4 +48,6 @@ class RyujinxNative {
|
|||||||
external fun inputConnectGamepad(index: Int): Int
|
external fun inputConnectGamepad(index: Int): Int
|
||||||
external fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int): Unit
|
external fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int): Unit
|
||||||
external fun graphicsSetSurface(surface: Long)
|
external fun graphicsSetSurface(surface: Long)
|
||||||
|
external fun deviceCloseEmulation()
|
||||||
|
external fun deviceSignalEmulationClose()
|
||||||
}
|
}
|
@ -6,10 +6,6 @@ import android.os.Build
|
|||||||
import android.os.PerformanceHintManager
|
import android.os.PerformanceHintManager
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.anggrayudi.storage.extension.launchOnUiThread
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.ryujinx.android.GameController
|
import org.ryujinx.android.GameController
|
||||||
import org.ryujinx.android.GameHost
|
import org.ryujinx.android.GameHost
|
||||||
import org.ryujinx.android.GraphicsConfiguration
|
import org.ryujinx.android.GraphicsConfiguration
|
||||||
@ -24,6 +20,7 @@ import java.io.File
|
|||||||
|
|
||||||
@SuppressLint("WrongConstant")
|
@SuppressLint("WrongConstant")
|
||||||
class MainViewModel(val activity: MainActivity) {
|
class MainViewModel(val activity: MainActivity) {
|
||||||
|
var gameHost: GameHost? = null
|
||||||
var controller: GameController? = null
|
var controller: GameController? = null
|
||||||
var performanceManager: PerformanceManager? = null
|
var performanceManager: PerformanceManager? = null
|
||||||
var selected: GameModel? = null
|
var selected: GameModel? = null
|
||||||
@ -42,9 +39,19 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loadGame(game:GameModel) : Boolean {
|
fun closeGame() {
|
||||||
GameHost.gameModel = game
|
RyujinxNative().deviceSignalEmulationClose()
|
||||||
|
gameHost?.close()
|
||||||
|
RyujinxNative().deviceCloseEmulation()
|
||||||
|
goBack()
|
||||||
|
activity.setFullScreen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun goBack(){
|
||||||
|
navController?.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadGame(game:GameModel) : Boolean {
|
||||||
var nativeRyujinx = RyujinxNative()
|
var nativeRyujinx = RyujinxNative()
|
||||||
|
|
||||||
val path = game.getPath() ?: return false
|
val path = game.getPath() ?: return false
|
||||||
@ -129,8 +136,6 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
if(!success)
|
if(!success)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
activity.physicalControllerManager.connect()
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,4 +168,7 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
fun setGameController(controller: GameController) {
|
fun setGameController(controller: GameController) {
|
||||||
this.controller = controller
|
this.controller = controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun backCalled() {
|
||||||
|
}
|
||||||
}
|
}
|
@ -310,7 +310,7 @@ class HomeViews {
|
|||||||
val success = viewModel.mainViewModel?.loadGame(gameModel) ?: false
|
val success = viewModel.mainViewModel?.loadGame(gameModel) ?: false
|
||||||
if(success) {
|
if(success) {
|
||||||
launchOnUiThread {
|
launchOnUiThread {
|
||||||
viewModel.mainViewModel?.activity?.setFullScreen()
|
viewModel.mainViewModel?.activity?.setFullScreen(true)
|
||||||
viewModel.mainViewModel?.navController?.navigate("game")
|
viewModel.mainViewModel?.navController?.navigate("game")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,25 @@
|
|||||||
package org.ryujinx.android.views
|
package org.ryujinx.android.views
|
||||||
|
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
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
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
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.padding
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
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.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -71,6 +83,7 @@ class MainView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun GameOverlay(mainViewModel: MainViewModel) {
|
fun GameOverlay(mainViewModel: MainViewModel) {
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
@ -135,6 +148,57 @@ class MainView {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var showBackNotice = remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
BackHandler {
|
||||||
|
showBackNotice.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showBackNotice.value) {
|
||||||
|
AlertDialog(onDismissRequest = { showBackNotice.value = false }) {
|
||||||
|
Column {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentWidth()
|
||||||
|
.wrapContentHeight(),
|
||||||
|
shape = MaterialTheme.shapes.large,
|
||||||
|
tonalElevation = AlertDialogDefaults.TonalElevation
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(text = "Are you sure you want to exit the game?")
|
||||||
|
Text(text = "All unsaved data will be lost!")
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Button(onClick = {
|
||||||
|
mainViewModel.closeGame()
|
||||||
|
}, modifier = Modifier.padding(16.dp)) {
|
||||||
|
Text(text = "Exit Game")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(onClick = {
|
||||||
|
showBackNotice.value = false
|
||||||
|
}, modifier = Modifier.padding(16.dp)) {
|
||||||
|
Text(text = "Dismiss")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,16 +135,6 @@ class SettingViews {
|
|||||||
})
|
})
|
||||||
}) { contentPadding ->
|
}) { contentPadding ->
|
||||||
Column(modifier = Modifier.padding(contentPadding)) {
|
Column(modifier = Modifier.padding(contentPadding)) {
|
||||||
BackHandler {
|
|
||||||
settingsViewModel.save(
|
|
||||||
isHostMapped,
|
|
||||||
useNce, enableVsync, enableDocked, enablePtc, ignoreMissingServices,
|
|
||||||
enableShaderCache,
|
|
||||||
enableTextureRecompression,
|
|
||||||
resScale,
|
|
||||||
useVirtualController
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ExpandableView(onCardArrowClick = { }, title = "System") {
|
ExpandableView(onCardArrowClick = { }, title = "System") {
|
||||||
Column(modifier = Modifier.fillMaxWidth()) {
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
Row(
|
Row(
|
||||||
@ -462,6 +452,18 @@ class SettingViews {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BackHandler() {
|
||||||
|
settingsViewModel.save(
|
||||||
|
isHostMapped,
|
||||||
|
useNce, enableVsync, enableDocked, enablePtc, ignoreMissingServices,
|
||||||
|
enableShaderCache,
|
||||||
|
enableTextureRecompression,
|
||||||
|
resScale,
|
||||||
|
useVirtualController
|
||||||
|
)
|
||||||
|
settingsViewModel.navController.popBackStack()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user