Change the system theme + filter bottomsheet

This commit is contained in:
Thomas Andres Gomez 2023-04-07 15:05:12 +02:00
parent 785e181482
commit 7cc08cf300
19 changed files with 387 additions and 147 deletions

View file

@ -9,7 +9,6 @@ import androidx.compose.material.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import com.pixelized.biblib.ui.composable.SystemThemeColor
import com.pixelized.biblib.ui.screen.launch.LauncherViewModel import com.pixelized.biblib.ui.screen.launch.LauncherViewModel
import com.pixelized.biblib.ui.theme.BibLibTheme import com.pixelized.biblib.ui.theme.BibLibTheme
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -48,12 +47,10 @@ class MainActivity : ComponentActivity() {
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
BibLibTheme { BibLibTheme {
SystemThemeColor { Surface(
Surface( color = MaterialTheme.colors.surface,
color = MaterialTheme.colors.surface, content = content,
content = content, )
)
}
} }
} }
} }

View file

@ -0,0 +1,29 @@
package com.pixelized.biblib.ui.composable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import com.pixelized.biblib.utils.extention.bibLib
@Composable
fun Handle(
modifier: Modifier = Modifier,
width: Dp = MaterialTheme.bibLib.dimen.handle.width,
thickness: Dp = MaterialTheme.bibLib.dimen.handle.thickness,
color: Color = MaterialTheme.bibLib.colors.handle,
shape: Shape = CircleShape
) = Box(
modifier = modifier
.size(width = width, height = thickness)
.background(
color = color,
shape = shape,
)
)

View file

@ -0,0 +1,139 @@
package com.pixelized.biblib.ui.composable
import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import com.google.accompanist.systemuicontroller.SystemUiController
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.pixelized.biblib.utils.extention.navigationBarsHeight
import com.pixelized.biblib.utils.extention.statusBarsHeight
val LocalStatusTheme = staticCompositionLocalOf<StatusThemeController> {
error("LocalStatusTheme is not ready yet.")
}
class StatusThemeController(
private val systemController: SystemUiController,
private val statusBackground: MutableState<Brush>,
private var statusDarkIcons: Boolean,
private val navigationBackground: MutableState<Brush>,
private var navigationDarkIcons: Boolean,
) {
init {
systemController.setStatusBarColor(
color = Color.Transparent,
darkIcons = statusDarkIcons,
)
systemController.setNavigationBarColor(
color = Color.Transparent,
darkIcons = navigationDarkIcons,
navigationBarContrastEnforced = false,
)
}
fun updateStatusTheme(
statusBackground: Brush = this.statusBackground.value,
statusDarkIcons: Boolean = this.statusDarkIcons,
navigationBackground: Brush = this.navigationBackground.value,
navigationDarkIcons: Boolean = this.navigationDarkIcons,
) {
if (this.statusDarkIcons != statusDarkIcons) {
this.statusDarkIcons = statusDarkIcons
systemController.setStatusBarColor(
color = Color.Transparent,
darkIcons = statusDarkIcons,
)
}
if (this.statusBackground.value != statusBackground) {
this.statusBackground.value = statusBackground
}
if (navigationDarkIcons != this.navigationDarkIcons) {
this.navigationDarkIcons = navigationDarkIcons
systemController.setNavigationBarColor(
color = Color.Transparent,
darkIcons = navigationDarkIcons,
navigationBarContrastEnforced = false,
)
}
if (this.navigationBackground.value != navigationBackground) {
this.statusBackground.value = navigationBackground
}
}
}
@Composable
fun SystemTheme(
systemController: SystemUiController = rememberSystemUiController(),
statusBackground: Color,
statusDarkIcons: Boolean,
navigationBackground: Color,
navigationDarkIcons: Boolean,
content: @Composable () -> Unit,
) {
val statusBackgroundState = remember {
mutableStateOf(
Brush.verticalGradient(
colors = listOf(statusBackground, Color.Transparent)
)
)
}
val navigationBackgroundState = remember {
mutableStateOf(
Brush.verticalGradient(
colors = listOf(Color.Transparent, navigationBackground)
)
)
}
val statusController = remember(systemController) {
StatusThemeController(
systemController = systemController,
statusBackground = statusBackgroundState,
statusDarkIcons = statusDarkIcons,
navigationBackground = navigationBackgroundState,
navigationDarkIcons = navigationDarkIcons,
)
}
CompositionLocalProvider(
LocalStatusTheme provides statusController,
) {
Box(
modifier = Modifier.fillMaxSize(),
) {
content()
Overlay(
height = statusBarsHeight(),
brush = statusBackgroundState,
)
Overlay(
modifier = Modifier.align(Alignment.BottomStart),
height = navigationBarsHeight(),
brush = navigationBackgroundState,
)
}
}
}
@Composable
private fun Overlay(
modifier: Modifier = Modifier,
height: Dp,
brush: State<Brush>,
) {
Box(
modifier = modifier
.height(height = height)
.fillMaxWidth()
.background(brush = brush.value)
)
}

