From 8888edde5cce01bf23c9d8254550523f15c158ce Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Wed, 8 May 2024 15:20:31 +0000 Subject: [PATCH] improve homeview extra options update gradle deps cleanup search bar --- src/RyujinxAndroid/app/build.gradle | 34 +- .../main/java/org/ryujinx/android/Icons.kt | 194 ++++++++++ .../java/org/ryujinx/android/MainActivity.kt | 5 +- .../org/ryujinx/android/views/GameViews.kt | 4 +- .../org/ryujinx/android/views/HomeViews.kt | 361 +++++++++++++----- src/RyujinxAndroid/build.gradle | 2 +- 6 files changed, 472 insertions(+), 128 deletions(-) diff --git a/src/RyujinxAndroid/app/build.gradle b/src/RyujinxAndroid/app/build.gradle index 121823144..1c461ac47 100644 --- a/src/RyujinxAndroid/app/build.gradle +++ b/src/RyujinxAndroid/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "org.ryujinx.android" minSdk 30 targetSdk 34 - versionCode 10026 - versionName '1.0.26t' + versionCode 10030 + versionName '1.0.30t' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -52,7 +52,7 @@ android { buildConfig true } composeOptions { - kotlinCompilerExtensionVersion '1.5.2' + kotlinCompilerExtensionVersion '1.5.13' } packagingOptions { jniLibs { @@ -77,18 +77,18 @@ tasks.named("preBuild") { dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' - implementation 'com.google.android.material:material:1.11.0' - implementation platform('androidx.compose:compose-bom:2023.03.00') - implementation platform('androidx.compose:compose-bom:2023.03.00') - androidTestImplementation platform('androidx.compose:compose-bom:2023.03.00') - androidTestImplementation platform('androidx.compose:compose-bom:2023.03.00') + implementation 'com.google.android.material:material:1.12.0' + implementation platform('androidx.compose:compose-bom:2024.05.00') + implementation platform('androidx.compose:compose-bom:2024.05.00') + androidTestImplementation platform('androidx.compose:compose-bom:2024.05.00') + androidTestImplementation platform('androidx.compose:compose-bom:2024.05.00') runtimeOnly project(":libryujinx") - implementation 'androidx.core:core-ktx:1.12.0' - implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0') + implementation 'androidx.core:core-ktx:1.13.1' + implementation platform('org.jetbrains.kotlin:kotlin-bom:1.9.24') implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0' - implementation "androidx.navigation:navigation-compose:2.7.6" - implementation 'androidx.activity:activity-compose:1.8.2' - implementation platform('androidx.compose:compose-bom:2023.06.00') + implementation "androidx.navigation:navigation-compose:2.7.7" + implementation 'androidx.activity:activity-compose:1.9.0' + implementation platform('androidx.compose:compose-bom:2024.05.00') implementation 'androidx.compose.ui:ui' implementation 'androidx.compose.ui:ui-graphics' implementation 'androidx.compose.ui:ui-tooling-preview' @@ -97,20 +97,20 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation "com.anggrayudi:storage:1.5.5" implementation "androidx.preference:preference-ktx:1.2.1" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.2' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0' implementation 'com.google.code.gson:gson:2.10.1' implementation 'net.lingala.zip4j:zip4j:2.11.5' implementation("br.com.devsrsouza.compose.icons:css-gg:1.1.0") - implementation "io.coil-kt:coil-compose:2.4.0" + implementation 'io.coil-kt:coil-compose:2.6.0' implementation("com.halilibo.compose-richtext:richtext-ui:0.20.0") implementation("com.halilibo.compose-richtext:richtext-commonmark:0.20.0") implementation("com.halilibo.compose-richtext:richtext-ui-material3:0.20.0") testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' - androidTestImplementation platform('androidx.compose:compose-bom:2023.06.00') + androidTestImplementation platform('androidx.compose:compose-bom:2024.05.00') androidTestImplementation 'androidx.compose.ui:ui-test-junit4' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0' debugImplementation 'androidx.compose.ui:ui-tooling' debugImplementation 'androidx.compose.ui:ui-test-manifest' } diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/Icons.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/Icons.kt index b6e2cea6b..8548efca6 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/Icons.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/Icons.kt @@ -23,6 +23,200 @@ class Icons { companion object{ /// Icons exported from https://www.composables.com/icons @Composable + fun listView(color: Color): ImageVector { + return remember { + ImageVector.Builder( + name = "list", + defaultWidth = 40.0.dp, + defaultHeight = 40.0.dp, + viewportWidth = 40.0f, + viewportHeight = 40.0f + ).apply { + path( + fill = SolidColor(color), + fillAlpha = 1f, + stroke = null, + strokeAlpha = 1f, + strokeLineWidth = 1.0f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1f, + pathFillType = PathFillType.NonZero + ) { + moveTo(13.375f, 14.458f) + quadToRelative(-0.583f, 0f, -0.958f, -0.395f) + quadToRelative(-0.375f, -0.396f, -0.375f, -0.938f) + quadToRelative(0f, -0.542f, 0.375f, -0.937f) + quadToRelative(0.375f, -0.396f, 0.958f, -0.396f) + horizontalLineToRelative(20.083f) + quadToRelative(0.584f, 0f, 0.959f, 0.396f) + quadToRelative(0.375f, 0.395f, 0.375f, 0.937f) + reflectiveQuadToRelative(-0.375f, 0.938f) + quadToRelative(-0.375f, 0.395f, -0.959f, 0.395f) + close() + moveToRelative(0f, 6.834f) + quadToRelative(-0.583f, 0f, -0.958f, -0.375f) + reflectiveQuadTo(12.042f, 20f) + quadToRelative(0f, -0.583f, 0.375f, -0.958f) + reflectiveQuadToRelative(0.958f, -0.375f) + horizontalLineToRelative(20.083f) + quadToRelative(0.584f, 0f, 0.959f, 0.395f) + quadToRelative(0.375f, 0.396f, 0.375f, 0.938f) + quadToRelative(0f, 0.542f, -0.375f, 0.917f) + reflectiveQuadToRelative(-0.959f, 0.375f) + close() + moveToRelative(0f, 6.916f) + quadToRelative(-0.583f, 0f, -0.958f, -0.396f) + quadToRelative(-0.375f, -0.395f, -0.375f, -0.937f) + reflectiveQuadToRelative(0.375f, -0.937f) + quadToRelative(0.375f, -0.396f, 0.958f, -0.396f) + horizontalLineToRelative(20.083f) + quadToRelative(0.584f, 0f, 0.959f, 0.396f) + quadToRelative(0.375f, 0.395f, 0.375f, 0.937f) + reflectiveQuadToRelative(-0.375f, 0.937f) + quadToRelative(-0.375f, 0.396f, -0.959f, 0.396f) + close() + moveToRelative(-6.833f, -13.75f) + quadToRelative(-0.584f, 0f, -0.959f, -0.395f) + quadToRelative(-0.375f, -0.396f, -0.375f, -0.938f) + quadToRelative(0f, -0.583f, 0.375f, -0.958f) + reflectiveQuadToRelative(0.959f, -0.375f) + quadToRelative(0.583f, 0f, 0.958f, 0.375f) + reflectiveQuadToRelative(0.375f, 0.958f) + quadToRelative(0f, 0.542f, -0.375f, 0.938f) + quadToRelative(-0.375f, 0.395f, -0.958f, 0.395f) + close() + moveToRelative(0f, 6.875f) + quadToRelative(-0.584f, 0f, -0.959f, -0.375f) + reflectiveQuadTo(5.208f, 20f) + quadToRelative(0f, -0.583f, 0.375f, -0.958f) + reflectiveQuadToRelative(0.959f, -0.375f) + quadToRelative(0.583f, 0f, 0.958f, 0.375f) + reflectiveQuadToRelative(0.375f, 0.958f) + quadToRelative(0f, 0.583f, -0.375f, 0.958f) + reflectiveQuadToRelative(-0.958f, 0.375f) + close() + moveToRelative(0f, 6.875f) + quadToRelative(-0.584f, 0f, -0.959f, -0.375f) + reflectiveQuadToRelative(-0.375f, -0.958f) + quadToRelative(0f, -0.542f, 0.375f, -0.937f) + quadToRelative(0.375f, -0.396f, 0.959f, -0.396f) + quadToRelative(0.583f, 0f, 0.958f, 0.396f) + quadToRelative(0.375f, 0.395f, 0.375f, 0.937f) + quadToRelative(0f, 0.583f, -0.375f, 0.958f) + reflectiveQuadToRelative(-0.958f, 0.375f) + close() + } + }.build() + } + } + + @Composable + fun gridView(color: Color): ImageVector { + return remember { + ImageVector.Builder( + name = "grid_view", + defaultWidth = 40.0.dp, + defaultHeight = 40.0.dp, + viewportWidth = 40.0f, + viewportHeight = 40.0f + ).apply { + path( + fill = SolidColor(color), + fillAlpha = 1f, + stroke = null, + strokeAlpha = 1f, + strokeLineWidth = 1.0f, + strokeLineCap = StrokeCap.Butt, + strokeLineJoin = StrokeJoin.Miter, + strokeLineMiter = 1f, + pathFillType = PathFillType.NonZero + ) { + moveTo(7.875f, 18.667f) + quadToRelative(-1.083f, 0f, -1.854f, -0.771f) + quadToRelative(-0.771f, -0.771f, -0.771f, -1.854f) + verticalLineTo(7.875f) + quadToRelative(0f, -1.083f, 0.771f, -1.854f) + quadToRelative(0.771f, -0.771f, 1.854f, -0.771f) + horizontalLineToRelative(8.167f) + quadToRelative(1.083f, 0f, 1.875f, 0.771f) + quadToRelative(0.791f, 0.771f, 0.791f, 1.854f) + verticalLineToRelative(8.167f) + quadToRelative(0f, 1.083f, -0.791f, 1.854f) + quadToRelative(-0.792f, 0.771f, -1.875f, 0.771f) + close() + moveToRelative(0f, 16.083f) + quadToRelative(-1.083f, 0f, -1.854f, -0.771f) + quadToRelative(-0.771f, -0.771f, -0.771f, -1.854f) + verticalLineToRelative(-8.167f) + quadToRelative(0f, -1.083f, 0.771f, -1.875f) + quadToRelative(0.771f, -0.791f, 1.854f, -0.791f) + horizontalLineToRelative(8.167f) + quadToRelative(1.083f, 0f, 1.875f, 0.791f) + quadToRelative(0.791f, 0.792f, 0.791f, 1.875f) + verticalLineToRelative(8.167f) + quadToRelative(0f, 1.083f, -0.791f, 1.854f) + quadToRelative(-0.792f, 0.771f, -1.875f, 0.771f) + close() + moveToRelative(16.083f, -16.083f) + quadToRelative(-1.083f, 0f, -1.854f, -0.771f) + quadToRelative(-0.771f, -0.771f, -0.771f, -1.854f) + verticalLineTo(7.875f) + quadToRelative(0f, -1.083f, 0.771f, -1.854f) + quadToRelative(0.771f, -0.771f, 1.854f, -0.771f) + horizontalLineToRelative(8.167f) + quadToRelative(1.083f, 0f, 1.854f, 0.771f) + quadToRelative(0.771f, 0.771f, 0.771f, 1.854f) + verticalLineToRelative(8.167f) + quadToRelative(0f, 1.083f, -0.771f, 1.854f) + quadToRelative(-0.771f, 0.771f, -1.854f, 0.771f) + close() + moveToRelative(0f, 16.083f) + quadToRelative(-1.083f, 0f, -1.854f, -0.771f) + quadToRelative(-0.771f, -0.771f, -0.771f, -1.854f) + verticalLineToRelative(-8.167f) + quadToRelative(0f, -1.083f, 0.771f, -1.875f) + quadToRelative(0.771f, -0.791f, 1.854f, -0.791f) + horizontalLineToRelative(8.167f) + quadToRelative(1.083f, 0f, 1.854f, 0.791f) + quadToRelative(0.771f, 0.792f, 0.771f, 1.875f) + verticalLineToRelative(8.167f) + quadToRelative(0f, 1.083f, -0.771f, 1.854f) + quadToRelative(-0.771f, 0.771f, -1.854f, 0.771f) + close() + moveTo(7.875f, 16.042f) + horizontalLineToRelative(8.167f) + verticalLineTo(7.875f) + horizontalLineTo(7.875f) + close() + moveToRelative(16.083f, 0f) + horizontalLineToRelative(8.167f) + verticalLineTo(7.875f) + horizontalLineToRelative(-8.167f) + close() + moveToRelative(0f, 16.083f) + horizontalLineToRelative(8.167f) + verticalLineToRelative(-8.167f) + horizontalLineToRelative(-8.167f) + close() + moveToRelative(-16.083f, 0f) + horizontalLineToRelative(8.167f) + verticalLineToRelative(-8.167f) + horizontalLineTo(7.875f) + close() + moveToRelative(16.083f, -16.083f) + close() + moveToRelative(0f, 7.916f) + close() + moveToRelative(-7.916f, 0f) + close() + moveToRelative(0f, -7.916f) + close() + } + }.build() + } + } + @Composable fun applets(color: Color): ImageVector { return remember { ImageVector.Builder( diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt index a91fd140f..06cf28edd 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/MainActivity.kt @@ -174,10 +174,9 @@ class MainActivity : BaseActivity() { } } - @SuppressLint("RestrictedApi") - override fun dispatchKeyEvent(event: KeyEvent?): Boolean { - event?.apply { + override fun dispatchKeyEvent(event: KeyEvent): Boolean { + event.apply { if (physicalControllerManager.onKeyEvent(this)) return true } diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/GameViews.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/GameViews.kt index c91343608..d7a883a76 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/GameViews.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/GameViews.kt @@ -178,9 +178,9 @@ class GameViews { modifier = Modifier.padding(16.dp), shape = MaterialTheme.shapes.medium ) { - Column { + Column(horizontalAlignment = Alignment.CenterHorizontally) { Row( - modifier = Modifier, + modifier = Modifier.padding(horizontal = 16.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { diff --git a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt index 275ab369f..ac5c26cf2 100644 --- a/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt +++ b/src/RyujinxAndroid/app/src/main/java/org/ryujinx/android/views/HomeViews.kt @@ -2,9 +2,13 @@ package org.ryujinx.android.views import android.content.res.Resources import android.graphics.BitmapFactory +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.basicMarquee +import androidx.compose.foundation.border import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -19,6 +23,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items @@ -34,33 +39,44 @@ import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialogDefaults import androidx.compose.material3.Card +import androidx.compose.material3.CardElevation import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ElevatedCard import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.OutlinedCard import androidx.compose.material3.Scaffold import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.HorizontalAlignmentLine +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Popup import androidx.navigation.NavHostController import com.anggrayudi.storage.extension.launchOnUiThread import org.ryujinx.android.R @@ -78,11 +94,12 @@ class HomeViews { const val ListImageSize = 150 const val GridImageSize = 300 - @OptIn(ExperimentalMaterial3Api::class) + @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun Home( viewModel: HomeViewModel = HomeViewModel(), - navController: NavHostController? = null + navController: NavHostController? = null, + isPreview: Boolean = false ) { viewModel.ensureReloadIfNecessary() val showAppActions = remember { mutableStateOf(false) } @@ -90,134 +107,269 @@ class HomeViews { val openTitleUpdateDialog = remember { mutableStateOf(false) } val canClose = remember { mutableStateOf(true) } val openDlcDialog = remember { mutableStateOf(false) } + var openAppBarExtra by remember { mutableStateOf(false) } + val selectedModel = remember { mutableStateOf(viewModel.mainViewModel?.selected) } val query = remember { mutableStateOf("") } + var refreshUser by remember { + mutableStateOf(true) + } Scaffold( modifier = Modifier.fillMaxSize(), topBar = { - TopAppBar( + SearchBar( modifier = Modifier .fillMaxWidth() - .padding(top = 8.dp), - title = { - SearchBar( - modifier = Modifier.fillMaxWidth(), - shape = SearchBarDefaults.inputFieldShape, - query = query.value, - onQueryChange = { - query.value = it - }, - onSearch = {}, - active = false, - onActiveChange = {}, - leadingIcon = { - Icon( - Icons.Filled.Search, - contentDescription = "Search Games" - ) - }, - placeholder = { - Text(text = "Ryujinx") - } - ) { } + .padding(8.dp), + shape = SearchBarDefaults.inputFieldShape, + query = query.value, + onQueryChange = { + query.value = it }, - actions = { + onSearch = {}, + active = false, + onActiveChange = {}, + leadingIcon = { + Icon( + Icons.Filled.Search, + contentDescription = "Search Games" + ) + }, + placeholder = { + Text(text = "Ryujinx") + }, + trailingIcon = { IconButton(onClick = { - navController?.navigate("user") + openAppBarExtra = !openAppBarExtra }) { - if (viewModel.mainViewModel?.userViewModel?.openedUser?.userPicture?.isNotEmpty() == true) { - val pic = - viewModel.mainViewModel.userViewModel.openedUser.userPicture - Image( - bitmap = BitmapFactory.decodeByteArray( - pic, - 0, - pic?.size ?: 0 + if (!refreshUser) { + refreshUser = true + } + if (refreshUser) + if (viewModel.mainViewModel?.userViewModel?.openedUser?.userPicture?.isNotEmpty() == true) { + val pic = + viewModel.mainViewModel.userViewModel.openedUser.userPicture + Image( + bitmap = BitmapFactory.decodeByteArray( + pic, + 0, + pic?.size ?: 0 + ) + .asImageBitmap(), + contentDescription = "user image", + contentScale = ContentScale.Crop, + modifier = Modifier + .padding(4.dp) + .size(52.dp) + .clip(CircleShape) ) - .asImageBitmap(), - contentDescription = "user image", - contentScale = ContentScale.Crop, - modifier = Modifier - .padding(4.dp) - .size(52.dp) - .clip(CircleShape) - ) - } else { - Icon( - Icons.Filled.Person, - contentDescription = "user" - ) - } - } - IconButton( - onClick = { - navController?.navigate("settings") - } - ) { - Icon( - Icons.Filled.Settings, - contentDescription = "Settings" - ) + } else { + Icon( + Icons.Filled.Person, + contentDescription = "user" + ) + } } } - ) + ) { + + } } ) { contentPadding -> - Box(modifier = Modifier.padding(contentPadding)) { - val list = remember { - viewModel.gameList - } - viewModel.filter(query.value) - var settings = QuickSettings(viewModel.activity!!) - - if (settings.isGrid) { - val size = GridImageSize / Resources.getSystem().displayMetrics.density - LazyVerticalGrid( - columns = GridCells.Adaptive(minSize = (size + 4).dp), + Column(modifier = Modifier.padding(contentPadding)) { + val iconSize = 52.dp + AnimatedVisibility( + visible = openAppBarExtra, + ) + { + Card( modifier = Modifier - .fillMaxSize() - .padding(4.dp), - horizontalArrangement = Arrangement.SpaceEvenly + .padding(vertical = 8.dp, horizontal = 16.dp) + .fillMaxWidth(), + shape = MaterialTheme.shapes.medium ) { - items(list) { - it.titleName?.apply { - if (this.isNotEmpty() && (query.value.trim() - .isEmpty() || this.lowercase(Locale.getDefault()) - .contains(query.value)) - ) - GridGameItem( - it, - viewModel, - showAppActions, - showLoading, - selectedModel + Column(modifier = Modifier.padding(8.dp)) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + if (refreshUser) { + Box( + modifier = Modifier + .border( + width = 2.dp, + color = Color(0xFF14bf00), + shape = CircleShape + ) + .size(iconSize) + .padding(2.dp), + contentAlignment = Alignment.Center + ) { + if (viewModel.mainViewModel?.userViewModel?.openedUser?.userPicture?.isNotEmpty() == true) { + val pic = + viewModel.mainViewModel.userViewModel.openedUser.userPicture + Image( + bitmap = BitmapFactory.decodeByteArray( + pic, + 0, + pic?.size ?: 0 + ) + .asImageBitmap(), + contentDescription = "user image", + contentScale = ContentScale.Crop, + modifier = Modifier + .padding(4.dp) + .size(iconSize) + .clip(CircleShape) + ) + } else { + Icon( + Icons.Filled.Person, + contentDescription = "user" + ) + } + } + Card( + modifier = Modifier + .padding(horizontal = 4.dp) + .fillMaxWidth(0.7f), + shape = MaterialTheme.shapes.small, + ) { + LazyRow { + if (viewModel.mainViewModel?.userViewModel?.userList?.isNotEmpty() == true) { + items(viewModel.mainViewModel.userViewModel.userList) { user -> + if (user.id != viewModel.mainViewModel.userViewModel.openedUser.id) { + Image( + bitmap = BitmapFactory.decodeByteArray( + user.userPicture, + 0, + user.userPicture?.size ?: 0 + ) + .asImageBitmap(), + contentDescription = "selected image", + contentScale = ContentScale.Crop, + modifier = Modifier + .padding(4.dp) + .size(iconSize) + .clip(CircleShape) + .combinedClickable( + onClick = { + viewModel.mainViewModel.userViewModel.openUser( + user + ) + refreshUser = + false + }) + ) + } + } + } + } + } + Box( + modifier = Modifier + .size(iconSize) + ) { + IconButton( + modifier = Modifier.fillMaxSize(), + onClick = { + openAppBarExtra = false + navController?.navigate("user") + }) { + Icon( + Icons.Filled.Add, + contentDescription = "N/A" + ) + } + } + } + } + TextButton(modifier = Modifier.fillMaxWidth(), + onClick = { + navController?.navigate("settings") + } + ) { + Row(modifier = Modifier.fillMaxWidth()) { + Icon( + Icons.Filled.Settings, + contentDescription = "Settings" ) + Text( + text = "Settings", + modifier = Modifier + .align(Alignment.CenterVertically) + .padding(start = 8.dp) + ) + } } } } - } else { - LazyColumn(Modifier.fillMaxSize()) { - items(list) { - it.titleName?.apply { - if (this.isNotEmpty() && (query.value.trim() - .isEmpty() || this.lowercase( - Locale.getDefault() - ) - .contains(query.value)) - ) - ListGameItem( - it, - viewModel, - showAppActions, - showLoading, - selectedModel, - ) + } + Box { + val list = remember { + viewModel.gameList + } + viewModel.filter(query.value) + + if (!isPreview) { + var settings = QuickSettings(viewModel.activity!!) + + if (settings.isGrid) { + val size = + GridImageSize / Resources.getSystem().displayMetrics.density + LazyVerticalGrid( + columns = GridCells.Adaptive(minSize = (size + 4).dp), + modifier = Modifier + .fillMaxSize() + .padding(4.dp), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + items(list) { + it.titleName?.apply { + if (this.isNotEmpty() && (query.value.trim() + .isEmpty() || this.lowercase(Locale.getDefault()) + .contains(query.value)) + ) + GridGameItem( + it, + viewModel, + showAppActions, + showLoading, + selectedModel + ) + } + } + } + } else { + LazyColumn(Modifier.fillMaxSize()) { + items(list) { + it.titleName?.apply { + if (this.isNotEmpty() && (query.value.trim() + .isEmpty() || this.lowercase( + Locale.getDefault() + ) + .contains(query.value)) + ) + Box(modifier = Modifier.animateItemPlacement()) { + ListGameItem( + it, + viewModel, + showAppActions, + showLoading, + selectedModel, + ) + } + } + } } } } @@ -248,7 +400,6 @@ class HomeViews { } } } - if (openTitleUpdateDialog.value) { AlertDialog(onDismissRequest = { openTitleUpdateDialog.value = false @@ -575,6 +726,6 @@ class HomeViews { @Preview @Composable fun HomePreview() { - Home() + Home(isPreview = true) } } diff --git a/src/RyujinxAndroid/build.gradle b/src/RyujinxAndroid/build.gradle index eecdbd845..0a46a83b7 100644 --- a/src/RyujinxAndroid/build.gradle +++ b/src/RyujinxAndroid/build.gradle @@ -2,5 +2,5 @@ plugins { id 'com.android.application' version '8.2.1' apply false id 'com.android.library' version '8.2.1' apply false - id 'org.jetbrains.kotlin.android' version '1.9.0' apply false + id 'org.jetbrains.kotlin.android' version '1.9.23' apply false }