Skip to content

Commit d922126

Browse files
authored
[Rich text editor] Add code block, quote and list indentation actions (#8045)
* Add remaining rich text editor actions * Render code blocks in the timeline * Hide indentation buttons when not in a list
1 parent 4174023 commit d922126

25 files changed

+181
-95
lines changed

changelog.d/8045.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[Rich text editor] Add code block, quote and indentation actions

dependencies.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ ext.libs = [
103103
],
104104
element : [
105105
'opusencoder' : "io.element.android:opusencoder:1.1.0",
106-
'wysiwyg' : "io.element.android:wysiwyg:0.23.0"
106+
'wysiwyg' : "io.element.android:wysiwyg:1.0.0"
107107
],
108108
squareup : [
109109
'moshi' : "com.squareup.moshi:moshi:$moshi",

library/ui-strings/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,7 +3503,11 @@
35033503
<string name="rich_text_editor_link">Set link</string>
35043504
<string name="rich_text_editor_numbered_list">Toggle numbered list</string>
35053505
<string name="rich_text_editor_bullet_list">Toggle bullet list</string>
3506+
<string name="rich_text_editor_indent">Indent</string>
3507+
<string name="rich_text_editor_unindent">Unindent</string>
3508+
<string name="rich_text_editor_quote">Toggle quote</string>
35063509
<string name="rich_text_editor_inline_code">Apply inline code format</string>
3510+
<string name="rich_text_editor_code_block">Toggle code block</string>
35073511
<string name="rich_text_editor_full_screen_toggle">Toggle full screen mode</string>
35083512

35093513
<string name="set_link_text">Text</string>

vector/src/androidTest/java/im/vector/app/features/html/EventHtmlRendererTest.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.core.text.toSpanned
2121
import androidx.test.platform.app.InstrumentationRegistry
2222
import im.vector.app.core.di.ActiveSessionHolder
2323
import im.vector.app.core.resources.ColorProvider
24+
import im.vector.app.core.utils.DimensionConverter
2425
import im.vector.app.core.utils.toTestSpan
2526
import im.vector.app.features.settings.VectorPreferences
2627
import io.mockk.every
@@ -40,9 +41,10 @@ class EventHtmlRendererTest {
4041
every { it.isRichTextEditorEnabled() } returns false
4142
}
4243
private val fakeSessionHolder = mockk<ActiveSessionHolder>()
44+
private val fakeDimensionConverter = mockk<DimensionConverter>()
4345

4446
private val renderer = EventHtmlRenderer(
45-
MatrixHtmlPluginConfigure(ColorProvider(context), context.resources, fakeVectorPreferences),
47+
MatrixHtmlPluginConfigure(ColorProvider(context), context.resources, fakeVectorPreferences, fakeDimensionConverter),
4648
context,
4749
fakeVectorPreferences,
4850
fakeSessionHolder,

vector/src/main/java/im/vector/app/features/home/room/detail/composer/RichTextComposerLayout.kt

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -232,23 +232,35 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
232232
addRichTextMenuItem(R.drawable.ic_composer_strikethrough, R.string.rich_text_editor_format_strikethrough, ComposerAction.STRIKE_THROUGH) {
233233
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.StrikeThrough)
234234
}
235-
addRichTextMenuItem(R.drawable.ic_composer_link, R.string.rich_text_editor_link, ComposerAction.LINK) {
236-
views.richTextComposerEditText.getLinkAction()?.let {
237-
when (it) {
238-
LinkAction.InsertLink -> callback?.onSetLink(isTextSupported = true, initialLink = null)
239-
is LinkAction.SetLink -> callback?.onSetLink(isTextSupported = false, initialLink = it.currentLink)
240-
}
241-
}
242-
}
243235
addRichTextMenuItem(R.drawable.ic_composer_bullet_list, R.string.rich_text_editor_bullet_list, ComposerAction.UNORDERED_LIST) {
244236
views.richTextComposerEditText.toggleList(ordered = false)
245237
}
246238
addRichTextMenuItem(R.drawable.ic_composer_numbered_list, R.string.rich_text_editor_numbered_list, ComposerAction.ORDERED_LIST) {
247239
views.richTextComposerEditText.toggleList(ordered = true)
248240
}
241+
addRichTextMenuItem(R.drawable.ic_composer_indent, R.string.rich_text_editor_indent, ComposerAction.INDENT) {
242+
views.richTextComposerEditText.indent()
243+
}
244+
addRichTextMenuItem(R.drawable.ic_composer_unindent, R.string.rich_text_editor_unindent, ComposerAction.UNINDENT) {
245+
views.richTextComposerEditText.unindent()
246+
}
247+
addRichTextMenuItem(R.drawable.ic_composer_quote, R.string.rich_text_editor_quote, ComposerAction.QUOTE) {
248+
views.richTextComposerEditText.toggleQuote()
249+
}
249250
addRichTextMenuItem(R.drawable.ic_composer_inline_code, R.string.rich_text_editor_inline_code, ComposerAction.INLINE_CODE) {
250251
views.richTextComposerEditText.toggleInlineFormat(InlineFormat.InlineCode)
251252
}
253+
addRichTextMenuItem(R.drawable.ic_composer_code_block, R.string.rich_text_editor_code_block, ComposerAction.CODE_BLOCK) {
254+
views.richTextComposerEditText.toggleCodeBlock()
255+
}
256+
addRichTextMenuItem(R.drawable.ic_composer_link, R.string.rich_text_editor_link, ComposerAction.LINK) {
257+
views.richTextComposerEditText.getLinkAction()?.let {
258+
when (it) {
259+
LinkAction.InsertLink -> callback?.onSetLink(isTextSupported = true, initialLink = null)
260+
is LinkAction.SetLink -> callback?.onSetLink(isTextSupported = false, initialLink = it.currentLink)
261+
}
262+
}
263+
}
252264
}
253265

254266
fun setLink(link: String?) =
@@ -331,11 +343,11 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
331343
* Updates the non-active input with the contents of the active input.
332344
*/
333345
private fun syncEditTexts() =
334-
if (isTextFormattingEnabled) {
335-
views.plainTextComposerEditText.setText(views.richTextComposerEditText.getMarkdown())
336-
} else {
337-
views.richTextComposerEditText.setMarkdown(views.plainTextComposerEditText.text.toString())
338-
}
346+
if (isTextFormattingEnabled) {
347+
views.plainTextComposerEditText.setText(views.richTextComposerEditText.getMarkdown())
348+
} else {
349+
views.richTextComposerEditText.setMarkdown(views.plainTextComposerEditText.text.toString())
350+
}
339351

340352
private fun addRichTextMenuItem(@DrawableRes iconId: Int, @StringRes description: Int, action: ComposerAction, onClick: () -> Unit) {
341353
val inflater = LayoutInflater.from(context)
@@ -355,6 +367,13 @@ internal class RichTextComposerLayout @JvmOverloads constructor(
355367
val stateForAction = menuState[action]
356368
button.isEnabled = stateForAction != ActionState.DISABLED
357369
button.isSelected = stateForAction == ActionState.REVERSED
370+
371+
if (action == ComposerAction.INDENT || action == ComposerAction.UNINDENT) {
372+
val indentationButtonIsVisible =
373+
menuState[ComposerAction.ORDERED_LIST] == ActionState.REVERSED ||
374+
menuState[ComposerAction.UNORDERED_LIST] == ActionState.REVERSED
375+
button.isVisible = indentationButtonIsVisible
376+
}
358377
}
359378

360379
fun estimateCollapsedHeight(): Int {

vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ class MatrixHtmlPluginConfigure @Inject constructor(
240240
private val colorProvider: ColorProvider,
241241
private val resources: Resources,
242242
private val vectorPreferences: VectorPreferences,
243+
private val dimensionConverter: DimensionConverter,
243244
) : HtmlPlugin.HtmlConfigure {
244245

245246
override fun configureHtml(plugin: HtmlPlugin) {
@@ -248,7 +249,7 @@ class MatrixHtmlPluginConfigure @Inject constructor(
248249
.addHandler(FontTagHandler())
249250
.addHandler(ParagraphHandler(DimensionConverter(resources)))
250251
.addHandler(MxReplyTagHandler())
251-
.addHandler(CodePostProcessorTagHandler(vectorPreferences))
252+
.addHandler(CodePostProcessorTagHandler(vectorPreferences, dimensionConverter))
252253
.addHandler(CodePreTagHandler())
253254
.addHandler(CodeTagHandler())
254255
.addHandler(SpanHandler(colorProvider))

vector/src/main/java/im/vector/app/features/html/HtmlCodeHandlers.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
package im.vector.app.features.html
1818

19+
import im.vector.app.core.utils.DimensionConverter
1920
import im.vector.app.features.settings.VectorPreferences
21+
import io.element.android.wysiwyg.spans.CodeBlockSpan
2022
import io.element.android.wysiwyg.spans.InlineCodeSpan
2123
import io.noties.markwon.MarkwonVisitor
2224
import io.noties.markwon.SpannableBuilder
@@ -68,6 +70,7 @@ internal class CodePreTagHandler : TagHandler() {
6870

6971
internal class CodePostProcessorTagHandler(
7072
private val vectorPreferences: VectorPreferences,
73+
private val dimensionConverter: DimensionConverter,
7174
) : TagHandler() {
7275

7376
override fun supportedTags() = listOf(HtmlRootTagPlugin.ROOT_TAG_NAME)
@@ -90,6 +93,7 @@ internal class CodePostProcessorTagHandler(
9093
val intermediateCodeSpan = code.what as IntermediateCodeSpan
9194
val theme = visitor.configuration().theme()
9295
val span = intermediateCodeSpan.toFinalCodeSpan(theme)
96+
9397
SpannableBuilder.setSpans(
9498
visitor.builder(), span, code.start, code.end
9599
)
@@ -98,9 +102,15 @@ internal class CodePostProcessorTagHandler(
98102

99103
private fun IntermediateCodeSpan.toFinalCodeSpan(
100104
markwonTheme: MarkwonTheme
101-
): Any = if (vectorPreferences.isRichTextEditorEnabled() && !isBlock) {
102-
InlineCodeSpan()
105+
): Any = if (vectorPreferences.isRichTextEditorEnabled()) {
106+
toRichTextEditorSpan()
103107
} else {
104108
HtmlCodeSpan(markwonTheme, isBlock)
105109
}
110+
111+
private fun IntermediateCodeSpan.toRichTextEditorSpan() = if (isBlock) {
112+
CodeBlockSpan(dimensionConverter.dpToPx(10), dimensionConverter.dpToPx(4))
113+
} else {
114+
InlineCodeSpan()
115+
}
106116
}

vector/src/main/res/drawable/ic_composer_bold.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
android:height="44dp"
44
android:viewportWidth="44"
55
android:viewportHeight="44">
6-
<path
7-
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"
8-
android:fillColor="#8D97A5"
9-
android:fillType="evenOdd"/>
6+
<path
7+
android:fillColor="?vctr_content_tertiary"
8+
android:fillType="evenOdd"
9+
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" />
1010
</vector>

vector/src/main/res/drawable/ic_composer_bullet_list.xml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
android:height="44dp"
44
android:viewportWidth="44"
55
android:viewportHeight="44">
6-
<group>
7-
<clip-path
8-
android:pathData="M10,10h24v24h-24z"/>
9-
<path
10-
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"
11-
android:fillColor="#8D97A5"/>
12-
</group>
6+
<group>
7+
<clip-path android:pathData="M10,10h24v24h-24z" />
8+
<path
9+
android:fillColor="?vctr_content_tertiary"
10+
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" />
11+
</group>
1312
</vector>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="44dp"
3+
android:height="44dp"
4+
android:viewportWidth="44"
5+
android:viewportHeight="44">
6+
<path
7+
android:fillColor="?vctr_content_tertiary"
8+
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" />
9+
</vector>

0 commit comments

Comments
 (0)