diff --git a/app/build.gradle b/app/build.gradle
index c7f1c027f464f23eb15efaddcb59ce3ad940cf29..85584f433807491ad59d2568f3cd5310824892a3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -22,7 +22,7 @@ android {
         viewBinding true
     }
 
-    signingConfigs{
+    signingConfigs {
         release {
             Properties properties = new Properties()
             if (rootProject.file("signing.properties").exists()) {
@@ -77,7 +77,7 @@ dependencies {
     implementation project(path: ':gallery')
 
     //Firebase
-    gplayImplementation platform('com.google.firebase:firebase-bom:32.5.0')
+    gplayImplementation platform('com.google.firebase:firebase-bom:32.6.0')
     gplayImplementation 'com.google.firebase:firebase-crashlytics-ktx'
     gplayImplementation 'com.google.firebase:firebase-analytics-ktx'
     gplayImplementation 'com.google.firebase:firebase-messaging-ktx'
@@ -88,13 +88,6 @@ dependencies {
     //Emoji
     implementation 'com.vanniktech:emoji-google:0.17.0'
 
-    //Markdown
-    def markwon_version = "4.6.2"
-    implementation "io.noties.markwon:core:$markwon_version"
-    implementation "io.noties.markwon:linkify:$markwon_version"
-    implementation "io.noties.markwon:ext-strikethrough:$markwon_version"
-    implementation "io.noties.markwon:ext-tasklist:$markwon_version"
-
     //Log
     implementation 'com.jakewharton.timber:timber:5.0.1'
 
diff --git a/app/src/main/java/org/futo/circles/extensions/EditableExtensions.kt b/app/src/main/java/org/futo/circles/extensions/EditableExtensions.kt
deleted file mode 100644
index bc1f20a2fca6913b1052fd12106c7fec80100460..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/extensions/EditableExtensions.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.futo.circles.extensions
-
-import android.text.Editable
-import org.futo.circles.feature.timeline.post.markdown.span.TextStyle
-import org.futo.circles.feature.timeline.post.markdown.span.toSpanClass
-
-fun Editable.getGivenSpansAt(
-    vararg span: TextStyle,
-    start: Int = 0,
-    end: Int = length
-): MutableList<Any> {
-    val spanList = mutableListOf<Any>()
-    for (selectedSpan in span) {
-        getSpans(start, end, selectedSpan.toSpanClass()).forEach { spanList.add(it) }
-    }
-    return spanList
-}
diff --git a/app/src/main/java/org/futo/circles/feature/notifications/DisplayableEventFormatter.kt b/app/src/main/java/org/futo/circles/feature/notifications/DisplayableEventFormatter.kt
index ce28f3d31155eb089cf4ed361794f2f5de48716e..dca27d5ce8f8ac055a2fda41b53e29a03c4eb902 100644
--- a/app/src/main/java/org/futo/circles/feature/notifications/DisplayableEventFormatter.kt
+++ b/app/src/main/java/org/futo/circles/feature/notifications/DisplayableEventFormatter.kt
@@ -4,7 +4,7 @@ import android.content.Context
 import dagger.hilt.android.qualifiers.ApplicationContext
 import org.futo.circles.R
 import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.feature.timeline.post.markdown.MarkdownParser
+import org.futo.circles.core.feature.markdown.MarkdownParser
 import org.matrix.android.sdk.api.session.events.model.Event
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toModel
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/TimelineDialogFragment.kt b/app/src/main/java/org/futo/circles/feature/timeline/TimelineDialogFragment.kt
index f55058b5cbc73ec13d399ce95d92e0558dda4a64..6da9154bacb1eddcf6c1f89ff3944adc8ac56dc6 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/TimelineDialogFragment.kt
+++ b/app/src/main/java/org/futo/circles/feature/timeline/TimelineDialogFragment.kt
@@ -84,6 +84,7 @@ class TimelineDialogFragment : BaseFullscreenDialogFragment(DialogFragmentTimeli
 
     private val listAdapter by lazy {
         TimelineAdapter(
+            requireContext(),
             getCurrentUserPowerLevel(args.roomId),
             this,
             isThread
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineAdapter.kt b/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineAdapter.kt
index 8f932c8a6541afd06420a627d5721a75447c2731..2a789691a2e5cdc96197e4def61e21fb0de2f336 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineAdapter.kt
+++ b/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineAdapter.kt
@@ -1,14 +1,17 @@
 package org.futo.circles.feature.timeline.list
 
 import android.annotation.SuppressLint
+import android.content.Context
 import android.view.ViewGroup
 import org.futo.circles.core.base.list.BaseRvAdapter
+import org.futo.circles.core.feature.markdown.MarkdownParser
 import org.futo.circles.core.model.Post
 import org.futo.circles.core.model.PostContentType
 import org.futo.circles.model.PostItemPayload
 import org.futo.circles.view.PostOptionsListener
 
 class TimelineAdapter(
+    context: Context,
     private var userPowerLevel: Int,
     private val postOptionsListener: PostOptionsListener,
     private val isThread: Boolean,
@@ -22,6 +25,9 @@ class TimelineAdapter(
         needToUpdateFullItem = new.content != old.content || new.postInfo != old.postInfo
     )
 }) {
+
+    private val markwon = MarkdownParser.markwonBuilder(context)
+
     @SuppressLint("NotifyDataSetChanged")
     fun updateUserPowerLevel(level: Int) {
         userPowerLevel = level
@@ -36,7 +42,7 @@ class TimelineAdapter(
                 parent, postOptionsListener, isThread
             )
 
-            else -> TextMediaPostViewHolder(parent, postOptionsListener, isThread)
+            else -> TextMediaPostViewHolder(parent, markwon, postOptionsListener, isThread)
         }
     }
 
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineViewHolder.kt b/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineViewHolder.kt
index d43530f631e7deb32e190ea15968cdd7299ef3c0..dc2e3b4cb2a9c9f78d6c5680af01e9abb9000cd3 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineViewHolder.kt
+++ b/app/src/main/java/org/futo/circles/feature/timeline/list/TimelineViewHolder.kt
@@ -8,12 +8,12 @@ import android.view.ViewGroup
 import android.widget.TextView
 import androidx.core.view.updateLayoutParams
 import androidx.recyclerview.widget.RecyclerView
+import io.noties.markwon.Markwon
+import org.futo.circles.core.base.list.ViewBindingHolder
 import org.futo.circles.core.extensions.gone
 import org.futo.circles.core.extensions.loadEncryptedThumbOrFullIntoWithAspect
 import org.futo.circles.core.extensions.setIsVisible
 import org.futo.circles.core.extensions.visible
-import org.futo.circles.core.base.list.ViewBindingHolder
-import org.futo.circles.core.base.list.context
 import org.futo.circles.core.model.MediaContent
 import org.futo.circles.core.model.MediaType
 import org.futo.circles.core.model.PollContent
@@ -21,7 +21,6 @@ import org.futo.circles.core.model.Post
 import org.futo.circles.core.model.TextContent
 import org.futo.circles.databinding.ViewPollPostBinding
 import org.futo.circles.databinding.ViewTextMediaPostBinding
-import org.futo.circles.feature.timeline.post.markdown.MarkdownParser
 import org.futo.circles.model.*
 import org.futo.circles.view.PostLayout
 import org.futo.circles.view.PostOptionsListener
@@ -31,7 +30,6 @@ sealed class PostViewHolder(view: View, private val isThread: Boolean) :
     RecyclerView.ViewHolder(view) {
 
     abstract val postLayout: PostLayout
-    protected val markwon = MarkdownParser.markwonBuilder(context)
 
     open fun bind(post: Post, userPowerLevel: Int) {
         postLayout.setData(post, userPowerLevel, isThread)
@@ -44,6 +42,7 @@ sealed class PostViewHolder(view: View, private val isThread: Boolean) :
 
 class TextMediaPostViewHolder(
     parent: ViewGroup,
+    private val markwon: Markwon,
     postOptionsListener: PostOptionsListener,
     isThread: Boolean
 ) : PostViewHolder(inflate(parent, ViewTextMediaPostBinding::inflate), isThread),
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/create/CreatePostDialogFragment.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/create/CreatePostDialogFragment.kt
index 2f02efc3bf74fa5ccf1c45e46e4dcf4a2205c950..37b629d3aaeda0588c4623ce8598d9d707f9e43d 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/create/CreatePostDialogFragment.kt
+++ b/app/src/main/java/org/futo/circles/feature/timeline/post/create/CreatePostDialogFragment.kt
@@ -11,26 +11,24 @@ import androidx.navigation.fragment.navArgs
 import dagger.hilt.android.AndroidEntryPoint
 import org.futo.circles.R
 import org.futo.circles.core.base.NetworkObserver
+import org.futo.circles.core.base.fragment.BaseFullscreenDialogFragment
 import org.futo.circles.core.extensions.navigateSafe
 import org.futo.circles.core.extensions.observeData
-import org.futo.circles.core.extensions.onBackPressed
 import org.futo.circles.core.extensions.showError
-import org.futo.circles.core.base.fragment.BaseFullscreenDialogFragment
+import org.futo.circles.core.feature.picker.helper.MediaPickerHelper
 import org.futo.circles.core.model.MediaContent
 import org.futo.circles.core.model.MediaType
 import org.futo.circles.core.model.PostContentType
 import org.futo.circles.core.model.TextContent
-import org.futo.circles.core.feature.picker.helper.MediaPickerHelper
 import org.futo.circles.databinding.DialogFragmentCreatePostBinding
 import org.futo.circles.feature.timeline.post.emoji.EmojiPickerListener
-import org.futo.circles.feature.timeline.post.markdown.span.TextStyle
-import org.futo.circles.view.PreviewPostListener
+import org.futo.circles.model.CreatePostContent
 import java.util.*
 
 @AndroidEntryPoint
 class CreatePostDialogFragment :
     BaseFullscreenDialogFragment(DialogFragmentCreatePostBinding::inflate),
-    PostConfigurationOptionListener, EmojiPickerListener {
+    PreviewPostListener, EmojiPickerListener {
 
     private val args: CreatePostDialogFragmentArgs by navArgs()
     private val binding by lazy {
@@ -58,29 +56,7 @@ class CreatePostDialogFragment :
     private fun setupViews() {
         setToolbarTitle()
         with(binding) {
-            btnSend.apply {
-                setOnClickListener {
-                    if (!NetworkObserver.isConnected()) {
-                        showError(getString(org.futo.circles.core.R.string.no_internet_connection))
-                        return@setOnClickListener
-                    }
-                    sendPost()
-                    onBackPressed()
-                }
-            }
-            binding.vPostOptions.apply {
-                setOptionsListener(this@CreatePostDialogFragment)
-                showMainOptionsList(!args.isEdit)
-            }
-            vPostPreview.setup(
-                object : PreviewPostListener {
-                    override fun onPostContentAvailable(isAvailable: Boolean) {
-                        binding.btnSend.isEnabled = isAvailable
-                    }
-                },
-                onHighlightTextStyle = { textStyle -> binding.vPostOptions.highlightStyle(textStyle) },
-                roomId = args.roomId
-            )
+            vPostPreview.setup(this@CreatePostDialogFragment, args.roomId, args.isEdit)
         }
     }
 
@@ -106,16 +82,16 @@ class CreatePostDialogFragment :
         binding.vPostPreview.setMedia(uri, type)
     }
 
-    private fun sendPost() {
-        if (args.isEdit) onEditPost()
+    private fun sendPost(content: CreatePostContent) {
+        if (args.isEdit) onEditPost(content)
         else createPostListener?.onSendPost(
-            args.roomId, binding.vPostPreview.getPostContent(), args.eventId
+            args.roomId, content, args.eventId
         )
     }
 
-    private fun onEditPost() {
+    private fun onEditPost(content: CreatePostContent) {
         val eventId = args.eventId ?: return
-        createPostListener?.onEditPost(args.roomId, binding.vPostPreview.getPostContent(), eventId)
+        createPostListener?.onEditPost(args.roomId, content, eventId)
     }
 
     override fun onUploadMediaClicked() {
@@ -131,20 +107,21 @@ class CreatePostDialogFragment :
         )
     }
 
-    override fun onMentionClicked() {
-        binding.vPostPreview.insertMention()
-    }
-
-    override fun onTextStyleSelected(textStyle: TextStyle, isSelected: Boolean) {
-        binding.vPostPreview.setTextStyle(textStyle, isSelected)
-    }
-
     override fun onAddLinkClicked() {
         AddLinkDialog(requireContext()) { title, link ->
             binding.vPostPreview.insertLink(title, link)
         }.show()
     }
 
+    override fun onSendClicked(content: CreatePostContent) {
+        if (!NetworkObserver.isConnected()) {
+            showError(getString(org.futo.circles.core.R.string.no_internet_connection))
+            return
+        }
+        sendPost(content)
+        dismiss()
+    }
+
     override fun onEmojiSelected(roomId: String?, eventId: String?, emoji: String) {
         binding.vPostPreview.insertEmoji(emoji)
     }
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/create/PostConfigurationOptionListener.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/create/PostConfigurationOptionListener.kt
deleted file mode 100644
index e07ad2f2fe140ff09ba723d1111adde3e115cadd..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/create/PostConfigurationOptionListener.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.futo.circles.feature.timeline.post.create
-
-import org.futo.circles.feature.timeline.post.markdown.span.TextStyle
-
-interface PostConfigurationOptionListener {
-    fun onUploadMediaClicked()
-    fun onEmojiClicked()
-    fun onMentionClicked()
-    fun onTextStyleSelected(textStyle: TextStyle, isSelected: Boolean)
-    fun onAddLinkClicked()
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/create/PreviewPostListener.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/create/PreviewPostListener.kt
new file mode 100644
index 0000000000000000000000000000000000000000..feb0d838003572dcf822999fa3049b51abc497a4
--- /dev/null
+++ b/app/src/main/java/org/futo/circles/feature/timeline/post/create/PreviewPostListener.kt
@@ -0,0 +1,10 @@
+package org.futo.circles.feature.timeline.post.create
+
+import org.futo.circles.model.CreatePostContent
+
+interface PreviewPostListener {
+    fun onUploadMediaClicked()
+    fun onEmojiClicked()
+    fun onAddLinkClicked()
+    fun onSendClicked(content: CreatePostContent)
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/EnhancedMovementMethod.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/EnhancedMovementMethod.kt
deleted file mode 100644
index c330c316775d5e0b90337c303dab173168606429..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/EnhancedMovementMethod.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.futo.circles.feature.timeline.post.markdown
-
-
-import android.text.Selection
-import android.text.Spannable
-import android.text.method.ArrowKeyMovementMethod
-import android.text.method.MovementMethod
-import android.text.style.ClickableSpan
-import android.view.MotionEvent
-import android.widget.TextView
-
-
-class EnhancedMovementMethod : ArrowKeyMovementMethod() {
-    private var sInstance: EnhancedMovementMethod? = null
-
-    fun getsInstance(): MovementMethod? {
-        if (sInstance == null) {
-            sInstance = EnhancedMovementMethod()
-        }
-        return sInstance
-    }
-
-    override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
-        val action = event.action
-        if (action == MotionEvent.ACTION_UP ||
-            action == MotionEvent.ACTION_DOWN
-        ) {
-            var x = event.x.toInt()
-            var y = event.y.toInt()
-            x -= widget.totalPaddingLeft
-            y -= widget.totalPaddingTop
-            x += widget.scrollX
-            y += widget.scrollY
-            val layout = widget.layout
-            val line = layout.getLineForVertical(y)
-            val off = layout.getOffsetForHorizontal(line, x.toFloat())
-            val link = buffer.getSpans(
-                off, off,
-                ClickableSpan::class.java
-            )
-            if (link.isNotEmpty()) {
-                if (action == MotionEvent.ACTION_UP) {
-                    if (x < layout.getLineMax(0)) {
-                        link[0].onClick(widget)
-                    }
-                } else {
-                    Selection.setSelection(
-                        buffer,
-                        buffer.getSpanStart(link[0]),
-                        buffer.getSpanEnd(link[0])
-                    )
-                }
-                return true
-            }
-        }
-        return super.onTouchEvent(widget, buffer, event)
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/MarkdownParser.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/MarkdownParser.kt
deleted file mode 100644
index 3928f432776aafef114b3e725c8a8037665c560d..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/MarkdownParser.kt
+++ /dev/null
@@ -1,140 +0,0 @@
-package org.futo.circles.feature.timeline.post.markdown
-
-import android.content.Context
-import android.graphics.Color
-import android.graphics.Typeface
-import android.text.Editable
-import android.text.style.StrikethroughSpan
-import android.text.style.StyleSpan
-import androidx.core.content.ContextCompat
-import androidx.core.text.getSpans
-import io.noties.markwon.AbstractMarkwonPlugin
-import io.noties.markwon.Markwon
-import io.noties.markwon.MarkwonSpansFactory
-import io.noties.markwon.core.spans.BulletListItemSpan
-import io.noties.markwon.core.spans.EmphasisSpan
-import io.noties.markwon.core.spans.LinkSpan
-import io.noties.markwon.core.spans.StrongEmphasisSpan
-import io.noties.markwon.ext.strikethrough.StrikethroughPlugin
-import io.noties.markwon.ext.tasklist.TaskListPlugin
-import io.noties.markwon.ext.tasklist.TaskListSpan
-import io.noties.markwon.linkify.LinkifyPlugin
-import org.commonmark.node.Emphasis
-import org.commonmark.node.StrongEmphasis
-import org.futo.circles.R
-import org.futo.circles.core.extensions.notEmptyDisplayName
-import org.futo.circles.core.provider.MatrixSessionProvider
-import org.futo.circles.extensions.getGivenSpansAt
-import org.futo.circles.feature.timeline.post.markdown.mentions.plugin.MentionPlugin
-import org.futo.circles.feature.timeline.post.markdown.span.MentionSpan
-import org.futo.circles.feature.timeline.post.markdown.span.OrderedListItemSpan
-import org.futo.circles.feature.timeline.post.markdown.span.TextStyle
-import org.matrix.android.sdk.api.session.getUserOrDefault
-
-
-object MarkdownParser {
-
-    const val mentionMark = "@"
-    private const val boldMark = "**"
-    private const val italicMark = "_"
-    private const val strikeMark = "~~"
-    private const val notDoneMark = "* [ ]"
-    private const val doneMark = "* [x]"
-
-    fun editableToMarkdown(text: Editable): String {
-        val textCopy = Editable.Factory.getInstance().newEditable(text)
-        text.getGivenSpansAt(span = TextStyle.values()).forEach {
-            val start = textCopy.getSpanStart(it)
-            val end = textCopy.getSpanEnd(it)
-            when (it) {
-                is StrongEmphasisSpan -> {
-                    val endIndex = calculateLastIndexToInsert(textCopy, end, boldMark)
-                    textCopy.insert(start, boldMark)
-                    textCopy.insert(endIndex, boldMark)
-                }
-
-                is EmphasisSpan -> {
-                    val endIndex = calculateLastIndexToInsert(textCopy, end, italicMark)
-                    textCopy.insert(start, italicMark)
-                    textCopy.insert(endIndex, italicMark)
-                }
-
-                is StrikethroughSpan -> {
-                    val endIndex = calculateLastIndexToInsert(textCopy, end, strikeMark)
-                    textCopy.insert(start, strikeMark)
-                    textCopy.insert(endIndex, strikeMark)
-                }
-
-                is LinkSpan -> {
-                    val linkStartMark = "["
-                    textCopy.insert(start, linkStartMark)
-                    textCopy.insert(end + linkStartMark.length, "](${it.link})")
-                }
-
-                is BulletListItemSpan -> textCopy.insert(start, "*")
-                is OrderedListItemSpan -> textCopy.insert(start, it.number)
-                is TaskListSpan -> {
-                    val taskSpanMark = if (it.isDone) doneMark else notDoneMark
-                    textCopy.insert(start, taskSpanMark)
-                }
-            }
-        }
-        text.getSpans<MentionSpan>().forEach {
-            val end = textCopy.getSpanEnd(it)
-            val textToInsert = it.name + mentionMark
-            textCopy.insert(end, textToInsert)
-        }
-        return textCopy.toString()
-    }
-
-    fun markwonBuilder(context: Context): Markwon = Markwon.builder(context)
-        .usePlugin(StrikethroughPlugin.create())
-        .usePlugin(LinkifyPlugin.create())
-        .usePlugin(MentionPlugin(context))
-        .usePlugin(
-            TaskListPlugin.create(
-                ContextCompat.getColor(context, R.color.blue),
-                ContextCompat.getColor(context, R.color.blue),
-                Color.WHITE
-            )
-        ).build()
-
-    fun markwonNotificationBuilder(context: Context): Markwon = Markwon.builder(context)
-        .usePlugin(object : AbstractMarkwonPlugin() {
-            override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
-                builder.setFactory(
-                    Emphasis::class.java
-                ) { _, _ -> StyleSpan(Typeface.ITALIC) }
-            }
-        })
-        .usePlugin(object : AbstractMarkwonPlugin() {
-            override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
-                builder.setFactory(
-                    StrongEmphasis::class.java
-                ) { _, _ -> StyleSpan(Typeface.BOLD) }
-            }
-        })
-        .usePlugin(StrikethroughPlugin.create())
-        .usePlugin(LinkifyPlugin.create())
-        .usePlugin(
-            TaskListPlugin.create(
-                ContextCompat.getColor(context, R.color.blue),
-                ContextCompat.getColor(context, R.color.blue),
-                Color.WHITE
-            )
-        ).build()
-
-    fun hasCurrentUserMention(text: String): Boolean {
-        val session = MatrixSessionProvider.currentSession ?: return false
-        val userName = session.getUserOrDefault(session.myUserId).notEmptyDisplayName()
-        val mentionString = mentionMark + userName + mentionMark
-        return text.contains(mentionString)
-    }
-
-    private fun calculateLastIndexToInsert(textCopy: Editable, spanEnd: Int, mark: String): Int {
-        var endIndex = spanEnd + mark.length
-        val lastChar = textCopy.getOrNull(spanEnd - 1).toString()
-        if (lastChar == " " || lastChar == "\n") endIndex -= 1
-        return endIndex
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/OrderedListItemSpan.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/OrderedListItemSpan.kt
deleted file mode 100644
index fc008d79ec29caea53eb2107e55ba84a5095cee4..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/OrderedListItemSpan.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.futo.circles.feature.timeline.post.markdown.span
-
-import android.graphics.Canvas
-import android.graphics.Paint
-import android.text.Layout
-import android.text.style.LeadingMarginSpan
-import io.noties.markwon.core.MarkwonTheme
-import io.noties.markwon.utils.LeadingMarginUtils
-
-
-class OrderedListItemSpan(
-    private val theme: MarkwonTheme,
-    val number: String
-) : LeadingMarginSpan {
-    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
-
-    private var margin = 0
-    override fun getLeadingMargin(first: Boolean): Int = margin.coerceAtLeast(theme.blockMargin)
-
-    override fun drawLeadingMargin(
-        c: Canvas,
-        p: Paint,
-        x: Int,
-        dir: Int,
-        top: Int,
-        baseline: Int,
-        bottom: Int,
-        text: CharSequence,
-        start: Int,
-        end: Int,
-        first: Boolean,
-        layout: Layout
-    ) {
-        if (!first || !LeadingMarginUtils.selfStart(start, text, this)) return
-
-        paint.set(p)
-        theme.applyListItemStyle(paint)
-
-        val numberWidth = (paint.measureText(number) + .5f).toInt()
-
-        var width = theme.blockMargin
-        if (numberWidth > width) {
-            width = numberWidth
-            margin = numberWidth
-        } else {
-            margin = 0
-        }
-        val left: Int = if (dir > 0) {
-            x + width * dir - numberWidth
-        } else {
-            x + width * dir + (width - numberWidth)
-        }
-
-        c.drawText(number, left.toFloat(), baseline.toFloat(), paint)
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/TextStyle.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/TextStyle.kt
deleted file mode 100644
index 1e06a1b9fc7773e3cdb3ef45f11ed1afd2d9bce4..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/TextStyle.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.futo.circles.feature.timeline.post.markdown.span
-
-import android.text.style.StrikethroughSpan
-import io.noties.markwon.core.spans.BulletListItemSpan
-import io.noties.markwon.core.spans.EmphasisSpan
-import io.noties.markwon.core.spans.LinkSpan
-import io.noties.markwon.core.spans.StrongEmphasisSpan
-import io.noties.markwon.ext.tasklist.TaskListSpan
-
-enum class TextStyle {
-    BOLD,
-    ITALIC,
-    STRIKE,
-    LINK,
-    UNORDERED_LIST,
-    ORDERED_LIST,
-    TASKS_LIST
-}
-
-fun TextStyle.toSpanClass() = when (this) {
-    TextStyle.BOLD -> StrongEmphasisSpan::class.java
-    TextStyle.ITALIC -> EmphasisSpan::class.java
-    TextStyle.STRIKE -> StrikethroughSpan::class.java
-    TextStyle.LINK -> LinkSpan::class.java
-    TextStyle.UNORDERED_LIST -> BulletListItemSpan::class.java
-    TextStyle.ORDERED_LIST -> OrderedListItemSpan::class.java
-    TextStyle.TASKS_LIST -> TaskListSpan::class.java
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/style_bar/OptionsStyleBarAdapter.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/style_bar/OptionsStyleBarAdapter.kt
deleted file mode 100644
index a45c7b440cf110f5347c9c94ca3b7d616a4413a8..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/style_bar/OptionsStyleBarAdapter.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.futo.circles.feature.timeline.post.markdown.style_bar
-
-import android.view.ViewGroup
-import org.futo.circles.core.base.list.BaseRvAdapter
-import org.futo.circles.model.StyleBarListItem
-
-class OptionsStyleBarAdapter(
-    private val onOptionSelected: (Int) -> Unit
-) : BaseRvAdapter<StyleBarListItem, StyleBarOptionViewHolder>(
-    DefaultIdEntityCallback()
-) {
-
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StyleBarOptionViewHolder {
-        return StyleBarOptionViewHolder(parent = parent) { onOptionSelected(getItem(it).id) }
-    }
-
-    override fun onBindViewHolder(holder: StyleBarOptionViewHolder, position: Int) {
-        holder.bind(getItem(position))
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/style_bar/StyleBarOptionViewHolder.kt b/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/style_bar/StyleBarOptionViewHolder.kt
deleted file mode 100644
index 0ab9ac3284b48a4298337ef8761fa6e8ee9d6e4d..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/style_bar/StyleBarOptionViewHolder.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.futo.circles.feature.timeline.post.markdown.style_bar
-
-import android.view.ViewGroup
-import androidx.core.content.ContextCompat
-import androidx.recyclerview.widget.RecyclerView
-import org.futo.circles.R
-import org.futo.circles.core.extensions.onClick
-import org.futo.circles.core.base.list.ViewBindingHolder
-import org.futo.circles.core.base.list.context
-import org.futo.circles.databinding.ListItemStyleBarBinding
-import org.futo.circles.model.StyleBarListItem
-
-class StyleBarOptionViewHolder(
-    parent: ViewGroup, onItemClicked: (Int) -> Unit
-) : RecyclerView.ViewHolder(
-    inflate(parent, ListItemStyleBarBinding::inflate)
-) {
-    private companion object : ViewBindingHolder
-
-    private val binding = baseBinding as ListItemStyleBarBinding
-
-    init {
-        onClick(binding.cvOption) { onItemClicked(it) }
-    }
-
-    fun bind(data: StyleBarListItem) {
-        binding.ivIcon.setImageResource(data.iconResId)
-        binding.cvOption.setCardBackgroundColor(
-            ContextCompat.getColor(
-                context, if (data.isSelected) R.color.blue else
-                    org.futo.circles.core.R.color.post_card_background_color
-            )
-        )
-    }
-}
-
diff --git a/app/src/main/java/org/futo/circles/view/DimensionConverter.kt b/app/src/main/java/org/futo/circles/view/DimensionConverter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2225c471de1b53bae1b9daee055daa446d91d6bc
--- /dev/null
+++ b/app/src/main/java/org/futo/circles/view/DimensionConverter.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.futo.circles.view
+
+import android.content.res.Resources
+import android.util.TypedValue
+import androidx.annotation.Px
+import javax.inject.Inject
+
+class DimensionConverter @Inject constructor(val resources: Resources) {
+
+    @Px
+    fun dpToPx(dp: Int): Int {
+        return TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP,
+                dp.toFloat(),
+                resources.displayMetrics
+        ).toInt()
+    }
+
+    @Px
+    fun spToPx(sp: Int): Int {
+        return TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_SP,
+                sp.toFloat(),
+                resources.displayMetrics
+        ).toInt()
+    }
+
+    fun pxToDp(@Px px: Int): Int {
+        return (px.toFloat() / resources.displayMetrics.density).toInt()
+    }
+}
diff --git a/app/src/main/java/org/futo/circles/view/MarkdownEditText.kt b/app/src/main/java/org/futo/circles/view/MarkdownEditText.kt
deleted file mode 100644
index 04efcc95af6916f148330cf1d739c8bc0df3a913..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/view/MarkdownEditText.kt
+++ /dev/null
@@ -1,304 +0,0 @@
-package org.futo.circles.view
-
-
-import android.content.Context
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
-import android.text.Editable
-import android.text.Spannable
-import android.text.Spanned
-import android.text.style.ClickableSpan
-import android.text.style.StrikethroughSpan
-import android.util.AttributeSet
-import android.view.View
-import androidx.appcompat.widget.AppCompatEditText
-import androidx.core.content.ContextCompat
-import androidx.core.widget.doOnTextChanged
-import io.noties.markwon.LinkResolverDef
-import io.noties.markwon.Markwon
-import io.noties.markwon.core.spans.BulletListItemSpan
-import io.noties.markwon.core.spans.EmphasisSpan
-import io.noties.markwon.core.spans.LinkSpan
-import io.noties.markwon.core.spans.StrongEmphasisSpan
-import io.noties.markwon.ext.tasklist.TaskListDrawable
-import io.noties.markwon.ext.tasklist.TaskListSpan
-import org.futo.circles.R
-import org.futo.circles.core.feature.autocomplete.Autocomplete
-import org.futo.circles.core.feature.autocomplete.AutocompleteCallback
-import org.futo.circles.core.feature.autocomplete.CharPolicy
-import org.futo.circles.core.model.UserListItem
-import org.futo.circles.extensions.getGivenSpansAt
-import org.futo.circles.feature.timeline.post.markdown.EnhancedMovementMethod
-import org.futo.circles.feature.timeline.post.markdown.MarkdownParser
-import org.futo.circles.feature.timeline.post.markdown.mentions.MentionsPresenter
-import org.futo.circles.feature.timeline.post.markdown.span.MentionSpan
-import org.futo.circles.feature.timeline.post.markdown.span.OrderedListItemSpan
-import org.futo.circles.feature.timeline.post.markdown.span.TextStyle
-
-
-class MarkdownEditText(
-    context: Context,
-    attrs: AttributeSet? = null
-) : AppCompatEditText(context, attrs) {
-
-    private val markwon: Markwon
-    private var isSelectionStyling = false
-    private var listSpanStart = 0
-    private var currentListSpanNumber = 0
-    private var currentListSpanLine = 0
-    private val taskBoxColor by lazy { ContextCompat.getColor(context, R.color.blue) }
-    private val taskBoxMarkColor = Color.WHITE
-    private val textStyles =
-        arrayOf(TextStyle.BOLD, TextStyle.ITALIC, TextStyle.STRIKE)
-    private val listStyles =
-        arrayOf(TextStyle.UNORDERED_LIST, TextStyle.ORDERED_LIST, TextStyle.TASKS_LIST)
-    private var onHighlightSpanListener: ((List<TextStyle>) -> Unit)? = null
-    private val selectedStyles = mutableSetOf<TextStyle>()
-
-    init {
-        movementMethod = EnhancedMovementMethod().getsInstance()
-        markwon = MarkdownParser.markwonBuilder(context)
-        doOnTextChanged { _, start, before, count ->
-            styliseText(start, start + count)
-            handleListSpanTextChange(before, count)
-        }
-    }
-
-    override fun getText(): Editable {
-        return super.getText() ?: Editable.Factory.getInstance().newEditable("")
-    }
-
-    fun getTextWithMarkdown() = MarkdownParser.editableToMarkdown(text)
-
-    fun setHighlightSelectedSpanListener(onHighlight: (List<TextStyle>) -> Unit) {
-        onHighlightSpanListener = onHighlight
-    }
-
-    fun insertMentionMark() {
-        insertText(MarkdownParser.mentionMark)
-    }
-
-    fun insertText(message: String) {
-        text.insert(selectionStart, message)
-    }
-
-    fun triggerStyle(textStyle: TextStyle, isSelected: Boolean) {
-        if (isSelected) {
-            selectOnlyOneListStyleIfNeed(textStyle)
-            selectedStyles.add(textStyle)
-        } else selectedStyles.remove(textStyle)
-        handleSelectionStylingIfNeed()
-        onHighlightSpanListener?.invoke(selectedStyles.toList())
-    }
-
-    fun initMentionsAutocomplete(roomId: String) {
-        Autocomplete.on<UserListItem>(this)
-            .with(CharPolicy('@', true))
-            .with(MentionsPresenter(context, roomId))
-            .with(
-                ColorDrawable(
-                    ContextCompat.getColor(
-                        context,
-                        org.futo.circles.core.R.color.post_card_background_color
-                    )
-                )
-            )
-            .with(object : AutocompleteCallback<UserListItem> {
-                override fun onPopupItemClicked(editable: Editable, item: UserListItem): Boolean {
-                    val range = CharPolicy.getQueryRange(editable) ?: return false
-                    insertMentionSpan(editable, item.user.name, range[0])
-                    return true
-                }
-
-                override fun onPopupVisibilityChanged(shown: Boolean) {
-                }
-            })
-            .with(6f)
-            .build()
-    }
-
-    private fun handleSelectionStylingIfNeed() {
-        if (!isSelectionStyling) return
-        text.getGivenSpansAt(span = textStyles, selectionStart, selectionEnd).forEach {
-            text.removeSpan(it)
-        }
-        styliseText(selectionStart, selectionEnd)
-    }
-
-    private fun selectOnlyOneListStyleIfNeed(textStyle: TextStyle) {
-        if (textStyle !in listStyles) return
-        selectedStyles.removeAll { it in listStyles }
-        triggerListStyle(textStyle)
-    }
-
-    private fun triggerListStyle(listSpanStyle: TextStyle) {
-        currentListSpanNumber = 1
-        val currentLineStart = layout.getLineStart(getCurrentCursorLine())
-        if (selectionStart == currentLineStart)
-            text.insert(selectionStart, " ")
-        else text.insert(selectionStart, "\n ")
-
-        listSpanStart = selectionStart - 1
-        text.setSpan(
-            getListSpan(listSpanStyle, "${currentListSpanNumber}.", false),
-            listSpanStart,
-            selectionStart,
-            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
-        )
-        currentListSpanNumber++
-        currentListSpanLine = lineCount
-    }
-
-    private fun handleListSpanTextChange(before: Int, count: Int) {
-        val listSpanStyle = selectedStyles.firstOrNull { it in listStyles } ?: return
-        if (before > count) return
-        if (selectionStart == selectionEnd && currentListSpanLine < lineCount) {
-            currentListSpanLine = lineCount
-            val string = text.toString()
-            // If user hit enter
-            if (string[selectionStart - 1] == '\n') {
-                listSpanStart = selectionStart
-                text.insert(selectionStart, " ")
-                text.setSpan(
-                    getListSpan(listSpanStyle, "${currentListSpanNumber}.", false),
-                    listSpanStart,
-                    listSpanStart + 1,
-                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
-                )
-                currentListSpanNumber++
-            } else {
-                for (listSpan in text.getGivenSpansAt(
-                    span = arrayOf(listSpanStyle),
-                    listSpanStart,
-                    listSpanStart + 1
-                )) {
-                    val number = (listSpan as? OrderedListItemSpan)?.number ?: ""
-                    val isDone = (listSpan as? TaskListSpan)?.isDone ?: false
-                    text.removeSpan(listSpan)
-                    text.setSpan(
-                        getListSpan(listSpanStyle, number, isDone),
-                        listSpanStart,
-                        selectionStart,
-                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
-                    )
-                }
-            }
-        }
-    }
-
-    private fun getListSpan(listSpanStyle: TextStyle, currentNum: String, isDone: Boolean): Any =
-        when (listSpanStyle) {
-            TextStyle.ORDERED_LIST -> OrderedListItemSpan(
-                markwon.configuration().theme(),
-                currentNum
-            )
-
-            TextStyle.TASKS_LIST -> setTaskSpan(listSpanStart, selectionStart, isDone)
-            else -> BulletListItemSpan(markwon.configuration().theme(), 0)
-        }
-
-    fun addLinkSpan(title: String?, link: String) {
-        val newTitle = if (title.isNullOrEmpty()) link else title
-        val cursorStart = selectionStart
-        text.insert(cursorStart, newTitle)
-        text.setSpan(
-            LinkSpan(markwon.configuration().theme(), link, LinkResolverDef()),
-            cursorStart,
-            cursorStart + newTitle.length,
-            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
-        )
-    }
-
-    private fun insertMentionSpan(editable: Editable, name: String, start: Int) {
-        editable.setSpan(
-            MentionSpan(context, name), start - 1, start,
-            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
-        )
-    }
-
-    private fun setTaskSpan(start: Int, end: Int, isDone: Boolean) {
-        val taskSpan = TaskListSpan(
-            markwon.configuration().theme(),
-            TaskListDrawable(taskBoxColor, taskBoxColor, taskBoxMarkColor),
-            isDone
-        )
-        text.setSpan(taskSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
-        text.setSpan(getTaskClickableSpan(taskSpan), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
-    }
-
-    private fun styliseText(start: Int, end: Int) {
-        if (start >= end) return
-        if (text.substring(start, end).isBlank()) return
-        selectedStyles.forEach { textStyle ->
-            val span = when (textStyle) {
-                TextStyle.BOLD -> StrongEmphasisSpan()
-                TextStyle.ITALIC -> EmphasisSpan()
-                TextStyle.STRIKE -> StrikethroughSpan()
-                else -> null
-            }
-            span?.let {
-                if (text.getGivenSpansAt(span = arrayOf(textStyle), start, end).isEmpty())
-                    text.setSpan(it, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
-            }
-        }
-    }
-
-    override fun onSelectionChanged(selStart: Int, selEnd: Int) {
-        super.onSelectionChanged(selStart, selEnd)
-        isSelectionStyling = selStart != selEnd
-        if (selStart <= 0) return
-        if (isDividerSymbol(selStart - 1) && !isSelectionStyling) return
-
-        val spans = mutableSetOf<TextStyle>()
-        val currentLineStart = layout.getLineStart(getCurrentCursorLine())
-        val listsSpans = text.getGivenSpansAt(
-            span = listStyles,
-            start = currentLineStart, end = currentLineStart + 1
-        )
-        listsSpans.forEach {
-            when (it) {
-                is BulletListItemSpan -> spans.add(TextStyle.UNORDERED_LIST)
-                is OrderedListItemSpan -> spans.add(TextStyle.ORDERED_LIST)
-                is TaskListSpan -> spans.add(TextStyle.TASKS_LIST)
-            }
-        }
-        val textStart = if (isSelectionStyling) selStart else selStart - 1
-        val textEnd = if (isSelectionStyling) selEnd else selStart
-        val textSpans = text.getGivenSpansAt(
-            span = textStyles,
-            start = textStart, end = textEnd
-        )
-        textSpans.forEach {
-            when (it) {
-                is StrongEmphasisSpan -> spans.add(TextStyle.BOLD)
-                is EmphasisSpan -> spans.add(TextStyle.ITALIC)
-                is StrikethroughSpan -> spans.add(TextStyle.STRIKE)
-            }
-        }
-        if (spans != selectedStyles) {
-            selectedStyles.clear()
-            selectedStyles.addAll(spans)
-        }
-        onHighlightSpanListener?.invoke(spans.toList())
-    }
-
-    private fun isDividerSymbol(index: Int): Boolean {
-        val char = text.getOrNull(index).toString()
-        return char == " " || char == "\n"
-    }
-
-    private fun getTaskClickableSpan(taskSpan: TaskListSpan) = object : ClickableSpan() {
-        override fun onClick(widget: View) {
-            val spanStart = text.getSpanStart(taskSpan)
-            val spanEnd = text.getSpanEnd(taskSpan)
-            taskSpan.isDone = !taskSpan.isDone
-            if (spanStart >= 0) {
-                text.setSpan(taskSpan, spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
-            }
-        }
-    }
-
-    private fun getCurrentCursorLine(): Int {
-        return if (selectionStart != -1) layout.getLineForOffset(selectionStart) else -1
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/view/MarkdownStyleBar.kt b/app/src/main/java/org/futo/circles/view/MarkdownStyleBar.kt
deleted file mode 100644
index 3af36c28d269f94108e4c1e0c5fe8fe493412e10..0000000000000000000000000000000000000000
--- a/app/src/main/java/org/futo/circles/view/MarkdownStyleBar.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.futo.circles.view
-
-import android.content.Context
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import androidx.constraintlayout.widget.ConstraintLayout
-import org.futo.circles.R
-import org.futo.circles.core.extensions.setIsVisible
-import org.futo.circles.databinding.ViewMarkdownStylebarBinding
-import org.futo.circles.feature.timeline.post.create.PostConfigurationOptionListener
-import org.futo.circles.model.MainStyleBarOption
-import org.futo.circles.model.StyleBarListItem
-import org.futo.circles.feature.timeline.post.markdown.span.TextStyle
-import org.futo.circles.feature.timeline.post.markdown.style_bar.OptionsStyleBarAdapter
-
-class MarkdownStyleBar(
-    context: Context,
-    attrs: AttributeSet? = null
-) : ConstraintLayout(context, attrs) {
-
-    private val binding =
-        ViewMarkdownStylebarBinding.inflate(LayoutInflater.from(context), this)
-
-    private val mainOptions = listOf(
-        StyleBarListItem(MainStyleBarOption.Media.ordinal, R.drawable.ic_image),
-        StyleBarListItem(MainStyleBarOption.Emoji.ordinal, R.drawable.ic_emoji),
-        StyleBarListItem(MainStyleBarOption.Mention.ordinal, R.drawable.ic_mention),
-        StyleBarListItem(MainStyleBarOption.Link.ordinal, R.drawable.ic_link),
-        StyleBarListItem(MainStyleBarOption.TextStyle.ordinal, R.drawable.ic_text)
-    )
-
-    private var textStyleOptions = listOf(
-        StyleBarListItem(TextStyle.BOLD.ordinal, R.drawable.ic_bold),
-        StyleBarListItem(TextStyle.ITALIC.ordinal, R.drawable.ic_italic),
-        StyleBarListItem(TextStyle.STRIKE.ordinal, R.drawable.ic_strikethrough),
-        StyleBarListItem(TextStyle.UNORDERED_LIST.ordinal, R.drawable.ic_bullet_list),
-        StyleBarListItem(TextStyle.ORDERED_LIST.ordinal, R.drawable.ic_number_list),
-        StyleBarListItem(TextStyle.TASKS_LIST.ordinal, R.drawable.ic_check_box)
-    )
-
-    private val mainOptionsAdapter = OptionsStyleBarAdapter(::onMainOptionSelected)
-    private val textStyleOptionsAdapter =
-        OptionsStyleBarAdapter(::onTextStyleSelected).apply { submitList(textStyleOptions) }
-
-    private var postConfigurationListener: PostConfigurationOptionListener? = null
-
-    private var isTextOptionsOpened = false
-
-    init {
-        setupViews()
-    }
-
-    fun setOptionsListener(listener: PostConfigurationOptionListener) {
-        postConfigurationListener = listener
-    }
-
-    fun showMainOptionsList(isMediaAvailable: Boolean) {
-        mainOptionsAdapter.submitList(
-            if (isMediaAvailable) mainOptions
-            else mainOptions.filter { it.id != MainStyleBarOption.Media.ordinal }
-        )
-    }
-
-    fun highlightStyle(textStyles: List<TextStyle>) {
-        textStyleOptions = textStyleOptions.map {
-            it.copy(isSelected = it.id in textStyles.map { it.ordinal })
-        }
-        textStyleOptionsAdapter.submitList(textStyleOptions)
-    }
-
-    private fun setupViews() {
-        setTextOptionsOpened(false)
-        binding.ivCancel.setOnClickListener { setTextOptionsOpened(false) }
-        binding.rvMainOptions.adapter = mainOptionsAdapter
-        binding.rvTextOptions.adapter = textStyleOptionsAdapter
-    }
-
-    private fun setTextOptionsOpened(isOpened: Boolean) {
-        isTextOptionsOpened = isOpened
-        binding.rvMainOptions.setIsVisible(!isTextOptionsOpened)
-        binding.textOptionsGroup.setIsVisible(isTextOptionsOpened)
-    }
-
-    private fun onMainOptionSelected(id: Int) {
-        when (MainStyleBarOption.values()[id]) {
-            MainStyleBarOption.Media -> postConfigurationListener?.onUploadMediaClicked()
-            MainStyleBarOption.Emoji -> postConfigurationListener?.onEmojiClicked()
-            MainStyleBarOption.Mention -> postConfigurationListener?.onMentionClicked()
-            MainStyleBarOption.Link -> postConfigurationListener?.onAddLinkClicked()
-            MainStyleBarOption.TextStyle -> setTextOptionsOpened(true)
-        }
-    }
-
-    private fun onTextStyleSelected(id: Int) {
-        val item = textStyleOptions.firstOrNull { it.id == id } ?: return
-        postConfigurationListener?.onTextStyleSelected(TextStyle.values()[id], !item.isSelected)
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/view/PostLayout.kt b/app/src/main/java/org/futo/circles/view/PostLayout.kt
index 40f74e3a9b9fef7ad19afddb08b2ab951f4df7de..808ffc9dd615465989ee663fb6a9b71ca99621a2 100644
--- a/app/src/main/java/org/futo/circles/view/PostLayout.kt
+++ b/app/src/main/java/org/futo/circles/view/PostLayout.kt
@@ -17,7 +17,7 @@ import org.futo.circles.core.model.Post
 import org.futo.circles.core.model.PostContent
 import org.futo.circles.core.model.TextContent
 import org.futo.circles.databinding.LayoutPostBinding
-import org.futo.circles.feature.timeline.post.markdown.MarkdownParser
+import org.futo.circles.core.feature.markdown.MarkdownParser
 import org.futo.circles.model.PostItemPayload
 import org.matrix.android.sdk.api.session.room.send.SendState
 
@@ -114,10 +114,10 @@ class PostLayout(
     private fun setMentionBorder(content: PostContent) {
         val hasMention = when (content) {
             is MediaContent -> content.caption?.let {
-                MarkdownParser.hasCurrentUserMention(it)
+                MarkdownParser.hasCurrentUserMention(it.toString())
             } ?: false
 
-            is TextContent -> MarkdownParser.hasCurrentUserMention(content.message)
+            is TextContent -> MarkdownParser.hasCurrentUserMention(content.message.toString())
             is PollContent -> false
         }
         if (hasMention) binding.lCard.setBackgroundResource(R.drawable.bg_mention_highlight)
diff --git a/app/src/main/java/org/futo/circles/view/PreviewPostView.kt b/app/src/main/java/org/futo/circles/view/PreviewPostView.kt
index 06264d5c6ee84a872fb651b9d734fc366dbdce93..f18fd33c2bf0edd88bd4c59695fe847706db7ccb 100644
--- a/app/src/main/java/org/futo/circles/view/PreviewPostView.kt
+++ b/app/src/main/java/org/futo/circles/view/PreviewPostView.kt
@@ -2,39 +2,56 @@ package org.futo.circles.view
 
 
 import android.content.Context
+import android.graphics.drawable.ColorDrawable
 import android.net.Uri
+import android.text.Editable
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.view.inputmethod.InputMethodManager
-import android.widget.TextView
+import android.widget.LinearLayout
+import androidx.annotation.DrawableRes
+import androidx.cardview.widget.CardView
 import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
 import androidx.core.view.updateLayoutParams
 import androidx.core.widget.doAfterTextChanged
-import org.futo.circles.core.extensions.loadEncryptedIntoWithAspect
+import io.element.android.wysiwyg.EditorEditText
+import io.element.android.wysiwyg.display.LinkDisplayHandler
+import io.element.android.wysiwyg.display.TextDisplay
+import io.element.android.wysiwyg.view.models.InlineFormat
+import org.futo.circles.R
 import org.futo.circles.core.extensions.loadEncryptedThumbOrFullIntoWithAspect
 import org.futo.circles.core.extensions.loadImage
 import org.futo.circles.core.extensions.notEmptyDisplayName
 import org.futo.circles.core.extensions.setIsVisible
+import org.futo.circles.core.feature.autocomplete.Autocomplete
+import org.futo.circles.core.feature.autocomplete.AutocompleteCallback
+import org.futo.circles.core.feature.autocomplete.CharPolicy
+import org.futo.circles.core.feature.markdown.mentions.MentionsLinkDisplayHandler
+import org.futo.circles.core.feature.markdown.mentions.MentionsPresenter
+import org.futo.circles.core.feature.markdown.span.MentionSpan
 import org.futo.circles.core.model.MediaContent
 import org.futo.circles.core.model.MediaType
+import org.futo.circles.core.model.UserListItem
 import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.utils.ImageUtils
 import org.futo.circles.core.utils.VideoUtils
 import org.futo.circles.core.utils.VideoUtils.getVideoDuration
 import org.futo.circles.core.utils.VideoUtils.getVideoDurationString
 import org.futo.circles.databinding.ViewPreviewPostBinding
+import org.futo.circles.databinding.ViewRichTextMenuButtonBinding
 import org.futo.circles.extensions.convertDpToPixel
-import org.futo.circles.feature.timeline.post.markdown.MarkdownParser
-import org.futo.circles.feature.timeline.post.markdown.span.TextStyle
+import org.futo.circles.feature.timeline.post.create.PreviewPostListener
 import org.futo.circles.model.CreatePostContent
 import org.futo.circles.model.MediaPostContent
 import org.futo.circles.model.TextPostContent
+import org.matrix.android.sdk.api.MatrixPatterns
 import org.matrix.android.sdk.api.session.getUser
+import org.matrix.android.sdk.api.session.permalinks.PermalinkService.Companion.MATRIX_TO_URL_BASE
 import org.matrix.android.sdk.api.session.user.model.User
-
-interface PreviewPostListener {
-    fun onPostContentAvailable(isAvailable: Boolean)
-}
+import uniffi.wysiwyg_composer.ActionState
+import uniffi.wysiwyg_composer.ComposerAction
 
 class PreviewPostView(
     context: Context,
@@ -59,47 +76,62 @@ class PreviewPostView(
             )
         }
         setOnClickListener { requestFocusOnText() }
-        binding.etTextPost.doAfterTextChanged {
-            listener?.onPostContentAvailable(it?.toString()?.isNotBlank() == true)
-        }
+
         binding.ivRemoveImage.setOnClickListener {
             setTextContent()
         }
+
         updateContentView()
+
+        binding.btnSend.setOnClickListener { listener?.onSendClicked(getPostContent()) }
+        binding.ivCancel.setOnClickListener { setTextEditorMode(false) }
+
+        with(binding.etTextPost) {
+            doAfterTextChanged {
+                binding.btnSend.isEnabled = it?.toString()?.isNotBlank() == true
+            }
+            linkDisplayHandler = MentionsLinkDisplayHandler(context)
+        }
+        setupRichTextMenu()
+    }
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        binding.etTextPost.actionStatesChangedListener =
+            EditorEditText.OnActionStatesChangedListener { state ->
+                for (action in state.keys) {
+                    updateMenuStateFor(action, state)
+                }
+            }
+    }
+
+    override fun onDetachedFromWindow() {
+        binding.etTextPost.setMarkdown("")
+        super.onDetachedFromWindow()
     }
 
     fun setup(
         previewPostListener: PreviewPostListener,
-        onHighlightTextStyle: (List<TextStyle>) -> Unit,
-        roomId: String
+        roomId: String,
+        isEdit: Boolean
     ) {
+        setTextEditorMode(false)
         listener = previewPostListener
-        binding.etTextPost.setHighlightSelectedSpanListener(onHighlightTextStyle)
-        binding.etTextPost.initMentionsAutocomplete(roomId)
+        setupMainMenu(!isEdit)
+        initMentionsAutocomplete(roomId)
     }
 
     fun setText(message: String) {
-        binding.etTextPost.setText(
-            MarkdownParser.markwonBuilder(context).toMarkdown(message),
-            TextView.BufferType.SPANNABLE
-        )
+        binding.etTextPost.setFormattedMarkdown(message)
         setTextContent()
     }
 
-    fun setTextStyle(style: TextStyle, isSelected: Boolean) {
-        binding.etTextPost.triggerStyle(style, isSelected)
-    }
-
     fun insertEmoji(unicode: String) {
-        binding.etTextPost.insertText(unicode)
-    }
-
-    fun insertMention() {
-        binding.etTextPost.insertMentionMark()
+        binding.etTextPost.append(unicode)
     }
 
     fun insertLink(title: String?, link: String) {
-        binding.etTextPost.addLinkSpan(title, link)
+        binding.etTextPost.insertLink(link, title ?: link)
     }
 
     fun setMediaFromExistingPost(mediaContent: MediaContent) {
@@ -116,7 +148,7 @@ class PreviewPostView(
         if (isVideo)
             binding.lMediaContent.tvDuration.text = mediaContent.mediaFileData.duration
 
-        listener?.onPostContentAvailable(true)
+        binding.btnSend.isEnabled = true
     }
 
 
@@ -131,12 +163,12 @@ class PreviewPostView(
             binding.lMediaContent.tvDuration.text =
                 getVideoDurationString(getVideoDuration(context, contentUri))
 
-        listener?.onPostContentAvailable(true)
+        binding.btnSend.isEnabled = true
     }
 
-    fun getPostContent() = (postContent as? MediaPostContent)?.copy(
-        caption = binding.etTextPost.getTextWithMarkdown().trim().takeIf { it.isNotEmpty() }
-    ) ?: TextPostContent(binding.etTextPost.getTextWithMarkdown().trim())
+    private fun getPostContent() = (postContent as? MediaPostContent)?.copy(
+        caption = binding.etTextPost.getFormattedMarkdown().takeIf { it.isNotEmpty() }
+    ) ?: TextPostContent(binding.etTextPost.getFormattedMarkdown())
 
     private fun updateContentView() {
         val isTextContent = postContent is TextPostContent || postContent == null
@@ -153,7 +185,7 @@ class PreviewPostView(
     private fun setTextContent() {
         postContent = null
         updateContentView()
-        listener?.onPostContentAvailable(binding.etTextPost.text.toString().isNotBlank())
+        binding.btnSend.isEnabled = false
     }
 
     private fun loadMediaCover(uri: Uri, mediaType: MediaType) {
@@ -183,10 +215,38 @@ class PreviewPostView(
         mediaContent.loadEncryptedThumbOrFullIntoWithAspect(image)
     }
 
+    private fun initMentionsAutocomplete(roomId: String) {
+        Autocomplete.on<UserListItem>(binding.etTextPost)
+            .with(CharPolicy('@', true))
+            .with(MentionsPresenter(context, roomId))
+            .with(
+                ColorDrawable(
+                    ContextCompat.getColor(
+                        context,
+                        org.futo.circles.core.R.color.post_card_background_color
+                    )
+                )
+            )
+            .with(object : AutocompleteCallback<UserListItem> {
+                override fun onPopupItemClicked(editable: Editable, item: UserListItem): Boolean {
+                    binding.etTextPost.setLinkSuggestion(
+                        MATRIX_TO_URL_BASE + item.id,
+                        "@${item.user.name}@"
+                    )
+                    return true
+                }
+
+                override fun onPopupVisibilityChanged(shown: Boolean) {
+                }
+            })
+            .with(6f)
+            .build()
+    }
+
     private fun requestFocusOnText() {
         binding.etTextPost.post {
             requestFocus()
-            binding.etTextPost.setSelection(binding.etTextPost.text.length)
+            binding.etTextPost.text?.let { binding.etTextPost.setSelection(it.length) }
             showKeyboard()
         }
     }
@@ -201,4 +261,119 @@ class PreviewPostView(
         val session = MatrixSessionProvider.currentSession
         return session?.myUserId?.let { session.getUser(it) }
     }
+
+    private fun setupMainMenu(isMediaAvailable: Boolean) {
+        if (isMediaAvailable) {
+            addMenuItem(binding.lMainMenu, R.drawable.ic_image) {
+                listener?.onUploadMediaClicked()
+            }
+        }
+        addMenuItem(binding.lMainMenu, R.drawable.ic_emoji) {
+            listener?.onEmojiClicked()
+        }
+        addMenuItem(binding.lMainMenu, org.futo.circles.core.R.drawable.ic_mention) {
+            binding.etTextPost.append("@")
+        }
+        addMenuItem(binding.lMainMenu, R.drawable.ic_link) {
+            listener?.onAddLinkClicked()
+        }
+        addMenuItem(binding.lMainMenu, R.drawable.ic_text) {
+            setTextEditorMode(true)
+        }
+    }
+
+    private fun setTextEditorMode(isEnabled: Boolean) {
+        binding.ivCancel.setIsVisible(isEnabled)
+        binding.lTextMenu.setIsVisible(isEnabled)
+        binding.lMainMenu.setIsVisible(!isEnabled)
+    }
+
+    private fun setupRichTextMenu() {
+        addMenuItem(
+            binding.lTextMenu,
+            R.drawable.ic_bold,
+            ComposerAction.BOLD
+        ) {
+            binding.etTextPost.toggleInlineFormat(InlineFormat.Bold)
+        }
+        addMenuItem(
+            binding.lTextMenu,
+            R.drawable.ic_italic,
+            ComposerAction.ITALIC
+        ) {
+            binding.etTextPost.toggleInlineFormat(InlineFormat.Italic)
+        }
+        addMenuItem(
+            binding.lTextMenu,
+            R.drawable.ic_strikethrough,
+            ComposerAction.STRIKE_THROUGH
+        ) {
+            binding.etTextPost.toggleInlineFormat(InlineFormat.StrikeThrough)
+        }
+        addMenuItem(
+            binding.lTextMenu,
+            R.drawable.ic_bullet_list,
+            ComposerAction.UNORDERED_LIST
+        ) {
+            binding.etTextPost.toggleList(ordered = false)
+        }
+        addMenuItem(
+            binding.lTextMenu,
+            R.drawable.ic_number_list,
+            ComposerAction.ORDERED_LIST
+        ) {
+            binding.etTextPost.toggleList(ordered = true)
+        }
+        addMenuItem(
+            binding.lTextMenu,
+            R.drawable.ic_composer_quote,
+            ComposerAction.QUOTE
+        ) {
+            binding.etTextPost.toggleQuote()
+        }
+    }
+
+    private fun addMenuItem(
+        container: LinearLayout,
+        @DrawableRes iconId: Int,
+        action: ComposerAction? = null,
+        onClick: () -> Unit
+    ) {
+        val inflater = LayoutInflater.from(context)
+        val item = ViewRichTextMenuButtonBinding.inflate(inflater, container, true)
+        action?.let {
+            item.root.tag = it
+        }
+        with(item.root) {
+            item.ivIcon.setImageResource(iconId)
+            setOnClickListener { onClick() }
+        }
+    }
+
+    private fun updateMenuStateFor(
+        action: ComposerAction,
+        menuState: Map<ComposerAction, ActionState>
+    ) {
+        val button = findViewWithTag<CardView>(action) ?: return
+        val stateForAction = menuState[action]
+        button.isEnabled = stateForAction != ActionState.DISABLED
+        button.isSelected = stateForAction == ActionState.REVERSED
+
+        if (action == ComposerAction.INDENT || action == ComposerAction.UNINDENT) {
+            val indentationButtonIsVisible =
+                menuState[ComposerAction.ORDERED_LIST] == ActionState.REVERSED ||
+                        menuState[ComposerAction.UNORDERED_LIST] == ActionState.REVERSED
+            button.isVisible = indentationButtonIsVisible
+        }
+    }
+
+    private fun EditorEditText.getFormattedMarkdown(): String = getMarkdown()
+        .replace("<br><br>", "")
+        .replace("\\", "")
+
+    private fun EditorEditText.setFormattedMarkdown(message: String) {
+        val formattedMessage = message.replace("\\r\\r|\\n\\n".toRegex(), "<br><br>")
+        setMarkdown(formattedMessage)
+    }
+
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/view/SimpleTextWatcher.kt b/app/src/main/java/org/futo/circles/view/SimpleTextWatcher.kt
new file mode 100644
index 0000000000000000000000000000000000000000..d471738bd4a6fecc6bf8f737e20858a25a5a0e78
--- /dev/null
+++ b/app/src/main/java/org/futo/circles/view/SimpleTextWatcher.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.futo.circles.view
+
+import android.text.Editable
+import android.text.TextWatcher
+
+/**
+ * TextWatcher with default no op implementation.
+ */
+open class SimpleTextWatcher : TextWatcher {
+    override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+        // No op
+    }
+
+    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+        // No op
+    }
+
+    override fun afterTextChanged(s: Editable) {
+        // No op
+    }
+}
diff --git a/app/src/main/java/org/futo/circles/view/UriContentListener.kt b/app/src/main/java/org/futo/circles/view/UriContentListener.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3cc04857fddff947b9ee079e09e7455eb073e60d
--- /dev/null
+++ b/app/src/main/java/org/futo/circles/view/UriContentListener.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.futo.circles.view
+
+import android.content.ClipData
+import android.net.Uri
+import android.view.View
+import androidx.core.view.ContentInfoCompat
+import androidx.core.view.OnReceiveContentListener
+
+class UriContentListener(
+        private val onContent: (uri: Uri) -> Unit
+) : OnReceiveContentListener {
+    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
+        val split = payload.partition { item -> item.uri != null }
+        val uriContent = split.first
+        val remaining = split.second
+
+        if (uriContent != null) {
+            val clip: ClipData = uriContent.clip
+            for (i in 0 until clip.itemCount) {
+                val uri = clip.getItemAt(i).uri
+                // ... app-specific logic to handle the URI ...
+                onContent(uri)
+            }
+        }
+        // Return anything that we didn't handle ourselves. This preserves the default platform
+        // behavior for text and anything else for which we are not implementing custom handling.
+        return remaining
+    }
+}
diff --git a/app/src/main/res/drawable/bg_code_block.xml b/app/src/main/res/drawable/bg_code_block.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ef7227f6842b28bc38823dbcb26415fed7bde875
--- /dev/null
+++ b/app/src/main/res/drawable/bg_code_block.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#F4F6FA" />
+    <stroke
+        android:width="@dimen/code_block_border_width"
+        android:color="#E3E8F0" />
+    <corners android:radius="@dimen/code_block_border_radius" />
+</shape>
diff --git a/app/src/main/res/drawable/bg_rich_text_menu_button.xml b/app/src/main/res/drawable/bg_rich_text_menu_button.xml
new file mode 100644
index 0000000000000000000000000000000000000000..03af9b25b9240b1888d8403bb7917adcfcf4efe9
--- /dev/null
+++ b/app/src/main/res/drawable/bg_rich_text_menu_button.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/blue" android:state_selected="true" />
+    <item android:color="@color/red" android:state_enabled="false" />
+    <item android:color="@color/post_card_background_color" />
+</selector>
diff --git a/app/src/main/res/drawable/ic_composer_bold.xml b/app/src/main/res/drawable/ic_composer_bold.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d2e26cf1e59a3105483837beaadd6acbfeadf1cb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_bold.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <path
+        android:fillColor="@color/blue"
+        android:fillType="evenOdd"
+        android:pathData="M16,14.5C16,13.672 16.672,13 17.5,13H22.288C25.139,13 27.25,15.466 27.25,18.25C27.25,19.38 26.902,20.458 26.298,21.34C27.765,22.268 28.75,23.882 28.75,25.75C28.75,28.689 26.311,31 23.393,31H17.5C16.672,31 16,30.328 16,29.5V14.5ZM19,16V20.5H22.288C23.261,20.5 24.25,19.608 24.25,18.25C24.25,16.892 23.261,16 22.288,16H19ZM19,23.5V28H23.393C24.735,28 25.75,26.953 25.75,25.75C25.75,24.547 24.735,23.5 23.393,23.5H19Z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_bullet_list.xml b/app/src/main/res/drawable/ic_composer_bullet_list.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d372209ced344182d558b43d73f89df20eaa9307
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_bullet_list.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <group>
+        <clip-path android:pathData="M10,10h24v24h-24z" />
+        <path
+            android:fillColor="@color/blue"
+            android:pathData="M14,20.5C13.17,20.5 12.5,21.17 12.5,22C12.5,22.83 13.17,23.5 14,23.5C14.83,23.5 15.5,22.83 15.5,22C15.5,21.17 14.83,20.5 14,20.5ZM14,14.5C13.17,14.5 12.5,15.17 12.5,16C12.5,16.83 13.17,17.5 14,17.5C14.83,17.5 15.5,16.83 15.5,16C15.5,15.17 14.83,14.5 14,14.5ZM14,26.5C13.17,26.5 12.5,27.18 12.5,28C12.5,28.82 13.18,29.5 14,29.5C14.82,29.5 15.5,28.82 15.5,28C15.5,27.18 14.83,26.5 14,26.5ZM18,29H30C30.55,29 31,28.55 31,28C31,27.45 30.55,27 30,27H18C17.45,27 17,27.45 17,28C17,28.55 17.45,29 18,29ZM18,23H30C30.55,23 31,22.55 31,22C31,21.45 30.55,21 30,21H18C17.45,21 17,21.45 17,22C17,22.55 17.45,23 18,23ZM17,16C17,16.55 17.45,17 18,17H30C30.55,17 31,16.55 31,16C31,15.45 30.55,15 30,15H18C17.45,15 17,15.45 17,16Z" />
+    </group>
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_code_block.xml b/app/src/main/res/drawable/ic_composer_code_block.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aaa3dbe78da6559eef7d6eb4c6c35e1dd7c9b32b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_code_block.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:tint="@color/menu_icon_color"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <path
+        android:fillColor="@color/white"
+        android:pathData="m18,22c0.7,-0.72 1.4,-1.4 2.1,-2.1 0.68,-0.98 -0.93,-1.9 -1.5,-0.96 -0.87,0.88 -1.8,1.7 -2.6,2.6 -0.45,0.67 0.27,1.2 0.7,1.6 0.75,0.74 1.5,1.5 2.2,2.2 0.98,0.68 1.9,-0.93 0.96,-1.5l-1.9,-1.9zM26.6,22c-0.71,0.72 -1.5,1.4 -2.1,2.2 -0.68,0.98 0.93,1.9 1.5,0.96 0.88,-0.89 1.8,-1.8 2.6,-2.7 0.45,-0.67 -0.27,-1.2 -0.7,-1.6 -0.75,-0.74 -1.5,-1.5 -2.2,-2.2 -0.99,-0.66 -2,0.94 -0.96,1.5l1.9,1.9zM13.6,32c-1.1,0.021 -1.9,-1 -1.7,-2.1 0.005,-5.7 -0.011,-11 0.008,-17 0.088,-1 1.1,-1.7 2.1,-1.5 5.6,0.005 11,-0.011 17,0.008 1,0.088 1.7,1.1 1.5,2.1 -0.005,5.6 0.011,11 -0.008,17 -0.088,1 -1.1,1.7 -2.1,1.5h-17zM13.6,30.3h17v-17h-17v17z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_indent.xml b/app/src/main/res/drawable/ic_composer_indent.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cbef736659cf55c7868cf0ddad15fd7a0acf24f8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_indent.xml
@@ -0,0 +1,13 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:tint="@color/menu_icon_color"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <group>
+        <clip-path android:pathData="M10,10h24v24h-24z" />
+        <path
+            android:fillColor="@color/blue"
+            android:pathData="M14,31H30C30.55,31 31,30.55 31,30C31,29.45 30.55,29 30,29H14C13.45,29 13,29.45 13,30C13,30.55 13.45,31 14,31ZM13,19.21V24.8C13,25.25 13.54,25.47 13.85,25.15L16.64,22.36C16.84,22.16 16.84,21.85 16.64,21.65L13.85,18.85C13.54,18.54 13,18.76 13,19.21ZM22,27H30C30.55,27 31,26.55 31,26C31,25.45 30.55,25 30,25H22C21.45,25 21,25.45 21,26C21,26.55 21.45,27 22,27ZM13,14C13,14.55 13.45,15 14,15H30C30.55,15 31,14.55 31,14C31,13.45 30.55,13 30,13H14C13.45,13 13,13.45 13,14ZM22,19H30C30.55,19 31,18.55 31,18C31,17.45 30.55,17 30,17H22C21.45,17 21,17.45 21,18C21,18.55 21.45,19 22,19ZM22,23H30C30.55,23 31,22.55 31,22C31,21.45 30.55,21 30,21H22C21.45,21 21,21.45 21,22C21,22.55 21.45,23 22,23Z" />
+    </group>
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_inline_code.xml b/app/src/main/res/drawable/ic_composer_inline_code.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bc054e639a79590165c84994b991961df2579493
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_inline_code.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <path
+        android:fillColor="@color/blue"
+        android:pathData="M24.958,15.621C25.117,15.092 24.816,14.534 24.287,14.375C23.758,14.217 23.201,14.517 23.042,15.046L19.042,28.379C18.883,28.908 19.184,29.466 19.713,29.624C20.242,29.783 20.799,29.483 20.958,28.954L24.958,15.621Z" />
+    <path
+        android:fillColor="@color/blue"
+        android:pathData="M15.974,17.232C15.549,16.878 14.919,16.936 14.565,17.36L11.232,21.36C10.923,21.731 10.923,22.269 11.232,22.64L14.565,26.64C14.919,27.065 15.549,27.122 15.974,26.768C16.398,26.415 16.455,25.784 16.102,25.36L13.302,22L16.102,18.64C16.455,18.216 16.398,17.585 15.974,17.232Z" />
+    <path
+        android:fillColor="@color/blue"
+        android:pathData="M28.027,17.232C28.451,16.878 29.081,16.936 29.435,17.36L32.768,21.36C33.077,21.731 33.077,22.269 32.768,22.64L29.435,26.64C29.081,27.065 28.451,27.122 28.027,26.768C27.602,26.415 27.545,25.784 27.898,25.36L30.698,22L27.898,18.64C27.545,18.216 27.602,17.585 28.027,17.232Z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_italic.xml b/app/src/main/res/drawable/ic_composer_italic.xml
new file mode 100644
index 0000000000000000000000000000000000000000..15c40a206504405f3a9bb5fbb2056e3da01512e2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_italic.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <path
+        android:pathData="M22.619,14.999L19.747,29.005H17.2C16.758,29.005 16.4,29.363 16.4,29.805C16.4,30.247 16.758,30.605 17.2,30.605H20.389C20.397,30.605 20.405,30.605 20.412,30.605H23.6C24.042,30.605 24.4,30.247 24.4,29.805C24.4,29.363 24.042,29.005 23.6,29.005H21.381L24.253,14.999H26.8C27.242,14.999 27.6,14.64 27.6,14.199C27.6,13.757 27.242,13.399 26.8,13.399H23.615C23.604,13.398 23.594,13.398 23.583,13.399H20.4C19.958,13.399 19.6,13.757 19.6,14.199C19.6,14.64 19.958,14.999 20.4,14.999H22.619Z"
+        android:fillColor="@color/blue"
+        android:fillType="evenOdd" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_link.xml b/app/src/main/res/drawable/ic_composer_link.xml
new file mode 100644
index 0000000000000000000000000000000000000000..be76286af10f63eb0c7dac33ec22a30781103e52
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_link.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M22.566,16.151L23.101,15.616C24.577,14.14 26.956,14.126 28.415,15.585C29.874,17.044 29.86,19.423 28.383,20.899L25.844,23.438C24.368,24.915 21.989,24.929 20.53,23.47M21.434,27.849L20.899,28.383C19.423,29.86 17.044,29.874 15.585,28.415C14.126,26.956 14.14,24.577 15.616,23.101L18.156,20.562C19.632,19.086 22.011,19.071 23.47,20.53"
+        android:strokeWidth="1.5"
+        android:strokeColor="@color/blue"
+        android:strokeLineCap="round" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_numbered_list.xml b/app/src/main/res/drawable/ic_composer_numbered_list.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5690e2de91efcec7eb129bfcf564f3139882153d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_numbered_list.xml
@@ -0,0 +1,24 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <path
+        android:pathData="m14.5,20h-2c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5h1.3l-1.68,1.96C12.04,23.05 12,23.17 12,23.28v0.22c0,0.28 0.22,0.5 0.5,0.5h2C14.78,24 15,23.78 15,23.5 15,23.22 14.78,23 14.5,23h-1.3l1.68,-1.96C14.96,20.95 15,20.83 15,20.72V20.5C15,20.22 14.78,20 14.5,20Z"
+        android:fillColor="@color/blue" />
+    <path
+        android:pathData="M12.5,15H13v2.5c0,0.28 0.22,0.5 0.5,0.5 0.28,0 0.5,-0.22 0.5,-0.5v-3C14,14.22 13.78,14 13.5,14h-1c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5z"
+        android:fillColor="@color/blue" />
+    <path
+        android:pathData="m14.5,26h-2c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5H14v0.5h-0.5c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5H14V29h-1.5c-0.28,0 -0.5,0.22 -0.5,0.5 0,0.28 0.22,0.5 0.5,0.5h2c0.28,0 0.5,-0.22 0.5,-0.5v-3C15,26.22 14.78,26 14.5,26Z"
+        android:fillColor="@color/blue" />
+    <path
+        android:pathData="M30,21H18c-0.55,0 -1,0.45 -1,1 0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1z"
+        android:fillColor="@color/blue" />
+    <path
+        android:pathData="M30,27H18c-0.55,0 -1,0.45 -1,1 0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1z"
+        android:fillColor="@color/blue" />
+    <path
+        android:pathData="m18,17h12c0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1H18c-0.55,0 -1,0.45 -1,1 0,0.55 0.45,1 1,1z"
+        android:fillColor="@color/blue" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_quote.xml b/app/src/main/res/drawable/ic_composer_quote.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f0b222fac6acbd29b20ddadf4acc4c439dc05a51
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_quote.xml
@@ -0,0 +1,19 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="36dp"
+    android:height="44dp"
+    android:tint="@color/menu_icon_color"
+    android:viewportWidth="36"
+    android:viewportHeight="44">
+    <path
+        android:fillColor="@color/blue"
+        android:pathData="M14.719,14.34C14.813,13.698 14.353,13.104 13.691,13.012C13.028,12.92 12.415,13.366 12.32,14.008L11.512,19.486C11.418,20.128 11.878,20.723 12.54,20.814C13.203,20.906 13.816,20.46 13.911,19.818L14.719,14.34Z" />
+    <path
+        android:fillColor="@color/blue"
+        android:pathData="M26.834,24.514C26.928,23.872 26.468,23.277 25.806,23.186C25.143,23.094 24.53,23.54 24.435,24.182L23.628,29.66C23.533,30.302 23.993,30.896 24.656,30.988C25.318,31.08 25.932,30.634 26.026,29.992L26.834,24.514Z" />
+    <path
+        android:fillColor="@color/blue"
+        android:pathData="M19.318,13.009C19.983,13.086 20.456,13.671 20.376,14.315L20.354,14.49C20.34,14.602 20.319,14.763 20.293,14.961C20.242,15.358 20.17,15.902 20.088,16.496C19.927,17.667 19.72,19.075 19.553,19.882C19.422,20.518 18.784,20.931 18.128,20.803C17.472,20.676 17.046,20.058 17.177,19.422C17.326,18.701 17.523,17.37 17.687,16.185C17.767,15.599 17.838,15.061 17.889,14.669C17.915,14.473 17.935,14.314 17.949,14.204L17.97,14.034C18.051,13.39 18.654,12.931 19.318,13.009Z" />
+    <path
+        android:fillColor="@color/blue"
+        android:pathData="M32.488,24.514C32.582,23.872 32.122,23.277 31.46,23.186C30.797,23.094 30.184,23.54 30.089,24.182L29.281,29.66C29.187,30.302 29.647,30.896 30.309,30.988C30.972,31.08 31.585,30.634 31.68,29.992L32.488,24.514Z" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_strikethrough.xml b/app/src/main/res/drawable/ic_composer_strikethrough.xml
new file mode 100644
index 0000000000000000000000000000000000000000..593cd3aca18017d5ffca71a20b2905dc443def31
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_strikethrough.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <path
+        android:pathData="M24.897,17.154C24.235,15.821 22.876,15.21 21.374,15.372C19.05,15.622 18.44,17.423 18.722,18.592C19.032,19.872 20.046,20.37 21.839,20.826H29.92C30.517,20.826 31,21.351 31,22C31,22.648 30.517,23.174 29.92,23.174H14.08C13.483,23.174 13,22.648 13,22C13,21.351 13.483,20.826 14.08,20.826H17.355C17.041,20.377 16.791,19.839 16.633,19.189C16.003,16.581 17.554,13.424 21.16,13.036C23.285,12.807 25.615,13.661 26.798,16.038C27.081,16.608 26.886,17.32 26.361,17.629C25.836,17.937 25.181,17.725 24.897,17.154Z"
+        android:fillColor="@color/blue" />
+    <path
+        android:pathData="M25.427,25.13H27.67C27.888,26.306 27.721,27.56 27.05,28.632C26.114,30.125 24.37,31 21.985,31C18.076,31 16.279,28.584 15.912,26.986C15.768,26.357 16.12,25.72 16.698,25.563C17.277,25.406 17.863,25.788 18.008,26.417C18.119,26.902 19.002,28.652 21.985,28.652C23.907,28.652 24.854,27.965 25.264,27.31C25.642,26.707 25.708,25.909 25.427,25.13Z"
+        android:fillColor="@color/blue" />
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_underlined.xml b/app/src/main/res/drawable/ic_composer_underlined.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c0b515adff45070dd208c65ef8ee2ebda6bfe451
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_underlined.xml
@@ -0,0 +1,13 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:tint="@color/menu_icon_color"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <group>
+        <clip-path android:pathData="M10,10h24v24h-24z" />
+        <path
+            android:fillColor="@color/blue"
+            android:pathData="M22.79,26.95C25.82,26.56 28,23.84 28,20.79V14.25C28,13.56 27.44,13 26.75,13C26.06,13 25.5,13.56 25.5,14.25V20.9C25.5,22.57 24.37,24.09 22.73,24.42C20.48,24.89 18.5,23.17 18.5,21V14.25C18.5,13.56 17.94,13 17.25,13C16.56,13 16,13.56 16,14.25V21C16,24.57 19.13,27.42 22.79,26.95ZM15,30C15,30.55 15.45,31 16,31H28C28.55,31 29,30.55 29,30C29,29.45 28.55,29 28,29H16C15.45,29 15,29.45 15,30Z" />
+    </group>
+</vector>
diff --git a/app/src/main/res/drawable/ic_composer_unindent.xml b/app/src/main/res/drawable/ic_composer_unindent.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a4a7fc69a4890a0e380e051ffe4876d5125672b1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_composer_unindent.xml
@@ -0,0 +1,13 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:tint="@color/menu_icon_color"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+    <group>
+        <clip-path android:pathData="M10,10h24v24h-24z" />
+        <path
+            android:fillColor="@color/blue"
+            android:pathData="M22,27H30C30.55,27 31,26.55 31,26C31,25.45 30.55,25 30,25H22C21.45,25 21,25.45 21,26C21,26.55 21.45,27 22,27ZM13.35,22.35L16.14,25.14C16.46,25.46 17,25.24 17,24.79V19.21C17,18.76 16.46,18.54 16.15,18.86L13.36,21.65C13.16,21.84 13.16,22.16 13.35,22.35ZM14,31H30C30.55,31 31,30.55 31,30C31,29.45 30.55,29 30,29H14C13.45,29 13,29.45 13,30C13,30.55 13.45,31 14,31ZM13,14C13,14.55 13.45,15 14,15H30C30.55,15 31,14.55 31,14C31,13.45 30.55,13 30,13H14C13.45,13 13,13.45 13,14ZM22,19H30C30.55,19 31,18.55 31,18C31,17.45 30.55,17 30,17H22C21.45,17 21,17.45 21,18C21,18.55 21.45,19 22,19ZM22,23H30C30.55,23 31,22.55 31,22C31,21.45 30.55,21 30,21H22C21.45,21 21,21.45 21,22C21,22.55 21.45,23 22,23Z" />
+    </group>
+</vector>
diff --git a/app/src/main/res/layout/dialog_fragment_create_post.xml b/app/src/main/res/layout/dialog_fragment_create_post.xml
index dd15dfc9bcbb3e671431bab5cd8d656c40a1d6f3..ac9ce83e80201a992489b57dc0f8e32cbc3ba6c5 100644
--- a/app/src/main/res/layout/dialog_fragment_create_post.xml
+++ b/app/src/main/res/layout/dialog_fragment_create_post.xml
@@ -40,38 +40,11 @@
             android:id="@+id/vPostPreview"
             android:layout_width="match_parent"
             android:layout_height="0dp"
-            app:layout_constraintBottom_toTopOf="@id/btnSend"
+            app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toTopOf="parent" />
 
-        <com.google.android.material.button.MaterialButton
-            android:id="@+id/btnSend"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:layout_marginEnd="8dp"
-            android:layout_marginBottom="8dp"
-            android:background="?selectableItemBackgroundBorderless"
-            android:enabled="false"
-            android:focusable="true"
-            android:minWidth="0dp"
-            android:minHeight="0dp"
-            android:padding="0dp"
-            app:icon="@drawable/ic_send"
-            app:iconGravity="end"
-            app:iconSize="40dp"
-            app:iconTint="@color/send_ic_state_color"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent" />
-
-        <org.futo.circles.view.MarkdownStyleBar
-            android:id="@+id/vPostOptions"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            app:layout_constraintBottom_toBottomOf="@id/btnSend"
-            app:layout_constraintEnd_toStartOf="@id/btnSend"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="@id/btnSend" />
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
diff --git a/app/src/main/res/layout/view_markdown_stylebar.xml b/app/src/main/res/layout/view_markdown_stylebar.xml
deleted file mode 100644
index f152df049e022e44cd5f7a8f89bc1f52b149551d..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/view_markdown_stylebar.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/rvMainOptions"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:paddingStart="8dp"
-        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        tools:ignore="RtlSymmetry" />
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/rvTextOptions"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@id/ivCancel"
-        app:layout_constraintTop_toTopOf="parent" />
-
-
-    <com.google.android.material.imageview.ShapeableImageView
-        android:id="@+id/ivCancel"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:background="@color/close_background"
-        android:clickable="true"
-        android:focusable="true"
-        android:padding="8dp"
-        android:src="@drawable/ic_close"
-        android:tint="@color/white"
-        app:layout_constraintBottom_toBottomOf="@id/rvTextOptions"
-        app:layout_constraintDimensionRatio="1:1"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="@id/rvTextOptions"
-        app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.CornerSize50Percent" />
-
-
-    <androidx.constraintlayout.widget.Group
-        android:id="@+id/textOptionsGroup"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:visibility="gone"
-        app:constraint_referenced_ids="ivCancel, rvTextOptions" />
-
-</merge>
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_preview_post.xml b/app/src/main/res/layout/view_preview_post.xml
index 13f7ae6b17bb69fbbd396196a4890d7049390cb1..f7fafaf9e2b557ddee31d13bac1c4140537ccc7c 100644
--- a/app/src/main/res/layout/view_preview_post.xml
+++ b/app/src/main/res/layout/view_preview_post.xml
@@ -39,9 +39,10 @@
 
     <ScrollView
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="0dp"
         android:layout_marginTop="8dp"
         android:orientation="vertical"
+        app:layout_constraintBottom_toTopOf="@id/lBottomContainer"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toBottomOf="@id/postHeader">
@@ -51,20 +52,20 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
 
-            <org.futo.circles.view.MarkdownEditText
+            <io.element.android.wysiwyg.EditorEditText
                 android:id="@+id/etTextPost"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:background="@null"
                 android:gravity="top"
                 android:hint="@string/enter_your_message_here"
-                android:inputType="textCapSentences|textMultiLine"
-                android:paddingStart="12dp"
-                android:paddingEnd="12dp"
-                app:layout_constraintBottom_toTopOf="@id/lMediaContent"
+                app:bulletGap="8sp"
+                app:bulletRadius="4sp"
+                app:pillBackgroundColor="@color/white"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toTopOf="parent" />
+                app:layout_constraintTop_toTopOf="parent"
+                tools:text="some text" />
 
 
             <include
@@ -91,8 +92,87 @@
                 app:layout_constraintEnd_toEndOf="@id/lMediaContent"
                 app:layout_constraintTop_toTopOf="@id/lMediaContent"
                 app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.CornerSize50Percent" />
-            
+
         </androidx.constraintlayout.widget.ConstraintLayout>
 
     </ScrollView>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/lBottomContainer"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent">
+
+        <com.google.android.material.imageview.ShapeableImageView
+            android:id="@+id/ivCancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:background="@color/close_background"
+            android:clickable="true"
+            android:focusable="true"
+            android:padding="8dp"
+            android:src="@drawable/ic_close"
+            android:tint="@color/white"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.CornerSize50Percent" />
+
+        <HorizontalScrollView
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:fadingEdgeLength="28dp"
+            android:fillViewport="true"
+            android:minHeight="52dp"
+            android:requiresFadingEdge="horizontal"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@id/btnSend"
+            app:layout_constraintStart_toEndOf="@id/ivCancel"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <LinearLayout
+                android:id="@+id/lMenu"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:orientation="horizontal">
+
+                <LinearLayout
+                    android:id="@+id/lMainMenu"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:orientation="horizontal" />
+
+                <LinearLayout
+                    android:id="@+id/lTextMenu"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:orientation="horizontal" />
+
+            </LinearLayout>
+
+        </HorizontalScrollView>
+
+        <com.google.android.material.button.MaterialButton
+            android:id="@+id/btnSend"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_marginEnd="8dp"
+            android:background="?selectableItemBackgroundBorderless"
+            android:enabled="false"
+            android:focusable="true"
+            android:minWidth="0dp"
+            android:minHeight="0dp"
+            android:padding="0dp"
+            app:icon="@drawable/ic_send"
+            app:iconGravity="end"
+            app:iconSize="40dp"
+            app:iconTint="@color/send_ic_state_color"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
 </merge>
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_rich_text_menu_button.xml b/app/src/main/res/layout/view_rich_text_menu_button.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ced20d9a86ae47272bc3715740f99c741ede1538
--- /dev/null
+++ b/app/src/main/res/layout/view_rich_text_menu_button.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/cvOption"
+    android:layout_width="48dp"
+    android:layout_height="48dp"
+    android:clickable="true"
+    android:elevation="4dp"
+    android:focusable="true"
+    android:foreground="?selectableItemBackground"
+    app:cardBackgroundColor="@drawable/bg_rich_text_menu_button"
+    app:cardCornerRadius="8dp"
+    app:cardUseCompatPadding="true">
+
+    <ImageView
+        android:id="@+id/ivIcon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:src="@drawable/ic_mention" />
+
+</androidx.cardview.widget.CardView>
+
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index ac9eed3a50e31cf0d63f6b3e43237019b581fe79..be23a2f4fb314a6cb382433b30295ae3cf4a6225 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -1,6 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
+    <attr name="vctr_content_quaternary" format="color" />
+
     <declare-styleable name="GroupPostHeaderView">
         <attr name="optionsVisible" format="boolean" />
     </declare-styleable>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index a56cca454e9ad1497609483baa3841852b78856d..ed95017c76f6572d163340f7c993dc9ad6cc3b11 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -19,6 +19,5 @@
     <color name="close_background">#80000000</color>
     <color name="highlight_color">#4D0E7AFE</color>
     <color name="launcher_background_color">#00008b</color>
-    <color name="transparent">#00000000</color>
 
 </resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 57b80004bddfd311f2648dba71b56de014ee6fe8..4671e2397061ff82636af83cf1e4aa33cb93816f 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -5,4 +5,7 @@
     <dimen name="post_text_side_margin">24dp</dimen>
     <dimen name="circle_icon_size">100dp</dimen>
     <dimen name="profile_avatar_size">50dp</dimen>
+
+    <dimen name="rich_text_composer_corner_radius_expanded">14dp</dimen>
+    <dimen name="rich_text_composer_menu_item_size">44dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index eade56ad373fabfec4110c8cf6297c5f078551d0..f748de26c95780acd5a507c8210aba181ac0e295 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -25,7 +25,6 @@
     <string name="invites">Invites</string>
     <string name="create_new_group">Create new group</string>
     <string name="create_new_circle">Create new circle</string>
-    <string name="circles_created">Circles created</string>
     <string name="private_circles">Private Circles</string>
     <string name="log_out">Log out</string>
     <string name="others">Others</string>
@@ -74,7 +73,6 @@
     <string name="severity_formatter">Severity: %d</string>
     <string name="add_reaction">Add reaction</string>
     <string name="unfollow">Unfollow</string>
-    <string name="requested_to_follow_format">%s requested to follow</string>
     <string name="request_to_join">Request to join</string>
     <string name="request_to_follow">Request to follow</string>
     <string name="select_circles_in_which_you_want_to_follow_this_timeline">Select circles in which you want to follow this timeline</string>
@@ -184,9 +182,6 @@
     <string name="unifiedpush_distributor_background_sync">Background synchronization</string>
     <string name="no_valid_google_play_services_apk">No valid Google Play Services APK found. Notifications may not work properly.</string>
     <string name="unable_to_register_receiver">Unable to register the receiver</string>
-    <string name="scan_profile">Scan profile</string>
-    <string name="mute_notifications">Mute notifications</string>
-    <string name="unmute_notifications">Unmute notifications</string>
     <string name="shortcut_disabled">Shortcut disabled</string>
     <string name="shared_circles_space_not_found">Shared Circles space not found</string>
     <string name="notification_method">Notification method</string>
@@ -202,7 +197,6 @@
     <string name="request_to_become_member_room">Request to join to become a member of this room</string>
     <string name="you_have_pending_invitation_user">You have a pending invitation to follow this user. Check your invite notifications</string>
     <string name="you_are_already_following_user">You are already following this user</string>
-    <string name="you_are_banned_user">You are banned</string>
     <string name="send_request_to_follow_user">Send request to follow this user</string>
     <string name="unable_to_parse_url">Unable to parse url</string>
     <string name="developer_mode_enabled">Developer mode is enabled</string>
@@ -216,6 +210,19 @@
     <string name="help">Help</string>
     <string name="optional_request_message">Optional: Request message</string>
 
+    <!-- Rich text editor -->
+    <string name="rich_text_editor_format_bold">Apply bold format</string>
+    <string name="rich_text_editor_format_italic">Apply italic format</string>
+    <string name="rich_text_editor_format_strikethrough">Apply strikethrough format</string>
+    <string name="rich_text_editor_format_underline">Apply underline format</string>
+    <string name="rich_text_editor_link">Set link</string>
+    <string name="rich_text_editor_numbered_list">Toggle numbered list</string>
+    <string name="rich_text_editor_bullet_list">Toggle bullet list</string>
+    <string name="rich_text_editor_indent">Indent</string>
+    <string name="rich_text_editor_unindent">Unindent</string>
+    <string name="rich_text_editor_quote">Toggle quote</string>
+    <string name="rich_text_editor_code_block">Toggle code block</string>
+
     <string-array name="report_categories">
         <item>@string/crude_language</item>
         <item>@string/copyright_violation</item>
diff --git a/build.gradle b/build.gradle
index 924f2bdbcbd6dd528a06efabe21af3db2a95853c..5eb8219f82e9b52c881e335243fc333223ce9736 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,7 +12,7 @@ buildscript {
         mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:8.1.3'
+        classpath 'com.android.tools.build:gradle:8.1.4'
         classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.21'
         classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$androidx_nav_version"
         classpath 'com.google.gms:google-services:4.4.0'
diff --git a/core/build.gradle b/core/build.gradle
index cca12aac79de792467a40ca7e63d38a56742a086..daecc1f1b5e4dd76cababd0d19863d2e8becac37 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -95,6 +95,15 @@ dependencies {
     //QR
     api 'com.google.zxing:core:3.5.2'
 
+    //Markdown
+    def markwon_version = "4.6.2"
+    api "io.noties.markwon:core:$markwon_version"
+    api "io.noties.markwon:linkify:$markwon_version"
+    api "io.noties.markwon:ext-strikethrough:$markwon_version"
+    api "io.noties.markwon:ext-tasklist:$markwon_version"
+    //noinspection GradleDependency
+    api "io.element.android:wysiwyg:2.2.2"
+
     //Shake detection
     implementation 'com.squareup:seismic:1.0.3'
 
diff --git a/core/src/main/java/org/futo/circles/core/base/NetworkObserver.kt b/core/src/main/java/org/futo/circles/core/base/NetworkObserver.kt
index ff318d241a79a6d9cc653881e2820c48ab4fd6b7..7c304a8936dfc7e117100c5de547618a758d35da 100644
--- a/core/src/main/java/org/futo/circles/core/base/NetworkObserver.kt
+++ b/core/src/main/java/org/futo/circles/core/base/NetworkObserver.kt
@@ -17,7 +17,7 @@ import org.matrix.android.sdk.api.extensions.orFalse
 
 object NetworkObserver {
 
-    private val internetConnectionFlow = MutableStateFlow(false)
+    private val internetConnectionFlow = MutableStateFlow(true)
 
     fun isConnected() = internetConnectionFlow.value
 
@@ -59,7 +59,7 @@ object NetworkObserver {
     }
 
     private fun isConnectedToInternet(context: Context): Boolean {
-        val connectivityManager = context.getSystemService<ConnectivityManager>() ?: return false
+        val connectivityManager = context.getSystemService<ConnectivityManager>() ?: return true
         val capabilities =
             connectivityManager.activeNetwork?.let { connectivityManager.getNetworkCapabilities(it) }
         val hasWifi = capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI).orFalse()
diff --git a/core/src/main/java/org/futo/circles/core/feature/markdown/MarkdownParser.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/MarkdownParser.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ccab220dcf8192a491b20369d203de5a1245b5a6
--- /dev/null
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/MarkdownParser.kt
@@ -0,0 +1,57 @@
+package org.futo.circles.core.feature.markdown
+
+import android.content.Context
+import android.graphics.Typeface
+import android.text.style.StyleSpan
+import io.noties.markwon.AbstractMarkwonPlugin
+import io.noties.markwon.Markwon
+import io.noties.markwon.MarkwonSpansFactory
+import io.noties.markwon.SoftBreakAddsNewLinePlugin
+import io.noties.markwon.ext.strikethrough.StrikethroughPlugin
+import io.noties.markwon.linkify.LinkifyPlugin
+import org.commonmark.node.Emphasis
+import org.commonmark.node.StrongEmphasis
+import org.futo.circles.core.extensions.notEmptyDisplayName
+import org.futo.circles.core.feature.markdown.mentions.plugin.MentionPlugin
+import org.futo.circles.core.provider.MatrixSessionProvider
+import org.matrix.android.sdk.api.session.getUserOrDefault
+
+
+object MarkdownParser {
+
+
+    fun markwonBuilder(context: Context): Markwon = Markwon.builder(context)
+        .usePlugin(SoftBreakAddsNewLinePlugin.create())
+        .usePlugin(StrikethroughPlugin.create())
+        .usePlugin(LinkifyPlugin.create())
+        .usePlugin(MentionPlugin(context))
+        .build()
+
+    fun markwonNotificationBuilder(context: Context): Markwon = Markwon.builder(context)
+        .usePlugin(SoftBreakAddsNewLinePlugin.create())
+        .usePlugin(object : AbstractMarkwonPlugin() {
+            override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
+                builder.setFactory(
+                    Emphasis::class.java
+                ) { _, _ -> StyleSpan(Typeface.ITALIC) }
+            }
+        })
+        .usePlugin(object : AbstractMarkwonPlugin() {
+            override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
+                builder.setFactory(
+                    StrongEmphasis::class.java
+                ) { _, _ -> StyleSpan(Typeface.BOLD) }
+            }
+        })
+        .usePlugin(StrikethroughPlugin.create())
+        .usePlugin(LinkifyPlugin.create())
+        .build()
+
+    fun hasCurrentUserMention(text: String): Boolean {
+        val session = MatrixSessionProvider.currentSession ?: return false
+        val userName = session.getUserOrDefault(session.myUserId).notEmptyDisplayName()
+        val mentionString = "@$userName@"
+        return text.contains(mentionString)
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/MentionsAdapter.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsAdapter.kt
similarity index 91%
rename from app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/MentionsAdapter.kt
rename to core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsAdapter.kt
index f2d8de1993e2f6c2be27c607c37ba7acc48668cb..43a4416fc5316648cc57d8a15675832c3c3c279d 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/MentionsAdapter.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsAdapter.kt
@@ -1,4 +1,4 @@
-package org.futo.circles.feature.timeline.post.markdown.mentions
+package org.futo.circles.core.feature.markdown.mentions
 
 import android.view.ViewGroup
 import org.futo.circles.core.base.list.BaseRvAdapter
diff --git a/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsLinkDisplayHandler.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsLinkDisplayHandler.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3e61d3e8b8d0f6e321ecd3b7f457fca5754ad7b3
--- /dev/null
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsLinkDisplayHandler.kt
@@ -0,0 +1,22 @@
+package org.futo.circles.core.feature.markdown.mentions
+
+import android.content.Context
+import io.element.android.wysiwyg.display.LinkDisplayHandler
+import io.element.android.wysiwyg.display.TextDisplay
+import org.futo.circles.core.feature.markdown.span.MentionSpan
+import org.matrix.android.sdk.api.MatrixPatterns
+import org.matrix.android.sdk.api.session.permalinks.PermalinkService
+
+class MentionsLinkDisplayHandler(private val context: Context) : LinkDisplayHandler {
+
+    override fun resolveLinkDisplay(text: String, url: String): TextDisplay {
+        val userId = url.removePrefix(PermalinkService.MATRIX_TO_URL_BASE)
+        return if (MatrixPatterns.isUserId(userId))
+            TextDisplay.Custom(
+                MentionSpan(
+                    context,
+                    text.replace("@", "")
+                )
+            ) else TextDisplay.Plain
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/MentionsPresenter.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsPresenter.kt
similarity index 96%
rename from app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/MentionsPresenter.kt
rename to core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsPresenter.kt
index 1024ed548fd3ea7fbf907c31a5ba17a348474af7..bedc93b4af49cdd16dcc485c64d760323b3b3433 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/MentionsPresenter.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/MentionsPresenter.kt
@@ -1,4 +1,4 @@
-package org.futo.circles.feature.timeline.post.markdown.mentions
+package org.futo.circles.core.feature.markdown.mentions
 
 import android.content.Context
 import androidx.recyclerview.widget.RecyclerView
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionDelimiterProcessor.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionDelimiterProcessor.kt
similarity index 93%
rename from app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionDelimiterProcessor.kt
rename to core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionDelimiterProcessor.kt
index 66c2bbf46cc9f3e2425a038bd31b34469acdd118..817dc7d4df479bb3d42f881bce34c624662528bd 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionDelimiterProcessor.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionDelimiterProcessor.kt
@@ -1,4 +1,4 @@
-package org.futo.circles.feature.timeline.post.markdown.mentions.plugin
+package org.futo.circles.core.feature.markdown.mentions.plugin
 
 import org.commonmark.node.Node
 import org.commonmark.node.Text
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionNode.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionNode.kt
similarity index 72%
rename from app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionNode.kt
rename to core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionNode.kt
index 4e0274255c76c70f3c273d722392ad098565918f..6aca6a1a2d95303145f66e2b351209391e8179b5 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionNode.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionNode.kt
@@ -1,4 +1,4 @@
-package org.futo.circles.feature.timeline.post.markdown.mentions.plugin
+package org.futo.circles.core.feature.markdown.mentions.plugin
 
 import org.commonmark.node.CustomNode
 import org.commonmark.node.Visitor
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionPlugin.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionPlugin.kt
similarity index 88%
rename from app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionPlugin.kt
rename to core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionPlugin.kt
index 797fc787e8f32866a56257a7e4d9d46bbd4e634f..2a2b1ff6b0f65ef42ef8398dde7c34cd09e06b45 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/mentions/plugin/MentionPlugin.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionPlugin.kt
@@ -1,11 +1,11 @@
-package org.futo.circles.feature.timeline.post.markdown.mentions.plugin
+package org.futo.circles.core.feature.markdown.mentions.plugin
 
 import android.content.Context
 import io.noties.markwon.AbstractMarkwonPlugin
 import io.noties.markwon.MarkwonVisitor
 import io.noties.markwon.SpannableBuilder
 import org.commonmark.parser.Parser
-import org.futo.circles.feature.timeline.post.markdown.span.MentionSpan
+import org.futo.circles.core.feature.markdown.span.MentionSpan
 
 
 class MentionPlugin(private val context: Context) : AbstractMarkwonPlugin() {
diff --git a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/MentionSpan.kt b/core/src/main/java/org/futo/circles/core/feature/markdown/span/MentionSpan.kt
similarity index 87%
rename from app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/MentionSpan.kt
rename to core/src/main/java/org/futo/circles/core/feature/markdown/span/MentionSpan.kt
index 04f900ea4edacf94494470b5c86e46e86f42b50d..bb331381539d859c66135cb2efa5ebd9ee628b3d 100644
--- a/app/src/main/java/org/futo/circles/feature/timeline/post/markdown/span/MentionSpan.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/markdown/span/MentionSpan.kt
@@ -1,11 +1,11 @@
-package org.futo.circles.feature.timeline.post.markdown.span
+package org.futo.circles.core.feature.markdown.span
 
 import android.content.Context
 import android.graphics.drawable.Drawable
 import android.text.style.DynamicDrawableSpan
 import androidx.core.content.ContextCompat
 import com.google.android.material.chip.ChipDrawable
-import org.futo.circles.R
+import org.futo.circles.core.R
 
 class MentionSpan(
     private val context: Context,
diff --git a/core/src/main/java/org/futo/circles/core/feature/timeline/data_source/BaseTimelineDataSource.kt b/core/src/main/java/org/futo/circles/core/feature/timeline/data_source/BaseTimelineDataSource.kt
index 82715bea1084a75cbcac35e2dfbe77aaba447993..c6de328db778fbc371a0bc78bddac362489184da 100644
--- a/core/src/main/java/org/futo/circles/core/feature/timeline/data_source/BaseTimelineDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/timeline/data_source/BaseTimelineDataSource.kt
@@ -3,11 +3,11 @@ package org.futo.circles.core.feature.timeline.data_source
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.SavedStateHandle
 import org.futo.circles.core.extensions.getOrThrow
-import org.futo.circles.core.model.Post
-import org.futo.circles.core.provider.MatrixSessionProvider
 import org.futo.circles.core.feature.timeline.builder.BaseTimelineBuilder
 import org.futo.circles.core.feature.timeline.builder.MultiTimelineBuilder
 import org.futo.circles.core.feature.timeline.builder.SingleTimelineBuilder
+import org.futo.circles.core.model.Post
+import org.futo.circles.core.provider.MatrixSessionProvider
 import org.matrix.android.sdk.api.session.getRoom
 import org.matrix.android.sdk.api.session.room.Room
 import org.matrix.android.sdk.api.session.room.timeline.Timeline
diff --git a/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostContentDataSource.kt b/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostContentDataSource.kt
index aae616280fc90761c8bef16b3230404bd12f95f4..2ee5c0b96fce1159037a9ddaac13052d3ceae075 100644
--- a/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostContentDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostContentDataSource.kt
@@ -15,6 +15,7 @@ class PostContentDataSource @Inject constructor() {
 
     private val session = MatrixSessionProvider.currentSession
 
+
     fun getPost(roomId: String, eventId: String): Post? {
         val roomForMessage = session?.getRoom(roomId)
         val timelineEvent = roomForMessage?.getTimelineEvent(eventId) ?: return null
diff --git a/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostOptionsDataSource.kt b/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostOptionsDataSource.kt
index 7db832ffd78486ffe04331d0e8a9ffa2b64e94a9..bae01ac4ff9df0f3008f1c5b4fd69a330a1c4bb0 100644
--- a/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostOptionsDataSource.kt
+++ b/core/src/main/java/org/futo/circles/core/feature/timeline/post/PostOptionsDataSource.kt
@@ -44,7 +44,7 @@ class PostOptionsDataSource @Inject constructor(
     suspend fun getShareableContent(content: PostContent): ShareableContent? = onBG {
         when (content) {
             is MediaContent -> getShareableMediaContent(content.mediaFileData)
-            is TextContent -> TextShareable(content.message)
+            is TextContent -> TextShareable(content.message.toString())
             else -> throw IllegalArgumentException("Not shareable post content")
         }
     }
diff --git a/core/src/main/java/org/futo/circles/core/mapping/TextPostContentMapping.kt b/core/src/main/java/org/futo/circles/core/mapping/TextPostContentMapping.kt
index a8104f4eb09f000175154ecd9d1dcac5a160766d..2044b74d571cc969659cb5f38f3d65d3be3f7edd 100644
--- a/core/src/main/java/org/futo/circles/core/mapping/TextPostContentMapping.kt
+++ b/core/src/main/java/org/futo/circles/core/mapping/TextPostContentMapping.kt
@@ -4,6 +4,8 @@ import org.futo.circles.core.model.TextContent
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent
 
-fun TimelineEvent.toTextContent(): TextContent = TextContent(
-    message = getTextEditableContent(false)
-)
\ No newline at end of file
+fun TimelineEvent.toTextContent(): TextContent =
+    TextContent(getTextEditableContent(false))
+
+
+
diff --git a/core/src/main/java/org/futo/circles/core/mapping/TimelineEventMapping.kt b/core/src/main/java/org/futo/circles/core/mapping/TimelineEventMapping.kt
index c024e6572c2b55778c154fff433fe04508ef6c1b..440831acc7021de534597870b9e4b4fa750186b6 100644
--- a/core/src/main/java/org/futo/circles/core/mapping/TimelineEventMapping.kt
+++ b/core/src/main/java/org/futo/circles/core/mapping/TimelineEventMapping.kt
@@ -30,13 +30,14 @@ private fun TimelineEvent.toPostInfo(): PostInfo = PostInfo(
     isEdited = hasBeenEdited()
 )
 
-private fun TimelineEvent.toPostContent(): PostContent = when (getPostContentType()) {
-    PostContentType.TEXT_CONTENT -> toTextContent()
-    PostContentType.IMAGE_CONTENT -> toMediaContent(MediaType.Image)
-    PostContentType.VIDEO_CONTENT -> toMediaContent(MediaType.Video)
-    PostContentType.POLL_CONTENT -> toPollContent()
-    else -> toTextContent()
-}
+private fun TimelineEvent.toPostContent(): PostContent =
+    when (getPostContentType()) {
+        PostContentType.TEXT_CONTENT -> toTextContent()
+        PostContentType.IMAGE_CONTENT -> toMediaContent(MediaType.Image)
+        PostContentType.VIDEO_CONTENT -> toMediaContent(MediaType.Video)
+        PostContentType.POLL_CONTENT -> toPollContent()
+        else -> toTextContent()
+    }
 
 private fun TimelineEvent.getReadByCount(receipts: List<Long>): Int {
     val eventTime = root.originServerTs ?: 0
diff --git a/app/src/main/res/drawable/ic_mention.xml b/core/src/main/res/drawable/ic_mention.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_mention.xml
rename to core/src/main/res/drawable/ic_mention.xml
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 1fe6f027a502a9afe13d7ea85427a37dbee6eb99..12b0cbde91f4e029ce1ba3b03019a0566ec39f2e 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -124,7 +124,6 @@
     <string name="delete_gallery_message">Are you sure you want to remove this gallery?</string>
     <string name="accept">Accept</string>
     <string name="decline">Decline</string>
-    <string name="requested_to_join_format">%s requested to join</string>
     <string name="invited_by_format">Invited by %s</string>
     <string name="circle_encryption_warning">NOTE: Circle name and cover image are not encrypted</string>
     <string name="circle_name">Circle name</string>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index 398bd338d110a0ccdc9333ab61c1cf3a26307316..aedfaa4c38711a05a5055af8e7cce525d812a477 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -71,13 +71,6 @@
         <item name="cornerSize">10%</item>
     </style>
 
-    <style name="ShapeAppearanceOverlay.App.Message" parent="">
-        <item name="cornerSizeTopRight">10dp</item>
-        <item name="cornerSizeBottomRight">10dp</item>
-        <item name="cornerSizeTopLeft">10dp</item>
-        <item name="cornerFamilyTopRight">rounded</item>
-    </style>
-
     <style name="settingMenuItem" parent="body">
         <item name="android:background">?attr/selectableItemBackground</item>
         <item name="android:clickable">true</item>
diff --git a/app/src/main/res/xml/bg_chip.xml b/core/src/main/res/xml/bg_chip.xml
similarity index 100%
rename from app/src/main/res/xml/bg_chip.xml
rename to core/src/main/res/xml/bg_chip.xml