Clean the confirmation dialog.
This commit is contained in:
parent
d916356653
commit
1401c7159c
6 changed files with 76 additions and 42 deletions
|
|
@ -5,8 +5,6 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import com.pixelized.biblib.R
|
|
||||||
import com.pixelized.biblib.utils.extention.context
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
@ -18,15 +16,10 @@ class ConfirmDialogViewModel @Inject constructor(
|
||||||
var dialog by mutableStateOf<ConfirmDialogUio?>(null)
|
var dialog by mutableStateOf<ConfirmDialogUio?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun show(email: String) {
|
fun show(bookId: Int, email: String) {
|
||||||
this.dialog = ConfirmDialogUio(
|
this.dialog = ConfirmDialogUio(
|
||||||
|
bookId = bookId,
|
||||||
email = email,
|
email = email,
|
||||||
title = context.getString(R.string.detail_send_confirm_title),
|
|
||||||
description = context.getString(R.string.detail_send_confirm_description),
|
|
||||||
help = context.getString(R.string.detail_send_confirm_help),
|
|
||||||
helpUrl = context.getString(R.string.detail_send_confirm_help_url),
|
|
||||||
confirm = context.getString(R.string.detail_send_confirm_confirm_action),
|
|
||||||
cancel = context.getString(R.string.detail_send_confirm_cancel_action),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.pixelized.biblib.ui.screen.home.detail
|
package com.pixelized.biblib.ui.screen.home.detail
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
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
|
||||||
|
|
@ -42,7 +41,7 @@ data class BookDetailUio(
|
||||||
author = "Asimov",
|
author = "Asimov",
|
||||||
date = "1951",
|
date = "1951",
|
||||||
series = "Foundation - 1",
|
series = "Foundation - 1",
|
||||||
description = "", // "En ce début de treizième millénaire, l'Empire n'a jamais été aussi puissant, aussi étendu à travers toute la galaxie. C'est dans sa capitale, Trantor, que l'éminent savant Hari Seldon invente la psychohistoire, une science nouvelle permettant de prédire l'avenir. Grâce à elle, Seldon prévoit l'effondrement de l'Empire d'ici cinq siècles, suivi d'une ère de ténèbres de trente mille ans. Réduire cette période à mille ans est peut-être possible, à condition de mener à terme son projet : la Fondation, chargée de rassembler toutes les connaissances humaines. Une entreprise visionnaire qui rencontre de nombreux et puissants détracteurs...",
|
description = "En ce début de treizième millénaire, l'Empire n'a jamais été aussi puissant, aussi étendu à travers toute la galaxie. C'est dans sa capitale, Trantor, que l'éminent savant Hari Seldon invente la psychohistoire, une science nouvelle permettant de prédire l'avenir. Grâce à elle, Seldon prévoit l'effondrement de l'Empire d'ici cinq siècles, suivi d'une ère de ténèbres de trente mille ans. Réduire cette période à mille ans est peut-être possible, à condition de mener à terme son projet : la Fondation, chargée de rassembler toutes les connaissances humaines. Une entreprise visionnaire qui rencontre de nombreux et puissants détracteurs...",
|
||||||
rating = 4.5f,
|
rating = 4.5f,
|
||||||
language = "Français",
|
language = "Français",
|
||||||
cover = "",
|
cover = "",
|
||||||
|
|
@ -107,7 +106,7 @@ fun DetailScreen(
|
||||||
.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
||||||
profileViewModel = profileViewModel,
|
profileViewModel = profileViewModel,
|
||||||
onEmail = { mail ->
|
onEmail = { mail ->
|
||||||
confirmViewModel.show(email = mail)
|
confirmViewModel.show(bookId = detail.id, email = mail)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -131,7 +130,10 @@ fun DetailScreen(
|
||||||
context.showToast(context.getString(R.string.error_no_amazon_email))
|
context.showToast(context.getString(R.string.error_no_amazon_email))
|
||||||
}
|
}
|
||||||
mails.size == 1 -> {
|
mails.size == 1 -> {
|
||||||
confirmViewModel.show(email = mails.first())
|
confirmViewModel.show(
|
||||||
|
bookId = detail.id,
|
||||||
|
email = mails.first()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
scope.launch { emailSheetState.show() }
|
scope.launch { emailSheetState.show() }
|
||||||
|
|
@ -151,7 +153,6 @@ fun DetailScreen(
|
||||||
ConfirmDialog(
|
ConfirmDialog(
|
||||||
modifier = Modifier.padding(all = MaterialTheme.bibLib.dimen.dp32),
|
modifier = Modifier.padding(all = MaterialTheme.bibLib.dimen.dp32),
|
||||||
confirmViewModel = confirmViewModel,
|
confirmViewModel = confirmViewModel,
|
||||||
detail = detail,
|
|
||||||
onConfirm = { id, email ->
|
onConfirm = { id, email ->
|
||||||
scope.launch {
|
scope.launch {
|
||||||
confirmViewModel.hide()
|
confirmViewModel.hide()
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
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.style.TextAlign
|
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
|
||||||
|
|
@ -22,28 +23,20 @@ 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.bibLib
|
||||||
import com.pixelized.biblib.utils.extention.default
|
import com.pixelized.biblib.utils.extention.default
|
||||||
|
import com.pixelized.biblib.utils.extention.highlight
|
||||||
|
import com.pixelized.biblib.utils.extention.stringRegex
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
@Immutable
|
@Immutable
|
||||||
data class ConfirmDialogUio(
|
data class ConfirmDialogUio(
|
||||||
|
val bookId: Int,
|
||||||
val email: String,
|
val email: String,
|
||||||
val title: String,
|
|
||||||
val description: String,
|
|
||||||
val help: String,
|
|
||||||
val helpUrl: String,
|
|
||||||
val confirm: String,
|
|
||||||
val cancel: String,
|
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
@Composable
|
@Composable
|
||||||
fun preview() = ConfirmDialogUio(
|
fun preview() = ConfirmDialogUio(
|
||||||
|
bookId = 90,
|
||||||
email = "R.Daneel.Olivaw.Kindle@gmail.com",
|
email = "R.Daneel.Olivaw.Kindle@gmail.com",
|
||||||
title = stringResource(R.string.detail_send_confirm_title),
|
|
||||||
description = stringResource(R.string.detail_send_confirm_description),
|
|
||||||
help = stringResource(R.string.detail_send_confirm_help),
|
|
||||||
helpUrl = stringResource(R.string.detail_send_confirm_help_url),
|
|
||||||
confirm = stringResource(R.string.detail_send_confirm_confirm_action),
|
|
||||||
cancel = stringResource(R.string.detail_send_confirm_cancel_action),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +45,6 @@ data class ConfirmDialogUio(
|
||||||
fun ConfirmDialog(
|
fun ConfirmDialog(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
confirmViewModel: ConfirmDialogViewModel,
|
confirmViewModel: ConfirmDialogViewModel,
|
||||||
detail: BookDetailUio,
|
|
||||||
onConfirm: (bookId: Int, mail: String) -> Unit = { _, _ -> },
|
onConfirm: (bookId: Int, mail: String) -> Unit = { _, _ -> },
|
||||||
onHelp: (url: String) -> Unit = default<String>(),
|
onHelp: (url: String) -> Unit = default<String>(),
|
||||||
onDismiss: () -> Unit
|
onDismiss: () -> Unit
|
||||||
|
|
@ -62,8 +54,8 @@ fun ConfirmDialog(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
uio = dialog,
|
uio = dialog,
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
onConfirm = { onConfirm(detail.id, dialog.email) },
|
|
||||||
onHelp = onHelp,
|
onHelp = onHelp,
|
||||||
|
onConfirm = onConfirm,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +67,7 @@ fun ConfirmDialog(
|
||||||
uio: ConfirmDialogUio,
|
uio: ConfirmDialogUio,
|
||||||
onDismissRequest: () -> Unit = default(),
|
onDismissRequest: () -> Unit = default(),
|
||||||
onHelp: (url: String) -> Unit = default<String>(),
|
onHelp: (url: String) -> Unit = default<String>(),
|
||||||
onConfirm: (mail: String) -> Unit = default<String>(),
|
onConfirm: (bookId: Int, mail: String) -> Unit = { _, _ -> },
|
||||||
) {
|
) {
|
||||||
Dialog(
|
Dialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
|
|
@ -97,8 +89,10 @@ fun ConfirmDialogContent(
|
||||||
uio: ConfirmDialogUio,
|
uio: ConfirmDialogUio,
|
||||||
onDismissRequest: () -> Unit = default(),
|
onDismissRequest: () -> Unit = default(),
|
||||||
onHelp: (url: String) -> Unit = default<String>(),
|
onHelp: (url: String) -> Unit = default<String>(),
|
||||||
onConfirm: (mail: String) -> Unit = default<String>(),
|
onConfirm: (bookId: Int, mail: String) -> Unit = { _, _ -> },
|
||||||
) {
|
) {
|
||||||
|
val amazonHelpUri = stringResource(R.string.detail_send_confirm_help_url)
|
||||||
|
|
||||||
Card(
|
Card(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
backgroundColor = MaterialTheme.bibLib.colors.dialogBackground,
|
backgroundColor = MaterialTheme.bibLib.colors.dialogBackground,
|
||||||
|
|
@ -108,14 +102,14 @@ fun ConfirmDialogContent(
|
||||||
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
||||||
style = MaterialTheme.typography.h6,
|
style = MaterialTheme.typography.h6,
|
||||||
color = MaterialTheme.bibLib.colors.typography.medium,
|
color = MaterialTheme.bibLib.colors.typography.medium,
|
||||||
text = uio.title
|
text = stringResource(R.string.detail_send_confirm_title)
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
modifier = Modifier.padding(bottom = MaterialTheme.bibLib.dimen.dp16),
|
||||||
style = MaterialTheme.typography.body1,
|
style = MaterialTheme.typography.body1,
|
||||||
color = MaterialTheme.bibLib.colors.typography.medium,
|
color = MaterialTheme.bibLib.colors.typography.medium,
|
||||||
text = uio.description
|
text = rememberDescription()
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -127,14 +121,14 @@ fun ConfirmDialogContent(
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(onClick = { onHelp(uio.helpUrl) })
|
.clickable(onClick = { onHelp(amazonHelpUri) })
|
||||||
.padding(vertical = MaterialTheme.bibLib.dimen.dp8),
|
.padding(vertical = MaterialTheme.bibLib.dimen.dp8),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
style = MaterialTheme.typography.caption,
|
style = MaterialTheme.typography.caption,
|
||||||
color = MaterialTheme.bibLib.colors.typography.strong,
|
color = MaterialTheme.bibLib.colors.typography.strong,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
text = uio.help
|
text = stringResource(R.string.detail_send_confirm_help),
|
||||||
)
|
)
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -147,19 +141,30 @@ fun ConfirmDialogContent(
|
||||||
colors = ButtonDefaults.outlinedButtonColors(),
|
colors = ButtonDefaults.outlinedButtonColors(),
|
||||||
onClick = onDismissRequest,
|
onClick = onDismissRequest,
|
||||||
) {
|
) {
|
||||||
Text(text = uio.cancel)
|
Text(
|
||||||
|
text = stringResource(R.string.detail_send_confirm_confirm_action)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
colors = ButtonDefaults.buttonColors(),
|
colors = ButtonDefaults.buttonColors(),
|
||||||
onClick = { onConfirm(uio.email) }
|
onClick = { onConfirm(uio.bookId, uio.email) }
|
||||||
) {
|
) {
|
||||||
Text(text = uio.confirm)
|
Text(
|
||||||
|
text = stringResource(R.string.detail_send_confirm_cancel_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
|
@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)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,42 @@
|
||||||
package com.pixelized.biblib.utils.extention
|
package com.pixelized.biblib.utils.extention
|
||||||
|
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
fun String.capitalize() = this.replaceFirstChar {
|
fun String.capitalize() = this.replaceFirstChar {
|
||||||
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
|
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun stringRegex(
|
||||||
|
annotatedText: String
|
||||||
|
) = remember(annotatedText) {
|
||||||
|
Regex(annotatedText)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun String.highlight(
|
||||||
|
highlight: Regex,
|
||||||
|
defaultStyle: SpanStyle = MaterialTheme.typography.body1.toSpanStyle(),
|
||||||
|
strongStyle: SpanStyle = defaultStyle.copy(fontWeight = FontWeight.Bold),
|
||||||
|
): AnnotatedString = remember(this, highlight, defaultStyle, strongStyle) {
|
||||||
|
buildAnnotatedString {
|
||||||
|
withStyle(defaultStyle) {
|
||||||
|
append(this@highlight)
|
||||||
|
}
|
||||||
|
highlight.find(this@highlight)?.let { result ->
|
||||||
|
addStyle(
|
||||||
|
style = strongStyle,
|
||||||
|
start = result.range.first,
|
||||||
|
end = result.range.last + 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
<string name="error_book">Oups! le téléchargement de la librairy à échoué !</string>
|
<string name="error_book">Oups! le téléchargement de la librairy à échoué !</string>
|
||||||
<string name="error_offline">Vous êtes hors ligne.</string>
|
<string name="error_offline">Vous êtes hors ligne.</string>
|
||||||
<string name="error_no_amazon_email">Vous n\'avez aucun mail lié à votre compte. Merci de vous rendre sur https://bib.bibulle.fr/ et d\'éditez voter profile pour en ajouter un.</string>
|
<string name="error_no_amazon_email">Vous n\'avez aucun mail lié à votre compte. Merci de vous rendre sur https://bib.bibulle.fr/ et d\'éditez voter profile pour en ajouter un.</string>
|
||||||
|
|
||||||
<string name="loading_authentication">Ouverture de BibLibrary.</string>
|
<string name="loading_authentication">Ouverture de BibLibrary.</string>
|
||||||
<string name="loading_book">Téléchargement de BibLibrary.</string>
|
<string name="loading_book">Téléchargement de BibLibrary.</string>
|
||||||
|
|
||||||
|
|
@ -51,7 +50,7 @@
|
||||||
<string name="detail_emails_title">Envoyer cet eBook à :</string>
|
<string name="detail_emails_title">Envoyer cet eBook à :</string>
|
||||||
|
|
||||||
<string name="detail_send_confirm_title">Envoyer sur votre Kindle</string>
|
<string name="detail_send_confirm_title">Envoyer sur votre Kindle</string>
|
||||||
<string name="detail_send_confirm_description">Assurez-vous que votre Kindle dispose d\'une connexion Internet et que l\'adresse e-mail suivante est correctement configurée.</string>
|
<string name="detail_send_confirm_description">Assurez-vous que votre Kindle dispose d\'une connexion Internet, que %1$s est un expéditeur approuvé et que l\'adresse e-mail suivante est correctement configurée sur votre compte Amazon.</string>
|
||||||
<string name="detail_send_confirm_help">Aide à la configuration du kindle</string>
|
<string name="detail_send_confirm_help">Aide à la configuration du kindle</string>
|
||||||
<string name="detail_send_confirm_help_url">https://www.amazon.fr/gp/help/customer/display.html?nodeId=G7NECT4B4ZWHQ8WV</string>
|
<string name="detail_send_confirm_help_url">https://www.amazon.fr/gp/help/customer/display.html?nodeId=G7NECT4B4ZWHQ8WV</string>
|
||||||
<string name="detail_send_confirm_confirm_action">Oui</string>
|
<string name="detail_send_confirm_confirm_action">Oui</string>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<string name="app_name" translatable="false">BibLibrary</string>
|
<string name="app_name" translatable="false">BibLibrary</string>
|
||||||
<string name="app_version" translatable="false">%1$s: %2$s - %3$d</string>
|
<string name="app_version" translatable="false">%1$s: %2$s - %3$d</string>
|
||||||
<string name="not_implemented_yet" translatable="false">Not implemented yet.</string>
|
<string name="not_implemented_yet" translatable="false">Not implemented yet.</string>
|
||||||
|
<string name="martin_sender">famille.martin@gmail.com</string>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
|
|
||||||
|
|
@ -61,11 +62,11 @@
|
||||||
<string name="detail_emails_title">Send this eBook to:</string>
|
<string name="detail_emails_title">Send this eBook to:</string>
|
||||||
|
|
||||||
<string name="detail_send_confirm_title">Send to your Kindle</string>
|
<string name="detail_send_confirm_title">Send to your Kindle</string>
|
||||||
<string name="detail_send_confirm_description">Make sure your Kindle has an internet connection and the following email address is correctly set up.</string>
|
<string name="detail_send_confirm_description">Make sure your Kindle has an internet connection, that %1$s is an approved expeditor and that the following email address is correctly set up on your Amazon Account.</string>
|
||||||
<string name="detail_send_confirm_help">Help me configure my kindle</string>
|
<string name="detail_send_confirm_help">Help me configure my kindle</string>
|
||||||
<string name="detail_send_confirm_help_url">https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=G7NECT4B4ZWHQ8WV</string>
|
<string name="detail_send_confirm_help_url">https://www.amazon.co.uk/gp/help/customer/display.html?nodeId=G7NECT4B4ZWHQ8WV</string>
|
||||||
<string name="detail_send_confirm_confirm_action">Oui</string>
|
<string name="detail_send_confirm_confirm_action">Yes</string>
|
||||||
<string name="detail_send_confirm_cancel_action">Annuler</string>
|
<string name="detail_send_confirm_cancel_action">Cancel</string>
|
||||||
|
|
||||||
<string name="search_title">Search on Biblib</string>
|
<string name="search_title">Search on Biblib</string>
|
||||||
<string name="search_filter_title">Search</string>
|
<string name="search_filter_title">Search</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue