finish UI for onboarding

This commit is contained in:
2023-06-25 05:24:40 +03:00
parent a99be170c0
commit 5c7c1d9036
@@ -5,32 +5,27 @@ import android.app.Activity
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.util.Log import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement 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.ColumnScope
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
@@ -64,37 +59,28 @@ import com.illusionware.npsbrowser.ui.theme.md_theme_dark_onSurface
import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.ContentPaste
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Surface import androidx.compose.material3.Switch
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.layoutId import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.semantics.Role import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.illusionware.npsbrowser.ui.components.NPSIconButton
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
const val PAGE_COUNT = 3; const val PAGE_COUNT = 3
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@SuppressLint("SourceLockedOrientationActivity") @SuppressLint("SourceLockedOrientationActivity")
@@ -243,11 +229,11 @@ fun OnBoardingSetupTSVs(
incrementPage: () -> Unit = {}, incrementPage: () -> Unit = {},
skipToEnd: () -> Unit = {} skipToEnd: () -> Unit = {}
) { ) {
Scaffold() { padding -> Scaffold { padding ->
Column( Column(
Modifier Modifier
.padding(padding) .padding(padding)
.padding(horizontal = 16.dp, vertical = 32.dp) .padding(vertical = 32.dp)
.fillMaxSize(), .fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween, verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
@@ -255,6 +241,11 @@ fun OnBoardingSetupTSVs(
Column( Column(
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
modifier = Modifier.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
) { ) {
Text(text = "Set up TSVs", style = Typography.displayMedium) Text(text = "Set up TSVs", style = Typography.displayMedium)
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
@@ -273,36 +264,44 @@ fun OnBoardingSetupTSVs(
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
} }
}
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.weight(1.0f, fill = false) .weight(1.0f, fill = false)
.padding(vertical = 16.dp), .padding(vertical = 16.dp),
) {
Column(
modifier = Modifier.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
) { ) {
TSVGroup(title = "PS Vita") { TSVGroup(title = "PS Vita") {
TSVItem("Games") TSVButton("Games")
TSVItem("Themes") TSVButton("Themes")
TSVItem("DLC") TSVButton("DLC")
} }
TSVGroup(title = "PSP") { TSVGroup(title = "PSP") {
TSVItem("Games") TSVButton("Games")
TSVItem("DLC") TSVButton("DLC")
Box(modifier = Modifier.width(110.dp)) Box(modifier = Modifier.width(110.dp))
} }
TSVGroup(title = "PS3") { TSVGroup(title = "PS3") {
TSVItem("Games") TSVButton("Games")
TSVItem("DLC") TSVButton("DLC")
Box(modifier = Modifier.width(110.dp)) Box(modifier = Modifier.width(110.dp))
} }
TSVGroup(title = "PSX") { TSVGroup(title = "PSX") {
TSVItem("Games") TSVButton("Games")
} }
TSVGroup(title = "PSM") { TSVGroup(title = "PSM") {
TSVItem("Games") TSVButton("Games")
} }
} }
}
Column(
modifier = Modifier.padding(horizontal = 16.dp)
) {
OnBoardingBottomButtons( OnBoardingBottomButtons(
page = page, page = page,
incrementPage = incrementPage, incrementPage = incrementPage,
@@ -312,10 +311,37 @@ fun OnBoardingSetupTSVs(
} }
} }
} }
}
@Composable
fun ColumnGroup(
title: String,
modifier: Modifier = Modifier,
titleModifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit
) {
Column(modifier = modifier) {
Text(
modifier = titleModifier,
text = title,
style = TextStyle.Default.copy(
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
),
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
content = content
)
}
}
@Composable @Composable
fun TSVGroup(title: String, content: @Composable RowScope.() -> Unit) { fun TSVGroup(title: String, content: @Composable RowScope.() -> Unit) {
Column() { Column {
Text( Text(
text = title, text = title,
style = TextStyle.Default.copy( style = TextStyle.Default.copy(
@@ -334,13 +360,14 @@ fun TSVGroup(title: String, content: @Composable RowScope.() -> Unit) {
} }
@Composable @Composable
fun TSVItem(title: String) { fun TSVButton(title: String) {
var hasSelected by rememberSaveable { mutableStateOf(false) } var hasSelected by rememberSaveable { mutableStateOf(false) }
val filePicker = rememberLauncherForActivityResult( val filePicker = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent(), contract = ActivityResultContracts.GetContent(),
) { fileUri -> ) { fileUri ->
if (fileUri != null) { if (fileUri != null) {
// TODO: store file URI in preferences
Log.d("TSVItem", "fileUri: $fileUri") Log.d("TSVItem", "fileUri: $fileUri")
hasSelected = true hasSelected = true
} }
@@ -405,6 +432,165 @@ fun TSVItem(title: String) {
} }
} }
@Composable
@Preview
fun OnBoardingSetupSettings(
page: Int = 2,
incrementPage: () -> Unit = {},
decrementPage: () -> Unit = {},
skipToEnd: () -> Unit = {},
navigateToHome: () -> Unit = {},
) {
val clipboard = LocalClipboardManager.current
var hmacKey by rememberSaveable { mutableStateOf("") }
var pkg2zipArgs by rememberSaveable { mutableStateOf("") }
Scaffold { padding ->
Column(
Modifier
.padding(padding)
.padding(vertical = 32.dp)
.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
modifier = Modifier.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Configure App", style = Typography.displayMedium)
Text(
text = "Set the app's settings to your liking and control how it behaves",
style = Typography.titleMedium.copy(color = MaterialTheme.colorScheme.outline),
textAlign = TextAlign.Center,
)
}
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.weight(1.0f, fill = false)
.padding(vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(24.dp),
) {
ColumnGroup(title = "HMAC Key", modifier = Modifier.padding(horizontal = 16.dp)) {
Text(
text = "The HMAC Key is used to decrypt the PS Vita game updates' urls. We cannot provide this key since it's the property of Sony",
style = Typography.bodyMedium.copy(color = MaterialTheme.colorScheme.outline),
)
OutlinedTextField(
value = hmacKey,
onValueChange = { hmacKey = it },
label = { Text(text = "HMAC Key") },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
trailingIcon = {
NPSIconButton(
tooltip = "Paste",
onClick = { hmacKey = clipboard.getText()?.text ?: "" }
) {
Icon(
imageVector = Icons.Filled.ContentPaste,
contentDescription = "Paste",
)
}
}
)
}
ColumnGroup(title = "Downloads", titleModifier = Modifier.padding(horizontal = 16.dp)) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = "Choose your desired directory to download and unpack packages",
style = Typography.bodyMedium.copy(color = MaterialTheme.colorScheme.outline),
)
Toggleable(
title = "Unpack in download directory",
)
Toggleable(
title = "Delete package after unpacking",
)
Box(
Modifier.fillMaxWidth().clickable { /*TODO*/ }
) {
Column(Modifier.padding(horizontal = 16.dp)) {
Text(
text = "Download Directory",
)
Text(
text = "sdcard/Downloads",
color = MaterialTheme.colorScheme.outline,
)
}
}
Box(
Modifier.fillMaxWidth().clickable { /*TODO*/ }
) {
Column(Modifier.padding(horizontal = 16.dp)) {
Text(
text = "Unpack Directory",
)
Text(
text = "sdcard/Unpack",
color = MaterialTheme.colorScheme.outline,
)
}
}
}
ColumnGroup(title = "PKG2ZIP", titleModifier = Modifier.padding(horizontal = 16.dp)) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = "Modify the parameters and arguments of pkg2zip",
style = Typography.bodyMedium.copy(color = MaterialTheme.colorScheme.outline),
)
Toggleable(
title = "Automatically decrypt downloaded content",
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
value = pkg2zipArgs,
onValueChange = { pkg2zipArgs = it }, // TODO: validate args are legal ??
label = { Text(text = "Pkg2zip args") },
placeholder = { Text(text = "-x {pkgFile} \"{zRifKey}\"") },
)
}
}
Column(
modifier = Modifier.padding(horizontal = 16.dp),
) {
OnBoardingBottomButtons(
page = page,
incrementPage = incrementPage,
decrementPage = decrementPage,
skipToEnd = skipToEnd,
navigateToHome = navigateToHome
)
}
}
}
}
}
@Composable
fun Toggleable(title: String) {
Box(
modifier = Modifier.clickable { /* TODO: */ },
) {
Row(
modifier = Modifier.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(text = title, color = MaterialTheme.colorScheme.onBackground, modifier = Modifier.weight(1.0f))
Switch(checked = true, onCheckedChange = { /* TODO: */ })
}
}
}
@Composable @Composable
fun OnBoardingBottomButtons( fun OnBoardingBottomButtons(
page: Int, page: Int,
@@ -449,26 +635,3 @@ fun OnBoardingBottomButtons(
} }
} }
} }
@Composable
@Preview
fun OnBoardingSetupSettings(
page: Int = 2,
incrementPage: () -> Unit = {},
decrementPage: () -> Unit = {},
skipToEnd: () -> Unit = {},
navigateToHome: () -> Unit = {},
) {
Scaffold() { padding ->
Column(Modifier.padding(padding)) {
Text(text = "Configure App")
OnBoardingBottomButtons(
page = page,
incrementPage = incrementPage,
decrementPage = decrementPage,
skipToEnd = skipToEnd,
navigateToHome = navigateToHome
)
}
}
}