Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Manga Notes #428

Open
wants to merge 41 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
2f7db31
Initial markdown render test
imkunet Feb 18, 2024
cd6432a
Add the text editor
imkunet Feb 18, 2024
9cfb52e
Polishing off note editor
imkunet Feb 19, 2024
d374a52
Added tablet notes
imkunet Feb 19, 2024
d2aca57
Make the edit notes button edit directly
imkunet Feb 19, 2024
4d31f83
Added fade transition between states
imkunet Feb 19, 2024
6dede4f
Make cursor jump to end by default
imkunet Feb 19, 2024
80b45ec
Fixed padding
imkunet Feb 19, 2024
378ad99
Impose note editor length limit
imkunet Feb 20, 2024
4a8566f
Fixes to pass relevant testing
imkunet Mar 5, 2024
37e662d
Add migration to add notes to manga
imkunet Sep 19, 2024
2834aa8
Make spotless
imkunet Sep 19, 2024
d5d9fcc
Design revision
imkunet Sep 19, 2024
45e06ee
Design revision 2
imkunet Sep 19, 2024
0c87a7c
Spotless
imkunet Sep 19, 2024
eb030bf
Abandon markdown for rich text
imkunet Sep 20, 2024
4834887
Rename composable from example name
imkunet Sep 20, 2024
70cd477
Reduce char limit, switch encoding
imkunet Sep 20, 2024
b6983fb
Bump richeditor and fix character count
imkunet Jan 19, 2025
2df33f1
Edit strings
imkunet Jan 19, 2025
df646ae
Resolve strange initialization pattern
imkunet Jan 27, 2025
7ce1bf7
Removed note nullity, tidied up model
imkunet Jan 27, 2025
dbc10a0
Changed strings to review recommendation
imkunet Jan 27, 2025
55d4016
Removed unnecessary code modification
imkunet Jan 27, 2025
062adac
Animate out all bumps caused by updating
imkunet Jan 27, 2025
97b4092
Fix characters remaining indicator
imkunet Jan 27, 2025
31042c7
Update domain/src/main/java/tachiyomi/domain/manga/interactor/SetMang…
imkunet Jan 30, 2025
9586543
Update app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt
imkunet Jan 30, 2025
df0dd5c
Spotless
imkunet Jan 30, 2025
32b639f
Fix awaitSetNotes parameter
imkunet Jan 30, 2025
8f0b459
Put state and model into the screen
imkunet Jan 30, 2025
af1d5ba
Update app/src/main/java/eu/kanade/tachiyomi/ui/manga/notes/MangaNote…
imkunet Jan 30, 2025
468b9ce
Update app/src/main/java/eu/kanade/tachiyomi/ui/manga/notes/MangaNote…
imkunet Jan 30, 2025
5c36cd3
Cleanup MangaNotesDisplay
imkunet Jan 30, 2025
1b57f7f
Idiomatic padding values on MangaNotesScreen
imkunet Feb 7, 2025
2d5ca0c
More explicit function parameter names
imkunet Feb 7, 2025
b6b0179
Manga notes in CHANGELOG
imkunet Feb 7, 2025
5c2e1cb
Even more consistency in names
imkunet Feb 7, 2025
e5cc465
Change names to suggestion
imkunet Feb 13, 2025
d4ba7b4
Refactor to include the names
imkunet Feb 13, 2025
ffe4ff9
Use lambda reference
imkunet Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,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)
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/eu/kanade/domain/DomainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import tachiyomi.domain.manga.interactor.GetMangaWithChapters
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
import tachiyomi.domain.manga.interactor.ResetViewerFlags
import tachiyomi.domain.manga.interactor.SetMangaChapterFlags
import tachiyomi.domain.manga.interactor.SetMangaNotes
import tachiyomi.domain.manga.repository.MangaRepository
import tachiyomi.domain.release.interactor.GetApplicationRelease
import tachiyomi.domain.release.service.ReleaseService
Expand Down Expand Up @@ -124,6 +125,7 @@ class DomainModule : InjektModule {
addFactory { GetUpcomingManga(get()) }
addFactory { ResetViewerFlags(get()) }
addFactory { SetMangaChapterFlags(get()) }
addFactory { SetMangaNotes(get()) }
addFactory { FetchInterval(get()) }
addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) }
addFactory { SetMangaViewerFlags(get()) }
Expand Down
57 changes: 57 additions & 0 deletions app/src/main/java/eu/kanade/presentation/manga/MangaNotesScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package eu.kanade.presentation.manga

import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
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.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
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 tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource

@Composable
fun MangaNotesScreen(
state: MangaNotesScreenState,
navigateUp: () -> Unit,
onSave: (String) -> Unit,
modifier: Modifier = Modifier,
) {
Scaffold(
topBar = { scrollBehavior ->
AppBar(
titleContent = {
AppBarTitle(title = stringResource(MR.strings.action_notes), subtitle = state.manga.title)
},
navigateUp = navigateUp,
scrollBehavior = scrollBehavior,
)
},
modifier = modifier
.imePadding(),
) { paddingValues ->
MangaNotesTextArea(
state = state,
onSave = onSave,
modifier = Modifier
.padding(
top = paddingValues.calculateTopPadding() + MaterialTheme.padding.small,
bottom = MaterialTheme.padding.small,
)
.padding(horizontal = MaterialTheme.padding.small)
imkunet marked this conversation as resolved.
Show resolved Hide resolved
.windowInsetsPadding(
WindowInsets.navigationBars
.only(WindowInsetsSides.Bottom),
),
)
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ fun MangaScreen(
onEditCategoryClicked: (() -> Unit)?,
onEditFetchIntervalClicked: (() -> Unit)?,
onMigrateClicked: (() -> Unit)?,
onNotesClicked: () -> Unit,

// For bottom action menu
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
Expand Down Expand Up @@ -160,6 +161,7 @@ fun MangaScreen(
onEditCategoryClicked = onEditCategoryClicked,
onEditIntervalClicked = onEditFetchIntervalClicked,
onMigrateClicked = onMigrateClicked,
onNotesClicked = onNotesClicked,
onMultiBookmarkClicked = onMultiBookmarkClicked,
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
Expand Down Expand Up @@ -195,6 +197,7 @@ fun MangaScreen(
onEditCategoryClicked = onEditCategoryClicked,
onEditIntervalClicked = onEditFetchIntervalClicked,
onMigrateClicked = onMigrateClicked,
onNotesClicked = onNotesClicked,
onMultiBookmarkClicked = onMultiBookmarkClicked,
onMultiMarkAsReadClicked = onMultiMarkAsReadClicked,
onMarkPreviousAsReadClicked = onMarkPreviousAsReadClicked,
Expand Down Expand Up @@ -240,6 +243,7 @@ private fun MangaScreenSmallImpl(
onEditCategoryClicked: (() -> Unit)?,
onEditIntervalClicked: (() -> Unit)?,
onMigrateClicked: (() -> Unit)?,
onNotesClicked: () -> Unit,

// For bottom action menu
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
Expand Down Expand Up @@ -305,6 +309,7 @@ private fun MangaScreenSmallImpl(
onClickEditCategory = onEditCategoryClicked,
onClickRefresh = onRefresh,
onClickMigrate = onMigrateClicked,
onClickNotes = onNotesClicked,
actionModeCounter = selectedChapterCount,
onSelectAll = { onAllChapterSelected(true) },
onInvertSelection = { onInvertSelection() },
Expand Down Expand Up @@ -414,8 +419,10 @@ private fun MangaScreenSmallImpl(
defaultExpandState = state.isFromSource,
description = state.manga.description,
tagsProvider = { state.manga.genre },
noteContent = state.manga.notes,
onTagSearch = onTagSearch,
onCopyTagToClipboard = onCopyTagToClipboard,
onClickNotes = onNotesClicked,
)
}

Expand Down Expand Up @@ -484,6 +491,7 @@ fun MangaScreenLargeImpl(
onEditCategoryClicked: (() -> Unit)?,
onEditIntervalClicked: (() -> Unit)?,
onMigrateClicked: (() -> Unit)?,
onNotesClicked: () -> Unit,

// For bottom action menu
onMultiBookmarkClicked: (List<Chapter>, bookmarked: Boolean) -> Unit,
Expand Down Expand Up @@ -542,6 +550,7 @@ fun MangaScreenLargeImpl(
onClickEditCategory = onEditCategoryClicked,
onClickRefresh = onRefresh,
onClickMigrate = onMigrateClicked,
onClickNotes = onNotesClicked,
actionModeCounter = selectedChapterCount,
onSelectAll = { onAllChapterSelected(true) },
onInvertSelection = { onInvertSelection() },
Expand Down Expand Up @@ -640,8 +649,10 @@ fun MangaScreenLargeImpl(
defaultExpandState = true,
description = state.manga.description,
tagsProvider = { state.manga.genre },
noteContent = state.manga.notes,
onTagSearch = onTagSearch,
onCopyTagToClipboard = onCopyTagToClipboard,
onClickNotes = onNotesClicked,
)
}
},
Expand Down Expand Up @@ -761,6 +772,7 @@ private fun LazyListScope.sharedChapterItems(
is ChapterList.MissingCount -> {
MissingChapterCountListItem(count = item.count)
}

imkunet marked this conversation as resolved.
Show resolved Hide resolved
is ChapterList.Item -> {
MangaChapterListItem(
title = if (manga.displayMode == Manga.CHAPTER_DISPLAY_NUMBER) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,10 @@ fun ExpandableMangaDescription(
defaultExpandState: Boolean,
description: String?,
tagsProvider: () -> List<String>?,
noteContent: String,
onTagSearch: (String) -> Unit,
onCopyTagToClipboard: (tag: String) -> Unit,
onClickNotes: () -> Unit,
imkunet marked this conversation as resolved.
Show resolved Hide resolved
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Expand All @@ -255,6 +257,8 @@ fun ExpandableMangaDescription(
expandedDescription = desc,
shrunkDescription = trimmedDescription,
expanded = expanded,
noteContent = noteContent,
onNotesEditClicked = onClickNotes,
modifier = Modifier
.padding(top = 8.dp)
.padding(horizontal = 16.dp)
Expand Down Expand Up @@ -559,7 +563,9 @@ private fun ColumnScope.MangaContentInfo(
private fun MangaSummary(
expandedDescription: String,
shrunkDescription: String,
noteContent: String,
expanded: Boolean,
onNotesEditClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
val animProgress by animateFloatAsState(
Expand All @@ -571,27 +577,43 @@ private fun MangaSummary(
contents = listOf(
{
Text(
text = "\n\n", // Shows at least 3 lines
// Shows at least 3 lines if no notes
// when there are notes show 6
text = if (noteContent.isBlank()) "\n\n" else "\n\n\n\n\n",
style = MaterialTheme.typography.bodyMedium,
)
},
{
Text(
text = expandedDescription,
style = MaterialTheme.typography.bodyMedium,
)
},
{
SelectionContainer {
Column {
MangaNotesSection(
content = noteContent,
expanded = true,
onClickNotes = onNotesEditClicked,
)
Text(
text = if (expanded) expandedDescription else shrunkDescription,
maxLines = Int.MAX_VALUE,
text = expandedDescription,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.secondaryItemAlpha(),
)
}
},
{
Column {
MangaNotesSection(
content = noteContent,
expanded = expanded,
onClickNotes = onNotesEditClicked,
)
SelectionContainer {
Text(
text = if (expanded) expandedDescription else shrunkDescription,
maxLines = Int.MAX_VALUE,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.secondaryItemAlpha(),
)
}
}
},
{
val colors = listOf(Color.Transparent, MaterialTheme.colorScheme.background)
Box(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package eu.kanade.presentation.manga.components

import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
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.Modifier
import androidx.compose.ui.draw.alpha
import com.mohamedrejeb.richeditor.model.rememberRichTextState
import com.mohamedrejeb.richeditor.ui.material3.RichText

@Composable
fun MangaNotesDisplay(
content: String,
modifier: Modifier,
) {
val alpha = remember { Animatable(1f) }
var isFirstUpdate by remember { mutableStateOf(true) }
imkunet marked this conversation as resolved.
Show resolved Hide resolved

val primaryColor = MaterialTheme.colorScheme.primary
val richTextState = rememberRichTextState()
imkunet marked this conversation as resolved.
Show resolved Hide resolved
LaunchedEffect(content) {
richTextState.setMarkdown(markdown = content)

if (!isFirstUpdate) {
alpha.snapTo(targetValue = 0f)
alpha.animateTo(targetValue = 1f, animationSpec = tween(500))
return@LaunchedEffect
}
AntsyLich marked this conversation as resolved.
Show resolved Hide resolved

isFirstUpdate = false
imkunet marked this conversation as resolved.
Show resolved Hide resolved
}
LaunchedEffect(Unit) {
richTextState.config.listIndent = 10
}
LaunchedEffect(primaryColor) {
richTextState.config.linkColor = primaryColor
}

// to prevent the content size from animating from first render
AntsyLich marked this conversation as resolved.
Show resolved Hide resolved
val richTextModifier = remember(isFirstUpdate) {
if (isFirstUpdate) modifier else modifier.animateContentSize()
}

SelectionContainer {
RichText(
modifier = richTextModifier
imkunet marked this conversation as resolved.
Show resolved Hide resolved
.alpha(alpha.value),
style = MaterialTheme.typography.bodyMedium,
state = richTextState,
)
}
}
Loading