Skip to content

Commit 89c0ed9

Browse files
authored
Merge pull request #968 from wordpress-mobile/feature/make-inline-code-exclusive-action
Make sure code can be selected as the only current inline action and format
2 parents f4e6dca + 1173880 commit 89c0ed9

File tree

7 files changed

+75
-38
lines changed

7 files changed

+75
-38
lines changed

aztec/src/main/kotlin/org/wordpress/aztec/formatting/InlineFormatter.kt

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import org.wordpress.aztec.spans.AztecStyleStrongSpan
2222
import org.wordpress.aztec.spans.AztecStyleSpan
2323
import org.wordpress.aztec.spans.AztecUnderlineSpan
2424
import org.wordpress.aztec.spans.HighlightSpan
25+
import org.wordpress.aztec.spans.IAztecExclusiveInlineSpan
2526
import org.wordpress.aztec.spans.IAztecInlineSpan
2627
import org.wordpress.aztec.spans.MarkSpan
2728
import org.wordpress.aztec.watchers.TextChangedEvent
@@ -37,23 +38,43 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
3738

3839
fun toggle(textFormat: ITextFormat) {
3940
if (!containsInlineStyle(textFormat)) {
41+
val inlineSpan = makeInlineSpan(textFormat)
42+
if (inlineSpan is IAztecExclusiveInlineSpan) {
43+
// If text format is exclusive, remove all the inclusive text formats already applied
44+
removeAllInclusiveFormats()
45+
} else {
46+
// If text format is inclusive, remove all the exclusive text formats already applied
47+
removeAllExclusiveFormats()
48+
}
4049
applyInlineStyle(textFormat)
4150
} else {
4251
removeInlineStyle(textFormat)
4352
}
4453
}
4554

55+
private fun removeAllInclusiveFormats() {
56+
editableText.getSpans(selectionStart, selectionEnd, IAztecInlineSpan::class.java).filter {
57+
it !is IAztecExclusiveInlineSpan
58+
}.forEach { removeInlineStyle(it) }
59+
}
60+
4661
/**
4762
* Removes all formats in the list but if none found, applies the first one
4863
*/
4964
fun toggleAny(textFormats: Set<ITextFormat>) {
5065
if (!textFormats
5166
.filter { containsInlineStyle(it) }
52-
.fold(false, { found, containedTextFormat -> removeInlineStyle(containedTextFormat); true })) {
67+
.fold(false) { found, containedTextFormat -> removeInlineStyle(containedTextFormat); true }) {
68+
removeAllExclusiveFormats()
5369
applyInlineStyle(textFormats.first())
5470
}
5571
}
5672

73+
private fun removeAllExclusiveFormats() {
74+
editableText.getSpans(selectionStart, selectionEnd, IAztecExclusiveInlineSpan::class.java)
75+
.forEach { removeInlineStyle(it) }
76+
}
77+
5778
fun handleInlineStyling(textChangedEvent: TextChangedEvent) {
5879
if (textChangedEvent.isEndOfBufferMarker()) return
5980

@@ -117,7 +138,7 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
117138
}
118139
}
119140

