Skip to content

Commit

Permalink
RTL text is now handled automatically, and independently of RTL layou…
Browse files Browse the repository at this point in the history
…t setting
  • Loading branch information
farmerbb committed Oct 13, 2022
1 parent 2033880 commit 6c17c69
Show file tree
Hide file tree
Showing 30 changed files with 176 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class PreferenceManager private constructor(
val showDate get() = Prefs.ShowDate.asFlow
val directEdit get() = Prefs.DirectEdit.asFlow
val markdown get() = Prefs.Markdown.asFlow
val rtlSupport get() = Prefs.RtlSupport.asFlow
val rtlLayout get() = Prefs.RtlSupport.asFlow
val firstRunComplete get() = Prefs.FirstRun.mapToFlow(::toBoolean)
val firstViewComplete get() = Prefs.FirstLoad.mapToFlow(::toBoolean)
val showDoubleTapMessage get() = Prefs.ShowDoubleTapMessage.asFlow
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/farmerbb/notepad/model/Prefs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ object PrefKeys {
val ShowDate = booleanPreferencesKey("show_date")
val DirectEdit = booleanPreferencesKey("direct_edit")
val Markdown = booleanPreferencesKey("markdown")
val RtlSupport = booleanPreferencesKey("rtl_support")
val RtlSupport = booleanPreferencesKey("rtl_layout")
val ShowDoubleTapMessage = booleanPreferencesKey("show_double_tap_message")
val FirstRun = intPreferencesKey("first-run")
val FirstLoad = intPreferencesKey("first-load")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
fun NotepadTheme(
isLightTheme: Boolean,
backgroundColorRes: Int,
rtlSupport: Boolean,
rtlLayout: Boolean,
content: @Composable () -> Unit
) {
val systemUiController = rememberSystemUiController()

val layoutDirection = when(rtlSupport) {
val layoutDirection = when (rtlLayout) {
true -> LayoutDirection.Rtl
false -> LayoutDirection.Ltr
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* Copyright 2022 Braden Farmer
*
* 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 com.farmerbb.notepad.ui.components

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
import java.text.Bidi

@Composable
fun RtlTextWrapper(
text: String,
rtlLayout: Boolean,
content: @Composable () -> Unit
) {
val flags = if (rtlLayout) {
Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT
} else {
Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT
}

val bidi = Bidi(text, flags)

val layoutDirection = if (text.isBlank()) {
when (rtlLayout) {
true -> LayoutDirection.Rtl
false -> LayoutDirection.Ltr
}
} else {
when (bidi.baseIsLeftToRight()) {
true -> LayoutDirection.Ltr
false -> LayoutDirection.Rtl
}
}

CompositionLocalProvider(
LocalLayoutDirection provides layoutDirection,
content = content
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.farmerbb.notepad.R
import com.farmerbb.notepad.ui.components.RtlTextWrapper
import com.farmerbb.notepad.ui.previews.EditNotePreview
import kotlinx.coroutines.delay

Expand All @@ -55,6 +56,7 @@ fun EditNoteContent(
isLightTheme: Boolean = true,
isPrinting: Boolean = false,
waitForAnimation: Boolean = false,
rtlLayout: Boolean = false,
onTextChanged: (String) -> Unit = {}
) {
val textStyle = if (isPrinting) {
Expand All @@ -78,25 +80,27 @@ fun EditNoteContent(
}
)

BasicTextField(
value = value,
onValueChange = {
value = it
onTextChanged(it.text)
},
textStyle = textStyle,
cursorBrush = brush,
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences
),
modifier = Modifier
.padding(
horizontal = 16.dp,
vertical = 12.dp
)
.fillMaxSize()
.focusRequester(focusRequester)
)
RtlTextWrapper(text, rtlLayout) {
BasicTextField(
value = value,
onValueChange = {
value = it
onTextChanged(it.text)
},
textStyle = textStyle,
cursorBrush = brush,
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences
),
modifier = Modifier
.padding(
horizontal = 16.dp,
vertical = 12.dp
)
.fillMaxSize()
.focusRequester(focusRequester)
)
}

if(value.text.isEmpty()) {
BasicText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
Expand All @@ -42,6 +43,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.farmerbb.notepad.R
import com.farmerbb.notepad.model.NoteMetadata
import com.farmerbb.notepad.ui.components.RtlTextWrapper
import com.farmerbb.notepad.ui.previews.NoteListPreview
import com.farmerbb.notepad.utils.safeGetOrDefault
import java.text.DateFormat
Expand All @@ -58,10 +60,11 @@ fun NoteListContent(
textStyle: TextStyle = TextStyle(),
dateStyle: TextStyle = TextStyle(),
showDate: Boolean = false,
rtlLayout: Boolean = false,
onNoteLongClick: (Long) -> Unit = {},
onNoteClick: (Long) -> Unit = {}
) {
when(notes.size) {
when (notes.size) {
0 -> Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
Expand Down Expand Up @@ -89,21 +92,24 @@ fun NoteListContent(
onLongClick = { onNoteLongClick(note.metadataId) }
)
) {
BasicText(
text = note.title,
style = textStyle,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.padding(
start = 16.dp,
end = 16.dp,
top = if(showDate) 8.dp else 12.dp,
bottom = if(showDate) 0.dp else 12.dp
)
)
RtlTextWrapper(note.title, rtlLayout) {
BasicText(
text = note.title,
style = textStyle,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.fillMaxWidth()
.padding(
start = 16.dp,
end = 16.dp,
top = if (showDate) 8.dp else 12.dp,
bottom = if (showDate) 0.dp else 12.dp
)
)
}

if(showDate) {
if (showDate) {
BasicText(
text = note.date.noteListFormat,
style = dateStyle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.farmerbb.notepad.R
import com.farmerbb.notepad.ui.components.RtlTextWrapper
import com.farmerbb.notepad.ui.previews.ViewNotePreview
import com.halilibo.richtext.markdown.Markdown
import com.halilibo.richtext.ui.RichText
Expand All @@ -52,6 +53,7 @@ fun ViewNoteContent(
text: String,
baseTextStyle: TextStyle = TextStyle(),
markdown: Boolean = false,
rtlLayout: Boolean = false,
isPrinting: Boolean = false,
showDoubleTapMessage: Boolean = false,
doubleTapMessageShown: () -> Unit = {},
Expand Down Expand Up @@ -89,47 +91,49 @@ fun ViewNoteContent(
)
.fillMaxWidth()

SelectionContainer {
if (markdown) {
val localTextStyle = compositionLocalOf {
textStyle.copy(color = Color.Unspecified)
}
val localContentColor = compositionLocalOf {
textStyle.color
}

RichTextThemeIntegration(
textStyle = { localTextStyle.current },
contentColor = { localContentColor.current },
ProvideTextStyle = { textStyle, content ->
CompositionLocalProvider(
localTextStyle provides textStyle,
content = content
)
},
ProvideContentColor = { color, content ->
CompositionLocalProvider(
localContentColor provides color,
content = content
)
RtlTextWrapper(text, rtlLayout) {
SelectionContainer {
if (markdown) {
val localTextStyle = compositionLocalOf {
textStyle.copy(color = Color.Unspecified)
}
) {
RichText(modifier = modifier) {
Markdown(
// Replace markdown images with links
text.replace(Regex("!\\[([^\\[]+)](\\(.*\\))")) {
it.value.replaceFirst("![", "[")
}
)
val localContentColor = compositionLocalOf {
textStyle.color
}

RichTextThemeIntegration(
textStyle = { localTextStyle.current },
contentColor = { localContentColor.current },
ProvideTextStyle = { textStyle, content ->
CompositionLocalProvider(
localTextStyle provides textStyle,
content = content
)
},
ProvideContentColor = { color, content ->
CompositionLocalProvider(
localContentColor provides color,
content = content
)
}
) {
RichText(modifier = modifier) {
Markdown(
// Replace markdown images with links
text.replace(Regex("!\\[([^\\[]+)](\\(.*\\))")) {
it.value.replaceFirst("![", "[")
}
)
}
}
} else {
LinkifyText(
text = text,
style = textStyle,
linkColor = colorResource(id = R.color.primary),
modifier = modifier
)
}
} else {
LinkifyText(
text = text,
style = textStyle,
linkColor = colorResource(id = R.color.primary),
modifier = modifier
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ fun NotepadPreferenceScreen(
),
SwitchPreference(
request = Prefs.RtlSupport,
title = stringResource(id = R.string.rtl_support),
title = stringResource(id = R.string.rtl_layout),
singleLineTitle = false
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fun NotepadComposeAppRoute() {

val isLightTheme by vm.prefs.isLightTheme.collectAsState()
val backgroundColorRes by vm.prefs.backgroundColorRes.collectAsState()
val rtlSupport by vm.prefs.rtlSupport.collectAsState()
val rtlLayout by vm.prefs.rtlLayout.collectAsState()
val draftId by vm.savedDraftId.collectAsState()

LaunchedEffect(Unit) {
Expand All @@ -112,7 +112,7 @@ fun NotepadComposeAppRoute() {

if (draftId == null) return

NotepadTheme(isLightTheme, backgroundColorRes, rtlSupport) {
NotepadTheme(isLightTheme, backgroundColorRes, rtlLayout) {
NotepadComposeApp(
vm = vm,
isMultiPane = configuration.screenWidthDp >= 600,
Expand Down Expand Up @@ -149,6 +149,7 @@ private fun NotepadComposeApp(
val directEdit by vm.prefs.directEdit.collectAsState()
val filenameFormat by vm.prefs.filenameFormat.collectAsState()
val showDialogs by vm.prefs.showDialogs.collectAsState()
val rtlLayout by vm.prefs.rtlLayout.collectAsState()
val firstRunComplete by vm.prefs.firstRunComplete.collectAsState()
val firstViewComplete by vm.prefs.firstViewComplete.collectAsState()
val showDoubleTapMessage by vm.prefs.showDoubleTapMessage.collectAsState()
Expand Down Expand Up @@ -369,6 +370,7 @@ private fun NotepadComposeApp(
textStyle = textStyle,
dateStyle = dateStyle,
showDate = showDate,
rtlLayout = rtlLayout,
onNoteLongClick = { id ->
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
multiSelectEnabled = true
Expand Down Expand Up @@ -501,6 +503,7 @@ private fun NotepadComposeApp(
text = note.text,
baseTextStyle = textStyle,
markdown = markdown,
rtlLayout = rtlLayout,
isPrinting = isPrinting,
showDoubleTapMessage = showDoubleTapMessage,
doubleTapMessageShown = vm::doubleTapMessageShown
Expand Down Expand Up @@ -549,6 +552,7 @@ private fun NotepadComposeApp(
isLightTheme = isLightTheme,
isPrinting = isPrinting,
waitForAnimation = note.id == -1L || directEdit,
rtlLayout = rtlLayout,
onTextChanged = vm::setText
)
}
Expand Down
Loading

0 comments on commit 6c17c69

Please sign in to comment.