Add option for rendering images in description (mihonapp/mihon#2076)
(cherry picked from commit 2ef8ae11c9da02c24bf4d12bf22b41c5d19bada4)
This commit is contained in:
parent
71548322e5
commit
7acd998b12
6 changed files with 98 additions and 8 deletions
|
|
@ -18,6 +18,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
|
||||||
- Add markdown support for manga descriptions ([@Secozzi](https://github.com/Secozzi)) ([#1948](https://github.com/mihonapp/mihon/pull/1948))
|
- Add markdown support for manga descriptions ([@Secozzi](https://github.com/Secozzi)) ([#1948](https://github.com/mihonapp/mihon/pull/1948))
|
||||||
- Use simpler markdown flavour ([@Secozzi](https://github.com/Secozzi)) ([#2000](https://github.com/mihonapp/mihon/pull/2000))
|
- Use simpler markdown flavour ([@Secozzi](https://github.com/Secozzi)) ([#2000](https://github.com/mihonapp/mihon/pull/2000))
|
||||||
- Use Github markdown flavour for Github releases & fix bullet list alignment ([@Secozzi](https://github.com/Secozzi)) ([#2024](https://github.com/mihonapp/mihon/pull/2024))
|
- Use Github markdown flavour for Github releases & fix bullet list alignment ([@Secozzi](https://github.com/Secozzi)) ([#2024](https://github.com/mihonapp/mihon/pull/2024))
|
||||||
|
- Add option to toggle image loading ([@Secozzi](https://github.com/Secozzi)) ([#2076](https://github.com/mihonapp/mihon/pull/2076))
|
||||||
- Add Nord Theme ([@Riztard](https://github.com/Riztard)) ([#1951](https://github.com/mihonapp/mihon/pull/1951))
|
- Add Nord Theme ([@Riztard](https://github.com/Riztard)) ([#1951](https://github.com/mihonapp/mihon/pull/1951))
|
||||||
- Option to keep read manga when clearing database ([@AwkwardPeak7](https://github.com/AwkwardPeak7)) ([#1979](https://github.com/mihonapp/mihon/pull/1979))
|
- Option to keep read manga when clearing database ([@AwkwardPeak7](https://github.com/AwkwardPeak7)) ([#1979](https://github.com/mihonapp/mihon/pull/1979))
|
||||||
- Add advanced option to always update manga title from source ([@FlaminSarge](https://github.com/FlaminSarge)) ([#1182](https://github.com/mihonapp/mihon/pull/1182))
|
- Add advanced option to always update manga title from source ([@FlaminSarge](https://github.com/FlaminSarge)) ([#1182](https://github.com/mihonapp/mihon/pull/1182))
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ class UiPreferences(
|
||||||
|
|
||||||
fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)
|
fun tabletUiMode() = preferenceStore.getEnum("tablet_ui_mode", TabletUiMode.AUTOMATIC)
|
||||||
|
|
||||||
|
fun imagesInDescription() = preferenceStore.getBoolean("pref_render_images_description", true)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
|
|
||||||
fun expandFilters() = preferenceStore.getBoolean("eh_expand_filters", false)
|
fun expandFilters() = preferenceStore.getBoolean("eh_expand_filters", false)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
import androidx.compose.foundation.layout.sizeIn
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.text.appendInlineContent
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.CallMerge
|
import androidx.compose.material.icons.automirrored.outlined.CallMerge
|
||||||
|
|
@ -72,8 +73,11 @@ import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.layout.Layout
|
import androidx.compose.ui.layout.Layout
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.text.LinkAnnotation
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
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.text.withLink
|
||||||
import androidx.compose.ui.unit.Constraints
|
import androidx.compose.ui.unit.Constraints
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -83,11 +87,15 @@ import coil3.request.ImageRequest
|
||||||
import coil3.request.crossfade
|
import coil3.request.crossfade
|
||||||
import com.mikepenz.markdown.model.markdownAnnotator
|
import com.mikepenz.markdown.model.markdownAnnotator
|
||||||
import com.mikepenz.markdown.model.markdownAnnotatorConfig
|
import com.mikepenz.markdown.model.markdownAnnotatorConfig
|
||||||
|
import com.mikepenz.markdown.utils.getUnescapedTextInNode
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.presentation.components.DropdownMenu
|
import eu.kanade.presentation.components.DropdownMenu
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
|
import org.intellij.markdown.MarkdownElementTypes
|
||||||
|
import org.intellij.markdown.MarkdownTokenTypes
|
||||||
|
import org.intellij.markdown.ast.findChildOfType
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
|
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
|
||||||
import tachiyomi.domain.manga.interactor.FetchInterval
|
import tachiyomi.domain.manga.interactor.FetchInterval
|
||||||
|
|
@ -862,8 +870,33 @@ private fun ColumnScope.MangaContentInfo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val descriptionAnnotator = markdownAnnotator(
|
private fun descriptionAnnotator(loadImages: Boolean, linkStyle: SpanStyle) = markdownAnnotator(
|
||||||
annotate = { content, child ->
|
annotate = { content, child ->
|
||||||
|
if (!loadImages && child.type == MarkdownElementTypes.IMAGE) {
|
||||||
|
val inlineLink = child.findChildOfType(MarkdownElementTypes.INLINE_LINK)
|
||||||
|
|
||||||
|
val url = inlineLink?.findChildOfType(MarkdownElementTypes.LINK_DESTINATION)
|
||||||
|
?.getUnescapedTextInNode(content)
|
||||||
|
?: inlineLink?.findChildOfType(MarkdownElementTypes.AUTOLINK)
|
||||||
|
?.findChildOfType(MarkdownTokenTypes.AUTOLINK)
|
||||||
|
?.getUnescapedTextInNode(content)
|
||||||
|
?: return@markdownAnnotator false
|
||||||
|
|
||||||
|
val textNode = inlineLink?.findChildOfType(MarkdownElementTypes.LINK_TITLE)
|
||||||
|
?: inlineLink?.findChildOfType(MarkdownElementTypes.LINK_TEXT)
|
||||||
|
val altText = textNode?.findChildOfType(MarkdownTokenTypes.TEXT)
|
||||||
|
?.getUnescapedTextInNode(content).orEmpty()
|
||||||
|
|
||||||
|
withLink(LinkAnnotation.Url(url = url)) {
|
||||||
|
pushStyle(linkStyle)
|
||||||
|
appendInlineContent(MARKDOWN_INLINE_IMAGE_TAG)
|
||||||
|
append(altText)
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
return@markdownAnnotator true
|
||||||
|
}
|
||||||
|
|
||||||
if (child.type in DISALLOWED_MARKDOWN_TYPES) {
|
if (child.type in DISALLOWED_MARKDOWN_TYPES) {
|
||||||
append(content.substring(child.startOffset, child.endOffset))
|
append(content.substring(child.startOffset, child.endOffset))
|
||||||
return@markdownAnnotator true
|
return@markdownAnnotator true
|
||||||
|
|
@ -884,6 +917,8 @@ private fun MangaSummary(
|
||||||
onEditNotesClicked: () -> Unit,
|
onEditNotesClicked: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
val preferences = remember { Injekt.get<UiPreferences>() }
|
||||||
|
val loadImages = remember { preferences.imagesInDescription().get() }
|
||||||
val animProgress by animateFloatAsState(
|
val animProgress by animateFloatAsState(
|
||||||
targetValue = if (expanded) 1f else 0f,
|
targetValue = if (expanded) 1f else 0f,
|
||||||
label = "summary",
|
label = "summary",
|
||||||
|
|
@ -911,7 +946,11 @@ private fun MangaSummary(
|
||||||
MarkdownRender(
|
MarkdownRender(
|
||||||
content = description,
|
content = description,
|
||||||
modifier = Modifier.secondaryItemAlpha(),
|
modifier = Modifier.secondaryItemAlpha(),
|
||||||
annotator = descriptionAnnotator,
|
annotator = descriptionAnnotator(
|
||||||
|
loadImages = loadImages,
|
||||||
|
linkStyle = getMarkdownLinkStyle().toSpanStyle(),
|
||||||
|
),
|
||||||
|
loadImages = loadImages,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -927,7 +966,11 @@ private fun MangaSummary(
|
||||||
MarkdownRender(
|
MarkdownRender(
|
||||||
content = description,
|
content = description,
|
||||||
modifier = Modifier.secondaryItemAlpha(),
|
modifier = Modifier.secondaryItemAlpha(),
|
||||||
annotator = descriptionAnnotator,
|
annotator = descriptionAnnotator(
|
||||||
|
loadImages = loadImages,
|
||||||
|
linkStyle = getMarkdownLinkStyle().toSpanStyle(),
|
||||||
|
),
|
||||||
|
loadImages = loadImages,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.text.InlineTextContent
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Image
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
|
@ -12,6 +16,8 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.FirstBaseline
|
import androidx.compose.ui.layout.FirstBaseline
|
||||||
|
import androidx.compose.ui.text.Placeholder
|
||||||
|
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.TextLinkStyles
|
import androidx.compose.ui.text.TextLinkStyles
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
|
@ -32,11 +38,13 @@ import com.mikepenz.markdown.compose.elements.MarkdownTableRow
|
||||||
import com.mikepenz.markdown.compose.elements.MarkdownText
|
import com.mikepenz.markdown.compose.elements.MarkdownText
|
||||||
import com.mikepenz.markdown.compose.elements.listDepth
|
import com.mikepenz.markdown.compose.elements.listDepth
|
||||||
import com.mikepenz.markdown.model.DefaultMarkdownColors
|
import com.mikepenz.markdown.model.DefaultMarkdownColors
|
||||||
|
import com.mikepenz.markdown.model.DefaultMarkdownInlineContent
|
||||||
import com.mikepenz.markdown.model.DefaultMarkdownTypography
|
import com.mikepenz.markdown.model.DefaultMarkdownTypography
|
||||||
import com.mikepenz.markdown.model.MarkdownAnnotator
|
import com.mikepenz.markdown.model.MarkdownAnnotator
|
||||||
import com.mikepenz.markdown.model.MarkdownColors
|
import com.mikepenz.markdown.model.MarkdownColors
|
||||||
import com.mikepenz.markdown.model.MarkdownPadding
|
import com.mikepenz.markdown.model.MarkdownPadding
|
||||||
import com.mikepenz.markdown.model.MarkdownTypography
|
import com.mikepenz.markdown.model.MarkdownTypography
|
||||||
|
import com.mikepenz.markdown.model.NoOpImageTransformerImpl
|
||||||
import com.mikepenz.markdown.model.markdownAnnotator
|
import com.mikepenz.markdown.model.markdownAnnotator
|
||||||
import com.mikepenz.markdown.model.rememberMarkdownState
|
import com.mikepenz.markdown.model.rememberMarkdownState
|
||||||
import org.intellij.markdown.MarkdownTokenTypes.Companion.HTML_TAG
|
import org.intellij.markdown.MarkdownTokenTypes.Companion.HTML_TAG
|
||||||
|
|
@ -59,12 +67,15 @@ import org.intellij.markdown.parser.markerblocks.providers.ListMarkerProvider
|
||||||
import org.intellij.markdown.parser.markerblocks.providers.SetextHeaderProvider
|
import org.intellij.markdown.parser.markerblocks.providers.SetextHeaderProvider
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
|
|
||||||
|
const val MARKDOWN_INLINE_IMAGE_TAG = "MARKDOWN_INLINE_IMAGE"
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MarkdownRender(
|
fun MarkdownRender(
|
||||||
content: String,
|
content: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
flavour: MarkdownFlavourDescriptor = SimpleMarkdownFlavourDescriptor,
|
flavour: MarkdownFlavourDescriptor = SimpleMarkdownFlavourDescriptor,
|
||||||
annotator: MarkdownAnnotator = remember { markdownAnnotator() },
|
annotator: MarkdownAnnotator = remember { markdownAnnotator() },
|
||||||
|
loadImages: Boolean = true,
|
||||||
) {
|
) {
|
||||||
Markdown(
|
Markdown(
|
||||||
markdownState = rememberMarkdownState(
|
markdownState = rememberMarkdownState(
|
||||||
|
|
@ -77,7 +88,10 @@ fun MarkdownRender(
|
||||||
typography = getMarkdownTypography(),
|
typography = getMarkdownTypography(),
|
||||||
padding = markdownPadding,
|
padding = markdownPadding,
|
||||||
components = markdownComponents,
|
components = markdownComponents,
|
||||||
imageTransformer = Coil3ImageTransformerImpl,
|
imageTransformer = remember(loadImages) {
|
||||||
|
if (loadImages) Coil3ImageTransformerImpl else NoOpImageTransformerImpl()
|
||||||
|
},
|
||||||
|
inlineContent = getMarkdownInlineContent(),
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -101,11 +115,15 @@ private fun getMarkdownColors(): MarkdownColors {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ReadOnlyComposable
|
@ReadOnlyComposable
|
||||||
private fun getMarkdownTypography(): MarkdownTypography {
|
fun getMarkdownLinkStyle() = MaterialTheme.typography.bodyMedium.copy(
|
||||||
val link = MaterialTheme.typography.bodyMedium.copy(
|
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
private fun getMarkdownTypography(): MarkdownTypography {
|
||||||
|
val link = getMarkdownLinkStyle()
|
||||||
return DefaultMarkdownTypography(
|
return DefaultMarkdownTypography(
|
||||||
h1 = MaterialTheme.typography.headlineMedium,
|
h1 = MaterialTheme.typography.headlineMedium,
|
||||||
h2 = MaterialTheme.typography.headlineSmall,
|
h2 = MaterialTheme.typography.headlineSmall,
|
||||||
|
|
@ -216,6 +234,27 @@ private val markdownComponents = markdownComponents(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
private fun getMarkdownInlineContent() = DefaultMarkdownInlineContent(
|
||||||
|
inlineContent = mapOf(
|
||||||
|
MARKDOWN_INLINE_IMAGE_TAG to InlineTextContent(
|
||||||
|
placeholder = Placeholder(
|
||||||
|
width = MaterialTheme.typography.bodyMedium.fontSize * 1.25,
|
||||||
|
height = MaterialTheme.typography.bodyMedium.fontSize * 1.25,
|
||||||
|
placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter,
|
||||||
|
),
|
||||||
|
children = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Image,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
private object SimpleMarkdownFlavourDescriptor : CommonMarkFlavourDescriptor() {
|
private object SimpleMarkdownFlavourDescriptor : CommonMarkFlavourDescriptor() {
|
||||||
override val markerProcessorFactory: MarkerProcessorFactory = SimpleMarkdownProcessFactory
|
override val markerProcessorFactory: MarkerProcessorFactory = SimpleMarkdownProcessFactory
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,10 @@ object SettingsAppearanceScreen : SearchableSettings {
|
||||||
formattedNow,
|
formattedNow,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
preference = uiPreferences.imagesInDescription(),
|
||||||
|
title = stringResource(MR.strings.pref_display_images_description),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,7 @@
|
||||||
<!-- "Today" instead of "2023-12-31" -->
|
<!-- "Today" instead of "2023-12-31" -->
|
||||||
<string name="pref_relative_format_summary">\"%1$s\" instead of \"%2$s\"</string>
|
<string name="pref_relative_format_summary">\"%1$s\" instead of \"%2$s\"</string>
|
||||||
<string name="pref_date_format">Date format</string>
|
<string name="pref_date_format">Date format</string>
|
||||||
|
<string name="pref_display_images_description">Render images in manga descriptions</string>
|
||||||
|
|
||||||
<string name="pref_manage_notifications">Manage notifications</string>
|
<string name="pref_manage_notifications">Manage notifications</string>
|
||||||
<string name="pref_app_language">App language</string>
|
<string name="pref_app_language">App language</string>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue