From d61c3916f972d7ea39c178859a2f41d0c32a49c8 Mon Sep 17 00:00:00 2001 From: Stefano Sansone Date: Mon, 24 Jun 2024 01:25:31 +0200 Subject: [PATCH 1/2] add right to left text support --- .../core/datastore/DataStoreConstants.kt | 1 + ...encesView.kt => ReaderPreferencesSheet.kt} | 9 ++++- .../omnivore/feature/reader/WebReader.kt | 1 + .../feature/reader/WebReaderContent.kt | 34 +++++++++++-------- .../reader/WebReaderLoadingContainer.kt | 8 +++-- .../feature/reader/WebReaderViewModel.kt | 15 ++++++++ .../app/src/main/res/values/strings.xml | 1 + 7 files changed, 51 insertions(+), 18 deletions(-) rename android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/{ReaderPreferencesView.kt => ReaderPreferencesSheet.kt} (97%) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/datastore/DataStoreConstants.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/datastore/DataStoreConstants.kt index d3b9908de..284ff0452 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/datastore/DataStoreConstants.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/core/datastore/DataStoreConstants.kt @@ -18,3 +18,4 @@ const val lastUsedSavedItemSortFilter = "lastUsedSavedItemSortFilter" const val preferredTheme = "preferredTheme" const val followingTabActive = "followingTabActive" const val volumeForScroll = "volumeForScroll" +const val rtlText = "rtlText" diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/ReaderPreferencesView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/ReaderPreferencesSheet.kt similarity index 97% rename from android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/ReaderPreferencesView.kt rename to android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/ReaderPreferencesSheet.kt index 21795f4a4..d5ce7ce3c 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/ReaderPreferencesView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/ReaderPreferencesSheet.kt @@ -46,7 +46,7 @@ import app.omnivore.omnivore.feature.components.SliderWithPlusMinus import app.omnivore.omnivore.feature.theme.OmnivoreTheme @Composable -fun ReaderPreferencesView( +fun ReaderPreferencesSheet( webReaderViewModel: WebReaderViewModel ) { val isDark = isSystemInDarkTheme() @@ -74,6 +74,8 @@ fun ReaderPreferencesView( val volumeForScrollState by webReaderViewModel.volumeRockerForScrollState.collectAsStateWithLifecycle() + val rtlTextState by webReaderViewModel.rtlTextState.collectAsStateWithLifecycle() + OmnivoreTheme { // Temporary wrapping for margin while migrating components to design system Column( @@ -282,6 +284,11 @@ fun ReaderPreferencesView( checked = volumeForScrollState, onCheckedChanged = { webReaderViewModel.setVolumeRockerForScrollState(it) }, ) + SwitchPreferenceWidget( + title = stringResource(R.string.reader_preferences_view_use_rtl), + checked = rtlTextState, + onCheckedChanged = { webReaderViewModel.setRtlTextState(it) }, + ) } } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReader.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReader.kt index cc3977e2b..a194c0728 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReader.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReader.kt @@ -168,6 +168,7 @@ fun WebReader( "utf-8", null ) + Log.d("HTMLContent", styledContent) requestFocus() setOnKeyListener { _, keyCode, event -> if (event.action == KeyEvent.ACTION_DOWN) { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderContent.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderContent.kt index 67f3e0fcf..1cd148d25 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderContent.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderContent.kt @@ -7,32 +7,25 @@ import com.google.gson.Gson enum class WebFont(val displayText: String, val rawValue: String) { INTER("Inter", "Inter"), SYSTEM("System Default", "system-ui"), OPEN_DYSLEXIC( - "Open Dyslexic", - "OpenDyslexic" + "Open Dyslexic", "OpenDyslexic" ), MERRIWEATHER("Merriweather", "Merriweather"), LORA("Lora", "Lora"), OPEN_SANS( - "Open Sans", - "Open Sans" + "Open Sans", "Open Sans" ), ROBOTO("Roboto", "Roboto"), CRIMSON_TEXT( - "Crimson Text", - "Crimson Text" + "Crimson Text", "Crimson Text" ), SOURCE_SERIF_PRO("Source Serif Pro", "Source Serif Pro"), NEWSREADER( - "Newsreader", - "Newsreader" + "Newsreader", "Newsreader" ), LEXEND("Lexend", "Lexend"), LXGWWENKAI( - "LXGW WenKai", - "LXGWWenKai" + "LXGW WenKai", "LXGWWenKai" ), ATKINSON_HYPERLEGIBLE( - "Atkinson Hyperlegible", - "AtkinsonHyperlegible" + "Atkinson Hyperlegible", "AtkinsonHyperlegible" ), SOURCE_SANS_PRO("Source Sans Pro", "SourceSansPro"), IBM_PLEX_SANS( - "IBM Plex Sans", - "IBMPlexSans" + "IBM Plex Sans", "IBMPlexSans" ), LITERATA("Literata", "Literata"), FRAUNCES("Fraunces", "Fraunces"), } @@ -55,6 +48,7 @@ data class ArticleContent( data class WebReaderContent( val preferences: WebPreferences, + val rtlText: Boolean, val item: SavedItem, val articleContent: ArticleContent, ) { @@ -68,6 +62,17 @@ data class WebReaderContent( val highlightCssFilePath = "highlight${if (preferences.themeKey == "Dark" || preferences.themeKey == "Black") "-dark" else ""}.css" + val rtlCss = if (rtlText) { + """ + body, html, #_omnivore-htmlContent, p, a, div, span { + direction: rtl; + text-align: right; + } + """ + } else { + "" + } + Log.d("theme", "current theme is: ${preferences.themeKey}") Log.d("sync", "HIGHLIGHTS JSON: ${articleContent.highlightsJSONString()}") @@ -80,6 +85,7 @@ data class WebReaderContent( diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderLoadingContainer.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderLoadingContainer.kt index 5ff5cf65f..6d10560a2 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderLoadingContainer.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderLoadingContainer.kt @@ -161,20 +161,22 @@ fun WebReaderLoadingContainer( val darkTheme = isSystemInDarkTheme() + val rtlTextState by webReaderViewModel.rtlTextState.collectAsStateWithLifecycle() + val styledContent by remember { derivedStateOf { webReaderParams?.let { val webReaderContent = WebReaderContent( preferences = webReaderViewModel.storedWebPreferences(darkTheme), + rtlText = rtlTextState, item = it.item, - articleContent = it.articleContent, + articleContent = it.articleContent ) webReaderContent.styledContent() } } } - val modalBottomSheetState = rememberModalBottomSheetState( initialValue = ModalBottomSheetValue.Hidden, skipHalfExpanded = bottomSheetState == BottomSheetState.EDITNOTE || bottomSheetState == BottomSheetState.HIGHLIGHTNOTE, @@ -217,7 +219,7 @@ fun WebReaderLoadingContainer( when (bottomSheetState) { BottomSheetState.PREFERENCES -> { BottomSheetUI { - ReaderPreferencesView(webReaderViewModel) + ReaderPreferencesSheet(webReaderViewModel) } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderViewModel.kt index abdb71073..3595cc2c9 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/reader/WebReaderViewModel.kt @@ -32,6 +32,7 @@ import app.omnivore.omnivore.core.datastore.preferredWebLineHeight import app.omnivore.omnivore.core.datastore.preferredWebMaxWidthPercentage import app.omnivore.omnivore.core.datastore.prefersJustifyText import app.omnivore.omnivore.core.datastore.prefersWebHighContrastText +import app.omnivore.omnivore.core.datastore.rtlText import app.omnivore.omnivore.core.datastore.volumeForScroll import app.omnivore.omnivore.core.network.Networker import app.omnivore.omnivore.core.network.createNewLabel @@ -132,6 +133,14 @@ class WebReaderViewModel @Inject constructor( } } + val rtlTextState: StateFlow = datastoreRepository.getBoolean( + rtlText + ).stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = false + ) + fun showNavBar() { onScrollChange(maxToolbarHeightPx) } @@ -581,6 +590,12 @@ class WebReaderViewModel @Inject constructor( } } + fun setRtlTextState(value: Boolean) { + viewModelScope.launch { + datastoreRepository.putBoolean(rtlText, value) + } + } + fun applyWebFont(font: WebFont) { runBlocking { datastoreRepository.putString(preferredWebFontFamily, font.rawValue) diff --git a/android/Omnivore/app/src/main/res/values/strings.xml b/android/Omnivore/app/src/main/res/values/strings.xml index 4bb7e948f..0f702f691 100644 --- a/android/Omnivore/app/src/main/res/values/strings.xml +++ b/android/Omnivore/app/src/main/res/values/strings.xml @@ -154,6 +154,7 @@ High Contrast Text Justify Text Use Volume Rocker to scroll + Right-to-left text We were unable to fetch your content. From b3358333cc1f143ecbe9580455bbd9f1b4edf529 Mon Sep 17 00:00:00 2001 From: Stefano Sansone Date: Mon, 24 Jun 2024 01:54:14 +0200 Subject: [PATCH 2/2] align saved card items --- .../omnivore/feature/library/LibraryView.kt | 5 --- .../omnivore/feature/library/SearchView.kt | 6 --- .../feature/savedItemViews/SavedItemCard.kt | 43 +++++++++---------- 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryView.kt index f619d0dbf..6240d8d71 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibraryView.kt @@ -473,11 +473,6 @@ fun LibraryViewContent( val intent = Intent(context, activityClass) intent.putExtra("SAVED_ITEM_SLUG", currentItem.slug) context.startActivity(intent) - }, - actionHandler = { - onSavedItemAction( - currentItem.savedItemId, it - ) }) }, ) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/SearchView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/SearchView.kt index 5b18aae4f..d7a63dfcc 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/SearchView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/SearchView.kt @@ -214,12 +214,6 @@ fun SearchViewContent(viewModel: SearchViewModel, modifier: Modifier) { val intent = Intent(context, activityClass) intent.putExtra("SAVED_ITEM_SLUG", cardDataWithLabels.savedItem.slug) context.startActivity(intent) - }, - actionHandler = { - viewModel.handleSavedItemAction( - cardDataWithLabels.savedItem.savedItemId, - it - ) } ) } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/savedItemViews/SavedItemCard.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/savedItemViews/SavedItemCard.kt index 134cb9bed..21d38cd7e 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/savedItemViews/SavedItemCard.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/savedItemViews/SavedItemCard.kt @@ -38,7 +38,6 @@ import app.omnivore.omnivore.core.database.entities.SavedItemLabel import app.omnivore.omnivore.core.database.entities.SavedItemWithLabelsAndHighlights import app.omnivore.omnivore.feature.components.LabelChip import app.omnivore.omnivore.feature.components.LabelChipColors -import app.omnivore.omnivore.feature.library.SavedItemAction import app.omnivore.omnivore.feature.library.SavedItemViewModel import coil.compose.rememberAsyncImagePainter @@ -48,10 +47,10 @@ fun SavedItemCard( selected: Boolean, savedItemViewModel: SavedItemViewModel, savedItem: SavedItemWithLabelsAndHighlights, - onClickHandler: () -> Unit, - actionHandler: (SavedItemAction) -> Unit + onClickHandler: () -> Unit ) { Column( + verticalArrangement = Arrangement.Center, modifier = Modifier .combinedClickable(onClick = onClickHandler, onLongClick = { savedItemViewModel.actionsMenuItemLiveData.postValue(savedItem) @@ -61,18 +60,17 @@ fun SavedItemCard( ) { Row( horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Top, + verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .padding(10.dp) + .padding(16.dp) .background(Color.Transparent) ) { Column( - verticalArrangement = Arrangement.spacedBy(5.dp), + verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterVertically), modifier = Modifier .weight(1f, fill = false) - .padding(end = 20.dp) .defaultMinSize(minHeight = 50.dp) ) { ReadInfo(item = savedItem) @@ -100,26 +98,27 @@ fun SavedItemCard( painter = rememberAsyncImagePainter(savedItem.savedItem.imageURLString), contentDescription = "Image associated with saved item", modifier = Modifier - .size(55.dp, 73.dp) - .clip(RoundedCornerShape(10.dp)) - .defaultMinSize(minWidth = 55.dp, minHeight = 73.dp) + .size(55.dp, 55.dp) .clip(RoundedCornerShape(10.dp)) + .defaultMinSize(minWidth = 55.dp, minHeight = 55.dp) ) } - FlowRow( - modifier = Modifier - .fillMaxWidth() - .padding(10.dp) - ) { - savedItem.labels.filter { !isFlairLabel(it) } - .sortedWith(compareBy { it.name.toLowerCase(Locale.current) }).forEach { label -> - val chipColors = LabelChipColors.fromHex(label.color) + if (savedItem.labels.any { !isFlairLabel(it) }) { + FlowRow( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, bottom = 16.dp, end = 16.dp) + ) { + savedItem.labels.filter { !isFlairLabel(it) } + .sortedWith(compareBy { it.name.toLowerCase(Locale.current) }).forEach { label -> + val chipColors = LabelChipColors.fromHex(label.color) - LabelChip( - modifier = Modifier.clickable { }, name = label.name, colors = chipColors - ) - } + LabelChip( + modifier = Modifier.clickable { }, name = label.name, colors = chipColors + ) + } + } } HorizontalDivider(thickness = 1.dp, color = MaterialTheme.colorScheme.outlineVariant)