View file

@ -1,36 +0,0 @@
package com.pixelized.biblib.ui.composable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.graphics.Color
import com.google.accompanist.systemuicontroller.SystemUiController
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.pixelized.biblib.ui.theme.color.ShadowPalette
val LocalSystemUiController = compositionLocalOf<SystemUiController> { error("") }
@Composable
fun SystemThemeColor(
systemUiController: SystemUiController = rememberSystemUiController(),
color: Color = ShadowPalette.system,
statusDarkIcons: Boolean = false,
navigationDarkIcons: Boolean = false,
content: @Composable () -> Unit,
) {
CompositionLocalProvider(LocalSystemUiController provides systemUiController) {
SideEffect {
systemUiController.setStatusBarColor(
color = color,
darkIcons = statusDarkIcons,
)
systemUiController.setNavigationBarColor(
color = color,
darkIcons = navigationDarkIcons,
navigationBarContrastEnforced = false,
)
}
content()
}
}

View file

@ -0,0 +1,18 @@
package com.pixelized.biblib.ui.composable
import androidx.compose.material.LocalAbsoluteElevation
import androidx.compose.material.LocalElevationOverlay
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
@Composable
fun colorElevation(
base: Color = MaterialTheme.colors.surface,
elevation: Dp,
): Color {
val localElevation = LocalElevationOverlay.current
val absoluteElevation = LocalAbsoluteElevation.current
return localElevation?.apply(color = base, elevation = absoluteElevation + elevation) ?: base
}

View file

