Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AniList Markdown preview #112

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/anilist/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ dependencies {
implementation(libs.hilt.android)
implementation(libs.hilt.navigationCompose)
ksp(libs.hilt.android.compiler)

implementation(libs.intellij.markdown)
}

apollo {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.imashnake.animite.api.anilist.markdown

import android.util.Log
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.withStyle
import org.intellij.markdown.MarkdownElementTypes
import org.intellij.markdown.MarkdownTokenTypes
import org.intellij.markdown.ast.ASTNode
import org.intellij.markdown.ast.getTextInNode

fun ASTNode.toAnnotatedString(text: String): AnnotatedString = buildAnnotatedString {
this@toAnnotatedString.traverse { currentNode ->
when (currentNode.type) {
MarkdownElementTypes.EMPH -> {
if (currentNode.children.size == 3) {
withStyle(style = SpanStyle(fontStyle = FontStyle.Italic)) {
append(currentNode.children[1].getTextInNode(text).toString())
}
}
}

MarkdownTokenTypes.TEXT, MarkdownTokenTypes.WHITE_SPACE -> {
append(currentNode.getTextInNode(text).toString())
}
}
currentNode.run {
Log.d(
"ASTNodeExt",
"\"${getTextInNode(text)}\" ||||| $startOffset - $endOffset ||||| ${type.name}"
)
}
}
}

fun ASTNode.traverse(
action: (currentNode: ASTNode) -> Unit
) {
val queue = ArrayDeque<ASTNode>()
queue.addFirst(this)

while(queue.isNotEmpty()) {
val currentNode = queue.removeLast()

action.invoke(currentNode)

for(childNode in currentNode.children) {
queue.addFirst(childNode)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ package com.imashnake.animite.api.anilist.sanitize.media
import android.graphics.Color
import com.imashnake.animite.api.anilist.MediaListQuery
import com.imashnake.animite.api.anilist.MediaQuery
import com.imashnake.animite.api.anilist.markdown.toAnnotatedString
import com.imashnake.animite.api.anilist.type.MediaRankType
import org.intellij.markdown.ast.ASTNode
import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor
import org.intellij.markdown.parser.MarkdownParser

data class Media(
/** @see MediaQuery.Media.bannerImage */
Expand All @@ -16,7 +21,7 @@ data class Media(
val title: String?,
/** TODO: https://github.com/imashnake0/Animite/issues/58.
* @see MediaQuery.Media.description */
val description: String,
val description: Pair<ASTNode, String>?,
/** @see MediaQuery.Media.rankings */
val rankings: List<Ranking>,
/** @see MediaQuery.Media.genres */
Expand Down Expand Up @@ -69,7 +74,14 @@ data class Media(
coverImage = query.coverImage?.extraLarge ?: query.coverImage?.large ?: query.coverImage?.medium,
color = query.coverImage?.color?.let { Color.parseColor(it) } ?: Color.TRANSPARENT,
title = query.title?.romaji ?: query.title?.english ?: query.title?.native,
description = query.description.orEmpty(),
description = "what the hell is even *this*?".let {
val flavour = CommonMarkFlavourDescriptor()

// val text = "<i>Some</i> funi _Markdown_"
// MarkdownParser(flavour).buildMarkdownTreeFromString(text).toAnnotatedString(text)

MarkdownParser(flavour).buildMarkdownTreeFromString(it) to it
},
rankings = if (query.rankings == null) { emptyList() } else {
// TODO: Is this filter valid?
query.rankings.filter {
Expand Down
122 changes: 122 additions & 0 deletions api/anilist/src/test/res/raw/anilist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# H1
<h1>H1</h1>
H1
==
H1
==========
## H2
<h2>H2</h2>
### H3
<h3>H3</h3>
#### H4
<h4>H4</h4>
##### H5
<h5>H5</h5>

One line

Two
lines

_italics_
*italics*
<i>italics</i>
<em>italics</em>

__bold__
**bold**
<b>bold</b>
<strong>bold</strong>

~~strikethrough~~
<del>strikethrough</del>
<strike>strikethrough</strike>

~~~center-aligned~~~
<center>center-aligned</center>
<p align="center">center-aligned</p>
<div align="center">center-aligned</div>

<p align="left">left-aligned</p>
<div align="left">left-aligned</div>

<p align="right">right-aligned</p>
<div align="right">right-aligned</div>

<p align="justify">justify-aligned</p>
<div align="justify">justify-aligned</div>

> block
> quote

<blockquote>block
quote</blockquote>

> nested
>> block quote

[anilist link](https://anilist.co/)
<a href="https://anilist.co/">anilist link</a>
<a href="https://anilist.co/" target="_blank">anilist link</a>
https://anilist.co/
<https://anilist.co/>

![anilist icon](https://anilist.co/img/icons/icon.svg)
<img alt="anilist icon" src="https://anilist.co/img/icons/icon.svg">
img420(https://anilist.co/img/icons/icon.svg)

---

----------

***

**********

- Bulleted
- List

* Bulleted
* List

+ Bulleted
+ List

<ul><li>Bulleted</li><li>List</li></ul>

+ Nested
+ List

1. Numbered
2. List

6. Numbered
9. List

<ol><li>Numbered</li><li>List</li></ol>

* Mixed
1. List
+ Containing
2. Different
* Types

`inline code`
<code>inline code</code>

block
code
```
block
code
```
<pre>
block
code
</pre>

~!spoiler!~
<div rel="spoiler">spoiler</div>

youtube(https://youtu.be/761Q37SNuSM)
webm(https://files.kiniro.uk/video/sonic.webm)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.imashnake.animite.features.media
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.text.Html
import android.util.Log
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
Expand Down Expand Up @@ -53,6 +52,8 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -113,9 +114,7 @@ fun MediaPage(
) {
MediaDetails(
title = media.title.orEmpty(),
description = Html
.fromHtml(media.description.orEmpty(), Html.FROM_HTML_MODE_COMPACT)
.toString(),
description = media.description,
// TODO Can we do something about this Modifier chain?
modifier = Modifier
.padding(
Expand Down Expand Up @@ -242,7 +241,7 @@ fun MediaBanner(
@Composable
fun MediaDetails(
title: String,
description: String,
description: AnnotatedString?,
modifier: Modifier = Modifier
) {
Column(modifier) {
Expand All @@ -254,7 +253,7 @@ fun MediaDetails(
overflow = TextOverflow.Ellipsis
)

ScrollableText(text = description)
ScrollableText(text = description ?: buildAnnotatedString { })
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.imashnake.animite.api.anilist.AnilistMediaRepository
import com.imashnake.animite.api.anilist.markdown.toAnnotatedString
import com.imashnake.animite.api.anilist.type.MediaType
import com.imashnake.animite.features.destinations.MediaPageDestination
import dagger.hilt.android.lifecycle.HiltViewModel
Expand Down Expand Up @@ -39,7 +40,7 @@ class MediaPageViewModel @Inject constructor(
coverImage = media?.coverImage,
color = media?.color,
title = media?.title,
description = media?.description,
description = media?.description?.first?.toAnnotatedString(media.description?.second.orEmpty()),
ranks = media?.rankings,
genres = media?.genres,
characters = media?.characters,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.imashnake.animite.features.media

import androidx.compose.ui.text.AnnotatedString
import com.imashnake.animite.api.anilist.sanitize.media.Media

data class MediaUiState(
val bannerImage: String? = null,
val coverImage: String? = null,
val color: Int? = null,
val title: String? = null,
val description: String? = null,
val description: AnnotatedString? = null,
val ranks: List<Media.Ranking>? = null,
val genres: List<String>? = null,
val characters: List<Media.Character>? = null,
Expand Down
11 changes: 10 additions & 1 deletion app/src/main/java/com/imashnake/animite/features/theme/Type.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.imashnake.animite.features.theme

import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.googlefonts.Font
import androidx.compose.ui.text.googlefonts.GoogleFont
Expand All @@ -28,7 +30,14 @@ val manropeFontFamily = FontFamily(
Font(manropeFont, fontProvider, FontWeight.Medium),
Font(manropeFont, fontProvider, FontWeight.Normal),
Font(manropeFont, fontProvider, FontWeight.Light),
Font(manropeFont, fontProvider, FontWeight.ExtraLight)
Font(manropeFont, fontProvider, FontWeight.ExtraLight),
Font(R.font.manrope_italic, FontWeight.Normal, FontStyle.Italic),
Font(R.font.manrope_bold_italic, FontWeight.Bold, FontStyle.Italic),
Font(R.font.manrope_extra_bold_italic, FontWeight.ExtraBold, FontStyle.Italic),
Font(R.font.manrope_light_italic, FontWeight.Light, FontStyle.Italic),
Font(R.font.manrope_medium_italic, FontWeight.Medium, FontStyle.Italic),
Font(R.font.manrope_extra_light_italic, FontWeight.ExtraLight, FontStyle.Italic),
Font(R.font.manrope_semi_bold_italic, FontWeight.SemiBold, FontStyle.Italic),
)

const val baselineShift = 0.2f
Expand Down
Binary file added app/src/main/res/font/manrope_bold_italic.ttf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added app/src/main/res/font/manrope_italic.ttf
Binary file not shown.
Binary file added app/src/main/res/font/manrope_light_italic.ttf
Binary file not shown.
Binary file added app/src/main/res/font/manrope_medium_italic.ttf
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Color.Companion.Transparent
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.Dp
import com.imashnake.animite.core.R

Expand Down Expand Up @@ -70,3 +71,54 @@ fun ScrollableText(
) { }
}
}

@Composable
fun ScrollableText(
text: AnnotatedString,
modifier: Modifier = Modifier,
gradientSize: Dp = dimensionResource(R.dimen.edge_gradient_size),
gradientColor: Color = MaterialTheme.colorScheme.background
) {
Box(modifier) {
Text(
text = text,
color = MaterialTheme.colorScheme.onBackground.copy(
alpha = ContentAlpha.medium
),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier
.verticalScroll(rememberScrollState())
.padding(vertical = gradientSize)
)

Box(
modifier = Modifier
.height(gradientSize)
.fillMaxWidth()
.align(Alignment.TopCenter)
.background(
Brush.verticalGradient(
listOf(
gradientColor,
Transparent
)
)
)
) { }

Box(
modifier = Modifier
.height(gradientSize)
.fillMaxWidth()
.align(Alignment.BottomCenter)
.background(
Brush.verticalGradient(
listOf(
Transparent,
gradientColor
)
)
)
) { }
}
}
Loading