mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
cleanup code
This commit is contained in:
@@ -67,7 +67,6 @@ add_library(CemuCafe
|
||||
HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h
|
||||
HW/Espresso/Recompiler/PPCRecompiler.cpp
|
||||
HW/Espresso/Recompiler/PPCRecompiler.h
|
||||
HW/Espresso/Recompiler/RecompilerTests.cpp
|
||||
HW/Espresso/Recompiler/IML/IML.h
|
||||
HW/Espresso/Recompiler/IML/IMLSegment.cpp
|
||||
HW/Espresso/Recompiler/IML/IMLSegment.h
|
||||
|
||||
@@ -72,6 +72,10 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if __ANDROID__
|
||||
#include <android/api-level.h>
|
||||
#endif
|
||||
|
||||
std::string _pathToExecutable;
|
||||
std::string _pathToBaseExecutable;
|
||||
|
||||
@@ -518,8 +522,9 @@ namespace CafeSystem
|
||||
{
|
||||
std::string buffer;
|
||||
const char* platform = NULL;
|
||||
#if __ANDROID__
|
||||
platform = "Android";
|
||||
#if __ANDROID__
|
||||
buffer = fmt::format("Android (API level {})", android_get_device_api_level());;
|
||||
platform = buffer.c_str();
|
||||
#elif BOOST_OS_WINDOWS
|
||||
uint32 buildNumber;
|
||||
std::string windowsVersionName = GetWindowsNamedVersion(buildNumber);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
void runRecompilerTests();
|
||||
@@ -333,8 +333,22 @@ inline uint64 _udiv128(uint64 highDividend, uint64 lowDividend, uint64 divisor,
|
||||
|
||||
// On aarch64 we handle some of the x86 intrinsics by implementing them as wrappers
|
||||
#if defined(__aarch64__)
|
||||
inline void _mm_pause(void)
|
||||
{
|
||||
asm volatile("isb");
|
||||
}
|
||||
|
||||
#include "sse2neon.h";
|
||||
inline uint64 __rdtsc()
|
||||
{
|
||||
uint64 t;
|
||||
asm volatile("mrs %0, cntvct_el0" : "=r" (t));
|
||||
return t;
|
||||
}
|
||||
|
||||
inline void _mm_mfence()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline unsigned char _addcarry_u64(unsigned char carry, unsigned long long a, unsigned long long b, unsigned long long *result)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,8 @@ import android.provider.DocumentsContract
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
@@ -25,25 +27,23 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import info.cemu.cemu.about.AboutCemuActivity
|
||||
import info.cemu.cemu.about.AboutCemuRoute
|
||||
import info.cemu.cemu.about.aboutCemuNavigation
|
||||
import info.cemu.cemu.emulation.EmulationActivity
|
||||
import info.cemu.cemu.features.DocumentsProvider
|
||||
import info.cemu.cemu.gamelist.GameDetailsScreen
|
||||
import info.cemu.cemu.gamelist.GameProfileEditScreen
|
||||
import info.cemu.cemu.gamelist.GameViewModel
|
||||
import info.cemu.cemu.gamelist.GamesListScreen
|
||||
import info.cemu.cemu.gamelist.GamesListScreenActions
|
||||
import info.cemu.cemu.graphicpacks.GraphicPacksActivity
|
||||
import info.cemu.cemu.guicore.ActivityContent
|
||||
import info.cemu.cemu.gamelist.GameListRoute
|
||||
import info.cemu.cemu.gamelist.gameListNavigation
|
||||
import info.cemu.cemu.graphicpacks.GraphicPacksRoute
|
||||
import info.cemu.cemu.graphicpacks.graphicPacksNavigation
|
||||
import info.cemu.cemu.guicore.components.ActivityContent
|
||||
import info.cemu.cemu.nativeinterface.NativeGameTitles.Game
|
||||
import info.cemu.cemu.nativeinterface.NativeSettings
|
||||
import info.cemu.cemu.settings.SettingsActivity
|
||||
import info.cemu.cemu.titlemanager.TitleManagerActivity
|
||||
import kotlinx.serialization.Serializable
|
||||
import info.cemu.cemu.settings.SettingsRoute
|
||||
import info.cemu.cemu.settings.settingsNavigation
|
||||
import info.cemu.cemu.titlemanager.TitleManagerRoute
|
||||
import info.cemu.cemu.titlemanager.titleManagerNavigation
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -62,135 +62,98 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun startGame(context: Context, game: Game) {
|
||||
context.startActivity(
|
||||
Intent(
|
||||
context,
|
||||
EmulationActivity::class.java
|
||||
).apply {
|
||||
putExtra(EmulationActivity.EXTRA_LAUNCH_PATH, game.path)
|
||||
}
|
||||
)
|
||||
Intent(
|
||||
context,
|
||||
EmulationActivity::class.java
|
||||
).apply {
|
||||
putExtra(EmulationActivity.EXTRA_LAUNCH_PATH, game.path)
|
||||
context.startActivity(this)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MainRoutes {
|
||||
@Serializable
|
||||
object GamesRoute
|
||||
|
||||
@Serializable
|
||||
object GameDetailsRoute
|
||||
|
||||
@Serializable
|
||||
object GameProfileEditRoute
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun MainNav() {
|
||||
private fun MainNav() {
|
||||
val navController = rememberNavController()
|
||||
val selectedGameViewModel: GameViewModel = viewModel()
|
||||
fun navigateBack() {
|
||||
navController.popBackStack()
|
||||
}
|
||||
NavHost(navController = navController, startDestination = MainRoutes.GamesRoute) {
|
||||
composable<MainRoutes.GamesRoute> {
|
||||
val context = LocalContext.current
|
||||
GamesListScreen(
|
||||
selectedGameViewModel = selectedGameViewModel,
|
||||
gameListActions = GamesListScreenActions(
|
||||
goToGameEditProfile = { navController.navigate(MainRoutes.GameProfileEditRoute) },
|
||||
startGame = { startGame(context, it) },
|
||||
goToGameDetails = { navController.navigate(MainRoutes.GameDetailsRoute) },
|
||||
),
|
||||
toolbarActions = {
|
||||
GameListToolBarActions()
|
||||
}
|
||||
)
|
||||
}
|
||||
composable<MainRoutes.GameDetailsRoute> {
|
||||
GameDetailsScreen(
|
||||
selectedGameViewModel = selectedGameViewModel,
|
||||
navigateBack = ::navigateBack,
|
||||
)
|
||||
}
|
||||
composable<MainRoutes.GameProfileEditRoute> {
|
||||
GameProfileEditScreen(
|
||||
selectedGameViewModel = selectedGameViewModel,
|
||||
navigateBack = ::navigateBack,
|
||||
val context = LocalContext.current
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = GameListRoute,
|
||||
enterTransition = { EnterTransition.None },
|
||||
exitTransition = { ExitTransition.None }
|
||||
) {
|
||||
gameListNavigation(navController, startGame = { startGame(context, it) }) {
|
||||
GameListToolBarActionsMenu(
|
||||
goToSettings = { navController.navigate(SettingsRoute) },
|
||||
goToTitleManager = { navController.navigate(TitleManagerRoute) },
|
||||
goToGraphicPacks = { navController.navigate(GraphicPacksRoute) },
|
||||
goToAboutCemu = { navController.navigate(AboutCemuRoute) }
|
||||
)
|
||||
}
|
||||
settingsNavigation(navController)
|
||||
titleManagerNavigation(navController)
|
||||
graphicPacksNavigation(navController)
|
||||
aboutCemuNavigation(navController)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GameListToolBarActions() {
|
||||
private fun GameListToolBarActionsMenu(
|
||||
goToSettings: () -> Unit,
|
||||
goToTitleManager: () -> Unit,
|
||||
goToGraphicPacks: () -> Unit,
|
||||
goToAboutCemu: () -> Unit,
|
||||
) {
|
||||
var expandMenu by remember { mutableStateOf(false) }
|
||||
val context = LocalContext.current
|
||||
|
||||
@Composable
|
||||
fun DropdownMenuItem(onClick: () -> Unit, text: String) {
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onClick()
|
||||
expandMenu = false
|
||||
},
|
||||
text = { Text(text) },
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
onClick = { expandMenu = true },
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { expandMenu = true }
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.MoreVert,
|
||||
contentDescription = "More options"
|
||||
)
|
||||
|
||||
}
|
||||
Icon(
|
||||
imageVector = Icons.Filled.MoreVert,
|
||||
contentDescription = "More options"
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = expandMenu,
|
||||
onDismissRequest = { expandMenu = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
context.goToActivity(SettingsActivity::class.java)
|
||||
expandMenu = false
|
||||
},
|
||||
text = { Text(stringResource(R.string.settings)) },
|
||||
onClick = goToSettings,
|
||||
text = stringResource(R.string.settings)
|
||||
)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
context.goToActivity(GraphicPacksActivity::class.java)
|
||||
expandMenu = false
|
||||
},
|
||||
text = { Text(stringResource(R.string.graphic_packs)) },
|
||||
onClick = goToGraphicPacks,
|
||||
text = stringResource(R.string.graphic_packs)
|
||||
)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
context.goToActivity(TitleManagerActivity::class.java)
|
||||
expandMenu = false
|
||||
},
|
||||
text = { Text(stringResource(R.string.title_manager)) },
|
||||
onClick = goToTitleManager,
|
||||
text = stringResource(R.string.title_manager)
|
||||
)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
openCemuFolder(context)
|
||||
expandMenu = false
|
||||
},
|
||||
text = { Text(stringResource(R.string.open_cemu_folder)) },
|
||||
onClick = { openCemuFolder(context) },
|
||||
text = stringResource(R.string.open_cemu_folder)
|
||||
)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
context.goToActivity(AboutCemuActivity::class.java)
|
||||
expandMenu = false
|
||||
},
|
||||
text = { Text(stringResource(R.string.about_cemu)) },
|
||||
onClick = goToAboutCemu,
|
||||
text = stringResource(R.string.about_cemu),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : ComponentActivity> Context.goToActivity(activityClass: Class<T>) {
|
||||
startActivity(
|
||||
Intent(
|
||||
this,
|
||||
activityClass,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun openCemuFolder(context: Context) {
|
||||
private fun openCemuFolder(context: Context) {
|
||||
try {
|
||||
Intent(Intent.ACTION_VIEW).apply {
|
||||
addCategory(Intent.CATEGORY_DEFAULT)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package info.cemu.cemu.about
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import info.cemu.cemu.guicore.ActivityContent
|
||||
|
||||
|
||||
class AboutCemuActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
ActivityContent {
|
||||
AboutCemuScreen(::onNavigateUp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package info.cemu.cemu.about
|
||||
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.composable
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
object AboutCemuRoute
|
||||
|
||||
fun NavGraphBuilder.aboutCemuNavigation(navController: NavHostController) {
|
||||
composable<AboutCemuRoute> {
|
||||
AboutCemuScreen { navController.popBackStack() }
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import info.cemu.cemu.BuildConfig
|
||||
import info.cemu.cemu.R
|
||||
import info.cemu.cemu.guicore.ScreenContent
|
||||
import info.cemu.cemu.guicore.components.ScreenContent
|
||||
|
||||
@Composable
|
||||
fun AboutCemuScreen(navigateBack: () -> Unit) {
|
||||
|
||||
@@ -7,32 +7,31 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import info.cemu.cemu.R
|
||||
import info.cemu.cemu.guicore.ScreenContent
|
||||
import info.cemu.cemu.guicore.enumtostringmapper.native.regionToStringId
|
||||
import info.cemu.cemu.guicore.components.ScreenContent
|
||||
import info.cemu.cemu.guicore.nativeenummapper.regionToStringId
|
||||
import info.cemu.cemu.nativeinterface.NativeGameTitles.Game
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
@Composable
|
||||
fun GameDetailsScreen(selectedGameViewModel: GameViewModel, navigateBack: () -> Unit) {
|
||||
val game by selectedGameViewModel.game.collectAsState()
|
||||
if (game == null) return
|
||||
fun GameDetailsScreen(game: Game?, navigateBack: () -> Unit) {
|
||||
if (game == null)
|
||||
return
|
||||
|
||||
ScreenContent(
|
||||
appBarText = stringResource(R.string.about_title),
|
||||
contentModifier = Modifier.padding(16.dp),
|
||||
contentVerticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
navigateBack = navigateBack,
|
||||
) {
|
||||
GameDetails(game!!)
|
||||
GameDetails(game)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package info.cemu.cemu.gamelist
|
||||
|
||||
import androidx.compose.animation.AnimatedContentScope
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.navigation
|
||||
import info.cemu.cemu.nativeinterface.NativeGameTitles
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
object GameListRoute
|
||||
|
||||
private object GameListRoutes {
|
||||
@Serializable
|
||||
object GamesRoute
|
||||
|
||||
@Serializable
|
||||
object GameDetailsRoute
|
||||
|
||||
@Serializable
|
||||
object GameProfileEditRoute
|
||||
}
|
||||
|
||||
private inline fun <reified T : Any> NavGraphBuilder.composableGameScreen(
|
||||
navController: NavController,
|
||||
noinline content: @Composable (AnimatedContentScope.(NativeGameTitles.Game) -> Unit),
|
||||
) {
|
||||
composable<T> {
|
||||
val previousBackStackEntry =
|
||||
navController.previousBackStackEntry ?: return@composable
|
||||
val game =
|
||||
viewModel<GameViewModel>(previousBackStackEntry).game ?: return@composable
|
||||
content(game)
|
||||
}
|
||||
}
|
||||
|
||||
fun NavGraphBuilder.gameListNavigation(
|
||||
navController: NavHostController,
|
||||
startGame: (NativeGameTitles.Game) -> Unit,
|
||||
gameListToolBarActions: @Composable (RowScope.() -> Unit),
|
||||
) {
|
||||
navigation<GameListRoute>(startDestination = GameListRoutes.GamesRoute) {
|
||||
composable<GameListRoutes.GamesRoute> { backStackEntry ->
|
||||
val gameViewModel: GameViewModel = viewModel(backStackEntry)
|
||||
GamesListScreen(
|
||||
startGame = startGame,
|
||||
goToGameEditProfile = { game ->
|
||||
gameViewModel.game = game
|
||||
navController.navigate(GameListRoutes.GameProfileEditRoute)
|
||||
},
|
||||
goToGameDetails = { game ->
|
||||
gameViewModel.game = game
|
||||
navController.navigate(GameListRoutes.GameDetailsRoute)
|
||||
},
|
||||
toolbarActions = gameListToolBarActions
|
||||
)
|
||||
}
|
||||
composableGameScreen<GameListRoutes.GameDetailsRoute>(navController) { game ->
|
||||
GameDetailsScreen(
|
||||
game = game,
|
||||
navigateBack = { navController.popBackStack() },
|
||||
)
|
||||
}
|
||||
composableGameScreen<GameListRoutes.GameProfileEditRoute>(navController) { game ->
|
||||
GameProfileEditScreen(
|
||||
game = game,
|
||||
navigateBack = { navController.popBackStack() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,15 @@ import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
class GameListViewModel : ViewModel() {
|
||||
private var gamePaths = NativeSettings.getGamesPaths().toSet()
|
||||
|
||||
private val _filterText = MutableStateFlow("")
|
||||
private val filterText = _filterText.asStateFlow()
|
||||
val filterText = _filterText.asStateFlow()
|
||||
fun setFilterText(filterText: String) {
|
||||
_filterText.value = filterText
|
||||
}
|
||||
|
||||
private val _games = MutableStateFlow<Set<Game>>(emptySet())
|
||||
val games: StateFlow<List<Game>> = filterText.combine(_games) { filter, games ->
|
||||
val games: StateFlow<List<Game>> = combine(_filterText, _games) { filter, games ->
|
||||
if (filter.isBlank()) {
|
||||
games
|
||||
} else {
|
||||
@@ -49,20 +50,8 @@ class GameListViewModel : ViewModel() {
|
||||
refreshGames()
|
||||
}
|
||||
|
||||
private val _gameToRemoveShaders = MutableStateFlow<Game?>(null)
|
||||
val gameToRemoveShaders = _gameToRemoveShaders.asStateFlow()
|
||||
fun removeShadersForSelectedGame() {
|
||||
if (_gameToRemoveShaders.value == null) return
|
||||
NativeGameTitles.removeShaderCacheFilesForTitle(_gameToRemoveShaders.value!!.titleId)
|
||||
_gameToRemoveShaders.value = null
|
||||
}
|
||||
|
||||
fun setGameForShadersRemoval(game: Game) {
|
||||
_gameToRemoveShaders.value = game
|
||||
}
|
||||
|
||||
fun clearSelectedGameForShaderRemoval() {
|
||||
_gameToRemoveShaders.value = null
|
||||
fun removeShadersForGame(game: Game) {
|
||||
NativeGameTitles.removeShaderCacheFilesForTitle(game.titleId)
|
||||
}
|
||||
|
||||
fun setGameTitleFavorite(game: Game, isFavorite: Boolean) {
|
||||
|
||||
@@ -6,18 +6,19 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import info.cemu.cemu.R
|
||||
import info.cemu.cemu.guicore.Header
|
||||
import info.cemu.cemu.guicore.ScreenContent
|
||||
import info.cemu.cemu.guicore.SingleSelection
|
||||
import info.cemu.cemu.guicore.Toggle
|
||||
import info.cemu.cemu.guicore.enumtostringmapper.native.cpuModeToStringId
|
||||
import info.cemu.cemu.guicore.components.Header
|
||||
import info.cemu.cemu.guicore.components.ScreenContent
|
||||
import info.cemu.cemu.guicore.components.SingleSelection
|
||||
import info.cemu.cemu.guicore.components.Toggle
|
||||
import info.cemu.cemu.guicore.nativeenummapper.cpuModeToStringId
|
||||
import info.cemu.cemu.nativeinterface.NativeGameTitles
|
||||
|
||||
@Composable
|
||||
fun GameProfileEditScreen(selectedGameViewModel: GameViewModel, navigateBack: () -> Unit) {
|
||||
val game = selectedGameViewModel.game.collectAsStateWithLifecycle().value ?: return
|
||||
fun GameProfileEditScreen(game: NativeGameTitles.Game?, navigateBack: () -> Unit) {
|
||||
if (game == null)
|
||||
return
|
||||
|
||||
val titleId = game.titleId
|
||||
ScreenContent(
|
||||
appBarText = stringResource(R.string.edit_game_profile),
|
||||
|
||||
@@ -2,14 +2,5 @@ package info.cemu.cemu.gamelist
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import info.cemu.cemu.nativeinterface.NativeGameTitles.Game
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class GameViewModel : ViewModel() {
|
||||
private val _game = MutableStateFlow<Game?>(null)
|
||||
val game = _game.asStateFlow()
|
||||
|
||||
fun setCurrentGame(game: Game?) {
|
||||
_game.value = game
|
||||
}
|
||||
}
|
||||
class GameViewModel(var game: Game? = null) : ViewModel()
|
||||
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
@@ -63,24 +64,19 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import info.cemu.cemu.R
|
||||
import info.cemu.cemu.emulation.EmulationActivity
|
||||
import info.cemu.cemu.guicore.FilledSearchToolbar
|
||||
import info.cemu.cemu.guicore.components.FilledSearchToolbar
|
||||
import info.cemu.cemu.nativeinterface.NativeGameTitles
|
||||
import info.cemu.cemu.nativeinterface.NativeGameTitles.Game
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import android.graphics.drawable.Icon as ShortcutIcon
|
||||
|
||||
data class GamesListScreenActions(
|
||||
val goToGameDetails: () -> Unit,
|
||||
val goToGameEditProfile: () -> Unit,
|
||||
val startGame: (Game) -> Unit,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun GamesListScreen(
|
||||
selectedGameViewModel: GameViewModel,
|
||||
gameListViewModel: GameListViewModel = viewModel(),
|
||||
gameListActions: GamesListScreenActions,
|
||||
goToGameDetails: (Game) -> Unit,
|
||||
goToGameEditProfile: (Game) -> Unit,
|
||||
startGame: (Game) -> Unit,
|
||||
toolbarActions: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
@@ -88,8 +84,9 @@ fun GamesListScreen(
|
||||
val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
var refreshing by remember { mutableStateOf(false) }
|
||||
val gameToRemoveShaders by gameListViewModel.gameToRemoveShaders.collectAsStateWithLifecycle()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val gameSearchQuery by gameListViewModel.filterText.collectAsStateWithLifecycle()
|
||||
val games by gameListViewModel.games.collectAsStateWithLifecycle()
|
||||
|
||||
val state = rememberPullToRefreshState()
|
||||
|
||||
@@ -109,6 +106,7 @@ fun GamesListScreen(
|
||||
FilledSearchToolbar(
|
||||
actions = toolbarActions,
|
||||
hint = stringResource(R.string.search_games),
|
||||
query = gameSearchQuery,
|
||||
onValueChange = gameListViewModel::setFilterText
|
||||
)
|
||||
},
|
||||
@@ -131,12 +129,26 @@ fun GamesListScreen(
|
||||
),
|
||||
) {
|
||||
GameList(
|
||||
gameListViewModel = gameListViewModel,
|
||||
selectedGameViewModel = selectedGameViewModel,
|
||||
actions = gameListActions,
|
||||
onFailedToCreateShortCut = {
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(context.getString(R.string.shortcut_not_supported)) }
|
||||
}
|
||||
games = games,
|
||||
setFavorite = gameListViewModel::setGameTitleFavorite,
|
||||
deleteShaderCaches = {
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(context.getString(R.string.shader_caches_removed_notification)) }
|
||||
gameListViewModel.removeShadersForGame(it)
|
||||
},
|
||||
startGame = startGame,
|
||||
goToGameDetails = goToGameDetails,
|
||||
goToGameEditProfile = goToGameEditProfile,
|
||||
createShortcut = { game ->
|
||||
createShortcutForGame(
|
||||
context,
|
||||
game,
|
||||
onFailedToCreateShortCut = {
|
||||
val errorMessage =
|
||||
context.getString(R.string.shortcut_not_supported)
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(errorMessage) }
|
||||
}
|
||||
)
|
||||
},
|
||||
)
|
||||
PullToRefreshDefaults.Indicator(
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
@@ -147,29 +159,18 @@ fun GamesListScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (gameToRemoveShaders != null) {
|
||||
ShaderCachesConfirmationDialog(
|
||||
gameName = gameToRemoveShaders?.name ?: "",
|
||||
onDismissRequest = gameListViewModel::clearSelectedGameForShaderRemoval,
|
||||
onConfirm = {
|
||||
gameListViewModel.removeShadersForSelectedGame()
|
||||
coroutineScope.launch { snackbarHostState.showSnackbar(context.getString(R.string.shader_caches_removed_notification)) }
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun GameList(
|
||||
gameListViewModel: GameListViewModel,
|
||||
selectedGameViewModel: GameViewModel,
|
||||
actions: GamesListScreenActions,
|
||||
onFailedToCreateShortCut: () -> Unit,
|
||||
private fun GameList(
|
||||
games: List<Game>,
|
||||
startGame: (Game) -> Unit,
|
||||
goToGameDetails: (Game) -> Unit,
|
||||
goToGameEditProfile: (Game) -> Unit,
|
||||
setFavorite: (Game, Boolean) -> Unit,
|
||||
createShortcut: (Game) -> Unit,
|
||||
deleteShaderCaches: (Game) -> Unit,
|
||||
) {
|
||||
val games by gameListViewModel.games.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
LazyVerticalGrid(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
@@ -177,34 +178,39 @@ fun GameList(
|
||||
columns = GridCells.Adaptive(620.dp)
|
||||
) {
|
||||
items(items = games, key = { it.titleId }) { game ->
|
||||
var showDeleteShaderConfirmationDialog by remember { mutableStateOf(false) }
|
||||
GameListItem(
|
||||
modifier = Modifier.animateItem(),
|
||||
game = game,
|
||||
onStartGame = actions.startGame,
|
||||
actions = GameContextMenuActions(
|
||||
onIsFavoriteChanged = { isFavorite ->
|
||||
gameListViewModel.setGameTitleFavorite(game, isFavorite)
|
||||
},
|
||||
onEditGameProfile = {
|
||||
selectedGameViewModel.setCurrentGame(game)
|
||||
actions.goToGameEditProfile()
|
||||
},
|
||||
onRemoveShaderCaches = { gameListViewModel.setGameForShadersRemoval(game) },
|
||||
onAboutTitle = {
|
||||
selectedGameViewModel.setCurrentGame(game)
|
||||
actions.goToGameDetails()
|
||||
},
|
||||
onCreateShortcut = {
|
||||
createShortcutForGame(
|
||||
context = context,
|
||||
game = game,
|
||||
onFailedToCreateShortCut = onFailedToCreateShortCut
|
||||
)
|
||||
},
|
||||
),
|
||||
onStartGame = startGame,
|
||||
onIsFavoriteChanged = { isFavorite ->
|
||||
setFavorite(game, isFavorite)
|
||||
},
|
||||
onEditGameProfile = {
|
||||
goToGameEditProfile(game)
|
||||
},
|
||||
onRemoveShaderCaches = { showDeleteShaderConfirmationDialog = true },
|
||||
onAboutTitle = {
|
||||
goToGameDetails(game)
|
||||
},
|
||||
onCreateShortcut = {
|
||||
createShortcut(game)
|
||||
},
|
||||
)
|
||||
|
||||
if (showDeleteShaderConfirmationDialog)
|
||||
ShaderCachesConfirmationDialog(
|
||||
gameName = game.name ?: "",
|
||||
onDismissRequest = { showDeleteShaderConfirmationDialog = false },
|
||||
onConfirm = {
|
||||
deleteShaderCaches(game)
|
||||
showDeleteShaderConfirmationDialog = false
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -240,8 +246,12 @@ fun ShaderCachesConfirmationDialog(
|
||||
|
||||
@Composable
|
||||
fun GameListItem(
|
||||
actions: GameContextMenuActions,
|
||||
onStartGame: (Game) -> Unit,
|
||||
onIsFavoriteChanged: (Boolean) -> Unit,
|
||||
onEditGameProfile: () -> Unit,
|
||||
onRemoveShaderCaches: () -> Unit,
|
||||
onAboutTitle: () -> Unit,
|
||||
onCreateShortcut: () -> Unit,
|
||||
game: Game,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -269,7 +279,7 @@ fun GameListItem(
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(2.dp)
|
||||
.size(24.dp)
|
||||
.clip(androidx.compose.foundation.shape.CircleShape)
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||
painter = painterResource(R.drawable.ic_favorite),
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
@@ -287,25 +297,25 @@ fun GameListItem(
|
||||
GameContextMenu(
|
||||
expanded = contextMenuExpanded,
|
||||
onDismissRequest = { contextMenuExpanded = false },
|
||||
actions = actions,
|
||||
game = game,
|
||||
onIsFavoriteChanged = onIsFavoriteChanged,
|
||||
onEditGameProfile = onEditGameProfile,
|
||||
onRemoveShaderCaches = onRemoveShaderCaches,
|
||||
onAboutTitle = onAboutTitle,
|
||||
onCreateShortcut = onCreateShortcut,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class GameContextMenuActions(
|
||||
val onIsFavoriteChanged: (Boolean) -> Unit,
|
||||
val onEditGameProfile: () -> Unit,
|
||||
val onRemoveShaderCaches: () -> Unit,
|
||||
val onAboutTitle: () -> Unit,
|
||||
val onCreateShortcut: () -> Unit,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun GameContextMenu(
|
||||
expanded: Boolean,
|
||||
onDismissRequest: () -> Unit,
|
||||
actions: GameContextMenuActions,
|
||||
onIsFavoriteChanged: (Boolean) -> Unit,
|
||||
onEditGameProfile: () -> Unit,
|
||||
onRemoveShaderCaches: () -> Unit,
|
||||
onAboutTitle: () -> Unit,
|
||||
onCreateShortcut: () -> Unit,
|
||||
game: Game,
|
||||
) {
|
||||
@Composable
|
||||
@@ -335,29 +345,29 @@ fun GameContextMenu(
|
||||
NativeGameTitles.titleHasShaderCacheFiles(game.titleId)
|
||||
}
|
||||
GameContextMenuItem(
|
||||
onClick = { actions.onIsFavoriteChanged(!game.isFavorite) },
|
||||
onClick = { onIsFavoriteChanged(!game.isFavorite) },
|
||||
text = stringResource(R.string.game_favorite),
|
||||
trailingIcon = {
|
||||
Checkbox(checked = game.isFavorite, onCheckedChange = null)
|
||||
}
|
||||
)
|
||||
GameContextMenuItem(
|
||||
onClick = actions.onEditGameProfile,
|
||||
onClick = onEditGameProfile,
|
||||
text = stringResource(R.string.edit_game_profile)
|
||||
)
|
||||
GameContextMenuItem(
|
||||
enabled = gameTitleHasCaches,
|
||||
onClick = {
|
||||
actions.onRemoveShaderCaches()
|
||||
onRemoveShaderCaches()
|
||||
},
|
||||
text = stringResource(R.string.remove_shader_caches)
|
||||
)
|
||||
GameContextMenuItem(
|
||||
onClick = actions.onAboutTitle,
|
||||
onClick = onAboutTitle,
|
||||
text = stringResource(R.string.about_title),
|
||||
)
|
||||
GameContextMenuItem(
|
||||
onClick = actions.onCreateShortcut,
|
||||
onClick = onCreateShortcut,
|
||||
text = stringResource(R.string.create_shortcut)
|
||||
)
|
||||
}
|
||||
|
||||
+17
-57
@@ -1,41 +1,21 @@
|
||||
package info.cemu.cemu.graphicpacks
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.animation.AnimatedContentScope
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.lifecycle.viewmodel.MutableCreationExtras
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import info.cemu.cemu.guicore.ActivityContent
|
||||
import info.cemu.cemu.nativeinterface.NativeSettings
|
||||
import androidx.navigation.compose.navigation
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
class GraphicPacksActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
ActivityContent {
|
||||
GraphicPacksNav(parentNavBack = ::onNavigateUp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@Serializable
|
||||
object GraphicPacksRoute
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
NativeSettings.saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
object GraphicPackRoutes {
|
||||
private object GraphicPackRoutes {
|
||||
@Serializable
|
||||
object GraphicPacksRootSectionRoute
|
||||
|
||||
@@ -62,42 +42,22 @@ private inline fun <reified T : Any, reified U : GraphicPackNode> NavGraphBuilde
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GraphicPacksNav(
|
||||
parentNavBack: () -> Unit,
|
||||
) {
|
||||
val navController = rememberNavController()
|
||||
|
||||
fun navigateBack() {
|
||||
if (!navController.popBackStack()) {
|
||||
parentNavBack()
|
||||
}
|
||||
private fun graphicPacksNavigate(navController: NavController, graphicPackNode: GraphicPackNode) {
|
||||
when (graphicPackNode) {
|
||||
is GraphicPackSectionNode -> navController.navigate(GraphicPackRoutes.GraphicPackSectionScreenRoute)
|
||||
is GraphicPackDataNode -> navController.navigate(GraphicPackRoutes.GraphicPackDataScreenRoute)
|
||||
}
|
||||
}
|
||||
|
||||
fun graphicPacksNavigate(graphicPackNode: GraphicPackNode) {
|
||||
when (graphicPackNode) {
|
||||
is GraphicPackSectionNode -> navController.navigate(GraphicPackRoutes.GraphicPackSectionScreenRoute)
|
||||
is GraphicPackDataNode -> navController.navigate(GraphicPackRoutes.GraphicPackDataScreenRoute)
|
||||
}
|
||||
}
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = GraphicPackRoutes.GraphicPacksRootSectionRoute,
|
||||
enterTransition = {
|
||||
EnterTransition.None
|
||||
},
|
||||
exitTransition = {
|
||||
ExitTransition.None
|
||||
}
|
||||
) {
|
||||
fun NavGraphBuilder.graphicPacksNavigation(navController: NavHostController) {
|
||||
navigation<GraphicPacksRoute>(startDestination = GraphicPackRoutes.GraphicPacksRootSectionRoute) {
|
||||
composable<GraphicPackRoutes.GraphicPacksRootSectionRoute> { backStackEntry ->
|
||||
val graphicPackViewModel: GraphicPackViewModel = viewModel(backStackEntry)
|
||||
GraphicPacksRootSectionScreen(
|
||||
navigateBack = ::navigateBack,
|
||||
navigateBack = { navController.popBackStack() },
|
||||
graphicPackNodeNavigate = {
|
||||
graphicPackViewModel.graphicPackNode = it
|
||||
graphicPacksNavigate(it)
|
||||
graphicPacksNavigate(navController, it)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -106,10 +66,10 @@ fun GraphicPacksNav(
|
||||
) { backStackEntry, graphicPackNode ->
|
||||
val graphicPacksViewModel: GraphicPackViewModel = viewModel(backStackEntry)
|
||||
GraphicPacksSectionScreen(
|
||||
navigateBack = ::navigateBack,
|
||||
navigateBack = { navController.popBackStack() },
|
||||
graphicPackNodeNavigate = {
|
||||
graphicPacksViewModel.graphicPackNode = it
|
||||
graphicPacksNavigate(it)
|
||||
graphicPacksNavigate(navController, it)
|
||||
},
|
||||
graphicPackSectionNode = graphicPackNode,
|
||||
)
|
||||
@@ -125,7 +85,7 @@ fun GraphicPacksNav(
|
||||
}
|
||||
)
|
||||
GraphicPackDataScreen(
|
||||
navigateBack = ::navigateBack,
|
||||
navigateBack = { navController.popBackStack() },
|
||||
graphicPackDataViewModel = graphicPackDataViewModel,
|
||||
)
|
||||
}
|
||||
@@ -58,10 +58,10 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.dropUnlessResumed
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import info.cemu.cemu.R
|
||||
import info.cemu.cemu.guicore.DefaultAppBarTitle
|
||||
import info.cemu.cemu.guicore.ScreenContentLazy
|
||||
import info.cemu.cemu.guicore.SearchToolbarInput
|
||||
import info.cemu.cemu.guicore.SingleSelection
|
||||
import info.cemu.cemu.guicore.components.DefaultAppBarTitle
|
||||
import info.cemu.cemu.guicore.components.ScreenContentLazy
|
||||
import info.cemu.cemu.guicore.components.SearchToolbarInput
|
||||
import info.cemu.cemu.guicore.components.SingleSelection
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package info.cemu.cemu.guicore
|
||||
package info.cemu.cemu.guicore.components
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package info.cemu.cemu.guicore
|
||||
package info.cemu.cemu.guicore.components
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user