mirror of
https://github.com/mihonapp/mihon.git
synced 2024-12-28 11:58:24 +01:00
Abandon markdown for rich text
Thank you Syer10 for recommending this library - Already built component for elegant rich text editing - Adds a dependency, could possibly remove another (NewUpdateScreen.kt's markdown viewer)
This commit is contained in:
parent
7f7177f597
commit
6dbc9efa17
@ -233,6 +233,7 @@ dependencies {
|
||||
}
|
||||
implementation(libs.insetter)
|
||||
implementation(libs.bundles.richtext)
|
||||
implementation(libs.richeditor.compose)
|
||||
implementation(libs.aboutLibraries.compose)
|
||||
implementation(libs.bundles.voyager)
|
||||
implementation(libs.compose.materialmotion)
|
||||
|
@ -1,52 +1,28 @@
|
||||
package eu.kanade.presentation.manga
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.EditNote
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import com.halilibo.richtext.markdown.Markdown
|
||||
import com.halilibo.richtext.ui.RichTextStyle
|
||||
import com.halilibo.richtext.ui.material3.RichText
|
||||
import com.halilibo.richtext.ui.string.RichTextStringStyle
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.AppBarTitle
|
||||
import eu.kanade.presentation.manga.components.MangaNotesTextArea
|
||||
import eu.kanade.tachiyomi.ui.manga.notes.MangaNotesScreenState
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.EmptyScreenAction
|
||||
|
||||
@Composable
|
||||
fun MangaNotesScreen(
|
||||
state: MangaNotesScreenState.Success,
|
||||
navigateUp: () -> Unit,
|
||||
beginEditing: () -> Unit,
|
||||
endEditing: () -> Unit,
|
||||
onSave: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@ -60,98 +36,22 @@ fun MangaNotesScreen(
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(
|
||||
true,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
modifier = Modifier
|
||||
.imePadding(),
|
||||
) {
|
||||
ExtendedFloatingActionButton(
|
||||
text = {
|
||||
Text(
|
||||
text = stringResource(
|
||||
if (state.editing) MR.strings.action_apply else MR.strings.action_edit,
|
||||
),
|
||||
)
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = if (state.editing) Icons.Filled.Check else Icons.Filled.Edit,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
onClick = { if (state.editing) endEditing() else beginEditing() },
|
||||
expanded = true,
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = modifier
|
||||
.imePadding(),
|
||||
) { paddingValues ->
|
||||
AnimatedVisibility(
|
||||
state.editing,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
MangaNotesTextArea(
|
||||
state = state,
|
||||
onSave = onSave,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding() + MaterialTheme.padding.small,
|
||||
bottom = MaterialTheme.padding.small,
|
||||
)
|
||||
.padding(horizontal = MaterialTheme.padding.small)
|
||||
.windowInsetsPadding(
|
||||
WindowInsets.navigationBars
|
||||
.only(WindowInsetsSides.Bottom),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
!state.editing && state.notes.isNullOrBlank(),
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
EmptyScreen(
|
||||
stringRes = MR.strings.information_no_notes,
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
actions = persistentListOf(
|
||||
EmptyScreenAction(
|
||||
MR.strings.action_add_notes,
|
||||
Icons.Filled.EditNote,
|
||||
beginEditing,
|
||||
),
|
||||
MangaNotesTextArea(
|
||||
state = state,
|
||||
onSave = onSave,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
top = paddingValues.calculateTopPadding() + MaterialTheme.padding.small,
|
||||
bottom = MaterialTheme.padding.small,
|
||||
)
|
||||
.padding(horizontal = MaterialTheme.padding.small)
|
||||
.windowInsetsPadding(
|
||||
WindowInsets.navigationBars
|
||||
.only(WindowInsetsSides.Bottom),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
!state.editing && !state.notes.isNullOrBlank(),
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
SelectionContainer {
|
||||
RichText(
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState())
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = MaterialTheme.padding.medium,
|
||||
vertical = paddingValues.calculateTopPadding() + MaterialTheme.padding.medium,
|
||||
),
|
||||
style = RichTextStyle(
|
||||
stringStyle = RichTextStringStyle(
|
||||
linkStyle = SpanStyle(color = MaterialTheme.colorScheme.primary),
|
||||
),
|
||||
),
|
||||
) {
|
||||
Markdown(content = state.notes.orEmpty())
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,6 @@ fun MangaScreen(
|
||||
onEditFetchIntervalClicked: (() -> Unit)?,
|
||||
onMigrateClicked: (() -> Unit)?,
|
||||
onNotesClicked: () -> Unit,
|
||||
onNotesEditClicked: () -> Unit,
|
||||
|
||||
// For bottom action menu
|
||||
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
|
||||
@ -163,7 +162,6 @@ fun MangaScreen(
|
||||
onEditIntervalClicked = onEditFetchIntervalClicked,
|
||||
onMigrateClicked = onMigrateClicked,
|
||||
onNotesClicked = onNotesClicked,
|
||||
onNotesEditClicked = onNotesEditClicked,
|
||||
onMultiBookmarkClicked = onMultiBookmarkClicked,
|
||||
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
|
||||
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
|
||||
@ -200,7 +198,6 @@ fun MangaScreen(
|
||||
onEditIntervalClicked = onEditFetchIntervalClicked,
|
||||
onMigrateClicked = onMigrateClicked,
|
||||
onNotesClicked = onNotesClicked,
|
||||
onNotesEditClicked = onNotesEditClicked,
|
||||
onMultiBookmarkClicked = onMultiBookmarkClicked,
|
||||
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
|
||||
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
|
||||
@ -247,7 +244,6 @@ private fun MangaScreenSmallImpl(
|
||||
onEditIntervalClicked: (() -> Unit)?,
|
||||
onMigrateClicked: (() -> Unit)?,
|
||||
onNotesClicked: () -> Unit,
|
||||
onNotesEditClicked: () -> Unit,
|
||||
|
||||
// For bottom action menu
|
||||
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
|
||||
@ -428,7 +424,7 @@ private fun MangaScreenSmallImpl(
|
||||
noteContent = state.manga.notes,
|
||||
onTagSearch = onTagSearch,
|
||||
onCopyTagToClipboard = onCopyTagToClipboard,
|
||||
onClickNotes = onNotesEditClicked,
|
||||
onClickNotes = onNotesClicked,
|
||||
)
|
||||
}
|
||||
|
||||
@ -498,7 +494,6 @@ fun MangaScreenLargeImpl(
|
||||
onEditIntervalClicked: (() -> Unit)?,
|
||||
onMigrateClicked: (() -> Unit)?,
|
||||
onNotesClicked: () -> Unit,
|
||||
onNotesEditClicked: () -> Unit,
|
||||
|
||||
// For bottom action menu
|
||||
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
|
||||
@ -659,7 +654,7 @@ fun MangaScreenLargeImpl(
|
||||
noteContent = state.manga.notes,
|
||||
onTagSearch = onTagSearch,
|
||||
onCopyTagToClipboard = onCopyTagToClipboard,
|
||||
onClickNotes = onNotesEditClicked,
|
||||
onClickNotes = onNotesClicked,
|
||||
)
|
||||
}
|
||||
},
|
||||
|
@ -0,0 +1,28 @@
|
||||
package eu.kanade.presentation.manga.components
|
||||
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.mohamedrejeb.richeditor.annotation.ExperimentalRichTextApi
|
||||
import com.mohamedrejeb.richeditor.model.rememberRichTextState
|
||||
import com.mohamedrejeb.richeditor.ui.material3.RichText
|
||||
|
||||
@OptIn(ExperimentalRichTextApi::class)
|
||||
@Composable
|
||||
fun MangaNotesDisplay(
|
||||
content: String,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
val richTextState = rememberRichTextState().setHtml(html = content)
|
||||
richTextState.config.linkColor = MaterialTheme.colorScheme.primary
|
||||
richTextState.config.listIndent = 15
|
||||
|
||||
SelectionContainer {
|
||||
RichText(
|
||||
modifier = modifier,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
state = richTextState,
|
||||
)
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.EditNote
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
@ -25,13 +24,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.halilibo.richtext.markdown.Markdown
|
||||
import com.halilibo.richtext.ui.RichTextStyle
|
||||
import com.halilibo.richtext.ui.material3.RichText
|
||||
import com.halilibo.richtext.ui.string.RichTextStringStyle
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Button
|
||||
import tachiyomi.presentation.core.components.material.ButtonDefaults
|
||||
@ -50,19 +44,10 @@ fun MangaNotesSection(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
if (!content.isNullOrBlank()) {
|
||||
SelectionContainer {
|
||||
RichText(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
style = RichTextStyle(
|
||||
stringStyle = RichTextStringStyle(
|
||||
linkStyle = SpanStyle(color = MaterialTheme.colorScheme.primary),
|
||||
),
|
||||
),
|
||||
) {
|
||||
Markdown(content = content)
|
||||
}
|
||||
}
|
||||
MangaNotesDisplay(
|
||||
content = content,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = expanded,
|
||||
|
@ -1,26 +1,52 @@
|
||||
package eu.kanade.presentation.manga.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.isImeVisible
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.FormatListBulleted
|
||||
import androidx.compose.material.icons.outlined.FormatBold
|
||||
import androidx.compose.material.icons.outlined.FormatItalic
|
||||
import androidx.compose.material.icons.outlined.FormatListNumbered
|
||||
import androidx.compose.material.icons.outlined.FormatSize
|
||||
import androidx.compose.material.icons.outlined.FormatUnderlined
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.mohamedrejeb.richeditor.model.rememberRichTextState
|
||||
import com.mohamedrejeb.richeditor.ui.material3.RichTextEditor
|
||||
import eu.kanade.tachiyomi.ui.manga.notes.MangaNotesScreenState
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
|
||||
private const val MAX_LENGTH = 10_000
|
||||
|
||||
@ -30,49 +56,135 @@ fun MangaNotesTextArea(
|
||||
onSave: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var text by remember {
|
||||
mutableStateOf(TextFieldValue(state.notes.orEmpty(), TextRange(Int.MAX_VALUE)))
|
||||
}
|
||||
val richTextState = rememberRichTextState()
|
||||
richTextState.config.linkColor = MaterialTheme.colorScheme.primary
|
||||
richTextState.config.listIndent = 15
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
Box(
|
||||
val largeFontSize = MaterialTheme.typography.headlineMedium.fontSize
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = text,
|
||||
onValueChange = { if (it.text.length <= MAX_LENGTH) text = it },
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.focusRequester(focusRequester),
|
||||
supportingText = {
|
||||
val displayWarning = text.text.length > MAX_LENGTH / 10 * 9
|
||||
if (!displayWarning) {
|
||||
Text(
|
||||
text = "0",
|
||||
modifier = Modifier.alpha(0f),
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
displayWarning,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
Text(
|
||||
text = "${text.text.length} / $MAX_LENGTH",
|
||||
)
|
||||
}
|
||||
RichTextEditor(
|
||||
state = richTextState,
|
||||
textStyle = MaterialTheme.typography.bodyMedium,
|
||||
maxLength = MAX_LENGTH,
|
||||
placeholder = {
|
||||
Text(text = stringResource(MR.strings.notes_placeholder))
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequester),
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = WindowInsets.isImeVisible,
|
||||
) {
|
||||
LazyRow(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp),
|
||||
) {
|
||||
item {
|
||||
SlackDemoPanelButton(
|
||||
onClick = { richTextState.toggleSpanStyle(SpanStyle(fontWeight = FontWeight.Bold)) },
|
||||
isSelected = richTextState.currentSpanStyle.fontWeight == FontWeight.Bold,
|
||||
icon = Icons.Outlined.FormatBold,
|
||||
)
|
||||
}
|
||||
item {
|
||||
SlackDemoPanelButton(
|
||||
onClick = { richTextState.toggleSpanStyle(SpanStyle(fontStyle = FontStyle.Italic)) },
|
||||
isSelected = richTextState.currentSpanStyle.fontStyle == FontStyle.Italic,
|
||||
icon = Icons.Outlined.FormatItalic,
|
||||
)
|
||||
}
|
||||
item {
|
||||
SlackDemoPanelButton(
|
||||
onClick = {
|
||||
richTextState.toggleSpanStyle(SpanStyle(textDecoration = TextDecoration.Underline))
|
||||
},
|
||||
isSelected =
|
||||
richTextState.currentSpanStyle.textDecoration?.contains(TextDecoration.Underline) == true,
|
||||
icon = Icons.Outlined.FormatUnderlined,
|
||||
)
|
||||
}
|
||||
item {
|
||||
VerticalDivider(
|
||||
modifier = Modifier
|
||||
.height(24.dp),
|
||||
)
|
||||
}
|
||||
item {
|
||||
SlackDemoPanelButton(
|
||||
onClick = { richTextState.toggleUnorderedList() },
|
||||
isSelected = richTextState.isUnorderedList,
|
||||
icon = Icons.AutoMirrored.Outlined.FormatListBulleted,
|
||||
)
|
||||
}
|
||||
item {
|
||||
SlackDemoPanelButton(
|
||||
onClick = { richTextState.toggleOrderedList() },
|
||||
isSelected = richTextState.isOrderedList,
|
||||
icon = Icons.Outlined.FormatListNumbered,
|
||||
)
|
||||
}
|
||||
item {
|
||||
VerticalDivider(
|
||||
modifier = Modifier
|
||||
.height(24.dp),
|
||||
)
|
||||
}
|
||||
item {
|
||||
SlackDemoPanelButton(
|
||||
onClick = { richTextState.toggleSpanStyle(SpanStyle(fontSize = largeFontSize)) },
|
||||
isSelected = richTextState.currentSpanStyle.fontSize == largeFontSize,
|
||||
icon = Icons.Outlined.FormatSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(focusRequester) {
|
||||
state.notes?.let { richTextState.setHtml(it) }
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
onSave(text.text)
|
||||
onSave(richTextState.toHtml())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SlackDemoPanelButton(
|
||||
onClick: () -> Unit,
|
||||
icon: ImageVector,
|
||||
isSelected: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.clickable(
|
||||
onClick = onClick,
|
||||
enabled = true,
|
||||
role = Role.Button,
|
||||
),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
icon,
|
||||
contentDescription = icon.name,
|
||||
tint = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier
|
||||
.background(color = if (isSelected) MaterialTheme.colorScheme.onBackground else Color.Transparent)
|
||||
.padding(6.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,6 @@ class MangaScreen(
|
||||
navigator.push(MigrateSearchScreen(successState.manga.id))
|
||||
}.takeIf { successState.manga.favorite },
|
||||
onNotesClicked = { navigator.push(MangaNotesScreen(manga = successState.manga)) },
|
||||
onNotesEditClicked = { navigator.push(MangaNotesScreen(manga = successState.manga, editing = true)) },
|
||||
onMultiBookmarkClicked = screenModel::bookmarkChapters,
|
||||
onMultiMarkAsReadClicked = screenModel::markChaptersRead,
|
||||
onMarkPreviousAsReadClicked = screenModel::markPreviousChapterRead,
|
||||
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.notes
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -14,7 +13,6 @@ import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class MangaNotesScreen(
|
||||
private val manga: Manga,
|
||||
private val editing: Boolean = false,
|
||||
) : Screen() {
|
||||
@Composable
|
||||
override fun Content() {
|
||||
@ -23,7 +21,6 @@ class MangaNotesScreen(
|
||||
val screenModel = rememberScreenModel {
|
||||
MangaNotesScreenModel(
|
||||
manga = manga,
|
||||
editing = editing,
|
||||
)
|
||||
}
|
||||
val state by screenModel.state.collectAsState()
|
||||
@ -35,22 +32,9 @@ class MangaNotesScreen(
|
||||
|
||||
val successState = state as MangaNotesScreenState.Success
|
||||
|
||||
BackHandler(
|
||||
onBack = {
|
||||
if (!successState.editing) {
|
||||
navigator.pop()
|
||||
return@BackHandler
|
||||
}
|
||||
|
||||
screenModel.endEditing()
|
||||
},
|
||||
)
|
||||
|
||||
MangaNotesScreen(
|
||||
state = successState,
|
||||
navigateUp = navigator::pop,
|
||||
beginEditing = { screenModel.beginEditing() },
|
||||
endEditing = { screenModel.endEditing() },
|
||||
onSave = { screenModel.saveText(it) },
|
||||
)
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import uy.kohesive.injekt.api.get
|
||||
|
||||
class MangaNotesScreenModel(
|
||||
val manga: Manga,
|
||||
editing: Boolean,
|
||||
private val setMangaNotes: SetMangaNotes = Injekt.get(),
|
||||
) : StateScreenModel<MangaNotesScreenState>(MangaNotesScreenState.Loading) {
|
||||
|
||||
@ -24,29 +23,10 @@ class MangaNotesScreenModel(
|
||||
MangaNotesScreenState.Success(
|
||||
manga = manga,
|
||||
notes = manga.notes,
|
||||
editing = editing,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun beginEditing() {
|
||||
mutableState.update {
|
||||
when (it) {
|
||||
MangaNotesScreenState.Loading -> it
|
||||
is MangaNotesScreenState.Success -> it.copy(editing = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun endEditing() {
|
||||
mutableState.update {
|
||||
when (it) {
|
||||
MangaNotesScreenState.Loading -> it
|
||||
is MangaNotesScreenState.Success -> it.copy(editing = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun saveText(content: String) {
|
||||
// don't save what isn't modified
|
||||
if (content == successState?.notes) return
|
||||
@ -75,7 +55,5 @@ sealed interface MangaNotesScreenState {
|
||||
data class Success(
|
||||
val manga: Manga,
|
||||
val notes: String?,
|
||||
|
||||
val editing: Boolean = false,
|
||||
) : MangaNotesScreenState
|
||||
}
|
||||
|
@ -56,6 +56,8 @@ natural-comparator = "com.github.gpanther:java-nat-sort:natural-comparator-1.1"
|
||||
richtext-commonmark = { module = "com.halilibo.compose-richtext:richtext-commonmark", version.ref = "richtext" }
|
||||
richtext-m3 = { module = "com.halilibo.compose-richtext:richtext-ui-material3", version.ref = "richtext" }
|
||||
|
||||
richeditor-compose = "com.mohamedrejeb.richeditor:richeditor-compose:1.0.0-rc06"
|
||||
|
||||
material = "com.google.android.material:material:1.12.0"
|
||||
flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013533"
|
||||
photoview = "com.github.chrisbanes:PhotoView:2.3.0"
|
||||
|
@ -146,9 +146,9 @@
|
||||
<string name="action_move_to_top_all_for_series">Move series to top</string>
|
||||
<string name="action_move_to_bottom">Move to bottom</string>
|
||||
<string name="action_move_to_bottom_all_for_series">Move series to bottom</string>
|
||||
<string name="action_notes">Notes</string>
|
||||
<string name="action_add_notes">Add Notes</string>
|
||||
<string name="action_edit_notes">Edit Notes</string>
|
||||
<string name="action_notes">Note</string>
|
||||
<string name="action_add_notes">Add Note</string>
|
||||
<string name="action_edit_notes">Edit Note</string>
|
||||
<string name="action_install">Install</string>
|
||||
<string name="action_share">Share</string>
|
||||
<string name="action_save">Save</string>
|
||||
@ -915,7 +915,7 @@
|
||||
<string name="information_cloudflare_bypass_failure">Failed to bypass Cloudflare</string>
|
||||
<string name="information_cloudflare_help">Tap here for help with Cloudflare</string>
|
||||
<string name="information_required_plain">*required</string>
|
||||
<string name="information_no_notes">There are no notes here yet!</string>
|
||||
<string name="information_no_notes">No notes</string>
|
||||
<!-- Do not translate "WebView" -->
|
||||
<string name="information_webview_required">WebView is required for the app to function</string>
|
||||
<!-- Do not translate "WebView" -->
|
||||
@ -956,4 +956,7 @@
|
||||
<string name="exception_http">HTTP %d, check website in WebView</string>
|
||||
<string name="exception_offline">No Internet connection</string>
|
||||
<string name="exception_unknown_host">Couldn\'t reach %s</string>
|
||||
|
||||
<!-- Notes screen -->
|
||||
<string name="notes_placeholder">My analysis of the story begins with ontological antirealism, that is to say...</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user