PixelDroid-App-Android/app/src/main/java/org/pixeldroid/app/posts/HtmlUtils.kt

147 lines
4.7 KiB
Kotlin
Raw Normal View History

2021-04-22 11:47:18 +02:00
package org.pixeldroid.app.posts
import android.content.Context
import android.os.Build
import android.text.Html
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.style.ClickableSpan
import android.text.style.URLSpan
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.core.text.toSpanned
2020-12-29 22:14:32 +01:00
import androidx.lifecycle.LifecycleCoroutineScope
2021-04-22 11:47:18 +02:00
import org.pixeldroid.app.R
import org.pixeldroid.app.utils.api.PixelfedAPI
import org.pixeldroid.app.utils.api.objects.Account.Companion.openAccountFromId
import org.pixeldroid.app.utils.api.objects.Mention
2021-06-07 22:23:59 +02:00
import org.pixeldroid.app.utils.api.objects.Tag.Companion.openTag
2021-04-22 11:47:18 +02:00
import org.pixeldroid.app.utils.di.PixelfedAPIHolder
import java.net.URI
import java.net.URISyntaxException
import java.text.ParseException
import java.util.*
fun fromHtml(html: String): Spanned {
val result: Spanned = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
} else {
@Suppress("DEPRECATION")
Html.fromHtml(html)
}
return result.trim().toSpanned()
}
fun getDomain(urlString: String?): String {
val uri: URI
try {
uri = URI(urlString!!)
} catch (e: URISyntaxException) {
return ""
}
val host: String = uri.host
return if (host.startsWith("www.")) {
host.substring(4)
} else {
host
}
}
fun parseHTMLText(
text: String,
mentions: List<Mention>?,
apiHolder: PixelfedAPIHolder,
context: Context,
lifecycleScope: LifecycleCoroutineScope,
) : Spanned {
//Convert text to spannable
val content = fromHtml(text)
//Retrive all links that should be made clickable
val builder = SpannableStringBuilder(content)
val urlSpans = content.getSpans(0, content.length, URLSpan::class.java)
for(span in urlSpans) {
val start = builder.getSpanStart(span)
val end = builder.getSpanEnd(span)
val flags = builder.getSpanFlags(span)
val text = builder.subSequence(start, end)
var customSpan: ClickableSpan? = null
//Handle hashtags
if (text[0] == '#') {
val tag = text.subSequence(1, text.length).toString()
customSpan = object : ClickableSpanNoUnderline() {
override fun onClick(widget: View) {
2021-06-07 22:23:59 +02:00
openTag(context, tag)
}
}
}
//Handle mentions
if(text[0] == '@' && !mentions.isNullOrEmpty()) {
val accountUsername = text.subSequence(1, text.length).toString()
var id: String? = null
//Go through all mentions stored in the status
for (mention in mentions) {
if (mention.username.equals(accountUsername, ignoreCase = true)
) {
id = mention.id
//Mentions can be of users in other domains
if (mention.url.contains(getDomain(span.url))) {
break
}
}
}
//Check that we found a user for the given mention
if (id != null) {
val accountId: String = id
customSpan = object : ClickableSpanNoUnderline() {
override fun onClick(widget: View) {
Log.e("MENTION", "CLICKED")
//Retrieve the account for the given profile
2020-12-29 22:14:32 +01:00
lifecycleScope.launchWhenCreated {
val api: PixelfedAPI = apiHolder.api ?: apiHolder.setToCurrentUser()
openAccountFromId(accountId, api, context)
2020-12-29 22:14:32 +01:00
}
}
}
}
}
builder.removeSpan(span)
builder.setSpan(customSpan, start, end, flags)
// Add zero-width space after links in end of line to fix its too large hitbox.
if (end >= builder.length || builder.subSequence(end, end + 1).toString() == "\n") {
builder.insert(end, "\u200B")
}
}
return builder
}
fun setTextViewFromISO8601(date: Date, textView: TextView, absoluteTime: Boolean, context: Context) {
val now = Date().time
try {
val then = date.time
val formattedDate = android.text.format.DateUtils
.getRelativeTimeSpanString(then, now,
android.text.format.DateUtils.SECOND_IN_MILLIS,
android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE)
textView.text = if(absoluteTime) context.getString(R.string.posted_on).format(date)
else "$formattedDate"
} catch (e: ParseException) {
e.printStackTrace()
}
}