diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 47b220b97..2288af691 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -1,10 +1,13 @@ name: PR build check on: pull_request: - paths-ignore: - - '**.md' - - 'i18n/src/commonMain/moko-resources/**/strings.xml' - - 'i18n/src/commonMain/moko-resources/**/plurals.xml' + paths: + - '**' + - '!**.md' + - '!i18n/src/commonMain/moko-resources/**/strings.xml' + - '!i18n/src/commonMain/moko-resources/**/plurals.xml' + - 'i18n/src/commonMain/moko-resources/base/strings.xml' + - 'i18n/src/commonMain/moko-resources/base/plurals.xml' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number }} diff --git a/.gitignore b/.gitignore index 70e152f0a..42c569b7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,16 @@ +# Build files .gradle .kotlin -/local.properties -/.idea/workspace.xml -.DS_Store +build + +# IDE files +*.iml .idea/* !.idea/icon.png -*iml -*.iml +/captures -# Built files -*/build -/build -*.apk -app/**/output.json +# Configuration files +local.properties -# Unnecessary file -*.swp \ No newline at end of file +# macOS specific files +.DS_Store diff --git a/app/.gitignore b/app/.gitignore deleted file mode 100644 index 12864471f..000000000 --- a/app/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/build -*iml -*.iml diff --git a/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt index 2d31c64e7..a5b6a0e1c 100644 --- a/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt +++ b/app/src/main/java/eu/kanade/domain/track/interactor/AddTracks.kt @@ -5,6 +5,7 @@ import eu.kanade.domain.track.model.toDomainTrack import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.EnhancedTracker import eu.kanade.tachiyomi.data.track.Tracker +import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import logcat.LogPriority @@ -14,17 +15,16 @@ import tachiyomi.core.common.util.system.logcat import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.manga.model.Manga -import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.InsertTrack import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.time.ZoneOffset class AddTracks( - private val getTracks: GetTracks, private val insertTrack: InsertTrack, private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack, private val getChaptersByMangaId: GetChaptersByMangaId, + private val trackerManager: TrackerManager, ) { // TODO: update all trackers based on common data @@ -79,7 +79,7 @@ class AddTracks( suspend fun bindEnhancedTrackers(manga: Manga, source: Source) = withNonCancellableContext { withIOContext { - getTracks.await(manga.id) + trackerManager.loggedInTrackers() .filterIsInstance() .filter { it.accept(source) } .forEach { service -> @@ -87,11 +87,11 @@ class AddTracks( service.match(manga)?.let { track -> track.manga_id = manga.id (service as Tracker).bind(track) - insertTrack.await(track.toDomainTrack()!!) + insertTrack.await(track.toDomainTrack(idRequired = false)!!) syncChapterProgressWithTrack.await( manga.id, - track.toDomainTrack()!!, + track.toDomainTrack(idRequired = false)!!, service, ) } diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index 8410cfb40..0587cbe24 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -166,23 +166,27 @@ private fun ColumnScope.SortPage( val sortingMode = category.sort.type val sortDescending = !category.sort.isAscending - val trackerSortOption = if (trackers.isEmpty()) { - emptyList() - } else { - listOf(MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean) + val options = remember(trackers.isEmpty()) { + val trackerMeanPair = if (trackers.isNotEmpty()) { + MR.strings.action_sort_tracker_score to LibrarySort.Type.TrackerMean + } else { + null + } + listOfNotNull( + MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical, + MR.strings.action_sort_total to LibrarySort.Type.TotalChapters, + MR.strings.action_sort_last_read to LibrarySort.Type.LastRead, + MR.strings.action_sort_last_manga_update to LibrarySort.Type.LastUpdate, + MR.strings.action_sort_unread_count to LibrarySort.Type.UnreadCount, + MR.strings.action_sort_latest_chapter to LibrarySort.Type.LatestChapter, + MR.strings.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate, + MR.strings.action_sort_date_added to LibrarySort.Type.DateAdded, + trackerMeanPair, + MR.strings.action_sort_random to LibrarySort.Type.Random, + ) } - listOf( - MR.strings.action_sort_alpha to LibrarySort.Type.Alphabetical, - MR.strings.action_sort_total to LibrarySort.Type.TotalChapters, - MR.strings.action_sort_last_read to LibrarySort.Type.LastRead, - MR.strings.action_sort_last_manga_update to LibrarySort.Type.LastUpdate, - MR.strings.action_sort_unread_count to LibrarySort.Type.UnreadCount, - MR.strings.action_sort_latest_chapter to LibrarySort.Type.LatestChapter, - MR.strings.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate, - MR.strings.action_sort_date_added to LibrarySort.Type.DateAdded, - MR.strings.action_sort_random to LibrarySort.Type.Random, - ).plus(trackerSortOption).map { (titleRes, mode) -> + options.map { (titleRes, mode) -> if (mode == LibrarySort.Type.Random) { BaseSortItem( label = stringResource(titleRes), diff --git a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt index 124f3a6c3..9370ee567 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt @@ -45,8 +45,8 @@ fun ReaderAppBars( onClickTopAppBar: () -> Unit, bookmarked: Boolean, onToggleBookmarked: () -> Unit, - onOpenInBrowser: (() -> Unit)?, onOpenInWebView: (() -> Unit)?, + onOpenInBrowser: (() -> Unit)?, onShare: (() -> Unit)?, viewer: Viewer?, @@ -120,14 +120,6 @@ fun ReaderAppBars( onClick = onToggleBookmarked, ), ) - onOpenInBrowser?.let { - add( - AppBar.OverflowAction( - title = stringResource(MR.strings.action_open_in_browser), - onClick = it, - ), - ) - } onOpenInWebView?.let { add( AppBar.OverflowAction( @@ -136,6 +128,14 @@ fun ReaderAppBars( ), ) } + onOpenInBrowser?.let { + add( + AppBar.OverflowAction( + title = stringResource(MR.strings.action_open_in_browser), + onClick = it, + ), + ) + } onShare?.let { add( AppBar.OverflowAction( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt index fa06f55bb..d6851a758 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt @@ -27,6 +27,7 @@ import tachiyomi.core.common.util.system.logcat import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.manga.interactor.GetFavorites import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.i18n.MR import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -43,6 +44,7 @@ class BackupCreator( private val parser: ProtoBuf = Injekt.get(), private val getFavorites: GetFavorites = Injekt.get(), private val backupPreferences: BackupPreferences = Injekt.get(), + private val mangaRepository: MangaRepository = Injekt.get(), private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(), private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(), @@ -75,7 +77,9 @@ class BackupCreator( throw IllegalStateException(context.stringResource(MR.strings.create_backup_file_error)) } - val backupManga = backupMangas(getFavorites.await(), options) + val nonFavoriteManga = if (options.readEntries) mangaRepository.getReadMangaNotInLibrary() else emptyList() + val backupManga = backupMangas(getFavorites.await() + nonFavoriteManga, options) + val backup = Backup( backupManga = backupManga, backupCategories = backupCategories(options), diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt index daaecff8e..efb20f6bf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupOptions.kt @@ -10,6 +10,7 @@ data class BackupOptions( val chapters: Boolean = true, val tracking: Boolean = true, val history: Boolean = true, + val readEntries: Boolean = true, val appSettings: Boolean = true, val extensionRepoSettings: Boolean = true, val sourceSettings: Boolean = true, @@ -22,6 +23,7 @@ data class BackupOptions( chapters, tracking, history, + readEntries, appSettings, extensionRepoSettings, sourceSettings, @@ -60,6 +62,12 @@ data class BackupOptions( getter = BackupOptions::categories, setter = { options, enabled -> options.copy(categories = enabled) }, ), + Entry( + label = MR.strings.non_library_settings, + getter = BackupOptions::readEntries, + setter = { options, enabled -> options.copy(readEntries = enabled) }, + enabled = { it.libraryEntries }, + ), ) val settingsOptions = persistentListOf( @@ -92,10 +100,11 @@ data class BackupOptions( chapters = array[2], tracking = array[3], history = array[4], - appSettings = array[5], - extensionRepoSettings = array[6], - sourceSettings = array[7], - privateSettings = array[8], + readEntries = array[5], + appSettings = array[6], + extensionRepoSettings = array[7], + sourceSettings = array[8], + privateSettings = array[9], ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 7f0b3ab35..b9a89751c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -390,8 +390,8 @@ class ReaderActivity : BaseActivity() { onClickTopAppBar = ::openMangaScreen, bookmarked = state.bookmarked, onToggleBookmarked = viewModel::toggleChapterBookmark, - onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource }, onOpenInWebView = ::openChapterInWebView.takeIf { isHttpSource }, + onOpenInBrowser = ::openChapterInBrowser.takeIf { isHttpSource }, onShare = ::shareChapter.takeIf { isHttpSource }, viewer = state.viewer, @@ -565,12 +565,6 @@ class ReaderActivity : BaseActivity() { } } - private fun openChapterInBrowser() { - assistUrl?.let { - openInBrowser(it.toUri(), forceDefaultBrowser = false) - } - } - private fun openChapterInWebView() { val manga = viewModel.manga ?: return val source = viewModel.getSource() ?: return @@ -580,6 +574,12 @@ class ReaderActivity : BaseActivity() { } } + private fun openChapterInBrowser() { + assistUrl?.let { + openInBrowser(it.toUri(), forceDefaultBrowser = false) + } + } + private fun shareChapter() { assistUrl?.let { val intent = it.toUri().toShareIntent(this, type = "text/plain") diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/buildSrc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts b/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts index 9dfa7eef2..3e604c8c0 100644 --- a/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts +++ b/buildSrc/src/main/kotlin/mihon.code.lint.gradle.kts @@ -6,6 +6,18 @@ plugins { val libs = the() +val xmlFormatExclude = buildList(2) { + add("**/build/**/*.xml") + + projectDir + .resolve("src/commonMain/moko-resources") + .takeIf { it.isDirectory } + ?.let(::fileTree) + ?.matching { exclude("/base/**") } + ?.let(::add) +} + .toTypedArray() + spotless { kotlin { target("**/*.kt", "**/*.kts") @@ -23,7 +35,7 @@ spotless { } format("xml") { target("**/*.xml") - targetExclude("**/build/**/*.xml") + targetExclude(*xmlFormatExclude) trimTrailingWhitespace() endWithNewline() } diff --git a/core-metadata/.gitignore b/core-metadata/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/core-metadata/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/core/archive/.gitignore b/core/archive/.gitignore deleted file mode 100644 index 796b96d1c..000000000 --- a/core/archive/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/core/common/.gitignore b/core/common/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/core/common/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/data/.gitignore b/data/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/data/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index f7aaf4c99..ae6c8d340 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -49,6 +49,10 @@ class MangaRepositoryImpl( return handler.awaitList { mangasQueries.getFavorites(MangaMapper::mapManga) } } + override suspend fun getReadMangaNotInLibrary(): List { + return handler.awaitList { mangasQueries.getReadMangaNotInLibrary(MangaMapper::mapManga) } + } + override suspend fun getLibraryManga(): List { return handler.awaitList { libraryViewQueries.library(MangaMapper::mapLibraryManga) } } diff --git a/data/src/main/sqldelight/tachiyomi/data/mangas.sq b/data/src/main/sqldelight/tachiyomi/data/mangas.sq index 3e21e5bc0..e3cb8076a 100644 --- a/data/src/main/sqldelight/tachiyomi/data/mangas.sq +++ b/data/src/main/sqldelight/tachiyomi/data/mangas.sq @@ -78,6 +78,15 @@ SELECT * FROM mangas WHERE favorite = 1; +getReadMangaNotInLibrary: +SELECT * +FROM mangas +WHERE favorite = 0 AND _id IN ( + SELECT DISTINCT chapters.manga_id + FROM chapters + WHERE read = 1 OR last_page_read != 0 +); + getAllManga: SELECT * FROM mangas; diff --git a/domain/.gitignore b/domain/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/domain/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt b/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt index 8c74851f3..f81650102 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt @@ -17,6 +17,8 @@ interface MangaRepository { suspend fun getFavorites(): List + suspend fun getReadMangaNotInLibrary(): List + suspend fun getLibraryManga(): List fun getLibraryMangaAsFlow(): Flow> diff --git a/gradle/androidx.versions.toml b/gradle/androidx.versions.toml index 45ea54535..5d3813567 100644 --- a/gradle/androidx.versions.toml +++ b/gradle/androidx.versions.toml @@ -1,5 +1,5 @@ [versions] -agp_version = "8.7.0" +agp_version = "8.7.1" lifecycle_version = "2.8.6" paging_version = "3.3.2" interpolator_version = "1.0.0" diff --git a/i18n/.gitignore b/i18n/.gitignore deleted file mode 100644 index e69de29bb..000000000 diff --git a/i18n/README.md b/i18n/README.md index b96cd6535..8228ac4fb 100644 --- a/i18n/README.md +++ b/i18n/README.md @@ -2,4 +2,4 @@ This module houses the string resources and translations. -Original English strings are manged in `src/commonMain/resources/MR/base/`. Translations are done externally via Weblate. See [our website](https://mihon.app/docs/contribute#translation) for more details. \ No newline at end of file +Original English strings are managed in `src/commonMain/moko-resources/base/`. Translations are done externally via Weblate. See [our website](https://mihon.app/docs/contribute#translation) for more details. \ No newline at end of file diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index f9e4d1ed6..f61df609c 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -546,6 +546,7 @@ Source settings Extension repos Include sensitive settings (e.g., tracker login tokens) + All read entries Creating backup Backup failed Storage permissions not granted diff --git a/macrobenchmark/.gitignore b/macrobenchmark/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/macrobenchmark/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/presentation-core/.gitignore b/presentation-core/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/presentation-core/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt index fd1fa8c4b..c43a6849d 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/FloatingActionButton.kt @@ -9,11 +9,11 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkHorizontally import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.sizeIn -import androidx.compose.foundation.layout.width import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.FloatingActionButtonElevation @@ -46,12 +46,8 @@ fun ExtendedFloatingActionButton( contentColor: Color = contentColorFor(containerColor), elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(), ) { - val minWidth by animateDpAsState( - targetValue = if (expanded) ExtendedFabMinimumWidth else FabContainerWidth, - label = "minWidth", - ) FloatingActionButton( - modifier = modifier.sizeIn(minWidth = minWidth), + modifier = modifier, onClick = onClick, interactionSource = interactionSource, shape = shape, @@ -59,18 +55,29 @@ fun ExtendedFloatingActionButton( contentColor = contentColor, elevation = elevation, ) { + val minWidth by animateDpAsState( + targetValue = if (expanded) ExtendedFabMinimumWidth else FabContainerWidth, + animationSpec = tween( + durationMillis = 500, + easing = EasingEmphasizedCubicBezier, + ), + label = "minWidth", + ) val startPadding by animateDpAsState( targetValue = if (expanded) ExtendedFabIconSize / 2 else 0.dp, + animationSpec = tween( + durationMillis = if (expanded) 300 else 900, + easing = EasingEmphasizedCubicBezier, + ), label = "startPadding", ) - val endPadding by animateDpAsState( - targetValue = if (expanded) ExtendedFabTextPadding else 0.dp, - label = "endPadding", - ) Row( - modifier = Modifier.padding(start = startPadding, end = endPadding), + modifier = Modifier + .sizeIn(minWidth = minWidth) + .padding(start = startPadding), verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center, ) { icon() AnimatedVisibility( @@ -78,8 +85,7 @@ fun ExtendedFloatingActionButton( enter = ExtendedFabExpandAnimation, exit = ExtendedFabCollapseAnimation, ) { - Row { - Spacer(Modifier.width(ExtendedFabIconPadding)) + Box(modifier = Modifier.padding(start = ExtendedFabIconPadding, end = ExtendedFabTextPadding)) { text() } } diff --git a/presentation-widget/.gitignore b/presentation-widget/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/presentation-widget/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/source-api/.gitignore b/source-api/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/source-api/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/source-local/.gitignore b/source-local/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/source-local/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file