Merge confirm & option dialog / bottomsheet

This commit is contained in:
Thomas Andres Gomez 2022-10-22 13:26:42 +02:00
parent 3e234cc37d
commit 2a92fd2b8b
6 changed files with 103 additions and 272 deletions

View file

@ -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,

View file

@ -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()),
)
} }

View file

@ -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
}
}

View file

@ -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) {

View file

@ -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(),
)
}
}

View file

@ -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)