fix: some markdown fixes
This commit is contained in:
parent
6eb654bf51
commit
b09f26ed34
13 changed files with 194 additions and 27 deletions
|
@ -19,6 +19,7 @@
|
|||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29" />
|
||||
|
|
|
@ -68,7 +68,6 @@ import android.widget.ImageView
|
|||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
|
@ -98,6 +97,7 @@ import ani.dantotsu.databinding.ItemCountDownBinding
|
|||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.notifications.IncognitoNotificationClickReceiver
|
||||
import ani.dantotsu.others.AlignTagHandler
|
||||
import ani.dantotsu.others.ImageViewDialog
|
||||
import ani.dantotsu.others.SpoilerPlugin
|
||||
import ani.dantotsu.parsers.ShowResponse
|
||||
|
@ -119,8 +119,8 @@ import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withC
|
|||
import com.bumptech.glide.load.resource.gif.GifDrawable
|
||||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.CustomTarget
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.bumptech.glide.request.target.ViewTarget
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
|
@ -1448,6 +1448,8 @@ fun openOrCopyAnilistLink(link: String) {
|
|||
} else {
|
||||
copyToClipboard(link, true)
|
||||
}
|
||||
} else if (getYoutubeId(link).isNotEmpty()) {
|
||||
openLinkInYouTube(link)
|
||||
} else {
|
||||
copyToClipboard(link, true)
|
||||
}
|
||||
|
@ -1484,6 +1486,7 @@ fun buildMarkwon(
|
|||
TagHandlerNoOp.create("h1", "h2", "h3", "h4", "h5", "h6", "hr", "pre", "a")
|
||||
)
|
||||
}
|
||||
plugin.addHandler(AlignTagHandler())
|
||||
})
|
||||
.usePlugin(GlideImagesPlugin.create(object : GlideImagesPlugin.GlideStore {
|
||||
|
||||
|
@ -1527,3 +1530,11 @@ fun buildMarkwon(
|
|||
.build()
|
||||
return markwon
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun getYoutubeId(url: String): String {
|
||||
val regex = """(?:youtube\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|(?:youtu\.be|youtube\.com)/)([^"&?/\s]{11})|youtube\.com/""".toRegex()
|
||||
val matchResult = regex.find(url)
|
||||
return matchResult?.groupValues?.getOrNull(1) ?: ""
|
||||
}
|
|
@ -2,7 +2,6 @@ package ani.dantotsu
|
|||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.drawable.Animatable
|
||||
|
@ -60,11 +59,11 @@ import ani.dantotsu.settings.saving.SharedPreferenceBooleanLiveData
|
|||
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
|
||||
import ani.dantotsu.settings.saving.internal.PreferencePackager
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import ani.dantotsu.util.AudioHelper
|
||||
import ani.dantotsu.util.Logger
|
||||
import ani.dantotsu.util.customAlertDialog
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
|
@ -455,7 +454,10 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PrefManager.getVal(PrefName.OC)) {
|
||||
AudioHelper.run(this, R.raw.audio)
|
||||
PrefManager.setVal(PrefName.OC, false)
|
||||
}
|
||||
val torrentManager = Injekt.get<TorrentAddonManager>()
|
||||
fun startTorrent() {
|
||||
if (torrentManager.isAvailable() && PrefManager.getVal(PrefName.TorrentEnabled)) {
|
||||
|
|
|
@ -353,6 +353,7 @@ class CommentsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
|
32
app/src/main/java/ani/dantotsu/others/AlignTagHandler.kt
Normal file
32
app/src/main/java/ani/dantotsu/others/AlignTagHandler.kt
Normal file
|
@ -0,0 +1,32 @@
|
|||
package ani.dantotsu.others
|
||||
|
||||
import android.text.Layout
|
||||
import android.text.style.AlignmentSpan
|
||||
import io.noties.markwon.MarkwonConfiguration
|
||||
import io.noties.markwon.RenderProps
|
||||
import io.noties.markwon.html.HtmlTag
|
||||
import io.noties.markwon.html.tag.SimpleTagHandler
|
||||
|
||||
|
||||
class AlignTagHandler : SimpleTagHandler() {
|
||||
|
||||
override fun getSpans(
|
||||
configuration: MarkwonConfiguration,
|
||||
renderProps: RenderProps,
|
||||
tag: HtmlTag
|
||||
): Any {
|
||||
val alignment: Layout.Alignment = if (tag.attributes().containsKey("center")) {
|
||||
Layout.Alignment.ALIGN_CENTER
|
||||
} else if (tag.attributes().containsKey("end")) {
|
||||
Layout.Alignment.ALIGN_OPPOSITE
|
||||
} else {
|
||||
Layout.Alignment.ALIGN_NORMAL
|
||||
}
|
||||
|
||||
return AlignmentSpan.Standard(alignment)
|
||||
}
|
||||
|
||||
override fun supportedTags(): Collection<String> {
|
||||
return setOf("align")
|
||||
}
|
||||
}
|
|
@ -23,12 +23,12 @@ import ani.dantotsu.databinding.ActivitySettingsBinding
|
|||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.openLinkInBrowser
|
||||
import ani.dantotsu.openLinkInYouTube
|
||||
import ani.dantotsu.others.AppUpdater
|
||||
import ani.dantotsu.others.CustomBottomDialog
|
||||
import ani.dantotsu.pop
|
||||
import ani.dantotsu.setSafeOnClickListener
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.startMainActivity
|
||||
import ani.dantotsu.statusBarHeight
|
||||
|
@ -217,10 +217,14 @@ class SettingsActivity : AppCompatActivity() {
|
|||
settingsLogo.setSafeOnClickListener {
|
||||
cursedCounter++
|
||||
(settingsLogo.drawable as Animatable).start()
|
||||
if (cursedCounter % 7 == 0) {
|
||||
toast(R.string.you_cursed)
|
||||
openLinkInYouTube(getString(R.string.cursed_yt))
|
||||
//PrefManager.setVal(PrefName.ImageUrl, !PrefManager.getVal(PrefName.ImageUrl, false))
|
||||
if (cursedCounter % 16 == 0) {
|
||||
val oldVal: Boolean = PrefManager.getVal(PrefName.OC)
|
||||
if (!oldVal) {
|
||||
toast(R.string.omega_cursed)
|
||||
} else {
|
||||
toast(R.string.omega_freed)
|
||||
}
|
||||
PrefManager.setVal(PrefName.OC, !oldVal)
|
||||
} else {
|
||||
snackString(array[(Math.random() * array.size).toInt()], context)
|
||||
}
|
||||
|
|
|
@ -191,6 +191,7 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
|||
SubscriptionNotificationStore(Pref(Location.Irrelevant, List::class, listOf<SubscriptionStore>())),
|
||||
UnreadCommentNotifications(Pref(Location.Irrelevant, Int::class, 0)),
|
||||
DownloadsDir(Pref(Location.Irrelevant, String::class, "")),
|
||||
OC(Pref(Location.Irrelevant, Boolean::class, false)),
|
||||
RefreshStatus(Pref(Location.Irrelevant, Boolean::class, false)),
|
||||
|
||||
//Protected
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.widget.FrameLayout
|
|||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import ani.dantotsu.R
|
||||
|
@ -42,7 +43,7 @@ class ActivityMarkdownCreator : AppCompatActivity() {
|
|||
BOLD("****", 2, R.id.formatBold),
|
||||
ITALIC("**", 1, R.id.formatItalic),
|
||||
STRIKETHROUGH("~~~~", 2, R.id.formatStrikethrough),
|
||||
SPOILER("~||~", 2, R.id.formatSpoiler),
|
||||
SPOILER("~!!~", 2, R.id.formatSpoiler),
|
||||
LINK("[Placeholder](%s)", 0, R.id.formatLink),
|
||||
IMAGE("img(%s)", 0, R.id.formatImage),
|
||||
YOUTUBE("youtube(%s)", 0, R.id.formatYoutube),
|
||||
|
@ -267,9 +268,13 @@ class ActivityMarkdownCreator : AppCompatActivity() {
|
|||
private fun previewMarkdown(preview: Boolean) {
|
||||
val markwon = buildMarkwon(this, false, anilist = true)
|
||||
if (preview) {
|
||||
binding.editText.isVisible = false
|
||||
binding.editText.isEnabled = false
|
||||
markwon.setMarkdown(binding.editText, text)
|
||||
binding.markdownPreview.isVisible = true
|
||||
markwon.setMarkdown(binding.markdownPreview, AniMarkdown.getBasicAniHTML(text))
|
||||
} else {
|
||||
binding.editText.isVisible = true
|
||||
binding.markdownPreview.isVisible = false
|
||||
binding.editText.setText(text)
|
||||
binding.editText.isEnabled = true
|
||||
val markwonEditor = MarkwonEditor.create(markwon)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package ani.dantotsu.util
|
||||
|
||||
import ani.dantotsu.getYoutubeId
|
||||
import ani.dantotsu.util.ColorEditor.Companion.toCssColor
|
||||
|
||||
class AniMarkdown { //istg anilist has the worst api
|
||||
companion object {
|
||||
private fun convertNestedImageToHtml(markdown: String): String {
|
||||
private fun String.convertNestedImageToHtml(): String {
|
||||
val regex = """\[!\[(.*?)]\((.*?)\)]\((.*?)\)""".toRegex()
|
||||
return regex.replace(markdown) { matchResult ->
|
||||
return regex.replace(this) { matchResult ->
|
||||
val altText = matchResult.groupValues[1]
|
||||
val imageUrl = matchResult.groupValues[2]
|
||||
val linkUrl = matchResult.groupValues[3]
|
||||
|
@ -14,26 +15,49 @@ class AniMarkdown { //istg anilist has the worst api
|
|||
}
|
||||
}
|
||||
|
||||
private fun convertImageToHtml(markdown: String): String {
|
||||
private fun String.convertImageToHtml(): String {
|
||||
val regex = """!\[(.*?)]\((.*?)\)""".toRegex()
|
||||
return regex.replace(markdown) { matchResult ->
|
||||
val anilistRegex = """img\(.*?\)""".toRegex()
|
||||
val markdownImage = regex.replace(this) { matchResult ->
|
||||
val altText = matchResult.groupValues[1]
|
||||
val imageUrl = matchResult.groupValues[2]
|
||||
"""<img src="$imageUrl" alt="$altText">"""
|
||||
}
|
||||
return anilistRegex.replace(markdownImage) { matchResult ->
|
||||
val imageUrl = matchResult.groupValues[1]
|
||||
"""<img src="$imageUrl" alt="Image">"""
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertLinkToHtml(markdown: String): String {
|
||||
private fun String.convertLinkToHtml(): String {
|
||||
val regex = """\[(.*?)]\((.*?)\)""".toRegex()
|
||||
return regex.replace(markdown) { matchResult ->
|
||||
return regex.replace(this) { 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(" ", " ")
|
||||
private fun String.convertYoutubeToHtml(): String {
|
||||
val regex = """<div class='youtube' id='(.*?)'></div>""".toRegex()
|
||||
return regex.replace(this) { matchResult ->
|
||||
val url = matchResult.groupValues[1]
|
||||
val id = getYoutubeId(url)
|
||||
if (id.isNotEmpty()) {
|
||||
"""<div>
|
||||
<a href="https://www.youtube.com/watch?v=$id"><img src="https://i3.ytimg.com/vi/$id/maxresdefault.jpg" alt="$url"></a>
|
||||
<align center>
|
||||
<a href="https://www.youtube.com/watch?v=$id">Youtube Link</a>
|
||||
</align>
|
||||
</div>""".trimIndent()
|
||||
} else {
|
||||
"""<a href="$url">Youtube Video</a>"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.replaceLeftovers(): String {
|
||||
return this.replace(" ", " ")
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
|
@ -46,18 +70,29 @@ class AniMarkdown { //istg anilist has the worst api
|
|||
.replace("\n", "<br>")
|
||||
}
|
||||
|
||||
private fun underlineToHtml(html: String): String {
|
||||
return html.replace("(?s)___(.*?)___".toRegex(), "<br><em><strong>$1</strong></em><br>")
|
||||
private fun String.underlineToHtml(): String {
|
||||
return this.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>")
|
||||
}
|
||||
|
||||
private fun String.convertCenterToHtml(): String {
|
||||
val regex = """~~~(.*?)~~~""".toRegex()
|
||||
return regex.replace(this) { matchResult ->
|
||||
val centerText = matchResult.groupValues[1]
|
||||
"""<align center>$centerText</align>"""
|
||||
}
|
||||
}
|
||||
|
||||
fun getBasicAniHTML(html: String): String {
|
||||
val step0 = convertNestedImageToHtml(html)
|
||||
val step1 = convertImageToHtml(step0)
|
||||
val step2 = convertLinkToHtml(step1)
|
||||
val step3 = replaceLeftovers(step2)
|
||||
return underlineToHtml(step3)
|
||||
return html
|
||||
.convertNestedImageToHtml()
|
||||
.convertImageToHtml()
|
||||
.convertLinkToHtml()
|
||||
.convertYoutubeToHtml()
|
||||
.convertCenterToHtml()
|
||||
.replaceLeftovers()
|
||||
.underlineToHtml()
|
||||
}
|
||||
|
||||
fun getFullAniHTML(html: String, textColor: Int): String {
|
||||
|
|
58
app/src/main/java/ani/dantotsu/util/AudioHelper.kt
Normal file
58
app/src/main/java/ani/dantotsu/util/AudioHelper.kt
Normal file
|
@ -0,0 +1,58 @@
|
|||
package ani.dantotsu.util
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaPlayer
|
||||
|
||||
class AudioHelper(private val context: Context) {
|
||||
|
||||
private val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
private var mediaPlayer: MediaPlayer? = null
|
||||
|
||||
fun routeAudioToSpeaker() {
|
||||
audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN)
|
||||
audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
audioManager.isSpeakerphoneOn = true
|
||||
}
|
||||
|
||||
private val maxVolume: Int
|
||||
get() = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
|
||||
private var oldVolume: Int = 0
|
||||
fun setVolume(percentage: Int) {
|
||||
oldVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||
val volume = (maxVolume * percentage) / 100
|
||||
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0)
|
||||
}
|
||||
|
||||
fun playAudio(audio: Int) {
|
||||
mediaPlayer?.release()
|
||||
mediaPlayer = MediaPlayer.create(context, audio)
|
||||
mediaPlayer?.setOnCompletionListener {
|
||||
setVolume(oldVolume)
|
||||
audioManager.abandonAudioFocus(null)
|
||||
it.release()
|
||||
}
|
||||
mediaPlayer?.setOnPreparedListener {
|
||||
it.start()
|
||||
}
|
||||
}
|
||||
|
||||
fun stopAudio() {
|
||||
mediaPlayer?.let {
|
||||
if (it.isPlaying) {
|
||||
it.stop()
|
||||
}
|
||||
it.release()
|
||||
mediaPlayer = null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun run(context: Context, audio: Int) {
|
||||
val audioHelper = AudioHelper(context)
|
||||
audioHelper.routeAudioToSpeaker()
|
||||
audioHelper.setVolume(90)
|
||||
audioHelper.playAudio(audio)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -92,6 +92,21 @@
|
|||
android:textIsSelectable="true"
|
||||
android:textSize="18sp"
|
||||
tools:ignore="LabelFor" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/markdownPreview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fontFamily="@font/poppins_semi_bold"
|
||||
android:gravity="top|start"
|
||||
android:hint="@string/reply_hint"
|
||||
android:nestedScrollingEnabled="true"
|
||||
android:padding="16dp"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone"
|
||||
tools:ignore="LabelFor" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
|
|
BIN
app/src/main/res/raw/audio.mp3
Normal file
BIN
app/src/main/res/raw/audio.mp3
Normal file
Binary file not shown.
|
@ -1042,5 +1042,7 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
|
|||
<string name="enable_forgot_password">Enable Forgot Password (hold clear button for 10 seconds)</string>
|
||||
<string name="hide_notification_dot">Hide Notification Dot</string>
|
||||
<string name="private_mode">Private</string>
|
||||
<string name="omega_cursed">you have been Ǫ̴̺̙͎̤̫͓̮̰̿͝M̴͇̤͗́̾̈́̑̍̿̈͌͝Ȅ̴̡̨̛͉̣̙̩̲̣̤̟̪̣̎͗̎̆̒̉͆̆̕ͅͅǴ̸̯̬̗̠̙͛͐̀̈͋̀̈̽́̎̿͘͘͝ͅĀ̶̧̲̀ͅ ̴̢̟͕̜̓̾̓C̶̬̜̰̘̝̱̫͓͙̭̈́͐͋̓̏̈̍̓̀̌̾̚Ư̸̛̤̱̈́͆̽͊͛̐̓́̑͘̕̕͝R̸̨̨͈̬̱̺͕̪̪̘͕͎̂͛́̅̆̓̀͝ͅS̴̨̨̛̩̭̗̹̰̭̥͉̮̝̠̓̔͆̂͊͆̀̈́̅̕͘̚͝È̴̢̛̝͈̳͉͈͒͒̒̄̏̈̈́D̸̢̡̨̜̞̩̼̫̹̗̮͛̀̈̋̾̇̕̕͜ͅ</string>
|
||||
<string name="omega_freed">you have been freed</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue