Add email bottom sheet choice in book detail.

This commit is contained in:
Thomas Andres Gomez 2022-06-30 15:56:06 +02:00
parent f6739f60ee
commit 3137c358c7
6 changed files with 131 additions and 22 deletions

View file

@ -15,6 +15,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import com.pixelized.biblib.ui.composable.dialog.ErrorCard import com.pixelized.biblib.ui.composable.dialog.ErrorCard
import com.pixelized.biblib.ui.composable.dialog.LoadingCard import com.pixelized.biblib.ui.composable.dialog.LoadingCard
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
sealed class StateUio<T> { sealed class StateUio<T> {
class Progress<T>(val progress: Float? = null) : StateUio<T>() class Progress<T>(val progress: Float? = null) : StateUio<T>()
@ -22,6 +24,14 @@ sealed class StateUio<T> {
class Success<T>(val value: T) : StateUio<T>() class Success<T>(val value: T) : StateUio<T>()
} }
@OptIn(ExperimentalContracts::class)
fun <T> StateUio<T>.isSuccessful(): Boolean {
contract {
returns(true) implies (this@isSuccessful is StateUio.Success<T>)
}
return this is StateUio.Success<T>
}
@OptIn(ExperimentalAnimationApi::class) @OptIn(ExperimentalAnimationApi::class)
@Composable @Composable
fun <T> StateUioHandler( fun <T> StateUioHandler(

View file

@ -20,7 +20,7 @@ import com.pixelized.biblib.utils.extention.showToast
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
val LocalBottomDetailController = staticCompositionLocalOf<BottomDetailState> { val LocalBottomDetailState = staticCompositionLocalOf<BottomDetailState> {
error("LocalBottomDetailController is not ready yet") error("LocalBottomDetailController is not ready yet")
} }
@ -31,7 +31,7 @@ fun BottomDetailScaffold(
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
CompositionLocalProvider( CompositionLocalProvider(
LocalBottomDetailController provides bottomDetailState LocalBottomDetailState provides bottomDetailState
) { ) {
ModalBottomSheetLayout( ModalBottomSheetLayout(
scrimColor = Color.Black.copy(alpha = 0.37f), scrimColor = Color.Black.copy(alpha = 0.37f),
@ -89,7 +89,6 @@ class BottomDetailState constructor(
} }
is StateUio.Success -> { is StateUio.Success -> {
bookDetail.value = book.value bookDetail.value = book.value
// bottomSheetState.animateTo(ModalBottomSheetValue.Expanded)
bottomSheetState.show() bottomSheetState.show()
} }
else -> Unit else -> Unit

View file

@ -2,21 +2,21 @@ package com.pixelized.biblib.ui.screen.detail
import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.activity.compose.BackHandler
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button import androidx.compose.material.*
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Download import androidx.compose.material.icons.filled.Download
import androidx.compose.material.icons.filled.Send import androidx.compose.material.icons.filled.Send
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -26,28 +26,76 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.core.text.toSpannable import androidx.core.text.toSpannable
import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.biblib.R import com.pixelized.biblib.R
import com.pixelized.biblib.ui.composable.Cover import com.pixelized.biblib.ui.composable.Cover
import com.pixelized.biblib.ui.composable.SpannedText import com.pixelized.biblib.ui.composable.SpannedText
import com.pixelized.biblib.ui.composable.StateUio
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
import com.pixelized.biblib.ui.composable.isSuccessful
import com.pixelized.biblib.ui.scaffold.BottomDetailState
import com.pixelized.biblib.ui.scaffold.LocalBottomDetailState
import com.pixelized.biblib.ui.screen.home.common.uio.BookUio import com.pixelized.biblib.ui.screen.home.common.uio.BookUio
import com.pixelized.biblib.ui.screen.home.common.uio.CoverUio import com.pixelized.biblib.ui.screen.home.common.uio.CoverUio
import com.pixelized.biblib.ui.screen.profile.ProfileViewModel
import com.pixelized.biblib.ui.screen.profile.UserUio
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.todo import com.pixelized.biblib.utils.extention.todo
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
fun DetailScreen( fun DetailScreen(
detailState: BottomDetailState = LocalBottomDetailState.current,
profileViewModel: ProfileViewModel = hiltViewModel(),
detail: BookUio? = null, detail: BookUio? = null,
) { ) {
if (detail != null) { val scope = rememberCoroutineScope()
DetailScreenContent( val sheet = rememberModalBottomSheetState(
modifier = Modifier.fillMaxSize(), initialValue = ModalBottomSheetValue.Hidden,
book = detail, skipHalfExpanded = true,
) )
} else {
Box(modifier = Modifier.fillMaxSize()) ModalBottomSheetLayout(
sheetState = sheet,
scrimColor = Color.Black.copy(alpha = 0.37f),
sheetContent = {
Box(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 1.dp)
.animateContentSize()
) {
val user by derivedStateOf { profileViewModel.user }
if (user.isSuccessful()) {
DetailScreenSendContent(
modifier = Modifier.navigationBarsPadding(),
emails = (user as StateUio.Success<UserUio>).value.amazonEmails,
)
}
}
},
content = {
if (detailState.bottomSheetState.isVisible) {
if (detail != null) {
DetailScreenContent(
modifier = Modifier.fillMaxSize(),
book = detail,
onSend = { scope.launch { sheet.show() } }
)
} else {
Box(modifier = Modifier.fillMaxSize())
}
} else {
LaunchedEffect(key1 = "email bottom sheet close") { sheet.hide() }
}
},
)
BackHandler(enabled = sheet.isVisible) {
scope.launch { sheet.hide() }
} }
} }
@ -61,7 +109,6 @@ private fun DetailScreenContent(
) { ) {
AnimatedDelayer( AnimatedDelayer(
targetState = book, targetState = book,
delay = 300,
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
@ -230,6 +277,44 @@ private fun TitleLabel(
} }
} }
@Composable
private fun DetailScreenSendContent(
modifier: Modifier = Modifier,
emails: List<String>,
) {
Column(
modifier = modifier.fillMaxWidth(),
) {
Text(
modifier = Modifier.padding(
vertical = MaterialTheme.bibLib.dimen.dp8,
horizontal = MaterialTheme.bibLib.dimen.dp16,
),
color = MaterialTheme.colors.primary,
style = MaterialTheme.typography.caption,
text = "Send this eBook to:",
)
LazyColumn {
items(items = emails) {
Box(
modifier = Modifier
.height(height = MaterialTheme.bibLib.dimen.dp48)
.fillMaxWidth(),
contentAlignment = Alignment.CenterStart
) {
Text(
modifier = Modifier.padding(horizontal = MaterialTheme.bibLib.dimen.dp16),
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.onSurface,
text = it
)
}
}
}
}
}
@Composable @Composable
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_NO) @Preview(showBackground = true, uiMode = UI_MODE_NIGHT_NO)
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES) @Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES)
@ -258,4 +343,18 @@ private fun DetailScreenContentPreview() {
BibLibTheme { BibLibTheme {
DetailScreenContent(book = book) DetailScreenContent(book = book)
} }
}
@Composable
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_NO)
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES)
private fun DetailScreenSendPreview() {
BibLibTheme {
DetailScreenSendContent(
emails = listOf(
"R.Giskard.Reventlov.Kindle@gmailcom",
"R.Daneel.Olivaw.Kindle@gmailcom",
),
)
}
} }

