mirror of
https://github.com/Ashinch/ReadYou.git
synced 2025-02-08 16:18:40 +01:00
feat(ui): show full screen image viewer when clicking on images (#578)
This commit is contained in:
parent
57c1d3a5b7
commit
802b14969e
@ -127,6 +127,9 @@ dependencies {
|
|||||||
implementation("io.coil-kt:coil-svg:$coil")
|
implementation("io.coil-kt:coil-svg:$coil")
|
||||||
implementation("io.coil-kt:coil-gif:$coil")
|
implementation("io.coil-kt:coil-gif:$coil")
|
||||||
|
|
||||||
|
// https://saket.github.io/telephoto/zoomableimage/
|
||||||
|
implementation("me.saket.telephoto:zoomable:0.7.1")
|
||||||
|
|
||||||
// Cancel TLSv1.3 support pre Android10
|
// Cancel TLSv1.3 support pre Android10
|
||||||
// implementation 'org.conscrypt:conscrypt-android:2.5.2'
|
// implementation 'org.conscrypt:conscrypt-android:2.5.2'
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ fun LazyListScope.htmlFormattedText(
|
|||||||
subheadUpperCase: Boolean = false,
|
subheadUpperCase: Boolean = false,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
@DrawableRes imagePlaceholder: Int,
|
@DrawableRes imagePlaceholder: Int,
|
||||||
|
onImageClick: ((imgUrl: String, altText: String) -> Unit)? = null,
|
||||||
onLinkClick: (String) -> Unit,
|
onLinkClick: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
Jsoup.parse(inputStream, null, baseUrl)
|
Jsoup.parse(inputStream, null, baseUrl)
|
||||||
@ -77,6 +78,7 @@ fun LazyListScope.htmlFormattedText(
|
|||||||
element = body,
|
element = body,
|
||||||
subheadUpperCase = subheadUpperCase,
|
subheadUpperCase = subheadUpperCase,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -87,6 +89,7 @@ private fun LazyListScope.formatBody(
|
|||||||
element: Element,
|
element: Element,
|
||||||
subheadUpperCase: Boolean = false,
|
subheadUpperCase: Boolean = false,
|
||||||
@DrawableRes imagePlaceholder: Int,
|
@DrawableRes imagePlaceholder: Int,
|
||||||
|
onImageClick: ((imgUrl: String, altText: String) -> Unit)? = null,
|
||||||
onLinkClick: (String) -> Unit,
|
onLinkClick: (String) -> Unit,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
) {
|
) {
|
||||||
@ -129,6 +132,7 @@ private fun LazyListScope.formatBody(
|
|||||||
subheadUpperCase = subheadUpperCase,
|
subheadUpperCase = subheadUpperCase,
|
||||||
lazyListScope = this,
|
lazyListScope = this,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -139,6 +143,7 @@ private fun LazyListScope.formatBody(
|
|||||||
private fun LazyListScope.formatCodeBlock(
|
private fun LazyListScope.formatCodeBlock(
|
||||||
element: Element,
|
element: Element,
|
||||||
@DrawableRes imagePlaceholder: Int,
|
@DrawableRes imagePlaceholder: Int,
|
||||||
|
onImageClick: ((imgUrl: String, altText: String) -> Unit)?,
|
||||||
onLinkClick: (String) -> Unit,
|
onLinkClick: (String) -> Unit,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
) {
|
) {
|
||||||
@ -175,6 +180,7 @@ private fun LazyListScope.formatCodeBlock(
|
|||||||
element.childNodes(), preFormatted = true,
|
element.childNodes(), preFormatted = true,
|
||||||
lazyListScope = this,
|
lazyListScope = this,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -188,6 +194,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
subheadUpperCase: Boolean = false,
|
subheadUpperCase: Boolean = false,
|
||||||
lazyListScope: LazyListScope,
|
lazyListScope: LazyListScope,
|
||||||
@DrawableRes imagePlaceholder: Int,
|
@DrawableRes imagePlaceholder: Int,
|
||||||
|
onImageClick: ((imgUrl: String, altText: String) -> Unit)?,
|
||||||
onLinkClick: (String) -> Unit,
|
onLinkClick: (String) -> Unit,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
) {
|
) {
|
||||||
@ -225,6 +232,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -234,6 +242,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -247,7 +256,12 @@ private fun TextComposer.appendTextChildren(
|
|||||||
withComposableStyle(
|
withComposableStyle(
|
||||||
style = { h1Style().toSpanStyle() }
|
style = { h1Style().toSpanStyle() }
|
||||||
) {
|
) {
|
||||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
append(
|
||||||
|
"\n${
|
||||||
|
if (subheadUpperCase) element.text()
|
||||||
|
.uppercase() else element.text()
|
||||||
|
}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,7 +271,12 @@ private fun TextComposer.appendTextChildren(
|
|||||||
withComposableStyle(
|
withComposableStyle(
|
||||||
style = { h2Style().toSpanStyle() }
|
style = { h2Style().toSpanStyle() }
|
||||||
) {
|
) {
|
||||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
append(
|
||||||
|
"\n${
|
||||||
|
if (subheadUpperCase) element.text()
|
||||||
|
.uppercase() else element.text()
|
||||||
|
}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,7 +286,12 @@ private fun TextComposer.appendTextChildren(
|
|||||||
withComposableStyle(
|
withComposableStyle(
|
||||||
style = { h3Style().toSpanStyle() }
|
style = { h3Style().toSpanStyle() }
|
||||||
) {
|
) {
|
||||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
append(
|
||||||
|
"\n${
|
||||||
|
if (subheadUpperCase) element.text()
|
||||||
|
.uppercase() else element.text()
|
||||||
|
}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,7 +301,12 @@ private fun TextComposer.appendTextChildren(
|
|||||||
withComposableStyle(
|
withComposableStyle(
|
||||||
style = { h4Style().toSpanStyle() }
|
style = { h4Style().toSpanStyle() }
|
||||||
) {
|
) {
|
||||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
append(
|
||||||
|
"\n${
|
||||||
|
if (subheadUpperCase) element.text()
|
||||||
|
.uppercase() else element.text()
|
||||||
|
}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +316,12 @@ private fun TextComposer.appendTextChildren(
|
|||||||
withComposableStyle(
|
withComposableStyle(
|
||||||
style = { h5Style().toSpanStyle() }
|
style = { h5Style().toSpanStyle() }
|
||||||
) {
|
) {
|
||||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
append(
|
||||||
|
"\n${
|
||||||
|
if (subheadUpperCase) element.text()
|
||||||
|
.uppercase() else element.text()
|
||||||
|
}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -297,7 +331,12 @@ private fun TextComposer.appendTextChildren(
|
|||||||
withComposableStyle(
|
withComposableStyle(
|
||||||
style = { h6Style().toSpanStyle() }
|
style = { h6Style().toSpanStyle() }
|
||||||
) {
|
) {
|
||||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
append(
|
||||||
|
"\n${
|
||||||
|
if (subheadUpperCase) element.text()
|
||||||
|
.uppercase() else element.text()
|
||||||
|
}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,6 +349,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -322,6 +362,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -334,6 +375,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -346,6 +388,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -358,6 +401,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -370,6 +414,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -383,6 +428,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -395,6 +441,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
preFormatted = true,
|
preFormatted = true,
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -406,6 +453,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
lazyListScope.formatCodeBlock(
|
lazyListScope.formatCodeBlock(
|
||||||
element = element,
|
element = element,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -419,6 +467,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
preFormatted = preFormatted,
|
preFormatted = preFormatted,
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -438,6 +487,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -454,6 +504,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
element.childNodes(),
|
element.childNodes(),
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -478,11 +529,11 @@ private fun TextComposer.appendTextChildren(
|
|||||||
BoxWithConstraints(
|
BoxWithConstraints(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(RectangleShape)
|
.clip(RectangleShape)
|
||||||
.clickable(
|
// .clickable(
|
||||||
enabled = onClick != null
|
// enabled = onClick != null
|
||||||
) {
|
// ) {
|
||||||
onClick?.invoke()
|
// onClick?.invoke()
|
||||||
}
|
// }
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
// This makes scrolling a pain, find a way to solve that
|
// This makes scrolling a pain, find a way to solve that
|
||||||
// .pointerInput("imgzoom") {
|
// .pointerInput("imgzoom") {
|
||||||
@ -497,17 +548,26 @@ private fun TextComposer.appendTextChildren(
|
|||||||
// }
|
// }
|
||||||
) {
|
) {
|
||||||
val imageSize = maxImageSize()
|
val imageSize = maxImageSize()
|
||||||
|
val imgUrl = imageCandidates.getBestImageForMaxSize(
|
||||||
|
pixelDensity = pixelDensity(),
|
||||||
|
maxSize = imageSize,
|
||||||
|
)
|
||||||
RYAsyncImage(
|
RYAsyncImage(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = imageHorizontalPadding().dp)
|
.padding(horizontal = imageHorizontalPadding().dp)
|
||||||
.clip(imageShape())
|
.clip(imageShape())
|
||||||
.clickable { },
|
.run {
|
||||||
data = imageCandidates.getBestImageForMaxSize(
|
if (onImageClick != null) {
|
||||||
pixelDensity = pixelDensity(),
|
this.clickable {
|
||||||
maxSize = imageSize,
|
onImageClick(imgUrl, alt)
|
||||||
),
|
}
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data = imgUrl,
|
||||||
contentDescription = alt,
|
contentDescription = alt,
|
||||||
size = imageSize,
|
size = imageSize,
|
||||||
precision = Precision.INEXACT,
|
precision = Precision.INEXACT,
|
||||||
@ -547,6 +607,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
|
onImageClick = onImageClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -565,6 +626,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
|
onImageClick = onImageClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -590,6 +652,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
|
onImageClick = onImageClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
ensureDoubleNewline()
|
ensureDoubleNewline()
|
||||||
@ -608,6 +671,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
|
onImageClick = onImageClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
terminateCurrentText()
|
terminateCurrentText()
|
||||||
@ -677,6 +741,7 @@ private fun TextComposer.appendTextChildren(
|
|||||||
subheadUpperCase = subheadUpperCase,
|
subheadUpperCase = subheadUpperCase,
|
||||||
lazyListScope = lazyListScope,
|
lazyListScope = lazyListScope,
|
||||||
imagePlaceholder = imagePlaceholder,
|
imagePlaceholder = imagePlaceholder,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = onLinkClick,
|
onLinkClick = onLinkClick,
|
||||||
baseUrl = baseUrl,
|
baseUrl = baseUrl,
|
||||||
)
|
)
|
||||||
@ -709,7 +774,7 @@ private fun testIt() {
|
|||||||
inputStream = stream,
|
inputStream = stream,
|
||||||
baseUrl = "https://cowboyprogrammer.org",
|
baseUrl = "https://cowboyprogrammer.org",
|
||||||
imagePlaceholder = R.drawable.ic_telegram,
|
imagePlaceholder = R.drawable.ic_telegram,
|
||||||
onLinkClick = {}
|
onLinkClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ fun LazyListScope.Reader(
|
|||||||
subheadUpperCase: Boolean = false,
|
subheadUpperCase: Boolean = false,
|
||||||
link: String,
|
link: String,
|
||||||
content: String,
|
content: String,
|
||||||
|
onImageClick: ((imgUrl: String, altText: String) -> Unit)? = null,
|
||||||
onLinkClick: (String) -> Unit
|
onLinkClick: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
Log.i("RLog", "Reader: ")
|
Log.i("RLog", "Reader: ")
|
||||||
@ -38,6 +39,7 @@ fun LazyListScope.Reader(
|
|||||||
inputStream = content.byteInputStream(),
|
inputStream = content.byteInputStream(),
|
||||||
subheadUpperCase = subheadUpperCase,
|
subheadUpperCase = subheadUpperCase,
|
||||||
baseUrl = link,
|
baseUrl = link,
|
||||||
|
onImageClick = onImageClick,
|
||||||
imagePlaceholder = R.drawable.ic_launcher_foreground,
|
imagePlaceholder = R.drawable.ic_launcher_foreground,
|
||||||
onLinkClick = onLinkClick
|
onLinkClick = onLinkClick
|
||||||
)
|
)
|
||||||
|
@ -31,7 +31,7 @@ fun Content(
|
|||||||
publishedDate: Date,
|
publishedDate: Date,
|
||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
isLoading: Boolean,
|
isLoading: Boolean,
|
||||||
isShowToolBar: Boolean,
|
onImageClick: ((imgUrl: String, altText: String) -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val subheadUpperCase = LocalReadingSubheadUpperCase.current
|
val subheadUpperCase = LocalReadingSubheadUpperCase.current
|
||||||
@ -90,6 +90,7 @@ fun Content(
|
|||||||
subheadUpperCase = subheadUpperCase.value,
|
subheadUpperCase = subheadUpperCase.value,
|
||||||
link = link ?: "",
|
link = link ?: "",
|
||||||
content = content,
|
content = content,
|
||||||
|
onImageClick = onImageClick,
|
||||||
onLinkClick = {
|
onLinkClick = {
|
||||||
context.openURL(it, openLink, openLinkSpecificBrowser)
|
context.openURL(it, openLink, openLinkSpecificBrowser)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
package me.ash.reader.ui.page.home.reading
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.systemBars
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Close
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.IconButtonDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import androidx.compose.ui.window.DialogWindowProvider
|
||||||
|
import me.ash.reader.R
|
||||||
|
import me.ash.reader.ui.component.base.RYAsyncImage
|
||||||
|
import me.saket.telephoto.zoomable.ZoomSpec
|
||||||
|
import me.saket.telephoto.zoomable.rememberZoomableState
|
||||||
|
import me.saket.telephoto.zoomable.zoomable
|
||||||
|
|
||||||
|
data class ImageData(val imageUrl: String = "", val altText: String = "")
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ReaderImageViewer(imageData: ImageData, onDismissRequest: () -> Unit = {}) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
properties = DialogProperties(usePlatformDefaultWidth = false)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
// .background(Color.Black)
|
||||||
|
.windowInsetsPadding(WindowInsets.systemBars)
|
||||||
|
) {
|
||||||
|
val dialogWindowProvider = LocalView.current.parent as? DialogWindowProvider
|
||||||
|
dialogWindowProvider?.window?.setDimAmount(1f)
|
||||||
|
|
||||||
|
val zoomableState = rememberZoomableState().apply {
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
}
|
||||||
|
|
||||||
|
RYAsyncImage(
|
||||||
|
data = imageData.imageUrl,
|
||||||
|
contentDescription = imageData.altText,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.Center)
|
||||||
|
.zoomable(zoomableState)
|
||||||
|
.fillMaxSize(),
|
||||||
|
)
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onClick = onDismissRequest,
|
||||||
|
colors = IconButtonDefaults.iconButtonColors(
|
||||||
|
containerColor = Color.Gray.copy(alpha = 0.5f),
|
||||||
|
contentColor = Color.White
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(12.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Close,
|
||||||
|
contentDescription = stringResource(id = R.string.close)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +1,25 @@
|
|||||||
package me.ash.reader.ui.page.home.reading
|
package me.ash.reader.ui.page.home.reading
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.ContentTransform
|
||||||
|
import androidx.compose.animation.EnterTransition
|
||||||
|
import androidx.compose.animation.ExitTransition
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.snapshotFlow
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
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 androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.distinctUntilChangedBy
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import me.ash.reader.infrastructure.preference.LocalReadingAutoHideToolbar
|
import me.ash.reader.infrastructure.preference.LocalReadingAutoHideToolbar
|
||||||
import me.ash.reader.infrastructure.preference.LocalReadingPageTonalElevation
|
import me.ash.reader.infrastructure.preference.LocalReadingPageTonalElevation
|
||||||
import me.ash.reader.ui.component.base.RYScaffold
|
import me.ash.reader.ui.component.base.RYScaffold
|
||||||
@ -31,7 +28,6 @@ import me.ash.reader.ui.ext.isScrollDown
|
|||||||
import me.ash.reader.ui.motion.materialSharedAxisY
|
import me.ash.reader.ui.motion.materialSharedAxisY
|
||||||
import me.ash.reader.ui.page.home.HomeViewModel
|
import me.ash.reader.ui.page.home.HomeViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalAnimationApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReadingPage(
|
fun ReadingPage(
|
||||||
navController: NavHostController,
|
navController: NavHostController,
|
||||||
@ -44,6 +40,9 @@ fun ReadingPage(
|
|||||||
val homeUiState = homeViewModel.homeUiState.collectAsStateValue()
|
val homeUiState = homeViewModel.homeUiState.collectAsStateValue()
|
||||||
|
|
||||||
var isReaderScrollingDown by remember { mutableStateOf(false) }
|
var isReaderScrollingDown by remember { mutableStateOf(false) }
|
||||||
|
var showFullScreenImageViewer by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
var currentImageData by remember { mutableStateOf(ImageData()) }
|
||||||
|
|
||||||
val isShowToolBar = if (LocalReadingAutoHideToolbar.current.value) {
|
val isShowToolBar = if (LocalReadingAutoHideToolbar.current.value) {
|
||||||
readingUiState.articleId != null && !isReaderScrollingDown
|
readingUiState.articleId != null && !isReaderScrollingDown
|
||||||
@ -128,7 +127,10 @@ fun ReadingPage(
|
|||||||
publishedDate = publishedDate,
|
publishedDate = publishedDate,
|
||||||
isLoading = content is ReaderState.Loading,
|
isLoading = content is ReaderState.Loading,
|
||||||
listState = listState,
|
listState = listState,
|
||||||
isShowToolBar = isShowToolBar,
|
onImageClick = { imgUrl, altText ->
|
||||||
|
currentImageData = ImageData(imgUrl, altText)
|
||||||
|
showFullScreenImageViewer = true
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,4 +161,7 @@ fun ReadingPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
if (showFullScreenImageViewer) {
|
||||||
|
ReaderImageViewer(imageData = currentImageData) { showFullScreenImageViewer = false }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user