@ -2,18 +2,18 @@ package com.pixelized.biblib.ui.composable.scaffold
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.*
import androidx.compose.material.ModalBottomSheetLayout
import androidx.compose.material.ModalBottomSheetState
import androidx.compose.material.ModalBottomSheetValue.Hidden import androidx.compose.material.ModalBottomSheetValue.Hidden
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -26,6 +26,8 @@ import com.pixelized.biblib.ui.screen.home.filter.viewModel.AuthorFilterViewMode
import com.pixelized.biblib.ui.screen.home.filter.viewModel.GenreFilterViewModel import com.pixelized.biblib.ui.screen.home.filter.viewModel.GenreFilterViewModel
import com.pixelized.biblib.ui.screen.home.filter.viewModel.LanguageFilterViewModel import com.pixelized.biblib.ui.screen.home.filter.viewModel.LanguageFilterViewModel
import com.pixelized.biblib.ui.screen.home.filter.viewModel.SeriesFilterViewModel import com.pixelized.biblib.ui.screen.home.filter.viewModel.SeriesFilterViewModel
import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.statusBarsHeight
import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -102,6 +104,7 @@ fun FilterBottomSheet(
skipHalfExpanded = true, skipHalfExpanded = true,
), ),
sheetState: FilterBottomSheetState = rememberFilterBottomSheetState(), sheetState: FilterBottomSheetState = rememberFilterBottomSheetState(),
sheetShape: Shape = MaterialTheme.bibLib.shapes.filterSheet,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
CompositionLocalProvider( CompositionLocalProvider(
@ -134,47 +137,53 @@ fun FilterBottomSheet(
onBack = { currentBottomSheetData?.dismiss() }, onBack = { currentBottomSheetData?.dismiss() },
) )
ModalBottomSheetLayout( BoxWithConstraints {
sheetState = bottomSheetState, val statusBarHeight = statusBarsHeight()
content = content, val bottomSheetHeight = remember(statusBarHeight) {
scrimColor = Color.Transparent, maxHeight - statusBarHeight - 16.dp
sheetContent = { }
val viewModel: IFilterViewModel? = when (sheetState.type) {
FilterType.Author -> hiltViewModel<AuthorFilterViewModel>()
FilterType.Series -> hiltViewModel<SeriesFilterViewModel>()
FilterType.Genre -> hiltViewModel<GenreFilterViewModel>()
FilterType.Language -> hiltViewModel<LanguageFilterViewModel>()
else -> null
}
if (viewModel != null) { ModalBottomSheetLayout(
val focusRequester = remember { FocusRequester() } sheetState = bottomSheetState,
sheetShape = sheetShape,
FilterPage( content = content,
viewModel = viewModel, scrimColor = Color.Transparent,
focusRequester = focusRequester, sheetContent = {
onFilter = { val viewModel: IFilterViewModel? = when (sheetState.type) {
currentBottomSheetData?.performAction(filter = it) FilterType.Author -> hiltViewModel<AuthorFilterViewModel>()
}, FilterType.Series -> hiltViewModel<SeriesFilterViewModel>()
onClose = { FilterType.Genre -> hiltViewModel<GenreFilterViewModel>()
currentBottomSheetData?.dismiss() FilterType.Language -> hiltViewModel<LanguageFilterViewModel>()
}, else -> null
onIMEDone = {
currentBottomSheetData?.dismiss()
}
)
LaunchedEffect(key1 = "FilterPageFocusRequest-${sheetState.type}") {
if (currentBottomSheetData != null) {
focusRequester.requestFocus()
keyboard?.show()
}
} }
} else { if (viewModel != null) {
Box(modifier = Modifier.height(1.dp)) val focusRequester = remember { FocusRequester() }
}
}, FilterPage(
) modifier = Modifier
.fillMaxWidth()
.height(bottomSheetHeight),
viewModel = viewModel,
focusRequester = focusRequester,
onFilter = {
currentBottomSheetData?.performAction(filter = it)
},
onIMEDone = {
currentBottomSheetData?.dismiss()
}
)
LaunchedEffect(key1 = "FilterPageFocusRequest-${sheetState.type}") {
if (currentBottomSheetData != null) {
focusRequester.requestFocus()
keyboard?.show()
}
}
} else {
Box(modifier = Modifier.height(1.dp))
}
},
)
}
} }
} }

View file

@ -42,6 +42,7 @@ import com.pixelized.biblib.model.search.FilterType
import com.pixelized.biblib.model.search.SortType import com.pixelized.biblib.model.search.SortType
import com.pixelized.biblib.model.search.SortValue import com.pixelized.biblib.model.search.SortValue
import com.pixelized.biblib.ui.LocalSnackHostState import com.pixelized.biblib.ui.LocalSnackHostState
import com.pixelized.biblib.ui.composable.colorElevation
import com.pixelized.biblib.ui.composable.scaffold.* import com.pixelized.biblib.ui.composable.scaffold.*
import com.pixelized.biblib.ui.navigation.LocalScreenNavHostController import com.pixelized.biblib.ui.navigation.LocalScreenNavHostController
import com.pixelized.biblib.ui.navigation.navigateToProfile import com.pixelized.biblib.ui.navigation.navigateToProfile
@ -444,14 +445,10 @@ private fun HomeToolbar(
onAvatarTap: () -> Unit, onAvatarTap: () -> Unit,
) { ) {
val direction = LocalLayoutDirection.current val direction = LocalLayoutDirection.current
val elevation = LocalElevationOverlay.current
Surface( Surface(
modifier = modifier, modifier = modifier,
shape = CircleShape, shape = CircleShape,
color = elevation?.apply( color = colorElevation(elevation = 1.dp),
MaterialTheme.colors.surface,
LocalAbsoluteElevation.current + 1.dp
) ?: MaterialTheme.colors.surface,
) { ) {
Row( Row(
modifier = Modifier.padding( modifier = Modifier.padding(

View file

@ -36,6 +36,7 @@ import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import com.pixelized.biblib.R import com.pixelized.biblib.R
import com.pixelized.biblib.ui.composable.Handle
import com.pixelized.biblib.ui.composable.SpannedText import com.pixelized.biblib.ui.composable.SpannedText
import com.pixelized.biblib.ui.composable.animation.AnimatedDelayer import com.pixelized.biblib.ui.composable.animation.AnimatedDelayer
import com.pixelized.biblib.ui.composable.animation.AnimatedOffset import com.pixelized.biblib.ui.composable.animation.AnimatedOffset
@ -117,6 +118,7 @@ fun DetailScreenContent(
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(all = 16.dp) .padding(all = 16.dp)
.systemBarsPadding(), .systemBarsPadding(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
Column( Column(
@ -148,7 +150,6 @@ fun DetailScreenContent(
AnimatedOffset { AnimatedOffset {
Column( Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Text( Text(
@ -161,7 +162,7 @@ fun DetailScreenContent(
Text( Text(
modifier = Modifier.clickable(onClick = { onSeries(series) }), modifier = Modifier.clickable(onClick = { onSeries(series) }),
style = MaterialTheme.typography.body1, style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.onSurface, color = MaterialTheme.bibLib.colors.typography.emphasis,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
text = series.label, text = series.label,
) )
@ -171,15 +172,14 @@ fun DetailScreenContent(
AnimatedOffset { AnimatedOffset {
Column( Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
book.authors.forEach { author -> book.authors.forEach { author ->
Text( Text(
modifier = Modifier.clickable(onClick = { onAuthor(author) }), modifier = Modifier.clickable(onClick = { onAuthor(author) }),
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Normal,
style = MaterialTheme.typography.h6, style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onSurface, color = MaterialTheme.bibLib.colors.typography.emphasis,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
text = author.name, text = author.name,
) )

View file

@ -1,5 +1,10 @@
package com.pixelized.biblib.ui.screen.home.filter package com.pixelized.biblib.ui.screen.home.filter
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@ -8,24 +13,27 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Clear
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.Immutable import androidx.compose.ui.Alignment
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.items import androidx.paging.compose.items
import com.pixelized.biblib.R
import com.pixelized.biblib.model.search.FilterType import com.pixelized.biblib.model.search.FilterType
import com.pixelized.biblib.ui.composable.Handle
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.imeHeight
import com.pixelized.biblib.utils.extention.navigationBarsHeight
import kotlinx.coroutines.flow.emptyFlow
@Stable @Stable
@Immutable @Immutable
@ -37,26 +45,23 @@ data class FilterItemUio(
@Composable @Composable
fun FilterPage( fun FilterPage(
modifier: Modifier,
viewModel: IFilterViewModel, viewModel: IFilterViewModel,
focusRequester: FocusRequester, focusRequester: FocusRequester,
onFilter: (FilterItemUio) -> Unit, onFilter: (FilterItemUio) -> Unit,
onClose: () -> Unit,
onIMEDone: KeyboardActionScope.() -> Unit, onIMEDone: KeyboardActionScope.() -> Unit,
) { ) {
val filters = viewModel.paging.collectAsLazyPagingItems() val filters = viewModel.paging.collectAsLazyPagingItems()
FilterPageContent( FilterPageContent(
modifier = Modifier modifier = modifier,
.fillMaxSize()
.imePadding()
.systemBarsPadding(),
focusRequester = focusRequester, focusRequester = focusRequester,
title = viewModel.title, title = viewModel.title,
search = viewModel.search, search = viewModel.search,
onSearchUpdate = { viewModel.updateSearch(it) }, onSearchUpdate = { viewModel.updateSearch(it) },
onClear = { viewModel.updateSearch("") },
filters = filters, filters = filters,
onFilter = onFilter, onFilter = onFilter,
onClose = onClose,
onIMEDone = onIMEDone, onIMEDone = onIMEDone,
) )
} }
@ -68,56 +73,64 @@ private fun FilterPageContent(
title: String, title: String,
search: State<String>, search: State<String>,
onSearchUpdate: (String) -> Unit, onSearchUpdate: (String) -> Unit,
onClear: () -> Unit,
filters: LazyPagingItems<FilterItemUio>, filters: LazyPagingItems<FilterItemUio>,
onFilter: (FilterItemUio) -> Unit, onFilter: (FilterItemUio) -> Unit,
onClose: () -> Unit,
onIMEDone: KeyboardActionScope.() -> Unit, onIMEDone: KeyboardActionScope.() -> Unit,
) { ) {
val navigationBarsHeight = navigationBarsHeight()
val imeHeight = imeHeight()
val paddingValues = remember(navigationBarsHeight, imeHeight) {
PaddingValues(
bottom = max(navigationBarsHeight, imeHeight)
)
}
Column( Column(
modifier = modifier, modifier = modifier,
) { ) {
TopAppBar( Handle(
backgroundColor = MaterialTheme.colors.surface, modifier = Modifier
elevation = 0.dp, .align(alignment = Alignment.CenterHorizontally)
title = { .padding(vertical = 16.dp),
Text( )
style = MaterialTheme.typography.h6, Text(
color = MaterialTheme.colors.onSurface, modifier = Modifier.padding(horizontal = 16.dp),
text = title, style = MaterialTheme.bibLib.typography.base.caption,
) color = MaterialTheme.bibLib.colors.typography.light,
}, text = title,
navigationIcon = {
IconButton(onClick = onClose) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = null,
)
}
}
) )
TextField( TextField(
modifier = Modifier modifier = Modifier
.focusRequester(focusRequester = focusRequester) .focusRequester(focusRequester = focusRequester)
.fillMaxWidth(), .fillMaxWidth(),
label = { trailingIcon = {
Text( AnimatedVisibility(
color = MaterialTheme.colors.onSurface, visible = search.value.isNotBlank(),
text = stringResource(id = R.string.search_filter_title) enter = fadeIn(),
) exit = fadeOut(),
) {
IconButton(
onClick = onClear,
) {
Icon(
imageVector = Icons.Default.Clear,
tint = MaterialTheme.bibLib.colors.typography.emphasis,
contentDescription = null,
)
}
}
}, },
value = search.value, value = search.value,
singleLine = true, singleLine = true,
colors = TextFieldDefaults.outlinedTextFieldColors( colors = TextFieldDefaults.outlinedTextFieldColors(),
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
disabledBorderColor = Color.Transparent,
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = onIMEDone), keyboardActions = KeyboardActions(onDone = onIMEDone),
onValueChange = onSearchUpdate onValueChange = onSearchUpdate
) )
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize(),
contentPadding = paddingValues,
) { ) {
items(items = filters, key = { it.filterId }) { items(items = filters, key = { it.filterId }) {
Text( Text(
@ -132,4 +145,22 @@ private fun FilterPageContent(
} }
} }
} }
}
@Composable
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_NO)
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES)
private fun FilterPageContentPreview() {
BibLibTheme {
FilterPageContent(
focusRequester = remember { FocusRequester() },
title = "Search by Author",
search = remember { mutableStateOf("") },
onSearchUpdate = { },
onClear = { },
filters = remember { emptyFlow<PagingData<FilterItemUio>>() }.collectAsLazyPagingItems(),
onFilter = { },
onIMEDone = { },
)
}
} }

View file

@ -26,7 +26,10 @@ class AuthorFilterViewModel @Inject constructor(
private val searchRepository: ISearchRepository, private val searchRepository: ISearchRepository,
) : ViewModel(), IFilterViewModel { ) : ViewModel(), IFilterViewModel {
override val title: String = application.getString(R.string.search_filter_author) override val title: String = application.getString(
R.string.search_filter_title,
application.getString(R.string.search_filter_author),
)
private var source: AuthorSearchSource? = null private var source: AuthorSearchSource? = null
override val paging: Flow<PagingData<FilterItemUio>> override val paging: Flow<PagingData<FilterItemUio>>

View file

@ -26,7 +26,10 @@ class GenreFilterViewModel @Inject constructor(
private val searchRepository: ISearchRepository, private val searchRepository: ISearchRepository,
) : ViewModel(), IFilterViewModel { ) : ViewModel(), IFilterViewModel {
override val title: String = application.getString(R.string.search_filter_genre) override val title: String = application.getString(
R.string.search_filter_title,
application.getString(R.string.search_filter_genre),
)
private var source: GenreSearchSource? = null private var source: GenreSearchSource? = null
override val paging: Flow<PagingData<FilterItemUio>> override val paging: Flow<PagingData<FilterItemUio>>

View file

@ -26,7 +26,10 @@ class LanguageFilterViewModel @Inject constructor(
private val searchRepository: ISearchRepository, private val searchRepository: ISearchRepository,
) : ViewModel(), IFilterViewModel { ) : ViewModel(), IFilterViewModel {
override val title: String = application.getString(R.string.search_filter_language) override val title: String = application.getString(
R.string.search_filter_title,
application.getString(R.string.search_filter_language),
)
private var source: LanguageSearchSource? = null private var source: LanguageSearchSource? = null
override val paging: Flow<PagingData<FilterItemUio>> override val paging: Flow<PagingData<FilterItemUio>>

View file

@ -26,7 +26,10 @@ class SeriesFilterViewModel @Inject constructor(
private val searchRepository: ISearchRepository, private val searchRepository: ISearchRepository,
) : ViewModel(), IFilterViewModel { ) : ViewModel(), IFilterViewModel {
override val title: String = application.getString(R.string.search_filter_series) override val title: String = application.getString(
R.string.search_filter_title,
application.getString(R.string.search_filter_series),
)
private var source: SeriesSearchSource? = null private var source: SeriesSearchSource? = null
override val paging: Flow<PagingData<FilterItemUio>> override val paging: Flow<PagingData<FilterItemUio>>

View file

@ -4,11 +4,13 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import com.pixelized.biblib.ui.composable.SystemTheme
import com.pixelized.biblib.ui.theme.color.bibLibDarkColors import com.pixelized.biblib.ui.theme.color.bibLibDarkColors
import com.pixelized.biblib.ui.theme.color.bibLibLightColors import com.pixelized.biblib.ui.theme.color.bibLibLightColors
import com.pixelized.biblib.ui.theme.dimen.BibLibDimen import com.pixelized.biblib.ui.theme.dimen.BibLibDimen
import com.pixelized.biblib.ui.theme.shape.BibLibShape import com.pixelized.biblib.ui.theme.shape.BibLibShape
import com.pixelized.biblib.ui.theme.typography.BibLibTypography import com.pixelized.biblib.ui.theme.typography.BibLibTypography
import com.pixelized.biblib.utils.extention.bibLib
@Composable @Composable
fun BibLibTheme( fun BibLibTheme(
@ -26,7 +28,15 @@ fun BibLibTheme(
colors = theme.colors.base, colors = theme.colors.base,
typography = theme.typography.base, typography = theme.typography.base,
shapes = theme.shapes.base, shapes = theme.shapes.base,
content = content content = {
SystemTheme(
statusBackground = MaterialTheme.bibLib.colors.system.status,
statusDarkIcons = darkTheme.not(),
navigationBackground = MaterialTheme.bibLib.colors.system.navigation,
navigationDarkIcons = darkTheme.not(),
content = content,
)
}
) )
} }
} }

View file

@ -1,10 +1,12 @@
package com.pixelized.biblib.ui.theme.color package com.pixelized.biblib.ui.theme.color
import androidx.compose.material.Colors import androidx.compose.material.Colors
import androidx.compose.material.MaterialTheme
import androidx.compose.material.darkColors import androidx.compose.material.darkColors
import androidx.compose.material.lightColors import androidx.compose.material.lightColors
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import com.pixelized.biblib.utils.extention.bibLib
import javax.annotation.concurrent.Immutable import javax.annotation.concurrent.Immutable
@ -12,9 +14,18 @@ import javax.annotation.concurrent.Immutable
@Immutable @Immutable
data class BibLibColor( data class BibLibColor(
val base: Colors, val base: Colors,
val system: System,
val handle: Color,
val typography: Typography, val typography: Typography,
val placeHolder: PlaceHolder, val placeHolder: PlaceHolder,
) { ) {
@Stable
@Immutable
data class System(
val status: Color,
val navigation: Color,
)
@Stable @Stable
@Immutable @Immutable
data class Typography( data class Typography(
@ -40,6 +51,11 @@ fun bibLibDarkColors(
error = BibLibColorPalette.Red, error = BibLibColorPalette.Red,
onError = Color.White, onError = Color.White,
), ),
system: BibLibColor.System = BibLibColor.System(
status = base.surface.copy(alpha = 0.5f),
navigation = base.surface.copy(alpha = 0.5f),
),
handle: Color = base.onSurface.copy(alpha = 0.2f),
typography: BibLibColor.Typography = BibLibColor.Typography( typography: BibLibColor.Typography = BibLibColor.Typography(
light = base.onSurface.copy(alpha = 0.67f), light = base.onSurface.copy(alpha = 0.67f),
medium = base.onSurface, medium = base.onSurface,
@ -51,6 +67,8 @@ fun bibLibDarkColors(
), ),
) = BibLibColor( ) = BibLibColor(
base = base, base = base,
system = system,
handle = handle,
typography = typography, typography = typography,
placeHolder = placeHolder, placeHolder = placeHolder,
) )
@ -68,6 +86,11 @@ fun bibLibLightColors(
surface = Color.White, surface = Color.White,
onSurface = BibLibColorPalette.VeryDarkGrey, onSurface = BibLibColorPalette.VeryDarkGrey,
), ),
system: BibLibColor.System = BibLibColor.System(
status = base.surface.copy(alpha = 0.5f),
navigation = base.surface.copy(alpha = 0.5f),
),
handle: Color = base.onSurface.copy(alpha = 0.1f),
typography: BibLibColor.Typography = BibLibColor.Typography( typography: BibLibColor.Typography = BibLibColor.Typography(
light = base.onSurface.copy(alpha = 0.67f), light = base.onSurface.copy(alpha = 0.67f),
medium = base.onSurface, medium = base.onSurface,
@ -79,6 +102,8 @@ fun bibLibLightColors(
), ),
) = BibLibColor( ) = BibLibColor(
base = base, base = base,
system = system,
handle = handle,
typography = typography, typography = typography,
placeHolder = placeHolder, placeHolder = placeHolder,
) )

View file

@ -11,6 +11,7 @@ import androidx.compose.ui.unit.dp
data class BibLibDimen( data class BibLibDimen(
val avatar: Avatar = Avatar(), val avatar: Avatar = Avatar(),
val progress: Progress = Progress(), val progress: Progress = Progress(),
val handle: Handle = Handle(),
val detail: BookDetail = BookDetail(), val detail: BookDetail = BookDetail(),
val thumbnail: BookThumbnail = BookThumbnail(), val thumbnail: BookThumbnail = BookThumbnail(),
) { ) {
@ -26,6 +27,13 @@ data class BibLibDimen(
val iconSize: Dp = 52.dp, val iconSize: Dp = 52.dp,
) )
@Stable
@Immutable
data class Handle(
val width: Dp = 32.dp,
val thickness: Dp = 4.dp,
)
@Stable @Stable
@Immutable @Immutable
data class BookDetail( data class BookDetail(

View file

@ -17,4 +17,5 @@ data class BibLibShape(
), ),
val bookThumbnailCoverSmall: Shape = RoundedCornerShape(4.dp), val bookThumbnailCoverSmall: Shape = RoundedCornerShape(4.dp),
val bookThumbnailCoverLarge: Shape = RoundedCornerShape(4.dp), val bookThumbnailCoverLarge: Shape = RoundedCornerShape(4.dp),
val filterSheet: Shape = RoundedCornerShape(topEnd = 16.dp, topStart = 16.dp),
) )

View file

@ -61,7 +61,7 @@
<string name="detail_send_success">eBook envoyé avec succès</string> <string name="detail_send_success">eBook envoyé avec succès</string>
<string name="search_title">Rechercher sur Biblib</string> <string name="search_title">Rechercher sur Biblib</string>
<string name="search_filter_title">Rechercher</string> <string name="search_filter_title">Rechercher par %1$s</string>
<string name="search_filter_param">%1$s : %2$s</string> <string name="search_filter_param">%1$s : %2$s</string>
<string name="search_filter_new">Nouveauté</string> <string name="search_filter_new">Nouveauté</string>
<string name="search_filter_author">Auteur</string> <string name="search_filter_author">Auteur</string>

View file

@ -77,7 +77,7 @@
<string name="detail_send_success">eBook sent with success</string> <string name="detail_send_success">eBook sent with success</string>
<string name="search_title">Search on Biblib</string> <string name="search_title">Search on Biblib</string>
<string name="search_filter_title">Search</string> <string name="search_filter_title">Search by %1$s</string>
<string name="search_filter_param">%1$s: %2$s</string> <string name="search_filter_param">%1$s: %2$s</string>
<string name="search_filter_new">New</string> <string name="search_filter_new">New</string>
<string name="search_filter_author">Authors</string> <string name="search_filter_author">Authors</string>