From 47a2f5815dcb0263c0e02e28e838de4ac4fdecf1 Mon Sep 17 00:00:00 2001 From: Mathew Tkachuk Date: Sat, 8 Mar 2025 16:47:41 +0300 Subject: [PATCH] refactor: UI code refactors --- .../kotlin/moe/crx/ovrport/ui/AppContent.kt | 25 +---- .../moe/crx/ovrport/ui/ApplicationInfo.kt | 52 ++++++++++ .../moe/crx/ovrport/ui/ApplicationInfoCard.kt | 95 ++----------------- .../moe/crx/ovrport/ui/ApplicationStatus.kt | 57 +++++++++++ .../moe/crx/ovrport/ui/BreathingIcon.kt | 37 ++++++++ .../moe/crx/ovrport/ui/FadeVisibility.kt | 20 ++++ .../kotlin/moe/crx/ovrport/ui/StartingCard.kt | 54 +---------- 7 files changed, 179 insertions(+), 161 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfo.kt create mode 100644 composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationStatus.kt create mode 100644 composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/BreathingIcon.kt create mode 100644 composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/FadeVisibility.kt diff --git a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/AppContent.kt b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/AppContent.kt index 23c1254..f46eedb 100644 --- a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/AppContent.kt +++ b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/AppContent.kt @@ -1,8 +1,5 @@ package moe.crx.ovrport.ui -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -21,16 +18,14 @@ import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import moe.crx.ovrport.AndroidPlatform import moe.crx.ovrport.getCurrentVersion -import moe.crx.ovrport.patch.Patch import moe.crx.ovrport.getPlatform import moe.crx.ovrport.model.GithubRelease import moe.crx.ovrport.patch.Constants +import moe.crx.ovrport.patch.Patch import moe.crx.ovrport.ui.theme.OverportTheme -import moe.crx.ovrport.utils.HttpUtil import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource import overportapp.composeapp.generated.resources.Res @@ -82,11 +77,7 @@ fun AppContent( } }, actions = { - AnimatedVisibility( - versionToUpdate?.name != null && versionToUpdate?.name != getCurrentVersion(), - enter = fadeIn(), - exit = fadeOut() - ) { + FadeVisibility(versionToUpdate?.name != null && versionToUpdate?.name != getCurrentVersion()) { Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip( RoundedCornerShape(16.dp) @@ -115,21 +106,13 @@ fun AppContent( val inProgress = viewModel.working val isPatcherVisible = viewModel.isApkLoaded() && !inProgress - AnimatedVisibility( - !isPatcherVisible, - enter = fadeIn(), - exit = fadeOut() - ) { + FadeVisibility(!isPatcherVisible) { StartingCard(innerPadding, inProgress) { onOpen() } } - AnimatedVisibility( - isPatcherVisible, - enter = fadeIn(), - exit = fadeOut() - ) { + FadeVisibility(isPatcherVisible) { ApplicationInfoCard( innerPadding, viewModel.currentAppName(), diff --git a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfo.kt b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfo.kt new file mode 100644 index 0000000..76f62ab --- /dev/null +++ b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfo.kt @@ -0,0 +1,52 @@ +package moe.crx.ovrport.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Widgets +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.unit.dp +import org.jetbrains.compose.resources.stringResource +import overportapp.composeapp.generated.resources.Res +import overportapp.composeapp.generated.resources.unknown_package + +@Composable +fun ApplicationInfo( + applicationName: String? = "Application", + applicationPackage: String? = "com.company.application", + applicationVersion: String? = "1.0.0", + applicationIcon: ImageBitmap? = null, +) { + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + if (applicationIcon == null) { + Icon( + Icons.Default.Widgets, + contentDescription = null, + modifier = Modifier.size(48.dp) + ) + } else { + Image( + applicationIcon, + contentDescription = null, + modifier = Modifier.size(48.dp).clip(RoundedCornerShape(8.dp)) + ) + } + Column( + modifier = Modifier.height(48.dp), + verticalArrangement = Arrangement.Center + ) { + Text("$applicationName ($applicationVersion)") + Text( + applicationPackage ?: stringResource(Res.string.unknown_package), + ) + } + } +} diff --git a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfoCard.kt b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfoCard.kt index b4d29d2..a7f0d8b 100644 --- a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfoCard.kt +++ b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationInfoCard.kt @@ -1,103 +1,22 @@ package moe.crx.ovrport.ui -import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Widgets -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment +import androidx.compose.material3.Button +import androidx.compose.material3.Checkbox +import androidx.compose.material3.ListItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.ImageBitmap -import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import moe.crx.ovrport.patch.Constants.LOADING_COMPATIBILITY import moe.crx.ovrport.patch.Patch import moe.crx.ovrport.patch.PatchStore -import moe.crx.ovrport.patch.getCompatibilityStatus -import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.ui.tooling.preview.Preview -import overportapp.composeapp.generated.resources.Res -import overportapp.composeapp.generated.resources.unknown_package - -@Composable -fun ApplicationInfo( - applicationName: String? = "Application", - applicationPackage: String? = "com.company.application", - applicationVersion: String? = "1.0.0", - applicationIcon: ImageBitmap? = null, -) { - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - ) { - if (applicationIcon == null) { - Icon( - Icons.Default.Widgets, - contentDescription = null, - modifier = Modifier.size(48.dp) - ) - } else { - Image( - applicationIcon, - contentDescription = null, - modifier = Modifier.size(48.dp).clip(RoundedCornerShape(8.dp)) - ) - } - Column( - modifier = Modifier.height(48.dp), - verticalArrangement = Arrangement.Center - ) { - Text("$applicationName ($applicationVersion)") - Text( - applicationPackage ?: stringResource(Res.string.unknown_package), - ) - } - } -} - -@Composable -fun ApplicationStatus( - applicationName: String? = "Application", - applicationPackage: String? = "", -) { - var statusInfo by remember(applicationPackage) { mutableStateOf(LOADING_COMPATIBILITY) } - val urlHandler = LocalUriHandler.current - - LaunchedEffect(applicationPackage) { - withContext(Dispatchers.IO) { - statusInfo = getCompatibilityStatus(applicationName, applicationPackage) - } - } - - - Card(colors = CardDefaults.cardColors(statusInfo.status.cardColor, statusInfo.status.contentColor)) { - Row( - verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip( - RoundedCornerShape(16.dp) - ).clickable { - urlHandler.openUri(statusInfo.url) - }) { - Icon( - statusInfo.status.icon, - contentDescription = null, - modifier = Modifier.padding(16.dp), - ) - Text( - stringResource(statusInfo.status.nameResource), - fontSize = 18.sp, - modifier = Modifier.padding(0.dp, 16.dp, 16.dp, 16.dp), - ) - } - } -} @OptIn(ExperimentalLayoutApi::class) @Composable diff --git a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationStatus.kt b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationStatus.kt new file mode 100644 index 0000000..6f3b0f4 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/ApplicationStatus.kt @@ -0,0 +1,57 @@ +package moe.crx.ovrport.ui + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import moe.crx.ovrport.patch.Constants.LOADING_COMPATIBILITY +import moe.crx.ovrport.patch.getCompatibilityStatus +import org.jetbrains.compose.resources.stringResource + +@Composable +fun ApplicationStatus( + applicationName: String? = "Application", + applicationPackage: String? = "", +) { + var statusInfo by remember(applicationPackage) { mutableStateOf(LOADING_COMPATIBILITY) } + val urlHandler = LocalUriHandler.current + + LaunchedEffect(applicationPackage) { + withContext(Dispatchers.IO) { + statusInfo = getCompatibilityStatus(applicationName, applicationPackage) + } + } + + Card(colors = CardDefaults.cardColors(statusInfo.status.cardColor, statusInfo.status.contentColor)) { + Row( + verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip( + RoundedCornerShape(16.dp) + ).clickable { + urlHandler.openUri(statusInfo.url) + }) { + Icon( + statusInfo.status.icon, + contentDescription = null, + modifier = Modifier.padding(16.dp), + ) + Text( + stringResource(statusInfo.status.nameResource), + fontSize = 18.sp, + modifier = Modifier.padding(0.dp, 16.dp, 16.dp, 16.dp), + ) + } + } +} diff --git a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/BreathingIcon.kt b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/BreathingIcon.kt new file mode 100644 index 0000000..1b86950 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/BreathingIcon.kt @@ -0,0 +1,37 @@ +package moe.crx.ovrport.ui + +import androidx.compose.animation.core.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Bolt +import androidx.compose.material3.Icon +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import kotlinx.coroutines.delay + +@Composable +fun BreathingIcon(modifier: Modifier, duration: Int = 1500) { + var isFaded by remember { mutableStateOf(false) } + + val alpha by animateFloatAsState( + targetValue = if (isFaded) 0.2f else 1f, + animationSpec = infiniteRepeatable( + animation = tween(durationMillis = duration, easing = LinearEasing), + repeatMode = RepeatMode.Reverse + ), + label = "" + ) + + LaunchedEffect(Unit) { + while (true) { + isFaded = !isFaded + delay(duration.toLong()) + } + } + + Icon( + Icons.Default.Bolt, + contentDescription = null, + modifier = modifier.alpha(alpha) + ) +} diff --git a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/FadeVisibility.kt b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/FadeVisibility.kt new file mode 100644 index 0000000..a68a7ad --- /dev/null +++ b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/FadeVisibility.kt @@ -0,0 +1,20 @@ +package moe.crx.ovrport.ui + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.AnimatedVisibilityScope +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.runtime.Composable + +@Composable +fun FadeVisibility( + condition: Boolean, + block: @Composable AnimatedVisibilityScope.() -> Unit +) { + AnimatedVisibility( + condition, + enter = fadeIn(), + exit = fadeOut(), + content = block + ) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/StartingCard.kt b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/StartingCard.kt index 28c32c9..2aea93d 100644 --- a/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/StartingCard.kt +++ b/composeApp/src/commonMain/kotlin/moe/crx/ovrport/ui/StartingCard.kt @@ -1,36 +1,14 @@ package moe.crx.ovrport.ui -import androidx.compose.animation.core.LinearEasing -import androidx.compose.animation.core.RepeatMode -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.core.infiniteRepeatable -import androidx.compose.animation.core.tween import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Bolt import androidx.compose.material.icons.filled.Download -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.Text +import androidx.compose.material3.* import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -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.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.rotate @@ -39,7 +17,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.PathEffect import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.unit.dp -import kotlinx.coroutines.delay import moe.crx.ovrport.AndroidPlatform import moe.crx.ovrport.getPlatform import org.jetbrains.compose.resources.stringResource @@ -125,30 +102,3 @@ fun StartingCard( } } } - -@Composable -fun BreathingIcon(modifier: Modifier, duration: Int = 1500) { - var isFaded by remember { mutableStateOf(false) } - - val alpha by animateFloatAsState( - targetValue = if (isFaded) 0.2f else 1f, - animationSpec = infiniteRepeatable( - animation = tween(durationMillis = duration, easing = LinearEasing), - repeatMode = RepeatMode.Reverse - ), - label = "" - ) - - LaunchedEffect(Unit) { - while (true) { - isFaded = !isFaded - delay(duration.toLong()) - } - } - - Icon( - Icons.Default.Bolt, - contentDescription = null, - modifier = modifier.alpha(alpha) - ) -} \ No newline at end of file