diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 5e3c93e2..49a14191 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -13,7 +13,6 @@
-
diff --git a/.idea/misc.xml b/.idea/misc.xml
index b36f4a6d..2161c1f5 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -13,7 +13,7 @@
-
+
diff --git a/app/build.gradle b/app/build.gradle
index 03a6bfd0..2dff1ff7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -163,7 +163,8 @@ dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.2'
// Markdown
- implementation project(':markdown')
+ implementation "com.github.discord:SimpleAST:2.7.0"
+ implementation "androidx.appcompat:appcompat:1.7.0-alpha02"
}
kapt {
diff --git a/app/src/main/java/chat/revolt/components/chat/Message.kt b/app/src/main/java/chat/revolt/components/chat/Message.kt
index ac09b65c..ece442a6 100644
--- a/app/src/main/java/chat/revolt/components/chat/Message.kt
+++ b/app/src/main/java/chat/revolt/components/chat/Message.kt
@@ -1,6 +1,8 @@
package chat.revolt.components.chat
import android.net.Uri
+import android.text.SpannableStringBuilder
+import android.text.TextUtils
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.foundation.*
@@ -9,11 +11,15 @@ import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.content.res.ResourcesCompat
+import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.asJanuaryProxyUrl
@@ -22,7 +28,6 @@ import chat.revolt.api.internals.WebCompat
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.components.generic.UserAvatar
import chat.revolt.components.generic.UserAvatarWidthPlaceholder
-import chat.revolt.markdown.Markdown
import chat.revolt.api.schemas.Message as MessageSchema
fun viewAttachmentInBrowser(ctx: android.content.Context, attachment: AutumnResource) {
@@ -49,10 +54,12 @@ fun formatLongAsTime(time: Long): String {
fun Message(
message: MessageSchema,
truncate: Boolean = false,
+ parse: (MessageSchema) -> SpannableStringBuilder = { SpannableStringBuilder(it.content) },
onMessageContextMenu: () -> Unit = {},
) {
val author = RevoltAPI.userCache[message.author] ?: return CircularProgressIndicator()
val context = LocalContext.current
+ val contentColor = LocalContentColor.current
Column {
if (message.tail == false) {
@@ -134,11 +141,17 @@ fun Message(
message.content?.let {
if (message.content.isBlank()) return@let // if only an attachment is sent
- Text(
- text = Markdown.annotate(it),
- maxLines = if (truncate) 1 else Int.MAX_VALUE,
- overflow = TextOverflow.Ellipsis
- )
+ AndroidView(factory = { ctx ->
+ androidx.appcompat.widget.AppCompatTextView(ctx).apply {
+ text = parse(message)
+ maxLines = if (truncate) 1 else Int.MAX_VALUE
+ ellipsize = TextUtils.TruncateAt.END
+ textSize = 16f
+ typeface = ResourcesCompat.getFont(ctx, R.font.inter)
+
+ setTextColor(contentColor.toArgb())
+ }
+ })
}
message.attachments?.let {
diff --git a/app/src/main/java/chat/revolt/components/generic/Markdown.kt b/app/src/main/java/chat/revolt/components/generic/Markdown.kt
new file mode 100644
index 00000000..b348c236
--- /dev/null
+++ b/app/src/main/java/chat/revolt/components/generic/Markdown.kt
@@ -0,0 +1,118 @@
+package chat.revolt.components.generic
+
+import android.text.SpannableStringBuilder
+import android.text.TextUtils
+import android.util.Log
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.content.res.ResourcesCompat
+import chat.revolt.R
+import chat.revolt.api.RevoltAPI
+import chat.revolt.internals.markdown.ChannelMentionRule
+import chat.revolt.internals.markdown.CustomEmoteRule
+import chat.revolt.internals.markdown.MarkdownContext
+import chat.revolt.internals.markdown.MarkdownParser
+import chat.revolt.internals.markdown.MarkdownState
+import chat.revolt.internals.markdown.UserMentionRule
+import chat.revolt.internals.markdown.createCodeRule
+import chat.revolt.internals.markdown.createInlineCodeRule
+import com.discord.simpleast.core.simple.SimpleMarkdownRules
+import com.discord.simpleast.core.simple.SimpleRenderer
+
+/**
+ * A Markdown rendering component for Markdown embedded in UI (e.g. in a button).
+ * @param text The text to render.
+ * @param fontSize The font size to use.
+ * @param modifier The modifier to apply to the rendered text. Will be applied to AndroidView and thus subject to AndroidView's limitations.
+ * @param maxLines The maximum number of lines to display. Text will always be ellipsized on overflow. Defaults to [Int.MAX_VALUE].
+ */
+@Composable
+fun UIMarkdown(
+ text: String,
+ fontSize: TextUnit,
+ modifier: Modifier = Modifier,
+ maxLines: Int = Int.MAX_VALUE,
+) {
+ val context = LocalContext.current
+ val foregroundColor = LocalContentColor.current
+ val codeBlockColor = MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)
+ val spannableStringBuilder = remember { mutableStateOf(SpannableStringBuilder()) }
+
+ LaunchedEffect(text) {
+ val parser = MarkdownParser()
+ .addRules(
+ SimpleMarkdownRules.createEscapeRule(),
+ UserMentionRule(),
+ ChannelMentionRule(),
+ CustomEmoteRule(),
+ )
+ .addRules(
+ createCodeRule(context, codeBlockColor.toArgb()),
+ createInlineCodeRule(context, codeBlockColor.toArgb()),
+ )
+ .addRules(
+ SimpleMarkdownRules.createSimpleMarkdownRules(
+ includeEscapeRule = false
+ )
+ )
+
+ spannableStringBuilder.value = SimpleRenderer.render(
+ source = text,
+ parser = parser,
+ initialState = MarkdownState(0),
+ renderContext = MarkdownContext(
+ memberMap = mapOf(),
+ userMap = RevoltAPI.userCache.toMap(),
+ channelMap = RevoltAPI.channelCache.mapValues { ch ->
+ ch.value.name ?: ch.value.id!!
+ },
+ emojiMap = RevoltAPI.emojiCache,
+ serverId = null
+ )
+ )
+
+ Log.d("Markdown", "Rendered: ${spannableStringBuilder.value}")
+ }
+
+ AndroidView(
+ factory = {
+ androidx.appcompat.widget.AppCompatTextView(it).apply {
+ ellipsize = TextUtils.TruncateAt.END
+ typeface = ResourcesCompat.getFont(it, R.font.inter)
+
+ setTextColor(foregroundColor.toArgb())
+ setMaxLines(maxLines)
+ setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, fontSize.value)
+
+ setText(spannableStringBuilder.value)
+ }
+ },
+ modifier = modifier,
+ update = {
+ it.text = spannableStringBuilder.value
+ },
+ )
+}
+
+@Preview
+@Composable
+fun UIMarkdownPreview() {
+ // Will not render in side preview but will render on device
+ UIMarkdown(
+ text = "Hello, **world**!",
+ fontSize = 16.sp,
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/revolt/internals/markdown/BlockBackgroundNode.kt b/app/src/main/java/chat/revolt/internals/markdown/BlockBackgroundNode.kt
new file mode 100644
index 00000000..4942e6d1
--- /dev/null
+++ b/app/src/main/java/chat/revolt/internals/markdown/BlockBackgroundNode.kt
@@ -0,0 +1,129 @@
+package chat.revolt.internals.markdown
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.RectF
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.style.LeadingMarginSpan
+import android.text.style.LineBackgroundSpan
+import androidx.annotation.ColorInt
+import com.discord.simpleast.core.node.Node
+
+// Attribution:
+// https://github.com/discord/SimpleAST/blob/567b61c51056cbdec39e839100690c576c26a4c6/app/src/main/java/com/discord/simpleast/sample/spans/BlockBackgroundNode.kt
+// LICENSED UNDER THE APACHE LICENSE, VERSION 2.0
+// Adapted for Revolt.
+
+/**
+ * Creates a block background for code sections.
+ */
+class BlockBackgroundNode(
+ private val quoteDepth: Int,
+ private val fillColor: Int = Color.DKGRAY,
+ private val strokeColor: Int = Color.BLACK,
+ vararg children: Node,
+) : Node.Parent(*children) {
+
+ override fun render(builder: SpannableStringBuilder, renderContext: R) {
+ // Ensure the block we want to append starts on a newline.
+ ensureEndsWithNewline(builder)
+
+ val codeStartIndex = builder.length
+ super.render(builder, renderContext)
+ // BlockBackgroundSpan requires this to function
+ ensureEndsWithNewline(builder)
+
+ val backgroundSpan = BlockBackgroundSpan(
+ fillColor, strokeColor,
+ strokeWidth = 2,
+ strokeRadius = 15,
+ leftMargin = 40 * quoteDepth
+ )
+ builder.setSpan(
+ backgroundSpan,
+ codeStartIndex,
+ builder.length,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+
+ // Apply a leading margin to all lines in the block.
+ val leadingMarginSpan = LeadingMarginSpan.Standard(15)
+ builder.setSpan(
+ leadingMarginSpan,
+ codeStartIndex,
+ builder.length,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
+ )
+ }
+
+ private fun ensureEndsWithNewline(builder: SpannableStringBuilder) {
+ if (builder.isNotEmpty()) {
+ val lastChar = CharArray(6)
+ builder.getChars(builder.length - 1, builder.length, lastChar, 0)
+ if (lastChar[0] != '\n') {
+ builder.append('\n')
+ }
+ }
+ }
+}
+
+/**
+ * Computes the position of the paragraph on the screen and draws the desired background.
+ */
+class BlockBackgroundSpan(
+ @ColorInt fillColor: Int,
+ @ColorInt strokeColor: Int,
+ strokeWidth: Int,
+ strokeRadius: Int,
+ val leftMargin: Int
+) : LineBackgroundSpan {
+
+ private val fillPaint = Paint().apply {
+ this.style = Paint.Style.FILL
+ this.color = fillColor
+ }
+
+ private val strokePaint = Paint().apply {
+ this.style = Paint.Style.STROKE
+ this.color = strokeColor
+ this.strokeWidth = strokeWidth.toFloat()
+ this.isAntiAlias = true
+ }
+
+ private val rect = RectF()
+ private val radius = strokeRadius.toFloat()
+
+ fun draw(canvas: Canvas) {
+ canvas.drawRoundRect(rect, radius, radius, fillPaint)
+ canvas.drawRoundRect(rect, radius, radius, strokePaint)
+ }
+
+ override fun drawBackground(
+ canvas: Canvas,
+ paint: Paint,
+ left: Int,
+ right: Int,
+ top: Int,
+ baseline: Int,
+ bottom: Int,
+ text: CharSequence,
+ start: Int,
+ end: Int,
+ lnum: Int
+ ) {
+ if (text !is Spanned) return
+
+ if (text.getSpanStart(this) == start) {
+ rect.left = left.toFloat() + leftMargin
+ rect.top = top.toFloat()
+ }
+
+ if (text.getSpanEnd(this) == end) {
+ rect.right = right.toFloat()
+ rect.bottom = bottom.toFloat()
+ draw(canvas)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/revolt/internals/markdown/MarkdownContext.kt b/app/src/main/java/chat/revolt/internals/markdown/MarkdownContext.kt
index 16e2a0a1..362d9f98 100644
--- a/app/src/main/java/chat/revolt/internals/markdown/MarkdownContext.kt
+++ b/app/src/main/java/chat/revolt/internals/markdown/MarkdownContext.kt
@@ -1,11 +1,20 @@
package chat.revolt.internals.markdown
-import androidx.compose.runtime.snapshots.SnapshotStateMap
+import chat.revolt.api.schemas.Emoji
import chat.revolt.api.schemas.User
+import com.discord.simpleast.core.node.Node
+import com.discord.simpleast.core.parser.Parser
+
+typealias MarkdownParser = Parser, MarkdownState>
+
+data class MarkdownState(val currentQuoteDepth: Int) {
+ fun newQuoteDepth(depth: Int): MarkdownState = MarkdownState(depth)
+}
data class MarkdownContext(
- val memberMap: SnapshotStateMap,
- val userMap: SnapshotStateMap,
- val channelMap: SnapshotStateMap,
- val serverId: String,
+ val memberMap: Map,
+ val userMap: Map,
+ val channelMap: Map,
+ val emojiMap: Map,
+ val serverId: String?
)
\ No newline at end of file
diff --git a/app/src/main/java/chat/revolt/internals/markdown/MarkdownNodes.kt b/app/src/main/java/chat/revolt/internals/markdown/MarkdownNodes.kt
new file mode 100644
index 00000000..010ba495
--- /dev/null
+++ b/app/src/main/java/chat/revolt/internals/markdown/MarkdownNodes.kt
@@ -0,0 +1,32 @@
+package chat.revolt.internals.markdown
+
+import android.text.SpannableStringBuilder
+import com.discord.simpleast.core.node.Node
+
+class UserMentionNode(private val userId: String) : Node() {
+ override fun render(builder: SpannableStringBuilder, renderContext: MarkdownContext) {
+ builder.append(
+ renderContext.memberMap[userId]?.let { "@$it" }
+ ?: renderContext.userMap[userId]?.let { "@${it.username}" }
+ ?: "<@${userId}>"
+ )
+ }
+}
+
+class ChannelMentionNode(private val channelId: String) : Node() {
+ override fun render(builder: SpannableStringBuilder, renderContext: MarkdownContext) {
+ builder.append(
+ renderContext.channelMap[channelId]?.let { "#$it" }
+ ?: "<#${channelId}>"
+ )
+ }
+}
+
+class CustomEmoteNode(private val emoteId: String) : Node() {
+ override fun render(builder: SpannableStringBuilder, renderContext: MarkdownContext) {
+ builder.append(
+ renderContext.emojiMap[emoteId]?.let { ":${it.name}:" }
+ ?: ":${emoteId}:"
+ )
+ }
+}
diff --git a/app/src/main/java/chat/revolt/internals/markdown/MarkdownRules.kt b/app/src/main/java/chat/revolt/internals/markdown/MarkdownRules.kt
new file mode 100644
index 00000000..8d6d4266
--- /dev/null
+++ b/app/src/main/java/chat/revolt/internals/markdown/MarkdownRules.kt
@@ -0,0 +1,138 @@
+package chat.revolt.internals.markdown
+
+import android.content.Context
+import android.text.style.BackgroundColorSpan
+import android.text.style.TextAppearanceSpan
+import chat.revolt.R
+import com.discord.simpleast.code.CodeRules
+import com.discord.simpleast.code.CodeStyleProviders
+import com.discord.simpleast.core.node.Node
+import com.discord.simpleast.core.node.StyleNode
+import com.discord.simpleast.core.parser.ParseSpec
+import com.discord.simpleast.core.parser.Parser
+import com.discord.simpleast.core.parser.Rule
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+class UserMentionRule :
+ Rule(Pattern.compile("^<@([0-9A-Z]{26})>")) {
+ override fun parse(
+ matcher: Matcher,
+ parser: Parser,
+ state: S
+ ): ParseSpec {
+ return ParseSpec.createTerminal(UserMentionNode(matcher.group(1)!!), state)
+ }
+}
+
+class ChannelMentionRule :
+ Rule(Pattern.compile("^<#([0-9A-Z]{26})>")) {
+ override fun parse(
+ matcher: Matcher,
+ parser: Parser,
+ state: S
+ ): ParseSpec {
+ return ParseSpec.createTerminal(ChannelMentionNode(matcher.group(1)!!), state)
+ }
+}
+
+class CustomEmoteRule :
+ Rule(Pattern.compile("^:([0-9A-Z]{26}):")) {
+ override fun parse(
+ matcher: Matcher,
+ parser: Parser,
+ state: S
+ ): ParseSpec {
+ return ParseSpec.createTerminal(CustomEmoteNode(matcher.group(1)!!), state)
+ }
+}
+
+fun createInlineCodeRule(context: Context, backgroundColor: Int): Rule, S> {
+ return CodeRules.createInlineCodeRule(
+ { listOf(TextAppearanceSpan(context, R.style.Code_TextAppearance)) },
+ { listOf(BackgroundColorSpan(backgroundColor)) }
+ )
+}
+
+fun createCodeRule(
+ context: Context,
+ backgroundColor: Int
+): Rule, S> {
+ val codeStyleProviders = CodeStyleProviders(
+ defaultStyleProvider = { listOf(TextAppearanceSpan(context, R.style.Code_TextAppearance)) },
+ commentStyleProvider = {
+ listOf(
+ TextAppearanceSpan(
+ context,
+ R.style.Code_TextAppearance_Comment
+ )
+ )
+ },
+ literalStyleProvider = {
+ listOf(
+ TextAppearanceSpan(
+ context,
+ R.style.Code_TextAppearance_Literal
+ )
+ )
+ },
+ keywordStyleProvider = {
+ listOf(
+ TextAppearanceSpan(
+ context,
+ R.style.Code_TextAppearance_Keyword
+ )
+ )
+ },
+ identifierStyleProvider = {
+ listOf(
+ TextAppearanceSpan(
+ context,
+ R.style.Code_TextAppearance_Identifier
+ )
+ )
+ },
+ typesStyleProvider = {
+ listOf(
+ TextAppearanceSpan(
+ context,
+ R.style.Code_TextAppearance_Types
+ )
+ )
+ },
+ genericsStyleProvider = {
+ listOf(
+ TextAppearanceSpan(
+ context,
+ R.style.Code_TextAppearance_Generics
+ )
+ )
+ },
+ paramsStyleProvider = {
+ listOf(
+ TextAppearanceSpan(
+ context,
+ R.style.Code_TextAppearance_Params
+ )
+ )
+ },
+ )
+ val languageMap = CodeRules.createCodeLanguageMap(codeStyleProviders)
+
+ return CodeRules.createCodeRule(
+ codeStyleProviders.defaultStyleProvider,
+ languageMap
+ ) { codeNode, block, state ->
+ if (!block) {
+ StyleNode(listOf(BackgroundColorSpan(backgroundColor)))
+ .apply { addChild(codeNode) }
+ } else {
+ BlockBackgroundNode(
+ state.currentQuoteDepth,
+ backgroundColor,
+ backgroundColor,
+ codeNode
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/revolt/screens/chat/dialogs/safety/ReportMessageDialog.kt b/app/src/main/java/chat/revolt/screens/chat/dialogs/safety/ReportMessageDialog.kt
index ba31df98..83bef37e 100644
--- a/app/src/main/java/chat/revolt/screens/chat/dialogs/safety/ReportMessageDialog.kt
+++ b/app/src/main/java/chat/revolt/screens/chat/dialogs/safety/ReportMessageDialog.kt
@@ -28,7 +28,6 @@ import chat.revolt.api.routes.user.blockUser
import chat.revolt.api.schemas.ContentReportReason
import chat.revolt.components.chat.Message
import chat.revolt.components.generic.FormTextField
-import chat.revolt.markdown.Markdown
import kotlinx.coroutines.launch
enum class ReportingState {
@@ -112,7 +111,7 @@ fun ReportMessageDialog(
if (messageIsBridged) {
Spacer(modifier = Modifier.height(8.dp))
Text(
- text = Markdown.annotate(stringResource(id = R.string.report_message_bridge_notice)),
+ text = stringResource(id = R.string.report_message_bridge_notice),
fontSize = 12.sp
)
}
diff --git a/app/src/main/java/chat/revolt/screens/chat/views/ChannelScreen.kt b/app/src/main/java/chat/revolt/screens/chat/views/ChannelScreen.kt
index f4906d59..a266b3ac 100644
--- a/app/src/main/java/chat/revolt/screens/chat/views/ChannelScreen.kt
+++ b/app/src/main/java/chat/revolt/screens/chat/views/ChannelScreen.kt
@@ -19,6 +19,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
@@ -55,6 +56,16 @@ import chat.revolt.components.screens.chat.AttachmentManager
import chat.revolt.components.screens.chat.ChannelIcon
import chat.revolt.components.screens.chat.ReplyManager
import chat.revolt.components.screens.chat.TypingIndicator
+import chat.revolt.internals.markdown.ChannelMentionRule
+import chat.revolt.internals.markdown.CustomEmoteRule
+import chat.revolt.internals.markdown.MarkdownContext
+import chat.revolt.internals.markdown.MarkdownParser
+import chat.revolt.internals.markdown.MarkdownState
+import chat.revolt.internals.markdown.UserMentionRule
+import chat.revolt.internals.markdown.createCodeRule
+import chat.revolt.internals.markdown.createInlineCodeRule
+import com.discord.simpleast.core.simple.SimpleMarkdownRules
+import com.discord.simpleast.core.simple.SimpleRenderer
import io.ktor.http.*
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
@@ -401,6 +412,8 @@ fun ChannelScreen(
val lazyListState = rememberLazyListState()
val coroutineScope = rememberCoroutineScope()
+ val codeBlockColor = MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)
+
val pickFileLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenMultipleDocuments()
) { uriList ->
@@ -520,7 +533,39 @@ fun ChannelScreen(
items = viewModel.renderableMessages,
key = { it.id!! }
) { message ->
- Message(message) {
+ Message(message, parse = {
+ val parser = MarkdownParser()
+ .addRules(
+ SimpleMarkdownRules.createEscapeRule(),
+ UserMentionRule(),
+ ChannelMentionRule(),
+ CustomEmoteRule(),
+ )
+ .addRules(
+ createCodeRule(context, codeBlockColor.toArgb()),
+ createInlineCodeRule(context, codeBlockColor.toArgb()),
+ )
+ .addRules(
+ SimpleMarkdownRules.createSimpleMarkdownRules(
+ includeEscapeRule = false
+ )
+ )
+
+ SimpleRenderer.render(
+ source = it.content ?: "",
+ parser = parser,
+ initialState = MarkdownState(0),
+ renderContext = MarkdownContext(
+ memberMap = mapOf(),
+ userMap = RevoltAPI.userCache.toMap(),
+ channelMap = RevoltAPI.channelCache.mapValues { ch ->
+ ch.value.name ?: ch.value.id!!
+ },
+ emojiMap = RevoltAPI.emojiCache,
+ serverId = channel.server ?: "",
+ )
+ )
+ }) {
navController.navigate("message/${message.id}/menu")
}
}
diff --git a/app/src/main/res/font/inter.xml b/app/src/main/res/font/inter.xml
new file mode 100644
index 00000000..888c31f4
--- /dev/null
+++ b/app/src/main/res/font/inter.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/font/jetbrainsmono_regular.ttf b/app/src/main/res/font/jetbrainsmono_regular.ttf
new file mode 100644
index 00000000..7d26f5a5
Binary files /dev/null and b/app/src/main/res/font/jetbrainsmono_regular.ttf differ
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 059450d3..a16f502f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -155,7 +155,7 @@
Thank you for taking the time to report this message. Please provide a reason for reporting this message.
Selected message:
- **Note:** This message may have been sent from another platform. It is recommended to also report the message on the platform it was sent from.
+ Note: This message may have been sent from another platform. It is recommended to also report the message on the platform it was sent from.
Thank you for taking the time to report this server. Please provide a reason for reporting this server.
Selected server:
Thank you for taking the time to report this user. Please provide a reason for reporting this user.
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..dc10fba1
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 940f944c..135e8333 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/markdown/.gitignore b/markdown/.gitignore
deleted file mode 100644
index 42afabfd..00000000
--- a/markdown/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
\ No newline at end of file
diff --git a/markdown/build.gradle b/markdown/build.gradle
deleted file mode 100644
index e084498d..00000000
--- a/markdown/build.gradle
+++ /dev/null
@@ -1,50 +0,0 @@
-plugins {
- id 'com.android.library'
- id 'org.jetbrains.kotlin.android'
-}
-
-android {
- namespace 'chat.revolt.markdown'
- compileSdk 33
-
- defaultConfig {
- minSdk 23
- targetSdk 33
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles "consumer-rules.pro"
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
- buildFeatures {
- compose true
- }
- composeOptions {
- kotlinCompilerExtensionVersion compose_version
- }
-}
-
-dependencies {
- implementation 'androidx.core:core-ktx:1.9.0'
- implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'com.google.android.material:material:1.8.0'
-
- implementation platform("androidx.compose:compose-bom:$compose_bom_version")
- implementation "androidx.compose.ui:ui"
-
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.5'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
-}
\ No newline at end of file
diff --git a/markdown/consumer-rules.pro b/markdown/consumer-rules.pro
deleted file mode 100644
index e69de29b..00000000
diff --git a/markdown/proguard-rules.pro b/markdown/proguard-rules.pro
deleted file mode 100644
index 481bb434..00000000
--- a/markdown/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/markdown/src/main/AndroidManifest.xml b/markdown/src/main/AndroidManifest.xml
deleted file mode 100644
index a5918e68..00000000
--- a/markdown/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/markdown/src/main/java/chat/revolt/markdown/Markdown.kt b/markdown/src/main/java/chat/revolt/markdown/Markdown.kt
deleted file mode 100644
index 1c559b9a..00000000
--- a/markdown/src/main/java/chat/revolt/markdown/Markdown.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package chat.revolt.markdown
-
-import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.SpanStyle
-import androidx.compose.ui.text.buildAnnotatedString
-import androidx.compose.ui.text.font.FontWeight
-
-object Markdown {
- fun annotateInContext(text: String, context: Ctx): AnnotatedString {
- // TODO this is all placeholder code
- val boldRegex = Regex("\\*\\*(.*?)\\*\\*")
- return buildAnnotatedString {
- append(text)
-
- boldRegex.findAll(text).forEach { match ->
- addStyle(
- style = SpanStyle(fontWeight = FontWeight.Bold),
- start = match.groups[1]!!.range.first,
- end = match.groups[1]!!.range.last + 1
- )
- }
-
- toAnnotatedString()
- }
- }
-
- fun annotate(text: String): AnnotatedString = annotateInContext(text, Unit)
-}
\ No newline at end of file
diff --git a/markdown/src/main/java/chat/revolt/markdown/ast/MdAst.kt b/markdown/src/main/java/chat/revolt/markdown/ast/MdAst.kt
deleted file mode 100644
index 0b15a5a6..00000000
--- a/markdown/src/main/java/chat/revolt/markdown/ast/MdAst.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package chat.revolt.markdown.ast
-
-/*
- * SPECS:
- * - Unist, the universal syntax tree @ https://github.com/syntax-tree/unist
- * - Mdast, the markdown syntax tree @ https://github.com/syntax-tree/mdast
- */
-
-open class Literal(
- /**
- * The value of a node.
- */
- open val value: String = ""
-) : Node()
-
-open class Parent(
- /**
- * List representing the children of a node.
- */
- val children: List = emptyList()
-) : Node()
-
-open class Root(
- override val type: String = "root"
-) : Parent()
-
-open class Paragraph(
- override val type: String = "paragraph"
-) : Parent()
-
-open class Text(
- override val type: String = "text",
- override val value: String = ""
-) : Literal()
-
-open class Heading(
- override val type: String = "heading",
- val depth: Int = 1
-) : Parent()
-
-open class ThematicBreak(
- override val type: String = "thematicBreak"
-) : Node()
-
-open class Blockquote(
- override val type: String = "blockquote"
-) : Parent()
-
-open class MdList(
- override val type: String = "list",
- val ordered: Boolean = false,
- val start: Int = 1,
- val spread: Boolean = false
-) : Parent()
-
-open class ListItem(
- override val type: String = "listItem",
- val spread: Boolean = false
-) : Parent()
-
-open class Code(
- override val type: String = "code",
- val lang: String? = null,
- val meta: String? = null
-) : Literal()
-
-open class Emphasis(
- override val type: String = "emphasis"
-) : Parent()
-
-open class Strong(
- override val type: String = "strong"
-) : Parent()
-
-open class Delete(
- override val type: String = "delete"
-) : Parent()
-
-open class InlineCode(
- override val type: String = "inlineCode"
-) : Literal()
-
-open class Break(
- override val type: String = "break"
-) : Node()
-
-open class Link(
- override val type: String = "link",
- val title: String? = null,
- val url: String = ""
-) : Parent()
\ No newline at end of file
diff --git a/markdown/src/main/java/chat/revolt/markdown/ast/UniSt.kt b/markdown/src/main/java/chat/revolt/markdown/ast/UniSt.kt
deleted file mode 100644
index cf5439db..00000000
--- a/markdown/src/main/java/chat/revolt/markdown/ast/UniSt.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package chat.revolt.markdown.ast
-
-/*
- * SPECS:
- * - Unist, the universal syntax tree @ https://github.com/syntax-tree/unist
- * - Mdast, the markdown syntax tree @ https://github.com/syntax-tree/mdast
- */
-
-class Point(
- /**
- * Line number in the document, starting at 1.
- */
- val line: Int = 1,
-
- /**
- * Column on line in the document, starting at 1.
- */
- val column: Int = 1,
-
- /**
- * Character offset in the document, starting at 0.
- */
- val offset: Int = 0
-)
-
-class Position(
- /**
- * Place of the first character of the parsed source region.
- */
- val start: Point = Point(),
-
- /**
- * Place of the first character after the parsed source region.
- */
- val end: Point = Point(),
-
- /**
- * Start column at each index (plus start line) in the source region,
- * for elements that span multiple lines.
- */
- val indent: List = emptyList()
-)
-
-open class Node(
- /**
- * The variant of the node.
- */
- open val type: String = "",
-
- /**
- * Information from the ecosystem.
- */
- val data: Map = emptyMap(),
-
- /**
- * Location of the node in a source document.
- * Must not be present if a node is generated.
- */
- val position: Position = Position()
-)
diff --git a/markdown/src/main/java/chat/revolt/markdown/parser/Parser.kt b/markdown/src/main/java/chat/revolt/markdown/parser/Parser.kt
deleted file mode 100644
index e18fad61..00000000
--- a/markdown/src/main/java/chat/revolt/markdown/parser/Parser.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package chat.revolt.markdown.parser
-
-class Parser {
-}
diff --git a/markdown/src/test/java/chat/revolt/markdown/ExampleUnitTest.kt b/markdown/src/test/java/chat/revolt/markdown/ExampleUnitTest.kt
deleted file mode 100644
index bd772617..00000000
--- a/markdown/src/test/java/chat/revolt/markdown/ExampleUnitTest.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package chat.revolt.markdown
-
-import org.junit.Test
-
-import org.junit.Assert.*
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index bd43743c..e7d9f024 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -10,8 +10,8 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
+ maven { url "https://jitpack.io" }
}
}
rootProject.name = "Revolt"
include ':app'
-include ':markdown'