fix: some anilist markdown
This commit is contained in:
parent
eb5e2623a0
commit
1028ac66cb
6 changed files with 119 additions and 71 deletions
|
@ -1350,10 +1350,10 @@ Page(page:$page,perPage:50) {
|
||||||
|
|
||||||
suspend fun getFeed(userId: Int?, global: Boolean = false, page: Int = 1): FeedResponse? {
|
suspend fun getFeed(userId: Int?, global: Boolean = false, page: Int = 1): FeedResponse? {
|
||||||
val filter = if (userId != null) "userId:$userId,"
|
val filter = if (userId != null) "userId:$userId,"
|
||||||
else if (global) "isFollowing:false,"
|
else if (global) "isFollowing:false,type:TEXT,"
|
||||||
else "isFollowing:true,"
|
else "isFollowing:true,type_not:MESSAGE,"
|
||||||
val res = executeQuery<FeedResponse>(
|
val res = executeQuery<FeedResponse>(
|
||||||
"""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}"""
|
"""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount likeCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}"""
|
||||||
)
|
)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ani.dantotsu.media.MediaAdaptor
|
||||||
import ani.dantotsu.media.user.ListActivity
|
import ani.dantotsu.media.user.ListActivity
|
||||||
import ani.dantotsu.setSlideIn
|
import ani.dantotsu.setSlideIn
|
||||||
import ani.dantotsu.setSlideUp
|
import ani.dantotsu.setSlideUp
|
||||||
import ani.dantotsu.util.ColorEditor.Companion.toCssColor
|
import ani.dantotsu.util.AniMarkdown.Companion.getFullAniHTML
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@ -72,8 +72,8 @@ class ProfileFragment : Fragment() {
|
||||||
binding.profileUserBio.settings.loadWithOverviewMode = true
|
binding.profileUserBio.settings.loadWithOverviewMode = true
|
||||||
binding.profileUserBio.settings.useWideViewPort = true
|
binding.profileUserBio.settings.useWideViewPort = true
|
||||||
binding.profileUserBio.setInitialScale(1)
|
binding.profileUserBio.setInitialScale(1)
|
||||||
val styledHtml = styled(
|
val styledHtml = getFullAniHTML(
|
||||||
convertMarkdownToHtml(user.about ?: ""),
|
user.about ?: "",
|
||||||
backGroundColorTypedValue.data,
|
backGroundColorTypedValue.data,
|
||||||
textColorTypedValue.data
|
textColorTypedValue.data
|
||||||
)
|
)
|
||||||
|
@ -175,16 +175,6 @@ class ProfileFragment : Fragment() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertMarkdownToHtml(markdown: String): String {
|
|
||||||
val regex = """\[\!\[(.*?)\]\((.*?)\)\]\((.*?)\)""".toRegex()
|
|
||||||
return regex.replace(markdown) { matchResult ->
|
|
||||||
val altText = matchResult.groupValues[1]
|
|
||||||
val imageUrl = matchResult.groupValues[2]
|
|
||||||
val linkUrl = matchResult.groupValues[3]
|
|
||||||
"""<a href="$linkUrl"><img src="$imageUrl" alt="$altText"></a>"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initRecyclerView(
|
private fun initRecyclerView(
|
||||||
mode: LiveData<ArrayList<Media>>,
|
mode: LiveData<ArrayList<Media>>,
|
||||||
container: View,
|
container: View,
|
||||||
|
@ -221,56 +211,6 @@ class ProfileFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun styled(html: String, backGroundColor: Int, textColor: Int): String { //istg anilist has the worst api
|
|
||||||
//remove some of the html entities
|
|
||||||
val step1 = html.replace(" ", " ")
|
|
||||||
.replace("&", "&")
|
|
||||||
.replace("<", "<")
|
|
||||||
.replace(">", ">")
|
|
||||||
.replace(""", "\"")
|
|
||||||
.replace("'", "'")
|
|
||||||
.replace("<pre>", "")
|
|
||||||
.replace("`", "")
|
|
||||||
.replace("~", "")
|
|
||||||
|
|
||||||
val step2 = step1.replace("(?s)___(.*?)___".toRegex(), "<br><em><strong>$1</strong></em><br>")
|
|
||||||
val step3 = step2.replace("(?s)__(.*?)__".toRegex(), "<br><strong>$1</strong><br>")
|
|
||||||
|
|
||||||
|
|
||||||
return """
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, charset=UTF-8">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background-color: ${backGroundColor.toCssColor()};
|
|
||||||
color: ${textColor.toCssColor()};
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: hidden; /* Prevent horizontal scrolling */
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto; /* Maintain aspect ratio */
|
|
||||||
}
|
|
||||||
video {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto; /* Maintain aspect ratio */
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: ${textColor.toCssColor()};
|
|
||||||
}
|
|
||||||
/* Add responsive design elements for other content as needed */
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
$step3
|
|
||||||
</body>
|
|
||||||
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance(query: Query.UserProfile): ProfileFragment {
|
fun newInstance(query: Query.UserProfile): ProfileFragment {
|
||||||
val args = Bundle().apply {
|
val args = Bundle().apply {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ani.dantotsu.connections.anilist.api.Activity
|
||||||
import ani.dantotsu.databinding.ItemActivityBinding
|
import ani.dantotsu.databinding.ItemActivityBinding
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import com.bumptech.glide.load.model.GlideUrl
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
@ -96,7 +97,7 @@ class ActivityItem(
|
||||||
binding.activityContent.visibility = View.VISIBLE
|
binding.activityContent.visibility = View.VISIBLE
|
||||||
if (!(context as android.app.Activity).isDestroyed) {
|
if (!(context as android.app.Activity).isDestroyed) {
|
||||||
val markwon = buildMarkwon(context, false)
|
val markwon = buildMarkwon(context, false)
|
||||||
markwon.setMarkdown(binding.activityContent, activity.text ?: "")
|
markwon.setMarkdown(binding.activityContent, getBasicAniHTML(activity.text ?: ""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class FeedActivity: AppCompatActivity() {
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
navBar = binding.feedNavBar
|
navBar = binding.feedNavBar
|
||||||
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin += navBarHeight }
|
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin += navBarHeight }
|
||||||
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Personal")
|
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Following")
|
||||||
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
|
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
|
||||||
navBar.addTab(personalTab)
|
navBar.addTab(personalTab)
|
||||||
navBar.addTab(globalTab)
|
navBar.addTab(globalTab)
|
||||||
|
|
|
@ -64,14 +64,17 @@ class FeedFragment : Fragment() {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
res?.data?.page?.activities?.let { activities ->
|
res?.data?.page?.activities?.let { activities ->
|
||||||
activityList = activities
|
activityList = activities
|
||||||
adapter.update(activityList.map { ActivityItem(it) { _, _ -> } })
|
val filtered = activities.filterNot { //filter out messages that are not directed to the user
|
||||||
|
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
||||||
|
}
|
||||||
|
adapter.update(filtered.map { ActivityItem(it) { _, _ -> } })
|
||||||
}
|
}
|
||||||
binding.listProgressBar.visibility = ViewGroup.GONE
|
binding.listProgressBar.visibility = ViewGroup.GONE
|
||||||
val scrollView = binding.listRecyclerView
|
val scrollView = binding.listRecyclerView
|
||||||
|
|
||||||
binding.listRecyclerView.setOnTouchListener { _, event ->
|
binding.listRecyclerView.setOnTouchListener { _, event ->
|
||||||
if (event?.action == MotionEvent.ACTION_UP) {
|
if (event?.action == MotionEvent.ACTION_UP) {
|
||||||
if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
|
if (activityList.size % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
|
||||||
snackString("No more activities")
|
snackString("No more activities")
|
||||||
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
|
} else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
|
||||||
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
||||||
|
@ -84,7 +87,10 @@ class FeedFragment : Fragment() {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
res?.data?.page?.activities?.let { activities ->
|
res?.data?.page?.activities?.let { activities ->
|
||||||
activityList += activities
|
activityList += activities
|
||||||
adapter.addAll(activities.map { ActivityItem(it) { _, _ -> } })
|
val filtered = activities.filterNot {
|
||||||
|
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
||||||
|
}
|
||||||
|
adapter.addAll(filtered.map { ActivityItem(it) { _, _ -> } })
|
||||||
}
|
}
|
||||||
binding.feedRefresh.visibility = ViewGroup.GONE
|
binding.feedRefresh.visibility = ViewGroup.GONE
|
||||||
}
|
}
|
||||||
|
|
101
app/src/main/java/ani/dantotsu/util/AniMarkdown.kt
Normal file
101
app/src/main/java/ani/dantotsu/util/AniMarkdown.kt
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package ani.dantotsu.util
|
||||||
|
|
||||||
|
import ani.dantotsu.util.ColorEditor.Companion.toCssColor
|
||||||
|
|
||||||
|
class AniMarkdown { //istg anilist has the worst api
|
||||||
|
companion object {
|
||||||
|
private fun convertNestedImageToHtml(markdown: String): String {
|
||||||
|
val regex = """\[\!\[(.*?)\]\((.*?)\)\]\((.*?)\)""".toRegex()
|
||||||
|
return regex.replace(markdown) { matchResult ->
|
||||||
|
val altText = matchResult.groupValues[1]
|
||||||
|
val imageUrl = matchResult.groupValues[2]
|
||||||
|
val linkUrl = matchResult.groupValues[3]
|
||||||
|
"""<a href="$linkUrl"><img src="$imageUrl" alt="$altText"></a>"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertImageToHtml(markdown: String): String {
|
||||||
|
val regex = """\!\[(.*?)\]\((.*?)\)""".toRegex()
|
||||||
|
return regex.replace(markdown) { matchResult ->
|
||||||
|
val altText = matchResult.groupValues[1]
|
||||||
|
val imageUrl = matchResult.groupValues[2]
|
||||||
|
"""<img src="$imageUrl" alt="$altText">"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertLinkToHtml(markdown: String): String {
|
||||||
|
val regex = """\[(.*?)\]\((.*?)\)""".toRegex()
|
||||||
|
return regex.replace(markdown) { matchResult ->
|
||||||
|
val linkText = matchResult.groupValues[1]
|
||||||
|
val linkUrl = matchResult.groupValues[2]
|
||||||
|
"""<a href="$linkUrl">$linkText</a>"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceLeftovers(html: String): String {
|
||||||
|
return html.replace(" ", " ")
|
||||||
|
.replace("&", "&")
|
||||||
|
.replace("<", "<")
|
||||||
|
.replace(">", ">")
|
||||||
|
.replace(""", "\"")
|
||||||
|
.replace("'", "'")
|
||||||
|
.replace("<pre>", "")
|
||||||
|
.replace("`", "")
|
||||||
|
.replace("~", "")
|
||||||
|
.replace(">\n<", "><")
|
||||||
|
.replace("\n", "<br>")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun underlineToHtml(html: String): String {
|
||||||
|
return html.replace("(?s)___(.*?)___".toRegex(), "<br><em><strong>$1</strong></em><br>")
|
||||||
|
.replace("(?s)__(.*?)__".toRegex(), "<br><strong>$1</strong><br>")
|
||||||
|
.replace("(?s)[\\s]+_([^_]+)_[\\s]+".toRegex(), "<em>$1</em>")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBasicAniHTML(html: String): String {
|
||||||
|
val step0 = convertNestedImageToHtml(html)
|
||||||
|
val step1 = convertImageToHtml(step0)
|
||||||
|
val step2 = convertLinkToHtml(step1)
|
||||||
|
val step3 = replaceLeftovers(step2)
|
||||||
|
return underlineToHtml(step3)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFullAniHTML(html: String, backGroundColor: Int, textColor: Int): String {
|
||||||
|
val basicHtml = getBasicAniHTML(html)
|
||||||
|
|
||||||
|
|
||||||
|
return """
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, charset=UTF-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: ${backGroundColor.toCssColor()};
|
||||||
|
color: ${textColor.toCssColor()};
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-x: hidden; /* Prevent horizontal scrolling */
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto; /* Maintain aspect ratio */
|
||||||
|
}
|
||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto; /* Maintain aspect ratio */
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: ${textColor.toCssColor()};
|
||||||
|
}
|
||||||
|
/* Add responsive design elements for other content as needed */
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
$basicHtml
|
||||||
|
</body>
|
||||||
|
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue