mirror of
https://github.com/IllusionMan1212/NPS-Browser.git
synced 2026-10-24 02:12:37 +00:00
WIP: UI for package list and grid + start of handling data
This commit is contained in:
@@ -3,17 +3,29 @@ package com.illusionware.npsbrowser.activities
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.basicMarquee
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
@@ -23,6 +35,9 @@ import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.ProvideTextStyle
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
@@ -40,18 +55,32 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
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.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.ColorPainter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.Font
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.illusionware.npsbrowser.ConsoleType
|
||||
import com.illusionware.npsbrowser.Layout
|
||||
import com.illusionware.npsbrowser.Preferences
|
||||
import com.illusionware.npsbrowser.R
|
||||
import com.illusionware.npsbrowser.ui.theme.ColorAccent
|
||||
@@ -60,12 +89,18 @@ import com.illusionware.npsbrowser.ui.theme.Typography
|
||||
import com.illusionware.npsbrowser.ui.components.*
|
||||
import com.illusionware.npsbrowser.ui.pages.SettingsScreen
|
||||
import com.illusionware.npsbrowser.ui.pages.OnBoarding
|
||||
import com.illusionware.npsbrowser.ui.theme.ColorOnPrimaryLight
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
val PlaceholderColor = Color(0x1F888888)
|
||||
val redHatDisplayFamily = FontFamily(
|
||||
Font(R.font.red_hat_display_bold, FontWeight.Bold),
|
||||
)
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -128,13 +163,18 @@ fun Router() {
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@Preview()
|
||||
@Preview
|
||||
fun HomePage(navigateToSettings: () -> Unit = {}) {
|
||||
val prefs = Preferences(LocalContext.current)
|
||||
var isSearchOpen by rememberSaveable { mutableStateOf(false)}
|
||||
var searchQuery by rememberSaveable { mutableStateOf("")}
|
||||
val searchBar = remember { FocusRequester() }
|
||||
var layoutDialogOpen by remember { mutableStateOf(false) }
|
||||
|
||||
val tsvs by remember { runBlocking { mutableStateOf(prefs.getAvailableTsvs()) }}
|
||||
var selectedBarItem by remember { mutableStateOf(ConsoleType.PSVITA) }
|
||||
// val noTsvs by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -213,12 +253,27 @@ fun HomePage(navigateToSettings: () -> Unit = {}) {
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
if (tsvs.isNotEmpty()) {
|
||||
NavBar(
|
||||
selectedTab = selectedBarItem,
|
||||
onTabSelected = { selectedBarItem = it },
|
||||
)
|
||||
}
|
||||
}
|
||||
) { padding ->
|
||||
Column(Modifier.padding(padding)) {
|
||||
NoTsvs(navigateToSettings = navigateToSettings)
|
||||
if (tsvs.isEmpty()) {
|
||||
NoTsvs(navigateToSettings = navigateToSettings)
|
||||
} else {
|
||||
// when (selectedBarItem) {
|
||||
// ConsoleType.PSVITA -> VitaPage(searchQuery = searchQuery)
|
||||
// ConsoleType.PS3 -> PS3Page(searchQuery = searchQuery)
|
||||
// }
|
||||
PackageList(selectedBarItem)
|
||||
}
|
||||
}
|
||||
// TODO: only show NoTsvs when there are no Tsvs loaded
|
||||
|
||||
if (layoutDialogOpen) {
|
||||
LayoutDialog(onDismiss = { layoutDialogOpen = false })
|
||||
@@ -226,6 +281,52 @@ fun HomePage(navigateToSettings: () -> Unit = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NavBar(selectedTab: ConsoleType, onTabSelected: (ConsoleType) -> Unit) {
|
||||
NavigationBar {
|
||||
NavigationBarItem(
|
||||
selected = selectedTab == ConsoleType.PSVITA,
|
||||
icon = { Icon(painterResource(id = R.drawable.vita_icon), contentDescription = "PS Vita") },
|
||||
label = { Text(text = "PS Vita") },
|
||||
onClick = {
|
||||
onTabSelected(ConsoleType.PSVITA)
|
||||
}
|
||||
)
|
||||
NavigationBarItem(
|
||||
selected = selectedTab == ConsoleType.PS3,
|
||||
icon = { Icon(painterResource(id = R.drawable.ps3_icon), contentDescription = "PS3") },
|
||||
label = { Text(text = "PS3") },
|
||||
onClick = {
|
||||
onTabSelected(ConsoleType.PS3)
|
||||
}
|
||||
)
|
||||
NavigationBarItem(
|
||||
selected = selectedTab == ConsoleType.PSP,
|
||||
icon = { Icon(painterResource(id = R.drawable.psp_icon), contentDescription = "PSP") },
|
||||
label = { Text(text = "PSP") },
|
||||
onClick = {
|
||||
onTabSelected(ConsoleType.PSP)
|
||||
}
|
||||
)
|
||||
NavigationBarItem(
|
||||
selected = selectedTab == ConsoleType.PSX,
|
||||
icon = { Icon(painterResource(id = R.drawable.psx_icon), contentDescription = "PSX") },
|
||||
label = { Text(text = "PSX") },
|
||||
onClick = {
|
||||
onTabSelected(ConsoleType.PSX)
|
||||
}
|
||||
)
|
||||
NavigationBarItem(
|
||||
selected = selectedTab == ConsoleType.PSM,
|
||||
icon = { Icon(painterResource(id = R.drawable.psm_icon), contentDescription = "PSM") },
|
||||
label = { Text(text = "PSM") },
|
||||
onClick = {
|
||||
onTabSelected(ConsoleType.PSM)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun NoTsvs(padding: PaddingValues = PaddingValues(0.dp), navigateToSettings: () -> Unit = {}) {
|
||||
@@ -267,9 +368,229 @@ fun NoTsvs(padding: PaddingValues = PaddingValues(0.dp), navigateToSettings: ()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LayoutDialog(onDismiss: () -> Unit = {}) {
|
||||
@Preview
|
||||
fun PackageList(type: ConsoleType = ConsoleType.PSVITA) {
|
||||
val prefs = Preferences(LocalContext.current)
|
||||
val layout = prefs.layout.collectAsState(initial = "")
|
||||
val layout = prefs.layout.collectAsState(initial = Layout.LIST.ordinal).value
|
||||
// val thing = when (type) {
|
||||
// ConsoleType.PSVITA -> {
|
||||
// var list = ArrayList<Package>()
|
||||
// list.add(Package("test"))
|
||||
// val gs = prefs.psvGames.collectAsState(initial = emptyList<Package>())
|
||||
// list.add(gs.value)
|
||||
// }
|
||||
// ConsoleType.PS3 -> {
|
||||
// prefs.ps3Games.collectAsState(initial = emptyList())
|
||||
// }
|
||||
// ConsoleType.PSP -> {
|
||||
// prefs.pspGames.collectAsState(initial = emptyList())
|
||||
// }
|
||||
// ConsoleType.PSX -> {
|
||||
// prefs.psxGames.collectAsState(initial = emptyList())
|
||||
// }
|
||||
// ConsoleType.PSM -> {
|
||||
// prefs.psmGames.collectAsState(initial = emptyList())
|
||||
// }
|
||||
// }
|
||||
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
if (layout == Layout.LIST.ordinal) {
|
||||
LazyColumn {
|
||||
items(15) {
|
||||
PackageListItem()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Adaptive(140.dp),
|
||||
contentPadding = PaddingValues(8.dp),
|
||||
) {
|
||||
items(15) {
|
||||
PackageGridItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun PackageListItem() {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { /* TODO: */ }) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
modifier = Modifier.weight(1.0f)
|
||||
) {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data("https://picsum.photos/200")
|
||||
.crossfade(true)
|
||||
.error(R.drawable.default_game_icon)
|
||||
.build(),
|
||||
placeholder = ColorPainter(PlaceholderColor),
|
||||
contentDescription = "Package Icon",
|
||||
modifier = Modifier.size(48.dp),
|
||||
contentScale = ContentScale.Crop,
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp),
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "10 Second Ninja X",
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
style = Typography.bodyLarge,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 2,
|
||||
modifier = Modifier
|
||||
.width(IntrinsicSize.Min)
|
||||
.weight(1.0f)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
ProvideTextStyle(value = Typography.bodySmall.copy(color = MaterialTheme.colorScheme.outline)) {
|
||||
Text(text = "US")
|
||||
Text(text = "3.69")
|
||||
Text(text = "223.8MB")
|
||||
Tag(title = "GAME", small = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Column {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.no_url_icon),
|
||||
contentDescription = "No PKG URL",
|
||||
tint = Color(0xFFCB5A5A)
|
||||
)
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.no_key_icon),
|
||||
contentDescription = "No Zrif Key",
|
||||
tint = Color(0xFFCB5A5A)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Tag(title: String, small: Boolean = false) {
|
||||
Box(
|
||||
Modifier
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(Color(0xFFEAF654))
|
||||
.layoutId("tag")
|
||||
.padding(horizontal = if (small) 6.dp else 8.dp, vertical = if (small) 2.dp else 4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = title.uppercase(),
|
||||
color = ColorOnPrimaryLight,
|
||||
style = Typography.bodySmall.copy(
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontFamily = redHatDisplayFamily,
|
||||
fontSize = if (small) 8.sp else 12.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun PackageGridItem() {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.clickable { /* TODO: */ }
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
modifier = Modifier.padding(8.dp)
|
||||
) {
|
||||
Layout(
|
||||
content = {
|
||||
AsyncImage(
|
||||
model = ImageRequest.Builder(LocalContext.current)
|
||||
.data("https://picsum.photos/200")
|
||||
.crossfade(true)
|
||||
.error(R.drawable.default_game_icon)
|
||||
.build(),
|
||||
placeholder = ColorPainter(PlaceholderColor),
|
||||
contentDescription = "Package Icon",
|
||||
modifier = Modifier
|
||||
.aspectRatio(1f / 1f)
|
||||
.fillMaxWidth(),
|
||||
contentScale = ContentScale.Crop,
|
||||
)
|
||||
Tag(title = "GAME")
|
||||
}
|
||||
) { measurables, constraints ->
|
||||
val imagePlaceable = measurables[0].measure(constraints)
|
||||
val tagPlaceable = measurables.first { it.layoutId == "tag" }.measure(constraints)
|
||||
|
||||
layout(imagePlaceable.width, imagePlaceable.height) {
|
||||
imagePlaceable.placeRelative(0, 0)
|
||||
tagPlaceable.placeRelative(
|
||||
x = imagePlaceable.width - tagPlaceable.width - 16,
|
||||
y = 16,
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = "10 Second Ninja X",
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
style = Typography.bodyLarge,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 2,
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
ProvideTextStyle(value = Typography.bodySmall.copy(color = MaterialTheme.colorScheme.outline)) {
|
||||
Text(text = "US")
|
||||
Text(text = "3.69")
|
||||
Text(text = "223.8MB")
|
||||
}
|
||||
}
|
||||
Row {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.no_url_icon),
|
||||
contentDescription = "No PKG URL",
|
||||
tint = Color(0xFFCB5A5A)
|
||||
)
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.no_key_icon),
|
||||
contentDescription = "No Zrif Key",
|
||||
tint = Color(0xFFCB5A5A)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LayoutDialog(onDismiss: () -> Unit) {
|
||||
val prefs = Preferences(LocalContext.current)
|
||||
val layout = prefs.layout.collectAsState(initial = Layout.LIST.ordinal).value
|
||||
|
||||
NPSAlertDialog(
|
||||
onDismiss = onDismiss,
|
||||
@@ -283,13 +604,13 @@ fun LayoutDialog(onDismiss: () -> Unit = {}) {
|
||||
Column {
|
||||
NPSRadioButton(
|
||||
text = "List",
|
||||
selected = layout.value == 0,
|
||||
onClick = { CoroutineScope(Dispatchers.IO).launch { prefs.changeLayout(0) } },
|
||||
selected = layout == Layout.LIST.ordinal,
|
||||
onClick = { CoroutineScope(Dispatchers.IO).launch { prefs.changeLayout(Layout.LIST.ordinal) } },
|
||||
)
|
||||
NPSRadioButton(
|
||||
text = "Grid",
|
||||
selected = layout.value == 1,
|
||||
onClick = { CoroutineScope(Dispatchers.IO).launch { prefs.changeLayout(1) } },
|
||||
selected = layout == Layout.GRID.ordinal,
|
||||
onClick = { CoroutineScope(Dispatchers.IO).launch { prefs.changeLayout(Layout.GRID.ordinal) } },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user