View file

@ -6,7 +6,7 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.biblib.ui.scaffold.LocalBottomDetailController import com.pixelized.biblib.ui.scaffold.LocalBottomDetailState
import com.pixelized.biblib.ui.screen.connectivity.ConnectivityViewModel import com.pixelized.biblib.ui.screen.connectivity.ConnectivityViewModel
import com.pixelized.biblib.ui.screen.home.common.composable.LazyBookThumbnailColumn import com.pixelized.biblib.ui.screen.home.common.composable.LazyBookThumbnailColumn
import com.pixelized.biblib.ui.screen.home.page.news.NewsPage import com.pixelized.biblib.ui.screen.home.page.news.NewsPage
@ -18,7 +18,7 @@ fun BooksPage(
connectivityViewModel: ConnectivityViewModel = hiltViewModel(), connectivityViewModel: ConnectivityViewModel = hiltViewModel(),
booksViewModel: BooksViewModel = hiltViewModel() booksViewModel: BooksViewModel = hiltViewModel()
) { ) {
val bottomDetailState = LocalBottomDetailController.current val bottomDetailState = LocalBottomDetailState.current
LazyBookThumbnailColumn( LazyBookThumbnailColumn(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.bibLib.dimen.thumbnail.arrangement), verticalArrangement = Arrangement.spacedBy(MaterialTheme.bibLib.dimen.thumbnail.arrangement),

View file

@ -6,7 +6,7 @@ import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.biblib.ui.scaffold.LocalBottomDetailController import com.pixelized.biblib.ui.scaffold.LocalBottomDetailState
import com.pixelized.biblib.ui.screen.connectivity.ConnectivityViewModel import com.pixelized.biblib.ui.screen.connectivity.ConnectivityViewModel
import com.pixelized.biblib.ui.screen.home.common.composable.LazyBookThumbnailColumn import com.pixelized.biblib.ui.screen.home.common.composable.LazyBookThumbnailColumn
import com.pixelized.biblib.ui.theme.BibLibTheme import com.pixelized.biblib.ui.theme.BibLibTheme
@ -17,7 +17,7 @@ fun NewsPage(
connectivityViewModel: ConnectivityViewModel = hiltViewModel(), connectivityViewModel: ConnectivityViewModel = hiltViewModel(),
booksViewModel: NewsBookViewModel = hiltViewModel() booksViewModel: NewsBookViewModel = hiltViewModel()
) { ) {
val bottomDetail = LocalBottomDetailController.current val bottomDetail = LocalBottomDetailState.current
LazyBookThumbnailColumn( LazyBookThumbnailColumn(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.bibLib.dimen.thumbnail.arrangement), verticalArrangement = Arrangement.spacedBy(MaterialTheme.bibLib.dimen.thumbnail.arrangement),

View file

@ -14,6 +14,7 @@ data class BibLibDimen(
val dp8: Dp = 8.dp, val dp8: Dp = 8.dp,
val dp16: Dp = 16.dp, val dp16: Dp = 16.dp,
val dp32: Dp = 32.dp, val dp32: Dp = 32.dp,
val dp48: Dp = 48.dp,
val dp64: Dp = 64.dp, val dp64: Dp = 64.dp,
val dialog: Dialog = Dialog(), val dialog: Dialog = Dialog(),
val thumbnail: BookThumbnail = BookThumbnail(), val thumbnail: BookThumbnail = BookThumbnail(),