120-
fun applyInlineStyle(textFormat: ITextFormat, start: Int = selectionStart, end: Int = selectionEnd, attrs: AztecAttributes = AztecAttributes()) {
141+
private fun applyInlineStyle(textFormat: ITextFormat, start: Int = selectionStart, end: Int = selectionEnd, attrs: AztecAttributes = AztecAttributes()) {
121142
val spanToApply = makeInlineSpan(textFormat)
122143
spanToApply.attributes = attrs
123144

@@ -144,7 +165,7 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
144165
if (spanEnd > start) {
145166
// ensure css style is applied
146167
(precedingSpan as IAztecInlineSpan).applyInlineStyleAttributes(editableText, start, end)
147-
return@applyInlineStyle // we are adding text inside span - no need to do anything special
168+
return // we are adding text inside span - no need to do anything special
148169
} else {
149170
applySpan(precedingSpan as IAztecInlineSpan, spanStart, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
150171
}
@@ -217,18 +238,18 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
217238
}
218239

219240
fun spanToTextFormat(span: IAztecInlineSpan): ITextFormat? {
220-
when (span::class.java) {
221-
AztecStyleBoldSpan::class.java -> return AztecTextFormat.FORMAT_BOLD
222-
AztecStyleStrongSpan::class.java -> return AztecTextFormat.FORMAT_STRONG
223-
AztecStyleItalicSpan::class.java -> return AztecTextFormat.FORMAT_ITALIC
224-
AztecStyleEmphasisSpan::class.java -> return AztecTextFormat.FORMAT_EMPHASIS
225-
AztecStyleCiteSpan::class.java -> return AztecTextFormat.FORMAT_CITE
226-
AztecStrikethroughSpan::class.java -> return AztecTextFormat.FORMAT_STRIKETHROUGH
227-
AztecUnderlineSpan::class.java -> return AztecTextFormat.FORMAT_UNDERLINE
228-
AztecCodeSpan::class.java -> return AztecTextFormat.FORMAT_CODE
229-
MarkSpan::class.java -> return AztecTextFormat.FORMAT_MARK
230-
HighlightSpan::class.java -> return AztecTextFormat.FORMAT_HIGHLIGHT
231-
else -> return null
241+
return when (span::class.java) {
242+
AztecStyleBoldSpan::class.java -> AztecTextFormat.FORMAT_BOLD
243+
AztecStyleStrongSpan::class.java -> AztecTextFormat.FORMAT_STRONG
244+
AztecStyleItalicSpan::class.java -> AztecTextFormat.FORMAT_ITALIC
245+
AztecStyleEmphasisSpan::class.java -> AztecTextFormat.FORMAT_EMPHASIS
246+
AztecStyleCiteSpan::class.java -> AztecTextFormat.FORMAT_CITE
247+
AztecStrikethroughSpan::class.java -> AztecTextFormat.FORMAT_STRIKETHROUGH
248+
AztecUnderlineSpan::class.java -> AztecTextFormat.FORMAT_UNDERLINE
249+
AztecCodeSpan::class.java -> AztecTextFormat.FORMAT_CODE
250+
MarkSpan::class.java -> AztecTextFormat.FORMAT_MARK
251+
HighlightSpan::class.java -> AztecTextFormat.FORMAT_HIGHLIGHT
252+
else -> null
232253
}
233254
}
234255

@@ -363,20 +384,20 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
363384
}
364385

365386
fun makeInlineSpan(textFormat: ITextFormat): IAztecInlineSpan {
366-
when (textFormat) {
367-
AztecTextFormat.FORMAT_BOLD -> return AztecStyleBoldSpan()
368-
AztecTextFormat.FORMAT_STRONG -> return AztecStyleStrongSpan()
369-
AztecTextFormat.FORMAT_ITALIC -> return AztecStyleItalicSpan()
370-
AztecTextFormat.FORMAT_EMPHASIS -> return AztecStyleEmphasisSpan()
371-
AztecTextFormat.FORMAT_CITE -> return AztecStyleCiteSpan()
372-
AztecTextFormat.FORMAT_STRIKETHROUGH -> return AztecStrikethroughSpan()
373-
AztecTextFormat.FORMAT_UNDERLINE -> return AztecUnderlineSpan()
374-
AztecTextFormat.FORMAT_CODE -> return AztecCodeSpan(codeStyle)
387+
return when (textFormat) {
388+
AztecTextFormat.FORMAT_BOLD -> AztecStyleBoldSpan()
389+
AztecTextFormat.FORMAT_STRONG -> AztecStyleStrongSpan()
390+
AztecTextFormat.FORMAT_ITALIC -> AztecStyleItalicSpan()
391+
AztecTextFormat.FORMAT_EMPHASIS -> AztecStyleEmphasisSpan()
392+
AztecTextFormat.FORMAT_CITE -> AztecStyleCiteSpan()
393+
AztecTextFormat.FORMAT_STRIKETHROUGH -> AztecStrikethroughSpan()
394+
AztecTextFormat.FORMAT_UNDERLINE -> AztecUnderlineSpan()
395+
AztecTextFormat.FORMAT_CODE -> AztecCodeSpan(codeStyle)
375396
AztecTextFormat.FORMAT_HIGHLIGHT -> {
376-
return HighlightSpan(highlightStyle = highlightStyle, context = editor.context)
397+
HighlightSpan(highlightStyle = highlightStyle, context = editor.context)
377398
}
378-
AztecTextFormat.FORMAT_MARK -> return MarkSpan()
379-
else -> return AztecStyleSpan(Typeface.NORMAL)
399+
AztecTextFormat.FORMAT_MARK -> MarkSpan()
400+
else -> AztecStyleSpan(Typeface.NORMAL)
380401
}
381402
}
382403

@@ -392,18 +413,16 @@ class InlineFormatter(editor: AztecText, val codeStyle: CodeStyle, private val h
392413
return false
393414
} else {
394415
val before = editableText.getSpans(start - 1, start, IAztecInlineSpan::class.java)
395-
.filter { it -> isSameInlineSpanType(it, spanToCheck) }
396-
.firstOrNull()
416+
.firstOrNull { isSameInlineSpanType(it, spanToCheck) }
397417
val after = editableText.getSpans(start, start + 1, IAztecInlineSpan::class.java)
398-
.filter { isSameInlineSpanType(it, spanToCheck) }
399-
.firstOrNull()
418+
.firstOrNull { isSameInlineSpanType(it, spanToCheck) }
400419
return before != null && after != null && isSameInlineSpanType(before, after)
401420
}
402421
} else {
403422
val builder = StringBuilder()
404423

405424
// Make sure no duplicate characters be added
406-
for (i in start..end - 1) {
425+
for (i in start until end) {
407426
val spans = editableText.getSpans(i, i + 1, IAztecInlineSpan::class.java)
408427

409428
for (span in spans) {

aztec/src/main/kotlin/org/wordpress/aztec/spans/AztecCodeSpan.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import android.text.style.MetricAffectingSpan
2424
import org.wordpress.aztec.AztecAttributes
2525
import org.wordpress.aztec.formatting.InlineFormatter
2626

27-
class AztecCodeSpan(override var attributes: AztecAttributes = AztecAttributes()) : MetricAffectingSpan(), IAztecInlineSpan {
27+
class AztecCodeSpan(override var attributes: AztecAttributes = AztecAttributes()) : MetricAffectingSpan(), IAztecExclusiveInlineSpan {
2828
override val TAG = "code"
2929

3030
var codeStyle = InlineFormatter.CodeStyle(0, 0.0f, 0)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
package org.wordpress.aztec.spans
22

33
interface IAztecInlineSpan : IAztecSpan
4+
5+
/**
6+
* Extend this interface if an inline span should be exclusive, meaning
7+
* only a single inline format can be applied to this span.
8+
*/
9+
interface IAztecExclusiveInlineSpan : IAztecInlineSpan

aztec/src/main/kotlin/org/wordpress/aztec/toolbar/AztecToolbar.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ class AztecToolbar : FrameLayout, IAztecToolbar, OnMenuItemClickListener {
494494
}
495495
}
496496

497-
fun highlightActionButtons(toolbarActions: ArrayList<IToolbarAction>) {
497+
fun highlightActionButtons(toolbarActions: List<IToolbarAction>) {
498498
ToolbarAction.values().forEach { action ->
499499
if (toolbarActions.contains(action)) {
500500
toggleButton(findViewById<ToggleButton>(action.buttonId), true)
@@ -556,8 +556,16 @@ class AztecToolbar : FrameLayout, IAztecToolbar, OnMenuItemClickListener {
556556
if (!isEditorAttached()) return
557557

558558
// if nothing is selected just mark the style as active
559-
if (!editor!!.isTextSelected() && action.actionType == ToolbarActionType.INLINE_STYLE) {
560-
val actions = getSelectedActions()
559+
if (!editor!!.isTextSelected() && action.isInlineAction()) {
560+
val toggledActionIsExclusive = action.actionType == ToolbarActionType.EXCLUSIVE_INLINE_STYLE
561+
val selectedActions = getSelectedActions()
562+
val actions = selectedActions.filter {
563+
val isExclusive = it.actionType == ToolbarActionType.EXCLUSIVE_INLINE_STYLE
564+
(it == action || !it.isInlineAction() || !toggledActionIsExclusive && !isExclusive)
565+
}
566+
if (selectedActions.size != actions.size) {
567+
highlightActionButtons(actions)
568+
}
561569
val textFormats = ArrayList<ITextFormat>()
562570

563571
actions.filter { it.isStylingAction() }

aztec/src/main/kotlin/org/wordpress/aztec/toolbar/IToolbarAction.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ interface IToolbarAction {
2828
fun isStylingAction(): Boolean {
2929
return actionType != ToolbarActionType.OTHER
3030
}
31+
32+
fun isInlineAction(): Boolean {
33+
return actionType == ToolbarActionType.INLINE_STYLE || actionType == ToolbarActionType.EXCLUSIVE_INLINE_STYLE
34+
}
3135
}

aztec/src/main/kotlin/org/wordpress/aztec/toolbar/ToolbarAction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ enum class ToolbarAction constructor(
9999
CODE(
100100
R.id.format_bar_button_code,
101101
R.drawable.format_bar_button_code_selector,
102-
ToolbarActionType.INLINE_STYLE,
102+
ToolbarActionType.EXCLUSIVE_INLINE_STYLE,
103103
setOf(AztecTextFormat.FORMAT_CODE),
104104
R.layout.format_bar_button_code),
105105
PREFORMAT(

aztec/src/main/kotlin/org/wordpress/aztec/toolbar/ToolbarActionType.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ package org.wordpress.aztec.toolbar
44
* Describes types of actions that can be performed by toolbar.
55
*/
66
enum class ToolbarActionType {
7-
INLINE_STYLE, BLOCK_STYLE, LINE_BLOCK, OTHER
7+
INLINE_STYLE, EXCLUSIVE_INLINE_STYLE, BLOCK_STYLE, LINE_BLOCK, OTHER
88
}

0 commit comments

Comments
 (0)