Move all preference composables to a separate package for better reusability

This commit is contained in:
Rafael Caetano 2023-03-12 16:06:35 +00:00
parent b538a8498f
commit 4bca90ee42
7 changed files with 294 additions and 217 deletions

View File

@ -0,0 +1,50 @@
package me.magnum.melonds.ui.common.preference
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.material.ContentAlpha
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@Composable
fun ActionLauncherItem(
name: String,
value: String,
enabled: Boolean = true,
onLaunchAction: () -> Unit,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.run {
if (enabled) {
clickable { onLaunchAction() }.focusable()
} else {
this
}
}
.heightIn(min = 64.dp)
.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp),
verticalArrangement = Arrangement.Center,
) {
Text(
text = name,
style = MaterialTheme.typography.body1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.typography.body1.color.copy(alpha = if (enabled) ContentAlpha.high else ContentAlpha.disabled)
)
Text(
text = value,
style = MaterialTheme.typography.caption,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.typography.caption.color.copy(alpha = if (enabled) ContentAlpha.medium else ContentAlpha.disabled)
)
}
}

View File

@ -0,0 +1,138 @@
package me.magnum.melonds.ui.common.preference
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import me.magnum.melonds.R
@Composable
fun SingleChoiceItem(
name: String,
value: String,
items: List<String>,
selectedItemIndex: Int,
onItemSelected: (Int) -> Unit,
) {
var isDialogShown by remember {
mutableStateOf(false)
}
Column(
modifier = Modifier
.fillMaxWidth()
.clickable { isDialogShown = true }
.focusable()
.heightIn(min = 64.dp)
.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp),
verticalArrangement = Arrangement.Center
) {
Text(
text = name,
style = MaterialTheme.typography.body1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = value,
style = MaterialTheme.typography.caption,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
if (isDialogShown) {
SingleChoiceDialog(
title = name,
items = items,
selectedItemIndex = selectedItemIndex,
onOptionSelected = onItemSelected,
onDismissRequest = { isDialogShown = false },
)
}
}
@Composable
private fun SingleChoiceDialog(
title: String,
items: List<String>,
selectedItemIndex: Int,
onOptionSelected: (index: Int) -> Unit,
onDismissRequest: () -> Unit,
) {
Dialog(
onDismissRequest = onDismissRequest,
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(Modifier.fillMaxWidth()) {
Box(
modifier = Modifier
.heightIn(min = 64.dp)
.padding(start = 24.dp, end = 24.dp),
contentAlignment = Alignment.CenterStart,
) {
Text(
modifier = Modifier,
text = title,
style = MaterialTheme.typography.h6,
fontWeight = FontWeight.Bold,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
}
LazyColumn {
itemsIndexed(items) { index, item ->
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
onOptionSelected(index)
onDismissRequest()
}
.heightIn(min = 48.dp)
.padding(start = 24.dp),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(
selected = index == selectedItemIndex,
onClick = null,
)
Spacer(Modifier.width(32.dp))
Text(text = item)
}
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(52.dp)
.padding(8.dp),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
TextButton(onClick = { onDismissRequest() }) {
Text(
text = stringResource(id = R.string.cancel).uppercase(),
style = MaterialTheme.typography.button,
color = MaterialTheme.colors.secondary,
)
}
}
}
}
}
}

View File

@ -0,0 +1,45 @@
package me.magnum.melonds.ui.common.preference
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import me.magnum.melonds.ui.common.melonSwitchColors
@Composable
fun SwitchItem(
name: String,
isOn: Boolean,
onToggle: (Boolean) -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onToggle(!isOn) }
.focusable()
.heightIn(min = 48.dp)
.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
modifier = Modifier.weight(1f),
text = name,
style = MaterialTheme.typography.body1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Spacer(Modifier.width(16.dp))
Switch(
checked = isOn,
onCheckedChange = null,
colors = melonSwitchColors(),
)
}
}

View File

@ -32,10 +32,8 @@ import coil.request.ImageRequest
import me.magnum.melonds.R
import me.magnum.melonds.domain.model.retroachievements.RAUserAchievement
import me.magnum.melonds.ui.common.MelonPreviewSet
import me.magnum.melonds.ui.romdetails.ui.preview.mockRAAchievementPreview
import me.magnum.melonds.ui.theme.MelonTheme
import me.magnum.rcheevosapi.model.RAAchievement
import me.magnum.rcheevosapi.model.RAGameId
import java.net.URL
@Composable
fun RomAchievementUi(
@ -191,20 +189,7 @@ fun PreviewRomAchievementUi() {
RomAchievementUi(
modifier = Modifier.fillMaxWidth(),
userAchievement = RAUserAchievement(
achievement = RAAchievement(
id = 123,
gameId = RAGameId(123),
totalAwardsCasual = 5435,
totalAwardsHardcore = 4532,
title = "Amazing Achievement [m]",
description = "Do the definitely amazing stuff while back-flipping on top of a turtle.",
points = 10,
displayOrder = 0,
badgeUrlUnlocked = URL("http://localhost:80"),
badgeUrlLocked = URL("http://localhost:80"),
memoryAddress = "",
type = RAAchievement.Type.CORE,
),
achievement = mockRAAchievementPreview(),
isUnlocked = true,
),
onViewAchievement = {},

View File

@ -4,31 +4,25 @@ import android.app.Activity
import android.content.Intent
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import me.magnum.melonds.R
import me.magnum.melonds.common.Permission
import me.magnum.melonds.common.contracts.FilePickerContract
import me.magnum.melonds.domain.model.RuntimeConsoleType
import me.magnum.melonds.domain.model.RuntimeMicSource
import me.magnum.melonds.ui.common.MelonPreviewSet
import me.magnum.melonds.ui.common.melonSwitchColors
import me.magnum.melonds.ui.common.preference.ActionLauncherItem
import me.magnum.melonds.ui.common.preference.SingleChoiceItem
import me.magnum.melonds.ui.common.preference.SwitchItem
import me.magnum.melonds.ui.layouts.LayoutSelectorActivity
import me.magnum.melonds.ui.romdetails.model.RomConfigUiModel
import me.magnum.melonds.ui.romdetails.model.RomConfigUiState
@ -149,196 +143,6 @@ private fun Content(
}
}
@Composable
private fun SingleChoiceItem(
name: String,
value: String,
items: List<String>,
selectedItemIndex: Int,
onItemSelected: (Int) -> Unit,
) {
var isDialogShown by remember {
mutableStateOf(false)
}
Column(
modifier = Modifier
.fillMaxWidth()
.clickable { isDialogShown = true }
.focusable()
.heightIn(min = 64.dp)
.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp),
verticalArrangement = Arrangement.Center
) {
Text(
text = name,
style = MaterialTheme.typography.body1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = value,
style = MaterialTheme.typography.caption,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
if (isDialogShown) {
SingleChoiceDialog(
title = name,
items = items,
selectedItemIndex = selectedItemIndex,
onOptionSelected = onItemSelected,
onDismissRequest = { isDialogShown = false },
)
}
}
@Composable
private fun SingleChoiceDialog(
title: String,
items: List<String>,
selectedItemIndex: Int,
onOptionSelected: (index: Int) -> Unit,
onDismissRequest: () -> Unit,
) {
Dialog(
onDismissRequest = onDismissRequest,
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(Modifier.fillMaxWidth()) {
Box(
modifier = Modifier
.heightIn(min = 64.dp)
.padding(start = 24.dp, end = 24.dp),
contentAlignment = Alignment.CenterStart,
) {
Text(
modifier = Modifier,
text = title,
style = MaterialTheme.typography.h6,
fontWeight = FontWeight.Bold,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
}
LazyColumn {
itemsIndexed(items) { index, item ->
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {
onOptionSelected(index)
onDismissRequest()
}
.heightIn(min = 48.dp)
.padding(start = 24.dp),
verticalAlignment = Alignment.CenterVertically,
) {
RadioButton(
selected = index == selectedItemIndex,
onClick = null,
)
Spacer(Modifier.width(32.dp))
Text(text = item)
}
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(52.dp)
.padding(8.dp),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
TextButton(onClick = { onDismissRequest() }) {
Text(
text = stringResource(id = R.string.cancel).uppercase(),
style = MaterialTheme.typography.button,
color = MaterialTheme.colors.secondary,
)
}
}
}
}
}
}
@Composable
private fun ActionLauncherItem(
name: String,
value: String,
enabled: Boolean = true,
onLaunchAction: () -> Unit,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.run {
if (enabled) {
clickable { onLaunchAction() }.focusable()
} else {
this
}
}
.heightIn(min = 64.dp)
.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp),
verticalArrangement = Arrangement.Center,
) {
Text(
text = name,
style = MaterialTheme.typography.body1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.typography.body1.color.copy(alpha = if (enabled) ContentAlpha.high else ContentAlpha.disabled)
)
Text(
text = value,
style = MaterialTheme.typography.caption,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.typography.caption.color.copy(alpha = if (enabled) ContentAlpha.medium else ContentAlpha.disabled)
)
}
}
@Composable
private fun SwitchItem(
name: String,
isOn: Boolean,
onToggle: (Boolean) -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onToggle(!isOn) }
.focusable()
.heightIn(min = 48.dp)
.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
modifier = Modifier.weight(1f),
text = name,
style = MaterialTheme.typography.body1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Spacer(Modifier.width(16.dp))
Switch(
checked = isOn,
onCheckedChange = null,
colors = melonSwitchColors(),
)
}
}
@MelonPreviewSet
@Composable
private fun PreviewRomConfigUi() {

View File

@ -19,10 +19,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import me.magnum.melonds.R
import me.magnum.melonds.domain.model.retroachievements.RAUserAchievement
import me.magnum.melonds.ui.common.MelonPreviewSet
import me.magnum.melonds.ui.common.melonButtonColors
import me.magnum.melonds.ui.romdetails.model.RomAchievementsSummary
import me.magnum.melonds.ui.romdetails.model.RomRetroAchievementsUiState
import me.magnum.melonds.ui.romdetails.ui.preview.mockRAAchievementPreview
import me.magnum.melonds.ui.theme.MelonTheme
import me.magnum.rcheevosapi.model.RAAchievement
@ -283,6 +285,24 @@ private fun LoadError(
}
}
@MelonPreviewSet
@Composable
private fun PreviewContent() {
MelonTheme {
Ready(
modifier = Modifier.fillMaxSize(),
content = RomRetroAchievementsUiState.Ready(
listOf(
RAUserAchievement(mockRAAchievementPreview(id = 1), false),
RAUserAchievement(mockRAAchievementPreview(id = 2, title = "This is another amazing achievement", description = "But this one cannot be missed."), false),
),
RomAchievementsSummary(50, 20, 85),
),
onViewAchievement = {},
)
}
}
@MelonPreviewSet
@Composable
private fun PreviewLoggedOut() {

View File

@ -0,0 +1,35 @@
package me.magnum.melonds.ui.romdetails.ui.preview
import me.magnum.rcheevosapi.model.RAAchievement
import me.magnum.rcheevosapi.model.RAGameId
import java.net.URL
fun mockRAAchievementPreview(
id: Long = 1,
gameId: Long = 123,
totalAwardsCasual: Int = 5435,
totalAwardsHardcore: Int = 4532,
title: String = "Amazing Achievement [m]",
description: String = "Do the definitely amazing stuff while back-flipping on top of a turtle.",
points: Int = 10,
displayOrder: Int = 0,
badgeUrlUnlocked: String = "http://localhost:80",
badgeUrlLocked: String = "http://localhost:80",
memoryAddress: String = "",
type: RAAchievement.Type = RAAchievement.Type.CORE,
): RAAchievement {
return RAAchievement(
id = id,
gameId = RAGameId(gameId),
totalAwardsCasual = totalAwardsCasual,
totalAwardsHardcore = totalAwardsHardcore,
title = title,
description = description,
points = points,
displayOrder = displayOrder,
badgeUrlUnlocked = URL(badgeUrlUnlocked),
badgeUrlLocked = URL(badgeUrlLocked),
memoryAddress = memoryAddress,
type = type,
)
}