Refactor the thumbnails.

This commit is contained in:
Thomas Andres Gomez 2023-04-06 13:08:52 +02:00
parent f6496e485d
commit 35d27534df
15 changed files with 356 additions and 481 deletions

View file

@ -2,6 +2,7 @@ package com.pixelized.biblib.ui.screen.home
import android.app.Application import android.app.Application
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@ -13,14 +14,11 @@ 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.repository.book.IBookRepository import com.pixelized.biblib.repository.book.IBookRepository
import com.pixelized.biblib.repository.search.ISearchRepository import com.pixelized.biblib.repository.search.ISearchRepository
import com.pixelized.biblib.ui.screen.home.common.item.LargeBookThumbnailUio import com.pixelized.biblib.ui.screen.home.common.item.BookThumbnailUio
import com.pixelized.biblib.ui.screen.home.common.item.MicroBookThumbnailUio
import com.pixelized.biblib.ui.screen.home.common.item.SmallBookThumbnailUio
import com.pixelized.biblib.ui.screen.home.filter.FilterChipUio import com.pixelized.biblib.ui.screen.home.filter.FilterChipUio
import com.pixelized.biblib.ui.screen.home.options.OptionsUio
import com.pixelized.biblib.utils.extention.stringResource import com.pixelized.biblib.utils.extention.stringResource
import com.pixelized.biblib.utils.extention.toLargeBookThumbnailUio import com.pixelized.biblib.utils.extention.toThumbnailUio
import com.pixelized.biblib.utils.extention.toMicroThumbnailUio
import com.pixelized.biblib.utils.extention.toSmallThumbnailUio
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -42,10 +40,19 @@ class BookSearchViewModel @Inject constructor(
private val _updating = mutableStateOf(false) private val _updating = mutableStateOf(false)
val updating: State<Boolean> = _updating val updating: State<Boolean> = _updating
private val _display = mutableStateOf(HomeDisplay.MICRO)
val display: State<HomeDisplay> = _display
val options = derivedStateOf {
when(display.value) {
HomeDisplay.MICRO -> OptionsUio(micro = true, small = false, large = false)
HomeDisplay.SMALL -> OptionsUio(micro = false, small = true, large = false)
HomeDisplay.GRID -> OptionsUio(micro = false, small = false, large = true)
}
}
private var searchSource: BookSearchSource? = null private var searchSource: BookSearchSource? = null
val microPaging: Flow<PagingData<MicroBookThumbnailUio>> val paging: Flow<PagingData<BookThumbnailUio>>
val smallPaging: Flow<PagingData<SmallBookThumbnailUio>>
val largePaging: Flow<PagingData<LargeBookThumbnailUio>>
private val _search = mutableStateOf<String?>(null) private val _search = mutableStateOf<String?>(null)
val search: State<String?> = _search val search: State<String?> = _search
@ -76,14 +83,8 @@ class BookSearchViewModel @Inject constructor(
pagingSourceFactory = ::buildBookSource, pagingSourceFactory = ::buildBookSource,
).flow ).flow
// keep transaction updated with the pager. // keep transaction updated with the pager.
microPaging = searchFlow paging = searchFlow
.map { pagingData -> pagingData.map { it.toMicroThumbnailUio() } } .map { pagingData -> pagingData.map { it.toThumbnailUio() } }
.cachedIn(viewModelScope + Dispatchers.IO)
smallPaging = searchFlow
.map { pagingData -> pagingData.map { it.toSmallThumbnailUio() } }
.cachedIn(viewModelScope + Dispatchers.IO)
largePaging = searchFlow
.map { pagingData -> pagingData.map { it.toLargeBookThumbnailUio() } }
.cachedIn(viewModelScope + Dispatchers.IO) .cachedIn(viewModelScope + Dispatchers.IO)
} }
@ -104,6 +105,10 @@ class BookSearchViewModel @Inject constructor(
} }
} }
fun onDisplay(type: HomeDisplay) {
_display.value = type
}
fun source(clean: Boolean = false, block: SortAndFilterScope.() -> Unit) { fun source(clean: Boolean = false, block: SortAndFilterScope.() -> Unit) {
val scope = if (clean) { val scope = if (clean) {
SortAndFilterScope( SortAndFilterScope(

View file

@ -2,11 +2,8 @@ package com.pixelized.biblib.ui.screen.home
import android.content.res.Configuration import android.content.res.Configuration
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.*
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.* import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
@ -48,26 +45,29 @@ 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
import com.pixelized.biblib.ui.screen.home.common.item.* import com.pixelized.biblib.ui.screen.home.common.item.*
import com.pixelized.biblib.ui.screen.home.common.preview.thumbnailPreviewResources
import com.pixelized.biblib.ui.screen.home.filter.FilterChip import com.pixelized.biblib.ui.screen.home.filter.FilterChip
import com.pixelized.biblib.ui.screen.home.filter.FilterChipUio import com.pixelized.biblib.ui.screen.home.filter.FilterChipUio
import com.pixelized.biblib.ui.screen.home.filter.filterPreview import com.pixelized.biblib.ui.screen.home.filter.filterPreview
import com.pixelized.biblib.ui.screen.home.header.LazyGridCollapsingHeaderLayout import com.pixelized.biblib.ui.screen.home.header.LazyGridCollapsingHeaderLayout
import com.pixelized.biblib.ui.screen.home.options.Options import com.pixelized.biblib.ui.screen.home.options.Options
import com.pixelized.biblib.ui.screen.home.options.OptionsUio import com.pixelized.biblib.ui.screen.home.options.OptionsUio
import com.pixelized.biblib.ui.screen.home.options.OptionsViewModel
import com.pixelized.biblib.ui.theme.BibLibTheme 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.imeHeight
import com.pixelized.biblib.utils.extention.navigationBarsHeight import com.pixelized.biblib.utils.extention.navigationBarsHeight
import com.skydoves.landscapist.glide.GlideImage import com.skydoves.landscapist.glide.GlideImage
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Stable
@Immutable
sealed class HomeScreenErrorUio( sealed class HomeScreenErrorUio(
@StringRes val message: Int, @StringRes val message: Int,
@StringRes val action: Int, @StringRes val action: Int,
) { ) {
@Stable
@Immutable
class LibraryUpdate( class LibraryUpdate(
@StringRes message: Int, @StringRes message: Int,
@StringRes action: Int, @StringRes action: Int,
@ -77,12 +77,19 @@ sealed class HomeScreenErrorUio(
) )
} }
@Stable
@Immutable
enum class HomeDisplay {
MICRO,
SMALL,
GRID,
}
@OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class) @OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class)
@Composable @Composable
fun HomeScreen( fun HomeScreen(
bookViewModel: BookSearchViewModel = hiltViewModel(), bookViewModel: BookSearchViewModel = hiltViewModel(),
profileViewModel: HomeViewModel = hiltViewModel(), profileViewModel: HomeViewModel = hiltViewModel(),
optionsViewModel: OptionsViewModel = hiltViewModel(),
) { ) {
val context = LocalContext.current val context = LocalContext.current
val navigation = LocalScreenNavHostController.current val navigation = LocalScreenNavHostController.current
@ -137,7 +144,7 @@ fun HomeScreen(
filterViewModel = bookViewModel, filterViewModel = bookViewModel,
filterState = filterState, filterState = filterState,
), ),
options = optionsViewModel.options, options = bookViewModel.options,
onUp = { onUp = {
scope.launch { scope.launch {
launch { largeGridState.animateScrollToItem(index = 0) } launch { largeGridState.animateScrollToItem(index = 0) }
@ -159,26 +166,21 @@ fun HomeScreen(
} }
} }
}, },
onMicro = optionsViewModel::onMicro, onDisplay = bookViewModel::onDisplay,
onSmall = optionsViewModel::onSmall,
onLarge = optionsViewModel::onLarge,
isLoading = bookViewModel.updating, isLoading = bookViewModel.updating,
onPullToRefresh = { onPullToRefresh = {
scope.launch { scope.launch {
bookViewModel.updateLibrary() bookViewModel.updateLibrary()
} }
}, },
largeGridState = largeGridState, display = bookViewModel.display,
largeGrid = bookViewModel.largePaging, gridState = largeGridState,
smallListState = smallListState, items = bookViewModel.paging,
smallList = bookViewModel.smallPaging,
microListState = microListState,
microList = bookViewModel.microPaging,
onBook = { onBook = {
// close the keyboard. // close the keyboard.
focus.clearFocus(force = true) focus.clearFocus(force = true)
keyboard?.hide() keyboard?.hide()
// opent the detail bottom sheet. // open the detail bottom sheet.
scope.launch { scope.launch {
detailState.expandBookDetail(id = it) detailState.expandBookDetail(id = it)
} }
@ -295,17 +297,12 @@ private fun HomeScreenContent(
options: State<OptionsUio>, options: State<OptionsUio>,
onUp: () -> Unit, onUp: () -> Unit,
onSort: () -> Unit, onSort: () -> Unit,
onMicro: () -> Unit, onDisplay: (HomeDisplay) -> Unit,
onSmall: () -> Unit,
onLarge: () -> Unit,
isLoading: State<Boolean>, isLoading: State<Boolean>,
onPullToRefresh: () -> Unit, onPullToRefresh: () -> Unit,
largeGridState: LazyGridState, display: State<HomeDisplay>,
largeGrid: Flow<PagingData<LargeBookThumbnailUio>>, gridState: LazyGridState,
smallListState: LazyListState, items: Flow<PagingData<BookThumbnailUio>>,
smallList: Flow<PagingData<SmallBookThumbnailUio>>,
microListState: LazyListState,
microList: Flow<PagingData<MicroBookThumbnailUio>>,
onBook: (id: Int) -> Unit, onBook: (id: Int) -> Unit,
) { ) {
val theme = MaterialTheme.bibLib val theme = MaterialTheme.bibLib
@ -348,9 +345,9 @@ private fun HomeScreenContent(
options = options.value, options = options.value,
onUp = onUp, onUp = onUp,
onSort = onSort, onSort = onSort,
onMicro = onMicro, onMicro = { onDisplay(HomeDisplay.MICRO) },
onSmall = onSmall, onSmall = { onDisplay(HomeDisplay.SMALL) },
onLarge = onLarge, onLarge = { onDisplay(HomeDisplay.GRID) },
) )
}, },
loader = { loader = {
@ -370,7 +367,7 @@ private fun HomeScreenContent(
content = { content = {
val navigationBarsHeight = navigationBarsHeight() val navigationBarsHeight = navigationBarsHeight()
val imeHeight = imeHeight() val imeHeight = imeHeight()
val padding = remember(navigationBarsHeight, imeHeight) { val paddingValues = remember(navigationBarsHeight, imeHeight) {
PaddingValues( PaddingValues(
start = theme.dimen.thumbnail.padding, start = theme.dimen.thumbnail.padding,
end = theme.dimen.thumbnail.padding, end = theme.dimen.thumbnail.padding,
@ -378,95 +375,18 @@ private fun HomeScreenContent(
bottom = theme.dimen.thumbnail.padding + max(navigationBarsHeight, imeHeight) bottom = theme.dimen.thumbnail.padding + max(navigationBarsHeight, imeHeight)
) )
} }
SwipeRefresh( SwipeRefresh(
state = rememberSwipeRefreshState(isRefreshing = false), state = rememberSwipeRefreshState(isRefreshing = false),
onRefresh = onPullToRefresh, onRefresh = onPullToRefresh,
) { ) {
AnimatedVisibility( BookList(
visible = options.value.large, modifier = Modifier.fillMaxSize(),
enter = fadeIn(animationSpec = tween(delayMillis = 150)), display = display,
exit = fadeOut(animationSpec = tween()), items = items,
) { paddingValues = paddingValues,
val items = largeGrid.collectAsLazyPagingItems() state = gridState,
LazyVerticalGrid( onBook = onBook,
modifier = Modifier.fillMaxSize(), )
columns = GridCells.Fixed(2),
contentPadding = padding,
horizontalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
verticalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
state = largeGridState,
) {
items(
count = items.itemCount,
key = { items[it]?.id ?: it }
) { index ->
val item = items[index]
LargeBookThumbnail(
thumbnail = item,
onClick = { onBook(it.id) }
)
}
}
}
AnimatedVisibility(
visible = options.value.small,
enter = fadeIn(animationSpec = tween(delayMillis = 150)),
exit = fadeOut(animationSpec = tween()),
) {
val items = smallList.collectAsLazyPagingItems()
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = padding,
verticalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
state = smallListState,
) {
items(
count = items.itemCount,
key = { items[it]?.id ?: it },
) { index ->
val item = items[index]
SmallBookThumbnail(
thumbnail = item,
onClick = { onBook(it.id) }
)
}
}
}
AnimatedVisibility(
visible = options.value.micro,
enter = fadeIn(animationSpec = tween(delayMillis = 150)),
exit = fadeOut(animationSpec = tween()),
) {
val items = microList.collectAsLazyPagingItems()
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = padding,
verticalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
state = microListState,
) {
items(
count = items.itemCount,
key = { "microList-${items[it]?.id ?: it}" },
) { index ->
val item = items[index]
MicroBookThumbnail(
thumbnail = item,
onClick = { onBook(it.id) }
)
}
}
}
} }
} }
) )
@ -586,6 +506,105 @@ private fun HomeToolbar(
} }
} }
@Composable
private fun BookList(
modifier: Modifier = Modifier,
display: State<HomeDisplay>,
items: Flow<PagingData<BookThumbnailUio>>,
paddingValues: PaddingValues,
state: LazyGridState,
onBook: (id: Int) -> Unit,
) {
val data = items.collectAsLazyPagingItems()
AnimatedVisibility(
visible = display.value == HomeDisplay.MICRO,
enter = fadeIn(tween(durationMillis = 150)),
exit = fadeOut(tween())
) {
LazyVerticalGrid(
modifier = modifier,
columns = GridCells.Fixed(1),
contentPadding = paddingValues,
horizontalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
verticalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
state = state,
) {
items(
count = data.itemCount,
key = { index -> data[index]?.id ?: index }
) { index ->
MicroBookThumbnail(
thumbnail = data[index],
onClick = { onBook(it.id) },
)
}
}
}
AnimatedVisibility(
visible = display.value == HomeDisplay.SMALL,
enter = fadeIn(tween(durationMillis = 150)),
exit = fadeOut(tween())
) {
LazyVerticalGrid(
modifier = modifier,
columns = GridCells.Fixed(1),
contentPadding = paddingValues,
horizontalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
verticalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
state = state,
) {
items(
count = data.itemCount,
key = { index -> data[index]?.id ?: index }
) { index ->
SmallBookThumbnail(
thumbnail = data[index],
onClick = { onBook(it.id) },
)
}
}
}
AnimatedVisibility(
visible = display.value == HomeDisplay.GRID,
enter = fadeIn(tween(durationMillis = 150)),
exit = fadeOut(tween())
) {
LazyVerticalGrid(
modifier = modifier,
columns = GridCells.Fixed(2),
contentPadding = paddingValues,
horizontalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
verticalArrangement = Arrangement.spacedBy(
space = MaterialTheme.bibLib.dimen.thumbnail.arrangement,
),
state = state,
) {
items(
count = data.itemCount,
key = { index -> data[index]?.id ?: index }
) { index ->
LargeBookThumbnail(
thumbnail = data[index],
onClick = { onBook(it.id) },
)
}
}
}
}
@OptIn(ExperimentalComposeUiApi::class) @OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
private fun CollapseKeyboardOnScrollHandler( private fun CollapseKeyboardOnScrollHandler(
@ -627,17 +646,12 @@ private fun HomeScreenPreview() {
options = options, options = options,
onUp = { }, onUp = { },
onSort = { }, onSort = { },
onMicro = { }, onDisplay = { },
onSmall = { },
onLarge = { },
isLoading = remember { mutableStateOf(false) }, isLoading = remember { mutableStateOf(false) },
onPullToRefresh = { }, onPullToRefresh = { },
largeGridState = rememberLazyGridState(), display = remember { mutableStateOf(HomeDisplay.MICRO) },
largeGrid = emptyFlow(), gridState = rememberLazyGridState(),
smallListState = rememberLazyListState(), items = thumbnailPreviewResources(),
smallList = emptyFlow(),
microListState = rememberLazyListState(),
microList = emptyFlow(),
onBook = { }, onBook = { },
) )
} }

View file

@ -0,0 +1,38 @@
package com.pixelized.biblib.ui.screen.home.common.item
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@Stable
@Immutable
data class BookThumbnailUio(
val id: Int,
val title: String,
val series: String?,
val genre: String?,
val author: String?,
val language: String?,
val date: String?,
val isNew: Boolean,
val thumbnail: String,
val cover: String,
)
class BookThumbnailPreviewProvider : PreviewParameterProvider<BookThumbnailUio?> {
override val values: Sequence<BookThumbnailUio?> = sequenceOf(
BookThumbnailUio(
id = 0,
title = "Foundation",
series = "Foundation - 1",
genre = "Sci-Fi",
author = "Asimov",
language = "Français",
date = "1951",
isNew = true,
thumbnail = "",
cover = "",
),
null
)
}

View file

@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material.Card import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -16,7 +15,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter 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.dp
import com.pixelized.biblib.R import com.pixelized.biblib.R
import com.pixelized.biblib.ui.theme.BibLibTheme import com.pixelized.biblib.ui.theme.BibLibTheme
@ -25,18 +23,11 @@ import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.pixelized.biblib.utils.extention.placeholder import com.pixelized.biblib.utils.extention.placeholder
import com.skydoves.landscapist.glide.GlideImage import com.skydoves.landscapist.glide.GlideImage
@Stable
data class LargeBookThumbnailUio(
val id: Int,
val isNew: Boolean,
val cover: String,
)
@Composable @Composable
fun LargeBookThumbnail( fun LargeBookThumbnail(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
thumbnail: LargeBookThumbnailUio?, thumbnail: BookThumbnailUio?,
onClick: (LargeBookThumbnailUio) -> Unit, onClick: (BookThumbnailUio) -> Unit,
) { ) {
Card( Card(
modifier = modifier modifier = modifier
@ -61,8 +52,8 @@ fun LargeBookThumbnail(
@Composable @Composable
private fun LargeBookThumbnailContent( private fun LargeBookThumbnailContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
thumbnail: LargeBookThumbnailUio, thumbnail: BookThumbnailUio,
onClick: (LargeBookThumbnailUio) -> Unit, onClick: (BookThumbnailUio) -> Unit,
) { ) {
GlideImage( GlideImage(
modifier = Modifier modifier = Modifier
@ -116,7 +107,7 @@ private fun Modifier.isNew(
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun LargeBookThumbnailPreview( private fun LargeBookThumbnailPreview(
@PreviewParameter(LargeBookThumbnailPreviewProvider::class) preview: LargeBookThumbnailUio?, @PreviewParameter(BookThumbnailPreviewProvider::class) preview: BookThumbnailUio?,
) { ) {
BibLibTheme { BibLibTheme {
LargeBookThumbnail( LargeBookThumbnail(
@ -126,14 +117,3 @@ private fun LargeBookThumbnailPreview(
) )
} }
} }
private class LargeBookThumbnailPreviewProvider : PreviewParameterProvider<LargeBookThumbnailUio?> {
override val values: Sequence<LargeBookThumbnailUio?> = sequenceOf(
LargeBookThumbnailUio(
id = 0,
isNew = true,
cover = "",
),
null
)
}

View file

@ -11,7 +11,6 @@ import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -20,6 +19,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayout
@ -31,21 +31,11 @@ import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.pixelized.biblib.utils.extention.placeholder import com.pixelized.biblib.utils.extention.placeholder
import com.skydoves.landscapist.glide.GlideImage import com.skydoves.landscapist.glide.GlideImage
@Stable
data class MicroBookThumbnailUio(
val id: Int,
val cover: String,
val title: String,
val author: String,
val series: String,
val isNew: Boolean,
)
@Composable @Composable
fun MicroBookThumbnail( fun MicroBookThumbnail(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
thumbnail: MicroBookThumbnailUio?, thumbnail: BookThumbnailUio?,
onClick: (MicroBookThumbnailUio) -> Unit, onClick: (BookThumbnailUio) -> Unit,
) { ) {
if (thumbnail != null) { if (thumbnail != null) {
MicroBookThumbnailContent( MicroBookThumbnailContent(
@ -63,8 +53,8 @@ fun MicroBookThumbnail(
@Composable @Composable
private fun MicroBookThumbnailContent( private fun MicroBookThumbnailContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
thumbnail: MicroBookThumbnailUio, thumbnail: BookThumbnailUio,
onClick: (MicroBookThumbnailUio) -> Unit, onClick: (BookThumbnailUio) -> Unit,
) { ) {
Card( Card(
modifier = modifier modifier = modifier
@ -89,7 +79,7 @@ private fun MicroBookThumbnailContent(
.size(size = MaterialTheme.bibLib.dimen.thumbnail.micro) .size(size = MaterialTheme.bibLib.dimen.thumbnail.micro)
.isNew { thumbnail.isNew }, .isNew { thumbnail.isNew },
previewPlaceholder = R.drawable.ic_fondation_thumbnail, previewPlaceholder = R.drawable.ic_fondation_thumbnail,
imageModel = thumbnail.cover, imageModel = thumbnail.thumbnail,
) )
Text( Text(
@ -117,7 +107,7 @@ private fun MicroBookThumbnailContent(
color = MaterialTheme.bibLib.colors.typography.light, color = MaterialTheme.bibLib.colors.typography.light,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
maxLines = 1, maxLines = 1,
text = thumbnail.author, text = thumbnail.author ?: "",
) )
Text( Text(
@ -131,7 +121,7 @@ private fun MicroBookThumbnailContent(
color = MaterialTheme.bibLib.colors.typography.light, color = MaterialTheme.bibLib.colors.typography.light,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
maxLines = 1, maxLines = 1,
text = thumbnail.series, text = thumbnail.series ?: "",
) )
} }
} }
@ -214,31 +204,14 @@ private fun Modifier.isNew(
} }
@Composable @Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun MicroBookThumbnailPreview() { private fun MicroBookThumbnailPreview(
@PreviewParameter(BookThumbnailPreviewProvider::class) preview: BookThumbnailUio?,
) {
BibLibTheme { BibLibTheme {
MicroBookThumbnail( MicroBookThumbnail(
thumbnail = MicroBookThumbnailUio( thumbnail = preview,
id = 0,
cover = "",
title = "Foundation",
author = "Asimov",
series = "Foundation - 1",
isNew = true,
),
onClick = { },
)
}
}
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun MicroBookThumbnailEmptyPreview() {
BibLibTheme {
MicroBookThumbnail(
thumbnail = null,
onClick = { }, onClick = { },
) )
} }

View file

@ -8,7 +8,6 @@ import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -17,6 +16,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension import androidx.constraintlayout.compose.Dimension
@ -27,22 +27,11 @@ import com.pixelized.biblib.utils.extention.modifier.drawDiagonalLabel
import com.pixelized.biblib.utils.extention.placeholder import com.pixelized.biblib.utils.extention.placeholder
import com.skydoves.landscapist.glide.GlideImage import com.skydoves.landscapist.glide.GlideImage
@Stable
data class SmallBookThumbnailUio(
val id: Int,
val genre: String,
val title: String,
val author: String,
val date: String?,
val isNew: Boolean,
val cover: String,
)
@Composable @Composable
fun SmallBookThumbnail( fun SmallBookThumbnail(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
thumbnail: SmallBookThumbnailUio?, thumbnail: BookThumbnailUio?,
onClick: (SmallBookThumbnailUio) -> Unit, onClick: (BookThumbnailUio) -> Unit,
) { ) {
if (thumbnail != null) { if (thumbnail != null) {
SmallBookThumbnailContent( SmallBookThumbnailContent(
@ -60,8 +49,8 @@ fun SmallBookThumbnail(
@Composable @Composable
private fun SmallBookThumbnailContent( private fun SmallBookThumbnailContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
thumbnail: SmallBookThumbnailUio, thumbnail: BookThumbnailUio,
onClick: (SmallBookThumbnailUio) -> Unit, onClick: (BookThumbnailUio) -> Unit,
) { ) {
Card( Card(
modifier = modifier modifier = modifier
@ -73,7 +62,7 @@ private fun SmallBookThumbnailContent(
ConstraintLayout( ConstraintLayout(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { ) {
val (cover, title, author, genre, date) = createRefs() val (cover, title, author, series, genre, date) = createRefs()
GlideImage( GlideImage(
modifier = Modifier modifier = Modifier
@ -86,7 +75,7 @@ private fun SmallBookThumbnailContent(
.size(size = MaterialTheme.bibLib.dimen.thumbnail.cover) .size(size = MaterialTheme.bibLib.dimen.thumbnail.cover)
.isNew { thumbnail.isNew }, .isNew { thumbnail.isNew },
previewPlaceholder = R.drawable.ic_fondation_thumbnail, previewPlaceholder = R.drawable.ic_fondation_thumbnail,
imageModel = thumbnail.cover, imageModel = thumbnail.thumbnail,
) )
Text( Text(
@ -106,7 +95,7 @@ private fun SmallBookThumbnailContent(
Text( Text(
modifier = Modifier.constrainAs(author) { modifier = Modifier.constrainAs(author) {
top.linkTo(title.bottom, margin = 4.dp) top.linkTo(title.bottom, margin = 4.dp)
bottom.linkTo(genre.top, margin = 4.dp) bottom.linkTo(series.top, margin = 4.dp)
start.linkTo(cover.end, margin = 8.dp) start.linkTo(cover.end, margin = 8.dp)
end.linkTo(parent.end, margin = 8.dp) end.linkTo(parent.end, margin = 8.dp)
width = Dimension.fillToConstraints width = Dimension.fillToConstraints
@ -116,7 +105,22 @@ private fun SmallBookThumbnailContent(
color = MaterialTheme.bibLib.colors.typography.light, color = MaterialTheme.bibLib.colors.typography.light,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
text = thumbnail.author text = thumbnail.author ?: ""
)
Text(
modifier = Modifier.constrainAs(series) {
top.linkTo(author.bottom, margin = 4.dp)
bottom.linkTo(genre.top, margin = 4.dp)
start.linkTo(cover.end, margin = 8.dp)
end.linkTo(parent.end, margin = 8.dp)
width = Dimension.fillToConstraints
},
style = MaterialTheme.typography.caption,
color = MaterialTheme.bibLib.colors.typography.light,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
text = thumbnail.series ?: ""
) )
Text( Text(
@ -130,7 +134,7 @@ private fun SmallBookThumbnailContent(
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.caption, style = MaterialTheme.typography.caption,
color = MaterialTheme.bibLib.colors.typography.light, color = MaterialTheme.bibLib.colors.typography.light,
text = thumbnail.genre text = thumbnail.genre ?: ""
) )
Text( Text(
@ -240,32 +244,14 @@ private fun Modifier.isNew(
} }
@Composable @Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun SmallBookThumbnailPreview() { private fun SmallBookThumbnailPreview(
@PreviewParameter(BookThumbnailPreviewProvider::class) preview: BookThumbnailUio?,
) {
BibLibTheme { BibLibTheme {
SmallBookThumbnail( SmallBookThumbnail(
thumbnail = SmallBookThumbnailUio( thumbnail = preview,
id = 0,
title = "Foundation",
genre = "Sci-Fi",
author = "Asimov",
date = "1951",
isNew = true,
cover = "",
),
onClick = { },
)
}
}
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun SmallBookThumbnailEmptyPreview() {
BibLibTheme {
SmallBookThumbnail(
thumbnail = null,
onClick = { }, onClick = { },
) )
} }

View file

@ -3,192 +3,99 @@ package com.pixelized.biblib.ui.screen.home.common.preview
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.paging.PagingData import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems import com.pixelized.biblib.ui.screen.home.common.item.BookThumbnailUio
import androidx.paging.compose.collectAsLazyPagingItems import kotlinx.coroutines.flow.Flow
import com.pixelized.biblib.ui.screen.home.common.item.LargeBookThumbnailUio
import com.pixelized.biblib.ui.screen.home.common.item.MicroBookThumbnailUio
import com.pixelized.biblib.ui.screen.home.common.item.SmallBookThumbnailUio
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
@Composable @Composable
fun microBookThumbnailPreviewResources(): LazyPagingItems<MicroBookThumbnailUio> { fun thumbnailPreviewResources(): Flow<PagingData<BookThumbnailUio>> {
val thumbnails = remember { val thumbnails = remember {
listOf( listOf(
MicroBookThumbnailUio( BookThumbnailUio(
id = 112, id = 112,
title = "Prélude à Fondation", title = "Prélude à Fondation",
author = "Asimov", author = "Asimov",
series = "Foundation", series = "Foundation",
genre = "SCI-FI",
isNew = false, isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/112.jpg", language = "Français",
),
MicroBookThumbnailUio(
id = 78,
title = "L'Aube de Fondation",
author = "Asimov",
series = "Foundation",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/78.jpg",
),
MicroBookThumbnailUio(
id = 90,
title = "Fondation",
author = "Asimov",
series = "Foundation",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/90.jpg",
),
MicroBookThumbnailUio(
id = 184,
title = "Fondation et Empire",
author = "Asimov",
series = "Foundation",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/184.jpg",
),
MicroBookThumbnailUio(
id = 185,
title = "Seconde Fondation",
author = "Asimov",
series = "Foundation",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/185.jpg",
),
MicroBookThumbnailUio(
id = 119,
title = "Fondation foudroyée",
author = "Asimov",
series = "Foundation",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/119.jpg",
),
MicroBookThumbnailUio(
id = 163,
title = "Terre et Fondation",
author = "Asimov",
series = "Foundation",
isNew = true,
cover = "https://bib.bibulle.fr/api/book/thumbnail/163.jpg",
),
)
}
return flowOf(PagingData.from(thumbnails)).collectAsLazyPagingItems()
}
@Composable
fun smallBookThumbnailPreviewResources(): LazyPagingItems<SmallBookThumbnailUio> {
val thumbnails = remember {
listOf(
SmallBookThumbnailUio(
id = 112,
title = "Prélude à Fondation",
author = "Asimov",
date = "1988", date = "1988",
genre = "Sci-Fi", cover = "https://bib.bibulle.fr/api/book/cover/90.jpg",
isNew = false, thumbnail = "https://bib.bibulle.fr/api/book/thumbnail/112.jpg",
cover = "https://bib.bibulle.fr/api/book/thumbnail/112.jpg",
), ),
SmallBookThumbnailUio( BookThumbnailUio(
id = 78, id = 78,
title = "L'Aube de Fondation", title = "L'Aube de Fondation",
series = "Foundation",
genre = "SCI-FI",
author = "Asimov", author = "Asimov",
language = "Français",
date = "1993", date = "1993",
genre = "Sci-Fi",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/78.jpg",
),
SmallBookThumbnailUio(
id = 90,
title = "Fondation",
author = "Asimov",
date = "1951",
genre = "Sci-Fi",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/90.jpg",
),
SmallBookThumbnailUio(
id = 184,
title = "Fondation et Empire",
author = "Asimov",
date = "1952",
genre = "Sci-Fi",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/184.jpg",
),
SmallBookThumbnailUio(
id = 185,
title = "Seconde Fondation",
author = "Asimov",
date = "1953",
genre = "Sci-Fi",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/185.jpg",
),
SmallBookThumbnailUio(
id = 119,
title = "Fondation foudroyée",
author = "Asimov",
date = "1982",
genre = "Sci-Fi",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/thumbnail/119.jpg",
),
SmallBookThumbnailUio(
id = 163,
title = "Terre et Fondation",
author = "Asimov",
date = "1986",
genre = "Sci-Fi",
isNew = true,
cover = "https://bib.bibulle.fr/api/book/thumbnail/163.jpg",
),
)
}
return flowOf(PagingData.from(thumbnails)).collectAsLazyPagingItems()
}
@Composable
fun largeBookThumbnailPreviewResources(): LazyPagingItems<LargeBookThumbnailUio> {
val thumbnails = remember {
listOf(
LargeBookThumbnailUio(
id = 112,
isNew = false,
cover = "https://bib.bibulle.fr/api/book/cover/112.jpg",
),
LargeBookThumbnailUio(
id = 78,
isNew = false,
cover = "https://bib.bibulle.fr/api/book/cover/78.jpg",
),
LargeBookThumbnailUio(
id = 90,
isNew = false, isNew = false,
cover = "https://bib.bibulle.fr/api/book/cover/90.jpg", cover = "https://bib.bibulle.fr/api/book/cover/90.jpg",
thumbnail = "https://bib.bibulle.fr/api/book/thumbnail/78.jpg",
), ),
LargeBookThumbnailUio( BookThumbnailUio(
id = 90,
title = "Fondation",
series = "Foundation",
genre = "SCI-FI",
author = "Asimov",
language = "Français",
date = "1951",
isNew = false,
cover = "https://bib.bibulle.fr/api/book/cover/90.jpg",
thumbnail = "https://bib.bibulle.fr/api/book/thumbnail/90.jpg",
),
BookThumbnailUio(
id = 184, id = 184,
title = "Fondation et Empire",
series = "Foundation",
genre = "SCI-FI",
author = "Asimov",
language = "Français",
date = "1952",
isNew = false, isNew = false,
cover = "https://bib.bibulle.fr/api/book/cover/184.jpg", cover = "https://bib.bibulle.fr/api/book/cover/90.jpg",
thumbnail = "https://bib.bibulle.fr/api/book/thumbnail/184.jpg",
), ),
LargeBookThumbnailUio( BookThumbnailUio(
id = 185, id = 185,
title = "Seconde Fondation",
series = "Foundation",
genre = "SCI-FI",
author = "Asimov",
language = "Français",
date = "1953",
isNew = false, isNew = false,
cover = "https://bib.bibulle.fr/api/book/cover/185.jpg", cover = "https://bib.bibulle.fr/api/book/cover/90.jpg",
thumbnail = "https://bib.bibulle.fr/api/book/thumbnail/185.jpg",
), ),
LargeBookThumbnailUio( BookThumbnailUio(
id = 119, id = 119,
title = "Fondation foudroyée",
series = "Foundation",
genre = "SCI-FI",
author = "Asimov",
language = "Français",
date = "1982",
isNew = false, isNew = false,
cover = "https://bib.bibulle.fr/api/book/cover/119.jpg", cover = "https://bib.bibulle.fr/api/book/cover/90.jpg",
thumbnail = "https://bib.bibulle.fr/api/book/thumbnail/119.jpg",
), ),
LargeBookThumbnailUio( BookThumbnailUio(
id = 163, id = 163,
title = "Terre et Fondation",
series = "Foundation",
genre = "SCI-FI",
author = "Asimov",
language = "Français",
date = "1986",
isNew = true, isNew = true,
cover = "https://bib.bibulle.fr/api/book/cover/163.jpg", cover = "https://bib.bibulle.fr/api/book/cover/90.jpg",
thumbnail = "https://bib.bibulle.fr/api/book/thumbnail/163.jpg",
), ),
) )
} }
return flowOf(PagingData.from(thumbnails)).collectAsLazyPagingItems() return flowOf(PagingData.from(thumbnails))
} }

View file

@ -4,13 +4,12 @@ import android.content.Context
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.biblib.R import com.pixelized.biblib.R
@ -69,6 +68,8 @@ fun DetailScreen(
when (val detail = detailViewModel.detail.value) { when (val detail = detailViewModel.detail.value) {
null -> EmptyDetail() null -> EmptyDetail()
else -> { else -> {
val bibLibUrl = stringResource(id = R.string.detail_open_on_biblib_url, detail.id)
ModalBottomSheetLayout( ModalBottomSheetLayout(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
sheetState = emailSheetState, sheetState = emailSheetState,
@ -92,10 +93,11 @@ fun DetailScreen(
if (detailState.bottomSheetState.isVisible) { if (detailState.bottomSheetState.isVisible) {
DetailScreenContent( DetailScreenContent(
book = detail, book = detail,
onOpenOnBibLib = {
uriHandler.openUri(bibLibUrl)
},
onAuthor = { onAuthor(it.name, it.id) }, onAuthor = { onAuthor(it.name, it.id) },
onSeries = { onSeries(it.name, it.id) }, onSeries = { onSeries(it.name, it.id) },
onMobi = { },
onEpub = { },
onSend = { onSend = {
scope.launch { scope.launch {
send( send(

View file

@ -89,10 +89,9 @@ data class BookDetailUio(
fun DetailScreenContent( fun DetailScreenContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
book: BookDetailUio, book: BookDetailUio,
onOpenOnBibLib: () -> Unit,
onAuthor: (BookDetailUio.AuthorUio) -> Unit, onAuthor: (BookDetailUio.AuthorUio) -> Unit,
onSeries: (BookDetailUio.SeriesUio) -> Unit, onSeries: (BookDetailUio.SeriesUio) -> Unit,
onMobi: () -> Unit,
onEpub: () -> Unit,
onSend: () -> Unit, onSend: () -> Unit,
) { ) {
val density = LocalDensity.current val density = LocalDensity.current
@ -110,16 +109,29 @@ fun DetailScreenContent(
.systemBarsPadding(), .systemBarsPadding(),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
GlideImage( Column(
modifier = Modifier modifier = Modifier.fillMaxWidth(),
.fillMaxWidth() horizontalAlignment = Alignment.CenterHorizontally,
.padding(vertical = 16.dp) ) {
.height(MaterialTheme.bibLib.dimen.detail.cover), GlideImage(
previewPlaceholder = R.drawable.ic_fondatoin_cover, modifier = Modifier.height(MaterialTheme.bibLib.dimen.detail.cover),
circularReveal = CircularReveal(duration = 1000), previewPlaceholder = R.drawable.ic_fondatoin_cover,
contentScale = ContentScale.FillHeight, circularReveal = CircularReveal(duration = 1000),
imageModel = book.cover, contentScale = ContentScale.FillHeight,
) imageModel = book.cover,
)
Text(
modifier = Modifier
.clickable(onClick = onOpenOnBibLib)
.padding(
horizontal = 8.dp,
vertical = 2.dp,
),
style = MaterialTheme.bibLib.typography.base.caption,
color = MaterialTheme.bibLib.colors.typography.emphasis,
text = stringResource(id = R.string.detail_open_on_biblib)
)
}
AnimatedOffset { AnimatedOffset {
Column( Column(
@ -263,10 +275,9 @@ private fun DetailScreenContentPreview() {
.verticalScroll(state = rememberScrollState()) .verticalScroll(state = rememberScrollState())
.padding(all = 16.dp), .padding(all = 16.dp),
book = BookDetailUio.preview(), book = BookDetailUio.preview(),
onOpenOnBibLib = { },
onAuthor = { }, onAuthor = { },
onSeries = { }, onSeries = { },
onMobi = { },
onEpub = { },
onSend = { }, onSend = { },
) )
} }

View file

@ -24,7 +24,7 @@ import com.pixelized.biblib.utils.extention.bibLib
@Stable @Stable
@Immutable @Immutable
data class OptionsUio( data class OptionsUio(
val sorting: Boolean, val sorting: Boolean = false,
val micro: Boolean, val micro: Boolean,
val small: Boolean, val small: Boolean,
val large: Boolean, val large: Boolean,

View file

@ -1,27 +0,0 @@
package com.pixelized.biblib.ui.screen.home.options
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class OptionsViewModel @Inject constructor() : ViewModel() {
private val _options = mutableStateOf(
OptionsUio(sorting = false, micro = true, small = false, large = false)
)
val options: State<OptionsUio> = _options
fun onMicro() {
_options.value = OptionsUio(false, true, false, false)
}
fun onSmall() {
_options.value = OptionsUio(false, false, true, false)
}
fun onLarge() {
_options.value = OptionsUio(false, false, false, true)
}
}

View file

@ -4,9 +4,7 @@ import androidx.annotation.StringDef
import com.pixelized.biblib.model.book.Book import com.pixelized.biblib.model.book.Book
import com.pixelized.biblib.model.book.Series import com.pixelized.biblib.model.book.Series
import com.pixelized.biblib.network.client.IBibLibClient import com.pixelized.biblib.network.client.IBibLibClient
import com.pixelized.biblib.ui.screen.home.common.item.LargeBookThumbnailUio import com.pixelized.biblib.ui.screen.home.common.item.BookThumbnailUio
import com.pixelized.biblib.ui.screen.home.common.item.MicroBookThumbnailUio
import com.pixelized.biblib.ui.screen.home.common.item.SmallBookThumbnailUio
import com.pixelized.biblib.ui.screen.home.detail.BookDetailUio import com.pixelized.biblib.ui.screen.home.detail.BookDetailUio
@ -17,34 +15,19 @@ import com.pixelized.biblib.ui.screen.home.detail.BookDetailUio
) )
annotation class CoverUrl annotation class CoverUrl
fun Book.toMicroThumbnailUio( fun Book.toThumbnailUio(
@CoverUrl coverBaseUrl: String = IBibLibClient.THUMBNAIL_URL @CoverUrl coverBaseUrl: String = IBibLibClient.COVER_URL,
) = MicroBookThumbnailUio( @CoverUrl thumbnailBaseUrl: String = IBibLibClient.THUMBNAIL_URL
) = BookThumbnailUio(
id = id, id = id,
cover = "${coverBaseUrl}/$id.jpg",
title = title, title = title,
author = author.joinToString { it.name },
series = series?.let { toLabel(it) } ?: "", series = series?.let { toLabel(it) } ?: "",
isNew = isNew,
)
fun Book.toSmallThumbnailUio(
@CoverUrl coverBaseUrl: String = IBibLibClient.THUMBNAIL_URL
) = SmallBookThumbnailUio(
id = id,
genre = genre?.joinToString { it.name } ?: "", genre = genre?.joinToString { it.name } ?: "",
title = title,
author = author.joinToString { it.name }, author = author.joinToString { it.name },
date = releaseDate.longDate(), language = language?.displayLanguage?.capitalize() ?: "",
isNew = isNew, date = releaseDate.year(),
cover = "${coverBaseUrl}/$id.jpg",
)
fun Book.toLargeBookThumbnailUio(
@CoverUrl coverBaseUrl: String = IBibLibClient.COVER_URL
) = LargeBookThumbnailUio(
id = id,
isNew = isNew, isNew = isNew,
thumbnail = "${thumbnailBaseUrl}/$id.jpg",
cover = "${coverBaseUrl}/$id.jpg", cover = "${coverBaseUrl}/$id.jpg",
) )

View file

@ -4,9 +4,9 @@ import java.text.Format
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
fun Date.longDate( fun Date.year(
default: String? = null, default: String? = null,
formatter: Format = SimpleDateFormat("MMMM yyyy", Locale.getDefault()), formatter: Format = SimpleDateFormat("yyyy", Locale.getDefault()),
): String? = format( ): String? = format(
default = default, default = default,
formatter = formatter formatter = formatter

View file

@ -42,6 +42,7 @@
<string name="authentication_password">Mot de passe</string> <string name="authentication_password">Mot de passe</string>
<string name="authentication_credential_remember">Mémoriser mes identifiants</string> <string name="authentication_credential_remember">Mémoriser mes identifiants</string>
<string name="detail_open_on_biblib">ouvrir sur bib.bibulle.fr</string>
<string name="detail_rating">Note</string> <string name="detail_rating">Note</string>
<string name="detail_language">Langue</string> <string name="detail_language">Langue</string>
<string name="detail_release">Publication</string> <string name="detail_release">Publication</string>

View file

@ -57,6 +57,8 @@
<string name="list_is_new" translatable="false">New</string> <string name="list_is_new" translatable="false">New</string>
<string name="detail_open_on_biblib">open on bib.bibulle.fr</string>
<string name="detail_open_on_biblib_url" translatable="false">https://bib.bibulle.fr/book/%1$s</string>
<string name="detail_rating">Rating</string> <string name="detail_rating">Rating</string>
<string name="detail_language">Language</string> <string name="detail_language">Language</string>
<string name="detail_release">Release</string> <string name="detail_release">Release</string>