diff --git a/app/src/main/java/com/pixelized/rplexicon/business/SearchUseCase.kt b/app/src/main/java/com/pixelized/rplexicon/business/SearchUseCase.kt index b5859ef..ac945c4 100644 --- a/app/src/main/java/com/pixelized/rplexicon/business/SearchUseCase.kt +++ b/app/src/main/java/com/pixelized/rplexicon/business/SearchUseCase.kt @@ -68,7 +68,7 @@ class SearchUseCase @Inject constructor( name = annotate( text = item.name, highlightRegex styleWith typography.search.titleHighlight, - dropCapRegex styleWith typography.titleMediumDropCap, + dropCapRegex styleWith typography.dropCap.titleMedium, ), diminutive = nullableAnnotate( text = item.diminutive, @@ -186,7 +186,7 @@ class SearchUseCase @Inject constructor( title = annotate( text = item.title, highlightRegex styleWith typography.search.titleHighlight, - dropCapRegex styleWith typography.titleMediumDropCap, + dropCapRegex styleWith typography.dropCap.titleMedium, ), owner = entry?.questGiverName?.let { AnnotatedString( @@ -269,7 +269,7 @@ class SearchUseCase @Inject constructor( title = annotate( text = item.name, highlightRegex styleWith typography.search.titleHighlight, - dropCapRegex styleWith typography.titleMediumDropCap, + dropCapRegex styleWith typography.dropCap.titleMedium, ), description = item.description?.let { extractSentence.find(it) }?.let { AnnotatedString( @@ -344,7 +344,7 @@ class SearchUseCase @Inject constructor( name = annotate( text = item.name, highlightRegex styleWith typography.search.titleHighlight, - dropCapRegex styleWith typography.titleMediumDropCap, + dropCapRegex styleWith typography.dropCap.titleMedium, ), translated = nullableAnnotate( text = itemDescription?.original, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt index 1d800ae..1f59559 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/error/FetchErrorUio.kt @@ -48,30 +48,30 @@ fun HandleFetchError( errors: Flow, onStructureError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Structure) -> Unit = { context, snackHost, error -> val messageResources = when (error.type) { - FetchErrorUio.Structure.Type.UNKNOWN -> R.string.error_structure_unknowed - FetchErrorUio.Structure.Type.ACTION -> R.string.error_structure_action - FetchErrorUio.Structure.Type.ALTERATION -> R.string.error_structure_alteration - FetchErrorUio.Structure.Type.CHARACTER -> R.string.error_structure_character - FetchErrorUio.Structure.Type.DESCRIPTION -> R.string.error_structure_description - FetchErrorUio.Structure.Type.EQUIPMENT -> R.string.error_structure_equipment - FetchErrorUio.Structure.Type.INVENTORY -> R.string.error_structure_inventory - FetchErrorUio.Structure.Type.OBJECT -> R.string.error_structure_objects - FetchErrorUio.Structure.Type.SKILL -> R.string.error_structure_skill - FetchErrorUio.Structure.Type.SPELL -> R.string.error_structure_spell - FetchErrorUio.Structure.Type.CATEGORY_ORDER -> R.string.error_structure_category_order - FetchErrorUio.Structure.Type.LEXICON -> R.string.error_structure_lexicon - FetchErrorUio.Structure.Type.LOCATION -> R.string.error_structure_location - FetchErrorUio.Structure.Type.QUEST -> R.string.error_structure_quest + FetchErrorUio.Structure.Type.UNKNOWN -> R.string.error__structure_unknowed + FetchErrorUio.Structure.Type.ACTION -> R.string.error__structure_action + FetchErrorUio.Structure.Type.ALTERATION -> R.string.error__structure_alteration + FetchErrorUio.Structure.Type.CHARACTER -> R.string.error__structure_character + FetchErrorUio.Structure.Type.DESCRIPTION -> R.string.error__structure_description + FetchErrorUio.Structure.Type.EQUIPMENT -> R.string.error__structure_equipment + FetchErrorUio.Structure.Type.INVENTORY -> R.string.error__structure_inventory + FetchErrorUio.Structure.Type.OBJECT -> R.string.error__structure_objects + FetchErrorUio.Structure.Type.SKILL -> R.string.error__structure_skill + FetchErrorUio.Structure.Type.SPELL -> R.string.error__structure_spell + FetchErrorUio.Structure.Type.CATEGORY_ORDER -> R.string.error__structure_category_order + FetchErrorUio.Structure.Type.LEXICON -> R.string.error__structure_lexicon + FetchErrorUio.Structure.Type.LOCATION -> R.string.error__structure_location + FetchErrorUio.Structure.Type.QUEST -> R.string.error__structure_quest } snackHost.showSnackbar(message = context.getString(messageResources)) }, onFirebaseError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Firebase) -> Unit = { context, snackHost, error -> snackHost.showSnackbar( - message = error.exception.localizedMessage ?: context.getString(R.string.error_generic) + message = error.exception.localizedMessage ?: context.getString(R.string.error__generic) ) }, onDefaultError: suspend (context: Context, snack: SnackbarHostState, error: FetchErrorUio.Default) -> Unit = { context, snackHost, _ -> - snackHost.showSnackbar(message = context.getString(R.string.error_generic)) + snackHost.showSnackbar(message = context.getString(R.string.error__generic)) }, ) { val context = LocalContext.current diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/form/TextFieldAppBar.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/form/TextFieldAppBar.kt index a2267fe..c9a2611 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/composable/form/TextFieldAppBar.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/form/TextFieldAppBar.kt @@ -128,7 +128,7 @@ private fun TextFieldPreview( .fillMaxWidth() .padding(all = 8.dp), field = TextFieldUio( - label = R.string.lexicon_search, + label = R.string.default_search_label, value = remember { mutableStateOf(preview) }, ), onBack = { }, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/composable/rememberAnimatedShadow.kt b/app/src/main/java/com/pixelized/rplexicon/ui/composable/rememberAnimatedShadow.kt new file mode 100644 index 0000000..ba7649b --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/composable/rememberAnimatedShadow.kt @@ -0,0 +1,31 @@ +package com.pixelized.rplexicon.ui.composable + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@Composable +fun rememberAnimatedShadow( + lazyListState: LazyListState, + rest: Dp = 0.dp, + target: Dp = 4.dp, +): State { + val shadowTarget = remember(lazyListState) { + derivedStateOf { + if (lazyListState.firstVisibleItemScrollOffset > 0 || lazyListState.firstVisibleItemIndex != 0) { + target + } else { + rest + } + } + } + return animateDpAsState( + targetValue = shadowTarget.value, + label = "animated shadow", + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/HomeNavHost.kt b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/HomeNavHost.kt deleted file mode 100644 index 831f88a..0000000 --- a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/HomeNavHost.kt +++ /dev/null @@ -1,194 +0,0 @@ -package com.pixelized.rplexicon.ui.navigation - -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.NavigationBar -import androidx.compose.material3.NavigationBarItem -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.Stable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.staticCompositionLocalOf -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.currentBackStackEntryAsState -import androidx.navigation.compose.rememberNavController -import com.pixelized.rplexicon.LocalSnack -import com.pixelized.rplexicon.R -import com.pixelized.rplexicon.ui.navigation.pages.LEXICON_LIST_ROUTE -import com.pixelized.rplexicon.ui.navigation.pages.LOCATION_LIST_ROUTE -import com.pixelized.rplexicon.ui.navigation.pages.QUEST_LIST_ROUTE -import com.pixelized.rplexicon.ui.navigation.pages.composableLexicon -import com.pixelized.rplexicon.ui.navigation.pages.composableLocations -import com.pixelized.rplexicon.ui.navigation.pages.composableQuests -import com.pixelized.rplexicon.ui.navigation.pages.navigateToLexicon -import com.pixelized.rplexicon.ui.navigation.pages.navigateToLocation -import com.pixelized.rplexicon.ui.navigation.pages.navigateToQuestList -import com.pixelized.rplexicon.ui.navigation.screens.navigateToSummary -import kotlinx.coroutines.launch - -val LocalPageNavHost = staticCompositionLocalOf { - error("LocalScreenNavHost not ready") -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun HomeNavHost( - navHostController: NavHostController = rememberNavController(), - bottomBarItems: List = rememberBottomBarItems(navHostController), - startDestination: String = LEXICON_LIST_ROUTE, - lexiconListState: LazyListState, - questListState: LazyListState, - locationListState: LazyListState, -) { - val screen = LocalScreenNavHost.current - val scope = rememberCoroutineScope() - - CompositionLocalProvider( - LocalSnack provides remember { SnackbarHostState() }, - ) { - val backStackEntry = navHostController.currentBackStackEntryAsState() - - Scaffold( - topBar = { - TopAppBar( - modifier = Modifier.shadow(elevation = 4.dp), - title = { - Text(text = stringResource(id = R.string.app_name)) - }, - actions = { - IconButton( - onClick = { screen.navigateToSummary() }, - ) { - Icon( - painter = painterResource(id = R.drawable.ic_crowned_skull_24), - contentDescription = null, - ) - } - } - ) - }, - snackbarHost = { - SnackbarHost( - hostState = LocalSnack.current, - ) - }, - bottomBar = { - NavigationBar( - containerColor = MaterialTheme.colorScheme.surface, - tonalElevation = 0.dp, - ) { - bottomBarItems.forEachIndexed { index, item -> - val selected by remember { - derivedStateOf { - item.route == backStackEntry.value?.destination?.route - } - } - NavigationBarItem( - selected = selected, - onClick = { - if (selected) { - scope.launch { - when (index) { - 0 -> lexiconListState.animateScrollToItem(index = 0) - 1 -> questListState.animateScrollToItem(index = 0) - 2 -> locationListState.animateScrollToItem(index = 0) - } - } - } else { - item.onClick.invoke() - } - }, - label = { - Text( - textAlign = TextAlign.Center, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - text = stringResource(id = item.label) - ) - }, - icon = { - Icon( - painter = painterResource(id = item.icon), - contentDescription = "", - ) - } - ) - } - } - }, - content = { padding -> - CompositionLocalProvider( - LocalPageNavHost provides navHostController, - ) { - NavHost( - modifier = Modifier.padding(padding), - navController = navHostController, - startDestination = startDestination, - ) { - composableLexicon(lazyListState = lexiconListState) - composableQuests(lazyListState = questListState) - composableLocations(lazyListState = locationListState) - } - } - } - ) - } -} - -@Stable -class BottomBarItem( - val route: String, - val icon: Int, - val label: Int, - val onClick: () -> Unit, -) - -@Composable -@Stable -private fun rememberBottomBarItems( - navHostController: NavHostController, -): List { - return remember(navHostController) { - val option = navHostController.pageOption() - listOf( - BottomBarItem( - route = LEXICON_LIST_ROUTE, - icon = R.drawable.ic_visored_helm_24, - label = R.string.home_lexicon, - onClick = { navHostController.navigateToLexicon(option) } - ), - BottomBarItem( - route = QUEST_LIST_ROUTE, - icon = R.drawable.ic_scroll_unfurled_24, - label = R.string.home_quest_log, - onClick = { navHostController.navigateToQuestList(option) } - ), - BottomBarItem( - route = LOCATION_LIST_ROUTE, - icon = R.drawable.ic_treasure_map_24, - label = R.string.home_location, - onClick = { navHostController.navigateToLocation(option) } - ) - ) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/ScreenNavHost.kt b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/ScreenNavHost.kt index 96e903f..151f04c 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/ScreenNavHost.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/ScreenNavHost.kt @@ -1,6 +1,5 @@ package com.pixelized.rplexicon.ui.navigation -import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.staticCompositionLocalOf @@ -9,18 +8,20 @@ import androidx.navigation.NavHostController import androidx.navigation.NavOptionsBuilder import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController +import com.pixelized.rplexicon.ui.navigation.screens.composableLexicon +import com.pixelized.rplexicon.ui.navigation.screens.composableLocations +import com.pixelized.rplexicon.ui.navigation.screens.composableQuests import com.pixelized.rplexicon.ui.navigation.screens.AUTHENTICATION_ROUTE import com.pixelized.rplexicon.ui.navigation.screens.composableAuthentication import com.pixelized.rplexicon.ui.navigation.screens.composableCharacterSheet -import com.pixelized.rplexicon.ui.navigation.screens.composableHome import com.pixelized.rplexicon.ui.navigation.screens.composableLanding import com.pixelized.rplexicon.ui.navigation.screens.composableLexiconDetail -import com.pixelized.rplexicon.ui.navigation.screens.composableSearch import com.pixelized.rplexicon.ui.navigation.screens.composableLocationDetail import com.pixelized.rplexicon.ui.navigation.screens.composableQuestDetail +import com.pixelized.rplexicon.ui.navigation.screens.composableSearch import com.pixelized.rplexicon.ui.navigation.screens.composableSpellDetail import com.pixelized.rplexicon.ui.navigation.screens.composableSummary -import com.pixelized.rplexicon.ui.navigation.screens.navigateToHome +import com.pixelized.rplexicon.ui.navigation.screens.navigateToLanding val LocalScreenNavHost = staticCompositionLocalOf { error("LocalScreenNavHost not ready") @@ -31,10 +32,6 @@ fun ScreenNavHost( navHostController: NavHostController = rememberNavController(), startDestination: String = AUTHENTICATION_ROUTE, ) { - val lexiconListState = rememberLazyListState() - val questListState = rememberLazyListState() - val locationListState = rememberLazyListState() - CompositionLocalProvider( LocalScreenNavHost provides navHostController, ) { @@ -44,22 +41,19 @@ fun ScreenNavHost( ) { composableAuthentication( onSignIn = { - navHostController.navigateToHome(option = rootOption()) + navHostController.navigateToLanding(option = rootOption()) }, ) - composableHome( - lexiconListState = lexiconListState, - questListState = questListState, - locationListState = locationListState, - ) composableLanding() - composableLexiconDetail() composableSearch() + composableLexicon() + composableLexiconDetail() + composableQuests() composableQuestDetail() + composableLocations() composableLocationDetail() composableCharacterSheet() composableSpellDetail() - composableSummary() } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableHome.kt b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableHome.kt deleted file mode 100644 index c329268..0000000 --- a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableHome.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.pixelized.rplexicon.ui.navigation.screens - -import androidx.compose.foundation.lazy.LazyListState -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHostController -import androidx.navigation.NavOptionsBuilder -import com.pixelized.rplexicon.ui.navigation.HomeNavHost -import com.pixelized.rplexicon.ui.navigation.NavigationAnimation -import com.pixelized.rplexicon.ui.navigation.animatedComposable - -private const val ROUTE = "home" - -const val HOME_ROUTE = ROUTE - -fun NavGraphBuilder.composableHome( - lexiconListState: LazyListState, - questListState: LazyListState, - locationListState: LazyListState, -) { - animatedComposable( - route = HOME_ROUTE, - animation = NavigationAnimation.Push, - ) { - HomeNavHost( - lexiconListState = lexiconListState, - questListState = questListState, - locationListState = locationListState, - ) - } -} - -fun NavHostController.navigateToHome( - option: NavOptionsBuilder.() -> Unit = {}, -) { - navigate(route = ROUTE, builder = option) -} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableLexicon.kt b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableLexicon.kt similarity index 67% rename from app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableLexicon.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableLexicon.kt index 14d054b..66c2c9c 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableLexicon.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableLexicon.kt @@ -1,6 +1,5 @@ -package com.pixelized.rplexicon.ui.navigation.pages +package com.pixelized.rplexicon.ui.navigation.screens -import androidx.compose.foundation.lazy.LazyListState import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.NavOptionsBuilder @@ -12,16 +11,12 @@ private const val ROUTE = "lexicon" const val LEXICON_LIST_ROUTE = ROUTE -fun NavGraphBuilder.composableLexicon( - lazyListState: LazyListState, -) { +fun NavGraphBuilder.composableLexicon() { animatedComposable( route = LEXICON_LIST_ROUTE, - animation = NavigationAnimation.Fade, + animation = NavigationAnimation.Push, ) { - LexiconScreen( - lazyListState = lazyListState - ) + LexiconScreen() } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableLocation.kt b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableLocation.kt similarity index 66% rename from app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableLocation.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableLocation.kt index 4d660a2..7cd2131 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableLocation.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableLocation.kt @@ -1,6 +1,5 @@ -package com.pixelized.rplexicon.ui.navigation.pages +package com.pixelized.rplexicon.ui.navigation.screens -import androidx.compose.foundation.lazy.LazyListState import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptionsBuilder @@ -12,16 +11,12 @@ private const val ROUTE = "locations" const val LOCATION_LIST_ROUTE = ROUTE -fun NavGraphBuilder.composableLocations( - lazyListState: LazyListState, -) { +fun NavGraphBuilder.composableLocations() { animatedComposable( route = LOCATION_LIST_ROUTE, - animation = NavigationAnimation.Fade, + animation = NavigationAnimation.Push, ) { - LocationScreen( - lazyListState = lazyListState, - ) + LocationScreen() } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableQuestList.kt b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableQuestList.kt similarity index 66% rename from app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableQuestList.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableQuestList.kt index 39af5e7..8e1ad9d 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/navigation/pages/ComposableQuestList.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/navigation/screens/ComposableQuestList.kt @@ -1,6 +1,5 @@ -package com.pixelized.rplexicon.ui.navigation.pages +package com.pixelized.rplexicon.ui.navigation.screens -import androidx.compose.foundation.lazy.LazyListState import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.NavOptionsBuilder @@ -12,16 +11,12 @@ private const val ROUTE = "quests" const val QUEST_LIST_ROUTE = ROUTE -fun NavGraphBuilder.composableQuests( - lazyListState: LazyListState, -) { +fun NavGraphBuilder.composableQuests() { animatedComposable( route = QUEST_LIST_ROUTE, - animation = NavigationAnimation.Fade, + animation = NavigationAnimation.Push, ) { - QuestListScreen( - lazyListState = lazyListState, - ) + QuestListScreen() } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/authentication/AuthenticationScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/authentication/AuthenticationScreen.kt index 85df76f..cd2a6a6 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/authentication/AuthenticationScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/authentication/AuthenticationScreen.kt @@ -114,7 +114,7 @@ fun AuthenticationScreen( onSignIn = onSignIn, onSignInError = { snack.showSnackbar( - message = it?.message ?: context.getString(R.string.error_generic) + message = it?.message ?: context.getString(R.string.error__generic) ) } ) @@ -172,7 +172,8 @@ private fun AuthenticationScreenContent( } Text( - style = remember { typography.labelSmall.copy(fontStyle = FontStyle.Italic) }, + style = typography.labelSmall, + fontStyle = FontStyle.Italic, text = version.toText(), ) } @@ -353,7 +354,7 @@ private fun rememberBackgroundGradient(): Brush { @Composable private fun rememeberGoogleStringResource(): AnnotatedString { val default = LocalTextStyle.current.toSpanStyle() - val google = stringResource(id = R.string.action_google_sign_in) + val google = stringResource(id = R.string.authentication__google_sign_in_action) return remember { buildAnnotatedString { withStyle( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/GenericHeader.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/GenericHeader.kt index 28f4256..f621540 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/GenericHeader.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/GenericHeader.kt @@ -60,7 +60,7 @@ fun GenericHeader( maxLines = 1, text = annotateWithDropCap( text = stringResource(id = label), - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ), ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellHeader.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellHeader.kt index f66fdac..0c9b414 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellHeader.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellHeader.kt @@ -83,7 +83,7 @@ fun SpellHeader( }, header.level ), - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ), ) header.count?.let { count -> diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/character/DeathHeader.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/character/DeathHeader.kt index 7e1666e..a092d56 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/character/DeathHeader.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/character/DeathHeader.kt @@ -74,7 +74,7 @@ fun DeathHeader( .padding(horizontal = 8.dp), style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Light, - text = stringResource(id = R.string.generic_success), + text = stringResource(id = R.string.character_sheet__death_header__success_label), ) } Icon( @@ -105,7 +105,7 @@ fun DeathHeader( .padding(horizontal = 8.dp), style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Light, - text = stringResource(id = R.string.generic_failure), + text = stringResource(id = R.string.character_sheet__death_header__failure_label), ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillDetail.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillDetail.kt index ae97ac5..748139d 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillDetail.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillDetail.kt @@ -83,7 +83,7 @@ fun SkillDetail( text = detail.name, spanStyles = listOf( AnnotatedString.Range( - item = MaterialTheme.lexicon.typography.titleMediumDropCap, + item = MaterialTheme.lexicon.typography.dropCap.titleMedium, start = 0, end = Integer.min(1, detail.name.length), ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationDetail.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationDetail.kt index 0b753e8..31d6013 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationDetail.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationDetail.kt @@ -82,7 +82,7 @@ fun AlterationDetail( maxLines = 1, text = annotateWithDropCap( text = detail.name, - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ), ) detail.original?.let { diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt index 9c500e7..b0967c8 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt @@ -90,7 +90,7 @@ class AlterationViewModel @Inject constructor( source = alteration.source, target = alteration.target, description = description?.description - ?: context.getString(R.string.no_available_description) + ?: context.getString(R.string.default_missing_description) ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingItem.kt index 29d7c4d..c190872 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingItem.kt @@ -6,14 +6,12 @@ import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -27,10 +25,13 @@ import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.Shape import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -51,85 +52,65 @@ data class LandingItemUio( fun LandingItem( modifier: Modifier = Modifier, item: LandingItemUio, + paddings: PaddingValues = PaddingValues(), + imagePadding: PaddingValues = PaddingValues(all = 16.dp), + shape: Shape = remember { RoundedCornerShape(size = 8.dp) }, rotation: Float = 0f, - ratio: Float = 0.23f, alpha: Float = 0.6f, - padding: PaddingValues = PaddingValues(), - onClick: (LandingItemUio) -> Unit, -) { - LandingHorizontalItem( - modifier = modifier, - item = item, - rotation = rotation, - ratio = ratio, - alpha = alpha, - padding = padding, - onClick = onClick, - ) -} - -@Composable -private fun LandingHorizontalItem( - modifier: Modifier = Modifier, - item: LandingItemUio, - rotation: Float, - ratio: Float, - alpha: Float, - padding: PaddingValues, - onClick: (LandingItemUio) -> Unit, + onClick: () -> Unit, ) { Box( - modifier = modifier.clickable { onClick(item) }, + modifier = Modifier + .clip(shape = shape) + .clickable(onClick = onClick) + .padding(paddingValues = paddings) + .then(other = modifier), + contentAlignment = Alignment.BottomCenter ) { + Image( + modifier = Modifier + .matchParentSize() + .padding(paddingValues = imagePadding) + .rotate(degrees = rotation), + painter = painterResource(id = item.icon), + alpha = alpha, + contentScale = ContentScale.FillHeight, + alignment = Alignment.TopCenter, + colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), + contentDescription = null, + ) + Box( modifier = Modifier - .fillMaxWidth() - .height(height = 48.dp) - .clip(shape = RectangleShape), - ) { - Image( - modifier = Modifier - .padding(paddingValues = padding) - .fillMaxWidth(fraction = ratio) - .aspectRatio(1f) - .rotate(degrees = rotation) - .align(alignment = Alignment.TopEnd), - painter = painterResource(id = item.icon), - alpha = alpha, - contentScale = ContentScale.FillBounds, - colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.onSurface), - contentDescription = null, - ) - Box( - modifier = Modifier - .matchParentSize() - .background(brush = rememberBackgroundGradient()) - ) - } - Row( - modifier = Modifier - .padding(paddingValues = padding) - .align(alignment = Alignment.CenterStart), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + .matchParentSize() + .background(brush = rememberBackgroundGradient()) + ) + + Column( + modifier = Modifier.align(alignment = Alignment.BottomCenter), + horizontalAlignment = Alignment.CenterHorizontally, ) { item.title?.let { Text( - modifier = Modifier.alignByBaseline(), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Normal, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + textAlign = TextAlign.Center, text = annotateWithDropCap( text = it, - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ) ) } item.subTitle?.let { Text( - modifier = Modifier.alignByBaseline(), style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Light, fontStyle = FontStyle.Italic, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + textAlign = TextAlign.Center, text = it, ) } @@ -141,7 +122,7 @@ private fun LandingHorizontalItem( private fun rememberBackgroundGradient(): Brush { val colorScheme = MaterialTheme.colorScheme return remember { - Brush.horizontalGradient( + Brush.verticalGradient( colors = listOf( colorScheme.surface.copy(alpha = 0.5f), colorScheme.surface.copy(alpha = 1.0f), @@ -159,9 +140,8 @@ private fun LandingItemPreview( LexiconTheme { Surface { LandingItem( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.size(256.dp), item = preview, - padding = PaddingValues(horizontal = 16.dp), onClick = { }, ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingScreen.kt index 39920a6..b40addd 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/landing/LandingScreen.kt @@ -2,114 +2,304 @@ package com.pixelized.rplexicon.ui.screens.landing import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES +import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column 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.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.pixelized.rplexicon.R +import com.pixelized.rplexicon.ui.composable.BackgroundImage +import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost +import com.pixelized.rplexicon.ui.navigation.screens.navigateToCharacterSheet +import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexicon +import com.pixelized.rplexicon.ui.navigation.screens.navigateToLocation +import com.pixelized.rplexicon.ui.navigation.screens.navigateToQuestList +import com.pixelized.rplexicon.ui.navigation.screens.navigateToSearch +import com.pixelized.rplexicon.ui.navigation.screens.navigateToSummary import com.pixelized.rplexicon.ui.theme.LexiconTheme +import com.pixelized.rplexicon.utilitary.annotateMajWithDropCap +import com.pixelized.rplexicon.utilitary.extentions.lexicon +import com.pixelized.rplexicon.utilitary.extentions.scrollOffset +import com.pixelized.rplexicon.utilitary.extentions.uri @Composable fun LandingScreen() { + val screen = LocalScreenNavHost.current + Surface( + modifier = Modifier.fillMaxSize() + ) { + LandingContent( + modifier = Modifier + .fillMaxSize() + .navigationBarsPadding(), + padding = PaddingValues( + start = 16.dp, + top = MaterialTheme.lexicon.dimens.detailPadding, + end = 16.dp, + bottom = 16.dp, + ), + onCharacter = { screen.navigateToCharacterSheet(name = it) }, + onSearch = { + screen.navigateToSearch( + enableLexicon = true, + enableQuests = true, + enableLocations = true, + enableSpells = true, + ) + }, + onGameMaster = { screen.navigateToSummary() }, + onLexicon = { screen.navigateToLexicon() }, + onQuest = { screen.navigateToQuestList() }, + onMap = { screen.navigateToLocation() }, + ) + } } @Composable private fun LandingContent( modifier: Modifier = Modifier, - padding: Dp = 16.dp, - items: State>, + padding: PaddingValues = PaddingValues(16.dp), + scrollState: ScrollState = rememberScrollState(), + sectionPadding: Dp = 32.dp, + onCharacter: (String) -> Unit, + onSearch: () -> Unit, + onGameMaster: () -> Unit, + onLexicon: () -> Unit, + onQuest: () -> Unit, + onMap: () -> Unit, ) { - LazyColumn( - modifier = modifier, - contentPadding = PaddingValues(vertical = padding), - verticalArrangement = Arrangement.spacedBy(space = 8.dp), - content = { - items(count = 1) { - Text( - modifier = Modifier.padding(horizontal = padding), - style = MaterialTheme.typography.labelSmall, - fontStyle = FontStyle.Italic, - fontWeight = FontWeight.Light, - text = "Feuilles de personnages", - ) + Box( + modifier = modifier.verticalScroll(scrollState), + ) { + BackgroundImage( + modifier = Modifier + .fillMaxWidth() + .aspectRatio(1f) + .scrollOffset(scrollState) { it / 2 }, + contentScale = ContentScale.Crop, + model = R.drawable.im_naderius.uri, + ) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues = padding), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + Text( + modifier = Modifier.fillMaxWidth(), + style = MaterialTheme.typography.displaySmall, + textAlign = TextAlign.Center, + text = annotateMajWithDropCap( + text = stringResource(id = R.string.landing__title), + style = MaterialTheme.lexicon.typography.dropCap.displaySmall, + ), + ) + + Text( + modifier = Modifier.padding(top = sectionPadding), + style = MaterialTheme.typography.labelSmall, + fontStyle = FontStyle.Italic, + fontWeight = FontWeight.Light, + text = stringResource(id = R.string.landing__caterogy__character), + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(space = 8.dp), + ) { + stringResource(id = R.string.landing__character_brulkhai).let { character -> + LandingItem( + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 8.dp), + item = LandingItemUio( + icon = R.drawable.ic_class_barbarian_24, + title = character, + subTitle = stringResource(id = R.string.class_barbarian), + ), + onClick = { onCharacter(character) }, + ) + } + stringResource(id = R.string.landing__character_leandre).let { character -> + LandingItem( + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 8.dp), + item = LandingItemUio( + icon = R.drawable.ic_class_cleric_24, + title = character, + subTitle = stringResource(id = R.string.class_cleric), + ), + onClick = { onCharacter(character) }, + ) + } + stringResource(id = R.string.landing__character_nelia).let { character -> + LandingItem( + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 8.dp), + item = LandingItemUio( + icon = R.drawable.ic_class_ranger_24, + title = character, + subTitle = stringResource(id = R.string.class_ranger), + ), + onClick = { onCharacter(character) }, + ) + } } - items(items = items.value) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(space = 8.dp), + ) { + stringResource(id = R.string.landing__character_tigrane).let { character -> + LandingItem( + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 8.dp), + item = LandingItemUio( + icon = R.drawable.ic_class_warlock_24, + title = character, + subTitle = stringResource(id = R.string.class_warlock), + ), + onClick = { onCharacter(character) }, + ) + } + stringResource(id = R.string.landing__character_unathana).let { character -> + LandingItem( + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 8.dp), + item = LandingItemUio( + icon = R.drawable.ic_class_bard_24, + title = character, + subTitle = stringResource(id = R.string.class_bard), + ), + onClick = { onCharacter(character) }, + ) + } + Spacer(modifier = Modifier.weight(1f)) + } + + Text( + modifier = Modifier.padding(top = sectionPadding), + style = MaterialTheme.typography.labelSmall, + fontStyle = FontStyle.Italic, + fontWeight = FontWeight.Light, + text = stringResource(id = R.string.landing__caterogy__tools), + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(space = 8.dp), + ) { LandingItem( - modifier = Modifier.fillMaxWidth(), - item = it, - rotation = 270f, - ratio = 0.75f, - alpha = 0.5f, - padding = PaddingValues(horizontal = padding), - onClick = { }, - ) - } - items(count = 1) { - Text( modifier = Modifier - .padding(horizontal = padding) - .padding(top = padding), - style = MaterialTheme.typography.labelSmall, - fontStyle = FontStyle.Italic, - fontWeight = FontWeight.Light, - text = "Encyclopédie", - ) - } - items(count = 1) { - LandingItem( - modifier = Modifier.fillMaxWidth(), + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 24.dp), item = LandingItemUio( - title = "Lexique de personnages", + title = stringResource(id = R.string.summary__title), + subTitle = null, + icon = R.drawable.ic_crowned_skull_24, + ), + onClick = onGameMaster, + ) + LandingItem( + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 24.dp), + item = LandingItemUio( + title = stringResource(id = R.string.default_search_label), + subTitle = null, + icon = R.drawable.ic_baseline_search_24, + ), + onClick = onSearch, + ) + Spacer(modifier = Modifier.weight(1f)) + } + + Text( + modifier = Modifier.padding(top = sectionPadding), + style = MaterialTheme.typography.labelSmall, + fontStyle = FontStyle.Italic, + fontWeight = FontWeight.Light, + text = stringResource(id = R.string.landing__caterogy__encyclopedia), + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(space = 8.dp), + ) { + LandingItem( + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 24.dp), + item = LandingItemUio( + title = stringResource(id = R.string.lexicon_list__title), subTitle = null, icon = R.drawable.ic_visored_helm_24, ), - padding = PaddingValues(horizontal = padding), - onClick = { }, + onClick = onLexicon, ) - } - items(count = 1) { LandingItem( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 24.dp), item = LandingItemUio( - title = "Journal de quêtes", + title = stringResource(id = R.string.quest_list__title), subTitle = null, icon = R.drawable.ic_scroll_unfurled_24, ), - padding = PaddingValues(horizontal = padding), - onClick = { }, + onClick = onQuest, ) - } - items(count = 1) { LandingItem( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .height(128.dp) + .weight(1f), + imagePadding = PaddingValues(all = 24.dp), item = LandingItemUio( - title = "Cartes du monde", + title = stringResource(id = R.string.location_list__title), subTitle = null, icon = R.drawable.ic_treasure_map_24, ), - padding = PaddingValues(horizontal = padding), - onClick = { }, + onClick = onMap, ) } - }, - ) + } + } } @Composable @@ -120,7 +310,12 @@ private fun LandingPreview() { Surface { LandingContent( modifier = Modifier.fillMaxSize(), - items = remember { mutableStateOf(landingItems()) } + onCharacter = { }, + onSearch = { }, + onGameMaster = { }, + onLexicon = { }, + onQuest = { }, + onMap = { }, ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt index e2411e1..f44bec3 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/detail/LexiconDetailScreen.kt @@ -152,7 +152,7 @@ private fun LexiconDetailContent( } }, title = { - Text(text = stringResource(id = R.string.detail_title)) + Text(text = stringResource(id = R.string.lexicon_detail__title)) }, ) }, @@ -191,7 +191,7 @@ private fun LexiconDetailContent( style = typography.base.headlineSmall, text = annotate( text = it, - dropCapRegex styleWith typography.headlineSmallDropCap, + dropCapRegex styleWith typography.dropCap.headlineSmall, highlightRegex styleWith typography.detail.highlightStyle, ), ) @@ -248,7 +248,7 @@ private fun LexiconDetailContent( modifier = Modifier.alignByBaseline(), style = typography.base.bodyMedium, fontWeight = FontWeight.Bold, - text = stringResource(id = R.string.detail_status), + text = stringResource(id = R.string.lexicon_detail__status), ) Text( modifier = Modifier.alignByBaseline(), @@ -270,7 +270,7 @@ private fun LexiconDetailContent( modifier = Modifier.alignByBaseline(), style = typography.base.bodyMedium, fontWeight = FontWeight.Bold, - text = stringResource(id = R.string.detail_location), + text = stringResource(id = R.string.lexicon_detail__location), ) Text( modifier = Modifier.alignByBaseline(), @@ -287,14 +287,14 @@ private fun LexiconDetailContent( Text( modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp), style = typography.base.titleMedium, - text = stringResource(id = R.string.detail_description), + text = stringResource(id = R.string.lexicon_detail__description), ) Text( modifier = Modifier.padding(horizontal = 16.dp), style = typography.base.bodyMedium, text = annotate( text = it, - dropCapRegex styleWith typography.bodyMediumDropCap, + dropCapRegex styleWith typography.dropCap.bodyMedium, highlightRegex styleWith typography.detail.highlightStyle, ), ) @@ -304,14 +304,14 @@ private fun LexiconDetailContent( Text( modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp), style = typography.base.titleMedium, - text = stringResource(id = R.string.detail_history), + text = stringResource(id = R.string.lexicon_detail__history), ) Text( modifier = Modifier.padding(horizontal = 16.dp), style = typography.base.bodyMedium, text = annotate( text = it, - dropCapRegex styleWith typography.bodyMediumDropCap, + dropCapRegex styleWith typography.dropCap.bodyMedium, highlightRegex styleWith typography.detail.highlightStyle, ), ) @@ -322,7 +322,7 @@ private fun LexiconDetailContent( Text( modifier = Modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp), style = typography.base.titleMedium, - text = stringResource(id = R.string.detail_portrait), + text = stringResource(id = R.string.lexicon_detail__portrait), ) LazyRow( contentPadding = PaddingValues(horizontal = 16.dp), diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconItem.kt index 6bb53a0..46f0ec8 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconItem.kt @@ -29,7 +29,6 @@ import androidx.compose.runtime.Stable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -40,6 +39,8 @@ import androidx.compose.ui.unit.dp import com.pixelized.rplexicon.R import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.utilitary.LOS_FULL +import com.pixelized.rplexicon.utilitary.annotateMajWithDropCap +import com.pixelized.rplexicon.utilitary.annotateWithDropCap import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.placeholder @@ -127,18 +128,9 @@ fun LexiconItem( fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, - text = AnnotatedString( + text = annotateWithDropCap( text = item.name, - spanStyles = when (item.placeholder) { - true -> emptyList() - else -> listOf( - AnnotatedString.Range( - item = typography.titleMediumDropCap, - start = 0, - end = 1, - ) - ) - }, + style = typography.dropCap.titleMedium, ), ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconScreen.kt index 2011766..19ae3f6 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items @@ -17,10 +18,14 @@ import androidx.compose.material.pullrefresh.PullRefreshState import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf @@ -29,6 +34,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -39,6 +46,7 @@ import com.pixelized.rplexicon.ui.composable.CategoryHeader import com.pixelized.rplexicon.ui.composable.FloatingActionButton import com.pixelized.rplexicon.ui.composable.Loader import com.pixelized.rplexicon.ui.composable.error.HandleFetchError +import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.navigation.screens.navigateToCharacterSheet import com.pixelized.rplexicon.ui.navigation.screens.navigateToLexiconDetail @@ -53,10 +61,10 @@ import kotlinx.coroutines.launch @Composable fun LexiconScreen( viewModel: LexiconViewModel = hiltViewModel(), - lazyListState: LazyListState, ) { val screen = LocalScreenNavHost.current val scope = rememberCoroutineScope() + val lazyListState = rememberLazyListState() val refresh = rememberPullRefreshState( refreshing = false, onRefresh = { @@ -75,11 +83,17 @@ fun LexiconScreen( modifier = Modifier.fillMaxSize(), ) { LexiconScreenContent( + modifier = Modifier + .fillMaxSize() + .systemBarsPadding(), items = viewModel.items, - lazyColumnState = lazyListState, + lazyListState = lazyListState, refreshState = refresh, refreshing = viewModel.isLoading, isFabExpended = isFabExpended, + onBack = { + screen.popBackStack() + }, onSearch = { screen.navigateToSearch(enableLexicon = true) }, @@ -97,87 +111,110 @@ fun LexiconScreen( } } -@OptIn(ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @Composable private fun LexiconScreenContent( modifier: Modifier = Modifier, - lazyColumnState: LazyListState, + lazyListState: LazyListState, refreshState: PullRefreshState, refreshing: State, items: State>, isFabExpended: State, + onBack: () -> Unit, onSearch: () -> Unit, onItem: (LexiconItemUio) -> Unit, onCharacterSheet: (LexiconItemUio) -> Unit, ) { - Box( + Scaffold( modifier = modifier, - ) { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .pullRefresh(state = refreshState), - state = lazyColumnState, - contentPadding = MaterialTheme.lexicon.dimens.itemListPadding, + containerColor = Color.Transparent, + topBar = { + val shadow = rememberAnimatedShadow(lazyListState) + TopAppBar( + modifier = Modifier.shadow(elevation = shadow.value), + navigationIcon = { + IconButton(onClick = onBack) { + Icon( + painter = painterResource(id = R.drawable.ic_arrow_back_ios_new_24), + contentDescription = null + ) + } + }, + title = { + Text(text = stringResource(id = R.string.lexicon_list__title)) + }, + ) + }, + ) { paddingValues -> + Box( + modifier = Modifier.padding(paddingValues), ) { - items.value.forEachIndexed { index, entry -> - entry.category?.let { - item( - contentType = { "Header" }, + LazyColumn( + modifier = Modifier + .fillMaxSize() + .pullRefresh(state = refreshState), + state = lazyListState, + contentPadding = MaterialTheme.lexicon.dimens.itemListPadding, + ) { + items.value.forEachIndexed { index, entry -> + entry.category?.let { + item( + contentType = { "Header" }, + ) { + CategoryHeader( + modifier = Modifier + .padding(top = if (index == 0) 0.dp else 16.dp) + .padding(horizontal = 16.dp), + text = it, + ) + } + } + items( + items = entry.items, + key = { it.id }, + contentType = { "Lexicon" }, ) { - CategoryHeader( - modifier = Modifier - .padding(top = if (index == 0) 0.dp else 16.dp) - .padding(horizontal = 16.dp), - text = it, + LexiconItem( + item = it, + onItem = onItem, + onCharacterSheet = onCharacterSheet ) } } - items( - items = entry.items, - key = { it.id }, - contentType = { "Lexicon" }, - ) { - LexiconItem( - item = it, - onItem = onItem, - onCharacterSheet = onCharacterSheet - ) - } } - } - AnimatedVisibility( - modifier = Modifier - .padding(all = 16.dp) - .align(Alignment.BottomEnd), - visible = items.value.isNotEmpty(), - enter = fadeIn(), - exit = fadeOut(), - ) { - FloatingActionButton( - expended = isFabExpended.value, - onClick = onSearch, - colors = ButtonDefaults.outlinedButtonColors( - containerColor = MaterialTheme.colorScheme.surface, - ), - icon = { - Icon( - painter = painterResource(id = R.drawable.ic_baseline_search_24), - contentDescription = null, - ) - }, - text = { - Text(text = stringResource(id = R.string.lexicon_search)) - }, + AnimatedVisibility( + modifier = Modifier + .padding(all = 16.dp) + .align(Alignment.BottomEnd), + visible = items.value.isNotEmpty(), + enter = fadeIn(), + exit = fadeOut(), + ) { + FloatingActionButton( + expended = isFabExpended.value, + onClick = onSearch, + colors = ButtonDefaults.outlinedButtonColors( + containerColor = MaterialTheme.colorScheme.surface, + ), + icon = { + Icon( + painter = painterResource(id = R.drawable.ic_baseline_search_24), + contentDescription = null, + ) + }, + text = { + Text(text = stringResource(id = R.string.default_search_label)) + }, + ) + } + + Loader( + modifier = Modifier.align(Alignment.TopCenter), + refreshState = refreshState, + refreshing = refreshing, ) } - - Loader( - modifier = Modifier.align(Alignment.TopCenter), - refreshState = refreshState, - refreshing = refreshing, - ) } } @@ -190,7 +227,7 @@ private fun LexiconScreenContentPreview() { Surface { LexiconScreenContent( modifier = Modifier.fillMaxSize(), - lazyColumnState = rememberLazyListState(), + lazyListState = rememberLazyListState(), refreshState = rememberPullRefreshState( refreshing = false, onRefresh = {}, @@ -198,6 +235,7 @@ private fun LexiconScreenContentPreview() { refreshing = remember { mutableStateOf(false) }, isFabExpended = remember { mutableStateOf(true) }, items = rememberLexiconGroupStatePreview(), + onBack = { }, onSearch = { }, onItem = { }, onCharacterSheet = { }, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt index 53637ac..e360583 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/lexicon/list/LexiconViewModel.kt @@ -53,7 +53,7 @@ class LexiconViewModel @Inject constructor( .groupBy( keySelector = { it.category - ?: context.getString(R.string.default_category_other) + ?: context.getString(R.string.default_category_other_label) }, valueTransform = { item -> LexiconItemUio( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/LocationDetailScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/LocationDetailScreen.kt index 53163a0..ebae578 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/LocationDetailScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/LocationDetailScreen.kt @@ -154,7 +154,7 @@ fun LocationDetailScreen( ) if (result == SnackbarResult.ActionPerformed) { viewModel.clip( - label = context.getString(R.string.map_label), + label = context.getString(R.string.location_detail__coordinates_toast), coordinate = it, ) uriHandler.openUri( @@ -270,7 +270,7 @@ private fun LocationContent( } }, title = { - Text(text = stringResource(id = R.string.map_title)) + Text(text = stringResource(id = R.string.location_detail__title)) }, ) }, @@ -343,7 +343,7 @@ private fun LocationContent( textAlign = TextAlign.Center, text = annotateWithDropCap( text = marquee.value?.name ?: "", - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ) ) } @@ -426,7 +426,7 @@ private fun LocationContent( style = MaterialTheme.typography.headlineSmall, text = annotate( text = item.value?.name ?: "", - dropCapRegex styleWith typography.headlineSmallDropCap, + dropCapRegex styleWith typography.dropCap.headlineSmall, highlightRegex styleWith typography.detail.highlightStyle, ), ) @@ -438,7 +438,7 @@ private fun LocationContent( style = MaterialTheme.typography.bodyMedium, text = annotate( text = it, - dropCapRegex styleWith typography.bodyMediumDropCap, + dropCapRegex styleWith typography.dropCap.bodyMedium, highlightRegex styleWith typography.detail.highlightStyle, ), ) @@ -451,8 +451,8 @@ private fun LocationContent( .padding(horizontal = 16.dp), style = MaterialTheme.typography.titleMedium, text = annotateWithDropCap( - text = stringResource(id = R.string.map_destination), - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + text = stringResource(id = R.string.location_detail__destination), + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ) ) item.value?.marquees?.forEach { @@ -474,7 +474,7 @@ private fun LocationContent( style = MaterialTheme.typography.bodyMedium, text = annotate( text = it.name, - dropCapRegex styleWith typography.bodyMediumDropCap, + dropCapRegex styleWith typography.dropCap.bodyMedium, highlightRegex styleWith typography.detail.highlightStyle, ), ) @@ -491,8 +491,8 @@ private fun LocationContent( .padding(horizontal = 16.dp), style = MaterialTheme.typography.titleMedium, text = annotateWithDropCap( - text = stringResource(id = R.string.map_illustrations), - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + text = stringResource(id = R.string.location_detail__illustrations), + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ) ) LazyRow( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/MarqueeItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/MarqueeItem.kt index 2663279..5a29e54 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/MarqueeItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/detail/MarqueeItem.kt @@ -39,7 +39,7 @@ fun MarqueeItem( maxLines = 3, text = annotateWithDropCap( text = marquee.name, - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ), ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationItem.kt index 5216f4e..5e421af 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationItem.kt @@ -112,7 +112,7 @@ fun LocationItem( true -> emptyList() else -> listOf( AnnotatedString.Range( - item = typography.titleMediumDropCap, + item = typography.dropCap.titleMedium, start = 0, end = 1, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationScreen.kt index 4f0ce1b..82fc943 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationScreen.kt @@ -16,10 +16,14 @@ import androidx.compose.material.pullrefresh.PullRefreshState import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf @@ -28,6 +32,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -38,6 +44,7 @@ import com.pixelized.rplexicon.ui.composable.CategoryHeader import com.pixelized.rplexicon.ui.composable.FloatingActionButton import com.pixelized.rplexicon.ui.composable.Loader import com.pixelized.rplexicon.ui.composable.error.HandleFetchError +import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.navigation.screens.navigateToLocationDetail import com.pixelized.rplexicon.ui.navigation.screens.navigateToSearch @@ -51,10 +58,10 @@ import kotlinx.coroutines.launch @Composable fun LocationScreen( viewModel: LocationViewModel = hiltViewModel(), - lazyListState: LazyListState, ) { val screen = LocalScreenNavHost.current val scope = rememberCoroutineScope() + val lazyListState = rememberLazyListState() val refresh = rememberPullRefreshState( refreshing = false, @@ -75,10 +82,13 @@ fun LocationScreen( ) { LocationContent( items = viewModel.items, - lazyColumnState = lazyListState, + lazyListState = lazyListState, refreshState = refresh, refreshing = viewModel.isLoading, isFabExpended = isFabExpended, + onBack = { + screen.popBackStack() + }, onSearch = { screen.navigateToSearch(enableLocations = true) }, @@ -93,85 +103,108 @@ fun LocationScreen( } } -@OptIn(ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @Composable private fun LocationContent( modifier: Modifier = Modifier, - lazyColumnState: LazyListState, + lazyListState: LazyListState, refreshState: PullRefreshState, refreshing: State, items: State>, isFabExpended: State, + onBack: () -> Unit, onSearch: () -> Unit, onItem: (LocationItemUio) -> Unit, ) { - Box( + Scaffold( modifier = modifier, - contentAlignment = Alignment.TopCenter, - ) { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .pullRefresh(state = refreshState), - state = lazyColumnState, - contentPadding = MaterialTheme.lexicon.dimens.itemListPadding, + containerColor = Color.Transparent, + topBar = { + val shadow = rememberAnimatedShadow(lazyListState) + TopAppBar( + modifier = Modifier.shadow(elevation = shadow.value), + navigationIcon = { + IconButton(onClick = onBack) { + Icon( + painter = painterResource(id = R.drawable.ic_arrow_back_ios_new_24), + contentDescription = null + ) + } + }, + title = { + Text(text = stringResource(id = R.string.location_list__title)) + }, + ) + }, + ) { paddingValues -> + Box( + modifier = Modifier.padding(paddingValues), + contentAlignment = Alignment.TopCenter, ) { - items.value.forEachIndexed { index, entry -> - entry.category?.let { - item( - contentType = { "Header" }, + LazyColumn( + modifier = Modifier + .fillMaxSize() + .pullRefresh(state = refreshState), + state = lazyListState, + contentPadding = MaterialTheme.lexicon.dimens.itemListPadding, + ) { + items.value.forEachIndexed { index, entry -> + entry.category?.let { + item( + contentType = { "Header" }, + ) { + CategoryHeader( + modifier = Modifier + .padding(top = if (index == 0) 0.dp else 16.dp) + .padding(horizontal = 16.dp), + text = it, + ) + } + } + items( + items = entry.maps, + key = { it.id }, + contentType = { "Location" }, ) { - CategoryHeader( - modifier = Modifier - .padding(top = if (index == 0) 0.dp else 16.dp) - .padding(horizontal = 16.dp), - text = it, + LocationItem( + item = it, + onItem = onItem, ) } } - items( - items = entry.maps, - key = { it.id }, - contentType = { "Location" }, - ) { - LocationItem( - item = it, - onItem = onItem, - ) - } } - } - AnimatedVisibility( - modifier = Modifier - .padding(all = 16.dp) - .align(Alignment.BottomEnd), - visible = items.value.isNotEmpty(), - enter = fadeIn(), - exit = fadeOut(), - ) { - FloatingActionButton( - expended = isFabExpended.value, - onClick = onSearch, - colors = ButtonDefaults.outlinedButtonColors( - containerColor = MaterialTheme.colorScheme.surface, - ), - icon = { - Icon( - painter = painterResource(id = R.drawable.ic_baseline_search_24), - contentDescription = null, - ) - }, - text = { - Text(text = stringResource(id = R.string.lexicon_search)) - }, + AnimatedVisibility( + modifier = Modifier + .padding(all = 16.dp) + .align(Alignment.BottomEnd), + visible = items.value.isNotEmpty(), + enter = fadeIn(), + exit = fadeOut(), + ) { + FloatingActionButton( + expended = isFabExpended.value, + onClick = onSearch, + colors = ButtonDefaults.outlinedButtonColors( + containerColor = MaterialTheme.colorScheme.surface, + ), + icon = { + Icon( + painter = painterResource(id = R.drawable.ic_baseline_search_24), + contentDescription = null, + ) + }, + text = { + Text(text = stringResource(id = R.string.default_search_label)) + }, + ) + } + + Loader( + refreshState = refreshState, + refreshing = refreshing, ) } - - Loader( - refreshState = refreshState, - refreshing = refreshing, - ) } } @@ -184,7 +217,7 @@ private fun QuestListPreview() { Surface { LocationContent( modifier = Modifier.fillMaxSize(), - lazyColumnState = rememberLazyListState(), + lazyListState = rememberLazyListState(), refreshState = rememberPullRefreshState( refreshing = false, onRefresh = { }, @@ -212,6 +245,7 @@ private fun QuestListPreview() { ) }, isFabExpended = remember { mutableStateOf(true) }, + onBack = { }, onSearch = { }, onItem = { }, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt index 6c9b3cf..45dd9ad 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/location/list/LocationViewModel.kt @@ -51,7 +51,7 @@ class LocationViewModel @Inject constructor( .groupBy( keySelector = { entry -> entry.category - ?: context.getString(R.string.default_category_other) + ?: context.getString(R.string.default_category_other_label) }, valueTransform = { entry -> LocationItemUio( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt index 8051e25..134ac20 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/detail/QuestDetailScreen.kt @@ -150,7 +150,7 @@ private fun QuestDetailContent( } }, title = { - Text(text = stringResource(id = R.string.quest_detail_title)) + Text(text = stringResource(id = R.string.quest_detail__title)) }, ) }, @@ -160,8 +160,8 @@ private fun QuestDetailContent( ) { Box( modifier = Modifier - .fillMaxWidth() .aspectRatio(ratio = 1f) + .fillMaxWidth() .scrollOffset(scrollState = state) { -it / 2 }, ) { BackgroundImage( @@ -176,7 +176,7 @@ private fun QuestDetailContent( .rotate(degrees = 12f), style = MaterialTheme.lexicon.typography.stamp, color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.35f), - text = stringResource(id = R.string.quest_detail_completed), + text = stringResource(id = R.string.quest_detail__completed), ) } } @@ -203,7 +203,7 @@ private fun QuestDetailContent( style = typography.base.headlineLarge, text = annotate( text = quest?.title ?: "", - dropCapRegex styleWith typography.headlineLargeDropCap, + dropCapRegex styleWith typography.dropCap.headlineLarge, highlightRegex styleWith typography.detail.highlightStyle, ), ) @@ -251,14 +251,14 @@ private fun QuestStep( maxLines = 3, text = annotate( text = it, - dropCapRegex styleWith typography.titleLargeDropCap, + dropCapRegex styleWith typography.dropCap.titleLarge, highlightRegex styleWith typography.detail.highlightStyle, ), ) } quest.giver?.let { SubTitle( - title = stringResource(id = R.string.quest_detail_giver), + title = stringResource(id = R.string.quest_detail__giver), label = annotate( text = when (quest.giverId) { null -> "$LOS_HOLLOW $it" @@ -271,7 +271,7 @@ private fun QuestStep( } quest.place?.let { SubTitle( - title = stringResource(id = R.string.quest_detail_area), + title = stringResource(id = R.string.quest_detail__area), label = annotate( text = when (quest.placeId) { null -> "$LOS_HOLLOW $it" @@ -284,7 +284,7 @@ private fun QuestStep( } quest.globalReward?.let { SubTitle( - title = stringResource(id = R.string.quest_detail_group_reward), + title = stringResource(id = R.string.quest_detail__group_reward), label = annotate( text = "$LOS_HOLLOW $it", highlightRegex styleWith typography.detail.highlightStyle, @@ -293,7 +293,7 @@ private fun QuestStep( } quest.individualReward?.let { SubTitle( - title = stringResource(id = R.string.quest_detail_individual_reward), + title = stringResource(id = R.string.quest_detail__individual_reward), label = annotate( text = "$LOS_HOLLOW $it", highlightRegex styleWith typography.detail.highlightStyle, @@ -305,7 +305,7 @@ private fun QuestStep( style = MaterialTheme.typography.bodyMedium, text = annotate( text = quest.description, - dropCapRegex styleWith typography.bodyMediumDropCap, + dropCapRegex styleWith typography.dropCap.bodyMedium, highlightRegex styleWith typography.detail.highlightStyle, ), ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestItem.kt index 0731b45..9f0cc55 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestItem.kt @@ -115,7 +115,7 @@ fun QuestItem( true -> emptyList() else -> listOf( AnnotatedString.Range( - item = typography.titleMediumDropCap, + item = typography.dropCap.titleMedium, start = 0, end = 1, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt index 1036b66..c65247c 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListScreen.kt @@ -16,10 +16,14 @@ import androidx.compose.material.pullrefresh.PullRefreshState import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf @@ -28,6 +32,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -38,6 +44,7 @@ import com.pixelized.rplexicon.ui.composable.CategoryHeader import com.pixelized.rplexicon.ui.composable.FloatingActionButton import com.pixelized.rplexicon.ui.composable.Loader import com.pixelized.rplexicon.ui.composable.error.HandleFetchError +import com.pixelized.rplexicon.ui.composable.rememberAnimatedShadow import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost import com.pixelized.rplexicon.ui.navigation.screens.navigateToQuestDetail import com.pixelized.rplexicon.ui.navigation.screens.navigateToSearch @@ -51,10 +58,10 @@ import kotlinx.coroutines.launch @Composable fun QuestListScreen( viewModel: QuestListViewModel = hiltViewModel(), - lazyListState: LazyListState, ) { - val scope = rememberCoroutineScope() val screen = LocalScreenNavHost.current + val scope = rememberCoroutineScope() + val lazyListState = rememberLazyListState() val refresh = rememberPullRefreshState( refreshing = false, @@ -75,10 +82,13 @@ fun QuestListScreen( ) { QuestListContent( items = viewModel.items, - lazyColumnState = lazyListState, + lazyListState = lazyListState, refreshState = refresh, refreshing = viewModel.isLoading, isFabExpended = isFabExpended, + onBack = { + screen.popBackStack() + }, onSearch = { screen.navigateToSearch(enableQuests = true) }, @@ -93,83 +103,106 @@ fun QuestListScreen( } } -@OptIn(ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class) @Composable private fun QuestListContent( modifier: Modifier = Modifier, - lazyColumnState: LazyListState, + lazyListState: LazyListState, refreshState: PullRefreshState, refreshing: State, isFabExpended: State, + onBack: () -> Unit, onSearch: () -> Unit, items: State>, onItem: (QuestItemUio) -> Unit, ) { - Box( + Scaffold( modifier = modifier, - contentAlignment = Alignment.TopCenter, - ) { - LazyColumn( - modifier = Modifier - .fillMaxSize() - .pullRefresh(state = refreshState), - state = lazyColumnState, - contentPadding = MaterialTheme.lexicon.dimens.itemListPadding, - ) { - items.value.forEachIndexed { index, entry -> - item( - contentType = { "Header" }, - ) { - CategoryHeader( - modifier = Modifier - .padding(top = if (index == 0) 0.dp else 16.dp) - .padding(horizontal = 16.dp), - text = entry.category, - ) - } - items( - items = entry.quests, - key = { it.id }, - contentType = { "Quest" }, - ) { - QuestItem( - item = it, - onItem = onItem, - ) - } - } - } - - AnimatedVisibility( - modifier = Modifier - .padding(all = 16.dp) - .align(Alignment.BottomEnd), - visible = items.value.isNotEmpty(), - enter = fadeIn(), - exit = fadeOut(), - ) { - FloatingActionButton( - expended = isFabExpended.value, - onClick = onSearch, - colors = ButtonDefaults.outlinedButtonColors( - containerColor = MaterialTheme.colorScheme.surface, - ), - icon = { - Icon( - painter = painterResource(id = R.drawable.ic_baseline_search_24), - contentDescription = null, - ) + containerColor = Color.Transparent, + topBar = { + val shadow = rememberAnimatedShadow(lazyListState) + TopAppBar( + modifier = Modifier.shadow(elevation = shadow.value), + navigationIcon = { + IconButton(onClick = onBack) { + Icon( + painter = painterResource(id = R.drawable.ic_arrow_back_ios_new_24), + contentDescription = null + ) + } }, - text = { - Text(text = stringResource(id = R.string.lexicon_search)) + title = { + Text(text = stringResource(id = R.string.quest_list__title)) }, ) - } + }, + ) { paddingValues -> + Box( + modifier = Modifier.padding(paddingValues), + contentAlignment = Alignment.TopCenter, + ) { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .pullRefresh(state = refreshState), + state = lazyListState, + contentPadding = MaterialTheme.lexicon.dimens.itemListPadding, + ) { + items.value.forEachIndexed { index, entry -> + item( + contentType = { "Header" }, + ) { + CategoryHeader( + modifier = Modifier + .padding(top = if (index == 0) 0.dp else 16.dp) + .padding(horizontal = 16.dp), + text = entry.category, + ) + } + items( + items = entry.quests, + key = { it.id }, + contentType = { "Quest" }, + ) { + QuestItem( + item = it, + onItem = onItem, + ) + } + } + } - Loader( - refreshState = refreshState, - refreshing = refreshing, - ) + AnimatedVisibility( + modifier = Modifier + .padding(all = 16.dp) + .align(Alignment.BottomEnd), + visible = items.value.isNotEmpty(), + enter = fadeIn(), + exit = fadeOut(), + ) { + FloatingActionButton( + expended = isFabExpended.value, + onClick = onSearch, + colors = ButtonDefaults.outlinedButtonColors( + containerColor = MaterialTheme.colorScheme.surface, + ), + icon = { + Icon( + painter = painterResource(id = R.drawable.ic_baseline_search_24), + contentDescription = null, + ) + }, + text = { + Text(text = stringResource(id = R.string.default_search_label)) + }, + ) + } + + Loader( + refreshState = refreshState, + refreshing = refreshing, + ) + } } } @@ -182,7 +215,7 @@ private fun QuestListPreview() { Surface { QuestListContent( modifier = Modifier.fillMaxSize(), - lazyColumnState = rememberLazyListState(), + lazyListState = rememberLazyListState(), refreshState = rememberPullRefreshState( refreshing = false, onRefresh = {}, @@ -218,6 +251,7 @@ private fun QuestListPreview() { ) }, isFabExpended = remember { mutableStateOf(true) }, + onBack = { }, onSearch = { }, onItem = { }, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt index 4817e60..1a6d855 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/quest/list/QuestListViewModel.kt @@ -52,7 +52,7 @@ class QuestListViewModel @Inject constructor( .groupBy( keySelector = { it.category - ?: context.getString(R.string.default_category_other) + ?: context.getString(R.string.default_category_other_label) }, valueTransform = { item -> QuestItemUio( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt index d8855bb..1fd3759 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt @@ -178,7 +178,7 @@ private fun RollOverlayContent( text = it, spanStyles = listOf( AnnotatedString.Range( - item = MaterialTheme.lexicon.typography.titleMediumDropCap, + item = MaterialTheme.lexicon.typography.dropCap.titleMedium, start = 0, end = Integer.min(1, it.length), ) @@ -220,7 +220,7 @@ private fun RollOverlayContent( ) { Text( modifier = Modifier.padding(horizontal = 8.dp), - text = stringResource(id = R.string.action_close), + text = stringResource(id = R.string.roll_overlay__close_action), ) } } @@ -257,6 +257,8 @@ private fun RollOverlayContent( .detailPaddingBottom(showDetail = showDetail, bottom = 128.dp), dice = dice, onDice = onDice, + criticalSuccess = stringResource(id = R.string.roll_overlay__critical_success), + criticalFailure = stringResource(id = R.string.roll_overlay__critical_failure), ) AnimatedVisibility( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt index 3c8a8b7..a077c46 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt @@ -136,7 +136,7 @@ class RollOverlayViewModel @Inject constructor( source = alteration.source, target = alteration.target, description = description?.description - ?: context.getString(R.string.no_available_description) + ?: context.getString(R.string.default_missing_description) ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/RollDice.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/RollDice.kt index 6c170c8..f827ada 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/RollDice.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/RollDice.kt @@ -36,9 +36,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp @@ -72,6 +73,8 @@ fun RollDice( modifier: Modifier = Modifier, diceSize: Dp = 64.dp * 2.5f, dice: State, + criticalSuccess: String, + criticalFailure: String, onDice: () -> Unit, ) { Column( @@ -102,6 +105,8 @@ fun RollDice( Critical( modifier = Modifier.fillMaxWidth(), dice = dice, + criticalSuccess = criticalSuccess, + criticalFailure = criticalFailure, ) } } @@ -160,6 +165,8 @@ private fun Result( private fun Critical( modifier: Modifier = Modifier, dice: State, + criticalSuccess: String, + criticalFailure: String, ) { val state = remember { derivedStateOf { @@ -189,8 +196,8 @@ private fun Critical( else -> MaterialTheme.colorScheme.onSurface }, text = when (it) { - 1 -> stringResource(id = R.string.generic_success_critical) - 2 -> stringResource(id = R.string.generic_failure_critical) + 1 -> criticalSuccess + 2 -> criticalFailure else -> "" }, ) @@ -199,7 +206,9 @@ private fun Critical( @Composable @Preview -private fun SkillRollPreview() { +private fun SkillRollPreview( + @PreviewParameter(SkillRollPreviewProvider::class) preview: Int, +) { LexiconTheme { Surface { RollDice( @@ -208,13 +217,20 @@ private fun SkillRollPreview() { RollDiceUio( icon = R.drawable.ic_d20_24, rotation = 0f, - isCriticalSuccess = true, - result = "20", + isCriticalSuccess = preview == 20, + isCriticalFailure = preview == 1, + result = "$preview", ) ) }, + criticalSuccess = "CRITICAL SUCCESS", + criticalFailure = "CRITICAL FAILURE", onDice = { }, ) } } +} + +private class SkillRollPreviewProvider : PreviewParameterProvider { + override val values: Sequence = sequenceOf(1, 14, 20) } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchFilter.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchFilter.kt index ce0cb6a..2877a2d 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchFilter.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/SearchFilter.kt @@ -31,21 +31,21 @@ sealed class SearchFilterUio( class Lexicon( selected: State = mutableStateOf(true), ) : SearchFilterUio( - label = R.string.home_lexicon, + label = R.string.lexicon_list__title, selected = selected, ) class Quest( selected: State = mutableStateOf(true), ) : SearchFilterUio( - label = R.string.home_quest_log, + label = R.string.quest_list__title, selected = selected, ) class Location( selected: State = mutableStateOf(true), ) : SearchFilterUio( - label = R.string.home_location, + label = R.string.location_list__title, selected = selected, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/item/LexiconSearchItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/item/LexiconSearchItem.kt index e947719..084c228 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/item/LexiconSearchItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/search/item/LexiconSearchItem.kt @@ -122,7 +122,7 @@ private fun LexiconSearchItemPreview() { category = AnnotatedString(text = "Lexique $PUC_FULL Personnage joueur"), name = annotateWithDropCap( text = "Brulkhai", - style = MaterialTheme.lexicon.typography.titleMediumDropCap, + style = MaterialTheme.lexicon.typography.dropCap.titleMedium, ), diminutive = AnnotatedString( text = "Bru" diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/spell/SpellDetailScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/spell/SpellDetailScreen.kt index 17cbb76..6f69235 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/spell/SpellDetailScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/spell/SpellDetailScreen.kt @@ -147,7 +147,7 @@ private fun SpellDetailContent( style = typography.base.headlineSmall, text = annotate( text = detail.name, - dropCapRegex styleWith typography.headlineSmallDropCap, + dropCapRegex styleWith typography.dropCap.headlineSmall, highlightRegex styleWith typography.detail.highlightStyle, ), ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt index 188847b..85785d5 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt @@ -189,7 +189,7 @@ private fun SummaryContent( ) } Text( - text = stringResource(id = R.string.summary_title), + text = stringResource(id = R.string.summary__title), style = MaterialTheme.typography.titleLarge, ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt index 48421a8..d20d88f 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt @@ -4,7 +4,6 @@ import android.app.Application import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.AndroidViewModel -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.pixelized.rplexicon.R import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository @@ -20,7 +19,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.lang.Appendable import javax.inject.Inject @HiltViewModel @@ -76,7 +74,7 @@ class StatisticViewModel @Inject constructor( source = alteration.source, target = alteration.target, description = description?.description - ?: context.getString(R.string.no_available_description) + ?: context.getString(R.string.default_missing_description) ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/theme/typography/LexiconTypography.kt b/app/src/main/java/com/pixelized/rplexicon/ui/theme/typography/LexiconTypography.kt index caf32c8..09f9c28 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/theme/typography/LexiconTypography.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/theme/typography/LexiconTypography.kt @@ -29,11 +29,7 @@ val stampFontFamily = FontFamily( data class LexiconTypography( val base: Typography, val stamp: TextStyle, - val bodyMediumDropCap: SpanStyle, // TODO DropCap class - val titleMediumDropCap: SpanStyle, // TODO DropCap class - val titleLargeDropCap: SpanStyle, // TODO DropCap class - val headlineSmallDropCap: SpanStyle, // TODO DropCap class - val headlineLargeDropCap: SpanStyle, // TODO DropCap class + val dropCap: DropCapTypography, val detail: Detail, val search: Search, ) { @@ -52,37 +48,113 @@ data class LexiconTypography( val extractHighlight: SpanStyle, val extractBold: SpanStyle, ) + + @Stable + data class DropCapTypography( + val displayLarge: SpanStyle, + val displayMedium: SpanStyle, + val displaySmall: SpanStyle, + val headlineLarge: SpanStyle, + val headlineMedium: SpanStyle, + val headlineSmall: SpanStyle, + val titleLarge: SpanStyle, + val titleMedium: SpanStyle, + val titleSmall: SpanStyle, + val bodyLarge: SpanStyle, + val bodyMedium: SpanStyle, + val bodySmall: SpanStyle, + val labelLarge: SpanStyle, + val labelMedium: SpanStyle, + val labelSmall: SpanStyle, + ) { + constructor(base: Typography) : this( + displayLarge = base.displayLarge.toDropCapSpan( + sizeRatio = 1.6f, + antiLetterSpacing = 4.sp, + baselineShift = BaselineShift(-0.07f), + ), + displayMedium = base.displayMedium.toDropCapSpan( + sizeRatio = 1.6f, + antiLetterSpacing = 4.sp, + baselineShift = BaselineShift(-0.08f), + ), + displaySmall = base.displaySmall.toDropCapSpan( + // never used + sizeRatio = 1.6f, + antiLetterSpacing = 4.sp, + baselineShift = BaselineShift(-0.07f), + ), + headlineLarge = base.headlineLarge.toDropCapSpan( + sizeRatio = 1.7f, + antiLetterSpacing = 4.sp, + baselineShift = BaselineShift(-0.06f), + ), + headlineMedium = base.headlineMedium.toDropCapSpan( + sizeRatio = 1.8f, + antiLetterSpacing = 4.sp, + baselineShift = BaselineShift(-0.06f), + ), + headlineSmall = base.headlineSmall.toDropCapSpan( + sizeRatio = 1.9f, + antiLetterSpacing = 4.sp, + baselineShift = BaselineShift(-0.06f), + ), + titleLarge = base.titleLarge.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 2.sp, + baselineShift = BaselineShift(-0.05f), + ), + titleMedium = base.titleMedium.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 2.sp, + baselineShift = BaselineShift(-0.06f), + ), + titleSmall = base.titleSmall.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 2.sp, + baselineShift = BaselineShift(-0.06f), + ), + bodyLarge = base.bodyLarge.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 1.sp, + baselineShift = BaselineShift(-0.1f), + ), + bodyMedium = base.bodyMedium.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 1.sp, + baselineShift = BaselineShift(-0.09f), + ), + bodySmall = base.bodySmall.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 1.sp, + baselineShift = BaselineShift(-0.09f), + ), + labelLarge = base.labelLarge.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 1.sp, + baselineShift = BaselineShift(-0.07f), + ), + labelMedium = base.labelMedium.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 1.sp, + baselineShift = BaselineShift(-0.1f), + ), + labelSmall = base.labelSmall.toDropCapSpan( + sizeRatio = 2f, + antiLetterSpacing = 1.sp, + baselineShift = BaselineShift(-0.1f), + ), + ) + } } fun lexiconTypography( colorScheme: LexiconColors, base: Typography = Typography(), + dropCap: LexiconTypography.DropCapTypography = LexiconTypography.DropCapTypography(base), stamp: TextStyle = base.headlineLarge.copy( fontFamily = stampFontFamily, ), - bodyMediumDropCap: SpanStyle = base.bodyMedium.toDropCapSpan( - sizeRatio = 2f, - antiLetterSpacing = 1.sp, - baselineShift = BaselineShift(-0.1f), - ), - titleMediumDropCap: SpanStyle = base.titleMedium.toDropCapSpan( - sizeRatio = 2f, - antiLetterSpacing = 2.sp, - baselineShift = BaselineShift(-0.05f), - ), - titleLargeDropCap: SpanStyle = base.titleLarge.toDropCapSpan( - sizeRatio = 2f, - antiLetterSpacing = 2.sp, - baselineShift = BaselineShift(-0.05f), - ), - headlineSmallDropCap: SpanStyle = base.headlineSmall.toDropCapSpan( - sizeRatio = 1.8f, - antiLetterSpacing = 4.sp, - ), - headlineLargeDropCap: SpanStyle = base.headlineLarge.toDropCapSpan( - sizeRatio = 1.6f, - antiLetterSpacing = 4.sp, - ), detail: LexiconTypography.Detail = LexiconTypography.Detail( highlightStyle = SpanStyle(color = colorScheme.search.highlight), ), @@ -113,12 +185,8 @@ fun lexiconTypography( ), ): LexiconTypography = LexiconTypography( base = base, + dropCap = dropCap, stamp = stamp, - bodyMediumDropCap = bodyMediumDropCap, - titleMediumDropCap = titleMediumDropCap, - titleLargeDropCap = titleLargeDropCap, - headlineSmallDropCap = headlineSmallDropCap, - headlineLargeDropCap = headlineLargeDropCap, detail = detail, search = search, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/AnnotatedStringHelper.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/AnnotatedStringHelper.kt index a8a8361..44895dc 100644 --- a/app/src/main/java/com/pixelized/rplexicon/utilitary/AnnotatedStringHelper.kt +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/AnnotatedStringHelper.kt @@ -21,8 +21,12 @@ private val List.extractSentencePattern: String private val dropCapPattern: String get() = "(?:^|\n\n)([A-Z])" +private val majCapsPattern: String + get() = "[A-Z]" + // Specific optimization for the DropCap regex. private val dropCapRegex = Regex(pattern = dropCapPattern) +private val majCapsRegex = Regex(pattern = majCapsPattern) @Immutable @Stable @@ -73,6 +77,15 @@ fun annotateWithDropCap( dropCapRegex styleWith style, ) +@Stable +fun annotateMajWithDropCap( + text: String, + style: SpanStyle, +) = annotate( + text = text, + majCapsRegex styleWith style, +) + @Stable fun dropCapRegex(): Regex = dropCapRegex diff --git a/app/src/main/res/drawable/im_naderius.webp b/app/src/main/res/drawable/im_naderius.webp new file mode 100644 index 0000000..bb1c93f Binary files /dev/null and b/app/src/main/res/drawable/im_naderius.webp differ diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 65086b8..8bf21c7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,29 +1,29 @@ Rp-Compagnon - Fermer - Autres + Fermer + Autres - Une erreur s\'est produite. - La structure des données semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille d\'actions semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille d\'altération semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille des personnages semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille de description semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille d\'équipement semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille d\'inventaire semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille d\'actions (object) semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille des talents semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille des sorts semble avoir changé et n\'est plus compatible avec cette application. - La structure de la feuille d\'ordre des catégories semble avoir changé et n\'est plus compatible avec cette application. - La structure du lexique semble avoir changé et n\'est plus compatible avec cette application. - La structure des cartes semble avoir changé et n\'est plus compatible avec cette application. - La structure des quêtes semble avoir changé et n\'est plus compatible avec cette application. + Une erreur s\'est produite. + La structure des données semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'actions semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'altération semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille des personnages semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille de description semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'équipement semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'inventaire semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'actions (object) semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille des talents semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille des sorts semble avoir changé et n\'est plus compatible avec cette application. + La structure de la feuille d\'ordre des catégories semble avoir changé et n\'est plus compatible avec cette application. + La structure du lexique semble avoir changé et n\'est plus compatible avec cette application. + La structure des cartes semble avoir changé et n\'est plus compatible avec cette application. + La structure des quêtes semble avoir changé et n\'est plus compatible avec cette application. - Succès - SUCCÈS CRITIQUE - Échec - ÉCHEC CRITIQUE + Succès + SUCCÈS CRITIQUE + Échec + ÉCHEC CRITIQUE Abjuration Divination @@ -34,20 +34,33 @@ Nécromancie Transmutation - Se connecter avec + Barbare + Barde + Clerc + Druide + Guerrier + Moine + Paladin + Rôdeur + Roublard + Ensorceleur + Occultiste + Magicien - Lexique - Journal de quêtes - Cartes + Se connecter avec - Rechercher + Lexique + Journal de quêtes + Cartes - Détails du personnage - Description : - Statut : - Localisation : - Histoire : - Portrait : + Rechercher + + Détails du personnage + Description : + Statut : + Localisation : + Histoire : + Portrait : Rechercher Lexique @@ -74,17 +87,17 @@ Durée : Description : - Détails de quête - Complétée - Commanditaire : - Lieu : - Récompense individuelle : - Récompense de groupe : + Détails de quête + Complétée + Commanditaire : + Lieu : + Récompense individuelle : + Récompense de groupe : - Carte - Coordonnées - Destinations : - Illustrations : + Carte + Coordonnées + Destinations : + Illustrations : Rafraichir Talents @@ -199,7 +212,7 @@ Source : %1$s Cible : %1$s - Aucune description disponnible + Aucune description disponnible Tête Visage @@ -216,4 +229,9 @@ Main droite Main gauche Aucune description n\'est attachée à cet equipement + + Game Master + Feuilles de personnage + Encyclopédie + Outils \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1128384..85bd73e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,29 +1,25 @@ Rp-Companion - Close - Others + An error occurred. + The file structure appears to have changed and is no longer compatible with this application + The action sheet structure appears to have changed and is no longer compatible with this application + The alteration sheet structure appears to have changed and is no longer compatible with this application + The character sheet structure appears to have changed and is no longer compatible with this application + The description sheet structure appears to have changed and is no longer compatible with this application + The equipment sheet structure appears to have changed and is no longer compatible with this application + The inventory sheet structure appears to have changed and is no longer compatible with this application + The objects sheet structure appears to have changed and is no longer compatible with this application + The skill sheet structure appears to have changed and is no longer compatible with this application + The spell sheet structure appears to have changed and is no longer compatible with this application + The category order sheet structure appears to have changed and is no longer compatible with this application + The lexicon sheet structure appears to have changed and is no longer compatible with this application + The location sheet structure appears to have changed and is no longer compatible with this application + The quest sheet structure appears to have changed and is no longer compatible with this application - An error occurred. - The file structure appears to have changed and is no longer compatible with this application - The action sheet structure appears to have changed and is no longer compatible with this application - The alteration sheet structure appears to have changed and is no longer compatible with this application - The character sheet structure appears to have changed and is no longer compatible with this application - The description sheet structure appears to have changed and is no longer compatible with this application - The equipment sheet structure appears to have changed and is no longer compatible with this application - The inventory sheet structure appears to have changed and is no longer compatible with this application - The objects sheet structure appears to have changed and is no longer compatible with this application - The skill sheet structure appears to have changed and is no longer compatible with this application - The spell sheet structure appears to have changed and is no longer compatible with this application - The category order sheet structure appears to have changed and is no longer compatible with this application - The lexicon sheet structure appears to have changed and is no longer compatible with this application - The location sheet structure appears to have changed and is no longer compatible with this application - The quest sheet structure appears to have changed and is no longer compatible with this application - - Success - CRITICAL SUCCESS - Failure - CRITICAL FAILURE + Others + Search + No available description Abjuration Divination @@ -34,20 +30,52 @@ Necromancy Transmutation - Sign in with + Barbarian + Bard + Cleric + Druid + Fighter + Monk + Paladin + Ranger + Rogue + Sorcerer + Warlock + Wizard - Lexicon - Quest logs - Location + Sign in with - Search + Curse of Strahd + Character\'s sheets + Tools + Encyclopedia + Brulkhai + Léandre + Nelia + Tigrane + Unathana - Character\'s details - Description: - Status: - Location: - History: - Portrait: + Lexicon + Character\'s details + Description: + Status: + Location: + History: + Portrait: + + Quest logs + Quest details + Completed + Quest giver: + Area: + Individual reward: + Group reward: + + Location + Map + Destinations: + Illustrations: + Coordinates Search Lexicon @@ -74,17 +102,8 @@ Duration: Description: - Quest details - Completed - Quest giver: - Area: - Individual reward: - Group reward: - - Map - Coordinates - Destinations: - Illustrations: + Success + Failure Refresh Proficiencies @@ -162,6 +181,10 @@ Cantrip Spell level %1$s + Close + CRITICAL SUCCESS + CRITICAL FAILURE + %1$s proficiency %1$s expertise Saving throw @@ -199,8 +222,6 @@ Source: %1$s Target: %1$s - No available description - Head face Shoulder @@ -217,8 +238,5 @@ Off hand This equipment does not have any description - Game Master - Statistic - Combat - Rolls + Game Master \ No newline at end of file