Merge confirm & option dialog / bottomsheet
This commit is contained in:
parent
3e234cc37d
commit
2a92fd2b8b
6 changed files with 103 additions and 272 deletions
|
|
@ -1,19 +1,18 @@
|
||||||
package com.pixelized.biblib.ui.screen.home.detail
|
package com.pixelized.biblib.ui.screen.home.detail
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.pixelized.biblib.R
|
import com.pixelized.biblib.R
|
||||||
import com.pixelized.biblib.network.client.IBibLibClient
|
import com.pixelized.biblib.network.client.IBibLibClient
|
||||||
import com.pixelized.biblib.network.factory.BookFactory
|
import com.pixelized.biblib.network.factory.BookFactory
|
||||||
import com.pixelized.biblib.repository.book.BookRepository
|
import com.pixelized.biblib.repository.book.BookRepository
|
||||||
import com.pixelized.biblib.utils.extention.stringResource
|
|
||||||
import com.pixelized.biblib.utils.extention.toDetailUio
|
import com.pixelized.biblib.utils.extention.toDetailUio
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -21,14 +20,15 @@ import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class BookDetailViewModel @Inject constructor(
|
class BookDetailViewModel @Inject constructor(
|
||||||
application: Application,
|
|
||||||
private val bookRepository: BookRepository,
|
private val bookRepository: BookRepository,
|
||||||
private val client: IBibLibClient,
|
private val client: IBibLibClient,
|
||||||
) : AndroidViewModel(application) {
|
) : ViewModel() {
|
||||||
|
|
||||||
|
private var detailJob: Job? = null
|
||||||
private val _detail = mutableStateOf<BookDetailUio?>(null)
|
private val _detail = mutableStateOf<BookDetailUio?>(null)
|
||||||
val detail: State<BookDetailUio?> get() = _detail
|
val detail: State<BookDetailUio?> get() = _detail
|
||||||
|
|
||||||
|
private var sendJob: Job? = null
|
||||||
private val _sendStatus = MutableSharedFlow<Boolean>()
|
private val _sendStatus = MutableSharedFlow<Boolean>()
|
||||||
val sendStatus: Flow<Boolean> get() = _sendStatus
|
val sendStatus: Flow<Boolean> get() = _sendStatus
|
||||||
|
|
||||||
|
|
@ -36,7 +36,8 @@ class BookDetailViewModel @Inject constructor(
|
||||||
val error: Flow<BookDetailUioErrorUio> get() = _error
|
val error: Flow<BookDetailUioErrorUio> get() = _error
|
||||||
|
|
||||||
fun getDetail(id: Int) {
|
fun getDetail(id: Int) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
detailJob?.cancel()
|
||||||
|
detailJob = viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
_detail.value = getCacheBookDetail(id = id)
|
_detail.value = getCacheBookDetail(id = id)
|
||||||
_detail.value = getBookDetail(id = id)
|
_detail.value = getBookDetail(id = id)
|
||||||
|
|
@ -46,8 +47,9 @@ class BookDetailViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun send(bookId: Int, email: String, format: String) {
|
fun send(bookId: Int, email: String, format: String) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
sendJob?.cancel()
|
||||||
|
sendJob = viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val data = client.service.send(bookId = bookId, mail = email, format = format)
|
val data = client.service.send(bookId = bookId, mail = email, format = format)
|
||||||
_sendStatus.emit(true)
|
_sendStatus.emit(true)
|
||||||
|
|
@ -72,8 +74,8 @@ class BookDetailViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toDetailErrorUio(bookId: Int) = BookDetailUioErrorUio.GetDetailInput(
|
private fun toDetailErrorUio(bookId: Int) = BookDetailUioErrorUio.GetDetailInput(
|
||||||
message = stringResource(R.string.error_get_book_detail_message),
|
message = R.string.error_get_book_detail_message,
|
||||||
action = stringResource(R.string.error_get_book_detail_action),
|
action = R.string.error_get_book_detail_action,
|
||||||
bookId = bookId,
|
bookId = bookId,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -82,8 +84,8 @@ class BookDetailViewModel @Inject constructor(
|
||||||
mail: String,
|
mail: String,
|
||||||
format: String
|
format: String
|
||||||
) = BookDetailUioErrorUio.SendBookInput(
|
) = BookDetailUioErrorUio.SendBookInput(
|
||||||
message = stringResource(R.string.error_send_book_message),
|
message = R.string.error_send_book_message,
|
||||||
action = stringResource(R.string.error_send_book_action),
|
action = R.string.error_send_book_action,
|
||||||
bookId = bookId,
|
bookId = bookId,
|
||||||
mail = mail,
|
mail = mail,
|
||||||
format = format,
|
format = format,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.pixelized.biblib.network.client.IBibLibClient
|
import com.pixelized.biblib.network.client.IBibLibClient
|
||||||
import com.pixelized.biblib.network.factory.UserFactory
|
import com.pixelized.biblib.network.factory.UserFactory
|
||||||
|
import com.pixelized.biblib.utils.extention.capitalize
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -21,7 +22,7 @@ class BookOptionViewModel @Inject constructor(
|
||||||
var emails by mutableStateOf(listOf<OptionUio>())
|
var emails by mutableStateOf(listOf<OptionUio>())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var formats by mutableStateOf(listOf(OptionUio(Format.EPUB, true), OptionUio(Format.MOBI)))
|
var formats by mutableStateOf(initialFormat())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -51,4 +52,9 @@ class BookOptionViewModel @Inject constructor(
|
||||||
it.copy(selected = it.value == format)
|
it.copy(selected = it.value == format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initialFormat() = listOf(
|
||||||
|
OptionUio(Format.EPUB.capitalize(), true),
|
||||||
|
OptionUio(Format.MOBI.capitalize()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package com.pixelized.biblib.ui.screen.home.detail
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@HiltViewModel
|
|
||||||
class ConfirmDialogViewModel @Inject constructor(
|
|
||||||
application: Application,
|
|
||||||
) : AndroidViewModel(application) {
|
|
||||||
|
|
||||||
var dialog by mutableStateOf<ConfirmDialogUio?>(null)
|
|
||||||
private set
|
|
||||||
|
|
||||||
fun show(bookId: Int, email: String, @Format format: String) {
|
|
||||||
this.dialog = ConfirmDialogUio(
|
|
||||||
bookId = bookId,
|
|
||||||
email = email,
|
|
||||||
format = format,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hide() {
|
|
||||||
dialog = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.pixelized.biblib.ui.screen.home.detail
|
package com.pixelized.biblib.ui.screen.home.detail
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.animation.animateContentSize
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
|
@ -19,7 +20,6 @@ import com.pixelized.biblib.ui.screen.home.page.profile.ProfileViewModel
|
||||||
import com.pixelized.biblib.ui.theme.color.ShadowPalette
|
import com.pixelized.biblib.ui.theme.color.ShadowPalette
|
||||||
import com.pixelized.biblib.utils.extention.bibLib
|
import com.pixelized.biblib.utils.extention.bibLib
|
||||||
import com.pixelized.biblib.utils.extention.showToast
|
import com.pixelized.biblib.utils.extention.showToast
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
|
|
@ -54,22 +54,22 @@ data class BookDetailUio(
|
||||||
@Stable
|
@Stable
|
||||||
@Immutable
|
@Immutable
|
||||||
sealed class BookDetailUioErrorUio(
|
sealed class BookDetailUioErrorUio(
|
||||||
val message: String,
|
@StringRes val message: Int,
|
||||||
val action: String?,
|
@StringRes val action: Int,
|
||||||
) {
|
) {
|
||||||
@Stable
|
@Stable
|
||||||
@Immutable
|
@Immutable
|
||||||
class GetDetailInput(
|
class GetDetailInput(
|
||||||
message: String,
|
@StringRes message: Int,
|
||||||
action: String?,
|
@StringRes action: Int,
|
||||||
val bookId: Int,
|
val bookId: Int,
|
||||||
) : BookDetailUioErrorUio(message, action)
|
) : BookDetailUioErrorUio(message, action)
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
@Immutable
|
@Immutable
|
||||||
class SendBookInput(
|
class SendBookInput(
|
||||||
message: String,
|
@StringRes message: Int,
|
||||||
action: String?,
|
@StringRes action: Int,
|
||||||
val bookId: Int,
|
val bookId: Int,
|
||||||
val mail: String,
|
val mail: String,
|
||||||
val format: String,
|
val format: String,
|
||||||
|
|
@ -80,7 +80,6 @@ sealed class BookDetailUioErrorUio(
|
||||||
@Composable
|
@Composable
|
||||||
fun DetailScreen(
|
fun DetailScreen(
|
||||||
detailViewModel: BookDetailViewModel = hiltViewModel(),
|
detailViewModel: BookDetailViewModel = hiltViewModel(),
|
||||||
confirmViewModel: ConfirmDialogViewModel = hiltViewModel(),
|
|
||||||
profileViewModel: ProfileViewModel = hiltViewModel(),
|
profileViewModel: ProfileViewModel = hiltViewModel(),
|
||||||
bookId: Int? = null,
|
bookId: Int? = null,
|
||||||
) {
|
) {
|
||||||
|
|
@ -107,8 +106,12 @@ fun DetailScreen(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.navigationBarsPadding()
|
.navigationBarsPadding()
|
||||||
.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
||||||
|
onHelp = { uri ->
|
||||||
|
uriHandler.openUri(uri)
|
||||||
|
},
|
||||||
onSend = { mail, format ->
|
onSend = { mail, format ->
|
||||||
confirmViewModel.show(bookId = detail.id, email = mail, format = format)
|
scope.launch { emailSheetState.hide() }
|
||||||
|
detailViewModel.send(bookId = detail.id, email = mail, format = format)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -131,13 +134,6 @@ fun DetailScreen(
|
||||||
mails.isEmpty() -> {
|
mails.isEmpty() -> {
|
||||||
context.showToast(context.getString(R.string.error_no_amazon_email))
|
context.showToast(context.getString(R.string.error_no_amazon_email))
|
||||||
}
|
}
|
||||||
mails.size == 1 -> {
|
|
||||||
confirmViewModel.show(
|
|
||||||
bookId = detail.id,
|
|
||||||
email = mails.first(),
|
|
||||||
format = Format.EPUB,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> {
|
else -> {
|
||||||
scope.launch { emailSheetState.show() }
|
scope.launch { emailSheetState.show() }
|
||||||
}
|
}
|
||||||
|
|
@ -152,20 +148,6 @@ fun DetailScreen(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ConfirmDialog(
|
|
||||||
modifier = Modifier.padding(all = MaterialTheme.bibLib.dimen.dp32),
|
|
||||||
confirmViewModel = confirmViewModel,
|
|
||||||
onConfirm = { id, email, format ->
|
|
||||||
scope.launch {
|
|
||||||
confirmViewModel.hide()
|
|
||||||
emailSheetState.hide()
|
|
||||||
detailViewModel.send(bookId = id, email = email, format = format)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onDismiss = { confirmViewModel.hide() },
|
|
||||||
onHelp = { url -> uriHandler.openUri(url) }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,9 +155,8 @@ fun DetailScreen(
|
||||||
LaunchedEffect(key1 = "DetailScreenError") {
|
LaunchedEffect(key1 = "DetailScreenError") {
|
||||||
detailViewModel.error.collect {
|
detailViewModel.error.collect {
|
||||||
val result = snackBarHost.showSnackbar(
|
val result = snackBarHost.showSnackbar(
|
||||||
message = it.message,
|
message = context.getString(it.message),
|
||||||
actionLabel = it.action,
|
actionLabel = context.getString(it.action),
|
||||||
duration = SnackbarDuration.Indefinite,
|
|
||||||
)
|
)
|
||||||
if (result == SnackbarResult.ActionPerformed) {
|
if (result == SnackbarResult.ActionPerformed) {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
|
|
||||||
|
|
@ -1,191 +0,0 @@
|
||||||
package com.pixelized.biblib.ui.screen.home.detail
|
|
||||||
|
|
||||||
import android.content.Context.*
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import androidx.annotation.StringDef
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.*
|
|
||||||
import androidx.compose.material.*
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import androidx.compose.runtime.Stable
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.window.Dialog
|
|
||||||
import androidx.compose.ui.window.DialogProperties
|
|
||||||
import com.pixelized.biblib.R
|
|
||||||
import com.pixelized.biblib.ui.theme.BibLibTheme
|
|
||||||
import com.pixelized.biblib.utils.extention.bibLib
|
|
||||||
import com.pixelized.biblib.utils.extention.default
|
|
||||||
import com.pixelized.biblib.utils.extention.highlight
|
|
||||||
import com.pixelized.biblib.utils.extention.stringRegex
|
|
||||||
|
|
||||||
|
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
|
||||||
@StringDef(Format.EPUB, Format.MOBI)
|
|
||||||
annotation class Format {
|
|
||||||
companion object {
|
|
||||||
const val EPUB = "epub"
|
|
||||||
const val MOBI = "mobi"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Stable
|
|
||||||
@Immutable
|
|
||||||
data class ConfirmDialogUio(
|
|
||||||
val bookId: Int,
|
|
||||||
val email: String,
|
|
||||||
@Format val format: String,
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
@Composable
|
|
||||||
fun preview() = ConfirmDialogUio(
|
|
||||||
bookId = 90,
|
|
||||||
email = "R.Daneel.Olivaw.Kindle@gmail.com",
|
|
||||||
format = Format.EPUB,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ConfirmDialog(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
confirmViewModel: ConfirmDialogViewModel,
|
|
||||||
onConfirm: (bookId: Int, mail: String, format: String) -> Unit = { _, _, _ -> },
|
|
||||||
onHelp: (url: String) -> Unit = default<String>(),
|
|
||||||
onDismiss: () -> Unit
|
|
||||||
) {
|
|
||||||
confirmViewModel.dialog?.let { dialog ->
|
|
||||||
ConfirmDialog(
|
|
||||||
modifier = modifier,
|
|
||||||
uio = dialog,
|
|
||||||
onDismissRequest = onDismiss,
|
|
||||||
onHelp = onHelp,
|
|
||||||
onConfirm = onConfirm,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeUiApi::class)
|
|
||||||
@Composable
|
|
||||||
fun ConfirmDialog(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
uio: ConfirmDialogUio,
|
|
||||||
onDismissRequest: () -> Unit = default(),
|
|
||||||
onHelp: (url: String) -> Unit = default<String>(),
|
|
||||||
onConfirm: (bookId: Int, mail: String, format: String) -> Unit = { _, _, _ -> },
|
|
||||||
) {
|
|
||||||
Dialog(
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
properties = remember { DialogProperties(usePlatformDefaultWidth = false) },
|
|
||||||
) {
|
|
||||||
ConfirmDialogContent(
|
|
||||||
modifier = modifier,
|
|
||||||
uio = uio,
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
onHelp = onHelp,
|
|
||||||
onConfirm = onConfirm,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ConfirmDialogContent(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
uio: ConfirmDialogUio,
|
|
||||||
onDismissRequest: () -> Unit = default(),
|
|
||||||
onHelp: (url: String) -> Unit = default<String>(),
|
|
||||||
onConfirm: (bookId: Int, mail: String, format: String) -> Unit = { _, _, _ -> },
|
|
||||||
) {
|
|
||||||
val amazonHelpUri = stringResource(R.string.detail_send_confirm_help_url)
|
|
||||||
|
|
||||||
Card(
|
|
||||||
modifier = modifier,
|
|
||||||
backgroundColor = MaterialTheme.bibLib.colors.dialogBackground,
|
|
||||||
) {
|
|
||||||
Column(modifier = Modifier.padding(all = MaterialTheme.bibLib.dimen.dp16)) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
|
||||||
style = MaterialTheme.typography.h6,
|
|
||||||
color = MaterialTheme.bibLib.colors.typography.medium,
|
|
||||||
text = stringResource(R.string.detail_send_confirm_title)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
|
||||||
style = MaterialTheme.typography.body1,
|
|
||||||
color = MaterialTheme.bibLib.colors.typography.medium,
|
|
||||||
text = rememberDescription()
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp8),
|
|
||||||
style = MaterialTheme.typography.caption,
|
|
||||||
color = MaterialTheme.bibLib.colors.typography.easy,
|
|
||||||
text = uio.email
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable(onClick = { onHelp(amazonHelpUri) })
|
|
||||||
.padding(vertical = MaterialTheme.bibLib.dimen.dp8),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
style = MaterialTheme.typography.caption,
|
|
||||||
color = MaterialTheme.bibLib.colors.typography.strong,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
maxLines = 1,
|
|
||||||
text = stringResource(R.string.detail_send_confirm_help),
|
|
||||||
)
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = MaterialTheme.bibLib.dimen.dp8),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End),
|
|
||||||
) {
|
|
||||||
Button(
|
|
||||||
colors = ButtonDefaults.outlinedButtonColors(),
|
|
||||||
onClick = onDismissRequest,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.detail_send_confirm_cancel_action)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
colors = ButtonDefaults.buttonColors(),
|
|
||||||
onClick = { onConfirm(uio.bookId, uio.email, uio.format) }
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.detail_send_confirm_confirm_action)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun rememberDescription(): AnnotatedString {
|
|
||||||
val email = stringResource(id = R.string.martin_sender)
|
|
||||||
val description = stringResource(R.string.detail_send_confirm_description, email)
|
|
||||||
return description.highlight(highlight = stringRegex(email))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
|
||||||
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
|
||||||
private fun DetailConfirmPreview() {
|
|
||||||
BibLibTheme {
|
|
||||||
ConfirmDialogContent(
|
|
||||||
uio = ConfirmDialogUio.preview(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package com.pixelized.biblib.ui.screen.home.detail
|
package com.pixelized.biblib.ui.screen.home.detail
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import androidx.annotation.StringDef
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
|
@ -18,13 +19,15 @@ import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
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.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import com.pixelized.biblib.R
|
import com.pixelized.biblib.R
|
||||||
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.*
|
||||||
import com.pixelized.biblib.utils.extention.capitalize
|
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
@Immutable
|
@Immutable
|
||||||
|
|
@ -33,10 +36,20 @@ data class OptionUio(
|
||||||
val selected: Boolean = false,
|
val selected: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
|
@StringDef(Format.EPUB, Format.MOBI)
|
||||||
|
annotation class Format {
|
||||||
|
companion object {
|
||||||
|
const val EPUB = "epub"
|
||||||
|
const val MOBI = "mobi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DetailScreenSendOption(
|
fun DetailScreenSendOption(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
optionViewModel: BookOptionViewModel = hiltViewModel(),
|
optionViewModel: BookOptionViewModel = hiltViewModel(),
|
||||||
|
onHelp: (url: String) -> Unit = default<String>(),
|
||||||
onSend: (email: String, format: String) -> Unit = { _, _ -> },
|
onSend: (email: String, format: String) -> Unit = { _, _ -> },
|
||||||
) {
|
) {
|
||||||
DetailScreenSendOption(
|
DetailScreenSendOption(
|
||||||
|
|
@ -45,6 +58,7 @@ fun DetailScreenSendOption(
|
||||||
formats = optionViewModel.formats,
|
formats = optionViewModel.formats,
|
||||||
onEmail = { optionViewModel.selectMail(it.value) },
|
onEmail = { optionViewModel.selectMail(it.value) },
|
||||||
onFormat = { optionViewModel.selectFormat(it.value) },
|
onFormat = { optionViewModel.selectFormat(it.value) },
|
||||||
|
onHelp = onHelp,
|
||||||
onSend = onSend,
|
onSend = onSend,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -54,19 +68,56 @@ fun DetailScreenSendOption(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
emails: List<OptionUio>,
|
emails: List<OptionUio>,
|
||||||
formats: List<OptionUio>,
|
formats: List<OptionUio>,
|
||||||
|
onHelp: (url: String) -> Unit = default<String>(),
|
||||||
onEmail: (OptionUio) -> Unit = { },
|
onEmail: (OptionUio) -> Unit = { },
|
||||||
onFormat: (OptionUio) -> Unit = { },
|
onFormat: (OptionUio) -> Unit = { },
|
||||||
onSend: (email: String, format: String) -> Unit = { _, _ -> },
|
onSend: (email: String, format: String) -> Unit = { _, _ -> },
|
||||||
) {
|
) {
|
||||||
|
val amazonHelpUri = stringResource(R.string.detail_send_confirm_help_url)
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
|
item {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = MaterialTheme.bibLib.dimen.dp16)
|
||||||
|
.padding(horizontal = MaterialTheme.bibLib.dimen.dp16),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
||||||
|
style = MaterialTheme.typography.h6,
|
||||||
|
color = MaterialTheme.bibLib.colors.typography.medium,
|
||||||
|
text = stringResource(R.string.detail_send_confirm_title)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp8),
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
color = MaterialTheme.bibLib.colors.typography.easy,
|
||||||
|
text = rememberDescription()
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(onClick = { onHelp(amazonHelpUri) })
|
||||||
|
.padding(vertical = MaterialTheme.bibLib.dimen.dp8),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
color = MaterialTheme.bibLib.colors.typography.strong,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
text = stringResource(R.string.detail_send_confirm_help),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(vertical = MaterialTheme.bibLib.dimen.dp8)
|
.padding(vertical = MaterialTheme.bibLib.dimen.dp8)
|
||||||
.padding(horizontal = MaterialTheme.bibLib.dimen.dp16),
|
.padding(horizontal = MaterialTheme.bibLib.dimen.dp16),
|
||||||
color = MaterialTheme.colors.primary,
|
color = MaterialTheme.bibLib.colors.typography.easy,
|
||||||
style = MaterialTheme.typography.caption,
|
style = MaterialTheme.typography.caption,
|
||||||
text = stringResource(id = R.string.detail_option_mail),
|
text = stringResource(id = R.string.detail_option_mail),
|
||||||
)
|
)
|
||||||
|
|
@ -85,7 +136,7 @@ fun DetailScreenSendOption(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(vertical = MaterialTheme.bibLib.dimen.dp8)
|
.padding(vertical = MaterialTheme.bibLib.dimen.dp8)
|
||||||
.padding(horizontal = MaterialTheme.bibLib.dimen.dp16),
|
.padding(horizontal = MaterialTheme.bibLib.dimen.dp16),
|
||||||
color = MaterialTheme.colors.primary,
|
color = MaterialTheme.bibLib.colors.typography.easy,
|
||||||
style = MaterialTheme.typography.caption,
|
style = MaterialTheme.typography.caption,
|
||||||
text = stringResource(id = R.string.detail_option_mail),
|
text = stringResource(id = R.string.detail_option_mail),
|
||||||
)
|
)
|
||||||
|
|
@ -147,6 +198,18 @@ private fun OptionItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun rememberDescription(
|
||||||
|
style: TextStyle = MaterialTheme.typography.caption,
|
||||||
|
): AnnotatedString {
|
||||||
|
val email = stringResource(id = R.string.martin_sender)
|
||||||
|
val description = stringResource(R.string.detail_send_confirm_description, email)
|
||||||
|
return description.highlight(
|
||||||
|
defaultStyle = style.toSpanStyle(),
|
||||||
|
highlight = stringRegex(email),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue