@@ -12,6 +12,7 @@ plugins {
|
|||||||
alias(mihonx.plugins.compose)
|
alias(mihonx.plugins.compose)
|
||||||
alias(mihonx.plugins.spotless)
|
alias(mihonx.plugins.spotless)
|
||||||
|
|
||||||
|
alias(libs.plugins.metro)
|
||||||
alias(libs.plugins.aboutLibraries)
|
alias(libs.plugins.aboutLibraries)
|
||||||
alias(libs.plugins.androidx.baselineProfile)
|
alias(libs.plugins.androidx.baselineProfile)
|
||||||
alias(libs.plugins.kotlin.serialization)
|
alias(libs.plugins.kotlin.serialization)
|
||||||
@@ -209,6 +210,7 @@ dependencies {
|
|||||||
implementation(projects.i18n)
|
implementation(projects.i18n)
|
||||||
implementation(projects.core.archive)
|
implementation(projects.core.archive)
|
||||||
implementation(projects.core.common)
|
implementation(projects.core.common)
|
||||||
|
implementation(projects.core.metro)
|
||||||
implementation(projects.coreMetadata)
|
implementation(projects.coreMetadata)
|
||||||
implementation(projects.sourceApi)
|
implementation(projects.sourceApi)
|
||||||
implementation(projects.sourceLocal)
|
implementation(projects.sourceLocal)
|
||||||
@@ -283,6 +285,9 @@ dependencies {
|
|||||||
|
|
||||||
// Dependency injection
|
// Dependency injection
|
||||||
implementation(libs.injekt)
|
implementation(libs.injekt)
|
||||||
|
implementation(libs.metro.runtime)
|
||||||
|
implementation(libs.metrox.viewmodel)
|
||||||
|
implementation(libs.metrox.viewmodel.compose)
|
||||||
|
|
||||||
// Image loading
|
// Image loading
|
||||||
implementation(libs.bundles.coil)
|
implementation(libs.bundles.coil)
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package eu.kanade.core.util
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import uy.kohesive.injekt.Injekt
|
import mihon.app.di.appGraph
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ifSourcesLoaded(): Boolean {
|
fun ifSourcesLoaded(): Boolean {
|
||||||
return remember { Injekt.get<SourceManager>().isInitialized }.collectAsState().value
|
val context = LocalContext.current
|
||||||
|
return remember { context.appGraph.sourceManager.isInitialized }.collectAsState().value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,209 +0,0 @@
|
|||||||
package eu.kanade.domain
|
|
||||||
|
|
||||||
import eu.kanade.domain.chapter.interactor.GetAvailableScanlators
|
|
||||||
import eu.kanade.domain.chapter.interactor.SetReadStatus
|
|
||||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
|
||||||
import eu.kanade.domain.download.interactor.DeleteDownload
|
|
||||||
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
|
|
||||||
import eu.kanade.domain.extension.interactor.GetExtensionSources
|
|
||||||
import eu.kanade.domain.extension.interactor.GetExtensionsByType
|
|
||||||
import eu.kanade.domain.extension.interactor.TrustExtension
|
|
||||||
import eu.kanade.domain.manga.interactor.GetExcludedScanlators
|
|
||||||
import eu.kanade.domain.manga.interactor.SetExcludedScanlators
|
|
||||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
|
||||||
import eu.kanade.domain.source.interactor.GetEnabledSources
|
|
||||||
import eu.kanade.domain.source.interactor.GetIncognitoState
|
|
||||||
import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
|
||||||
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
|
||||||
import eu.kanade.domain.source.interactor.ToggleIncognito
|
|
||||||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
|
||||||
import eu.kanade.domain.source.interactor.ToggleSource
|
|
||||||
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
|
||||||
import eu.kanade.domain.track.interactor.AddTracks
|
|
||||||
import eu.kanade.domain.track.interactor.RefreshTracks
|
|
||||||
import eu.kanade.domain.track.interactor.SyncChapterProgressWithTrack
|
|
||||||
import eu.kanade.domain.track.interactor.TrackChapter
|
|
||||||
import mihon.data.extension.repository.ExtensionStoreRepositoryImpl
|
|
||||||
import mihon.data.extension.service.ExtensionStoreService
|
|
||||||
import mihon.domain.chapter.interactor.FilterChaptersForDownload
|
|
||||||
import mihon.domain.extension.interactor.AddExtensionStore
|
|
||||||
import mihon.domain.extension.interactor.GetExtensionStoreCountAsFlow
|
|
||||||
import mihon.domain.extension.interactor.GetExtensionStores
|
|
||||||
import mihon.domain.extension.interactor.RemoveExtensionStore
|
|
||||||
import mihon.domain.extension.interactor.UpdateExtensionStores
|
|
||||||
import mihon.domain.extension.repository.ExtensionStoreRepository
|
|
||||||
import mihon.domain.migration.usecases.MigrateMangaUseCase
|
|
||||||
import mihon.domain.source.interactor.UpdateMangaFromRemote
|
|
||||||
import mihon.domain.upcoming.interactor.GetUpcomingManga
|
|
||||||
import tachiyomi.data.category.CategoryRepositoryImpl
|
|
||||||
import tachiyomi.data.chapter.ChapterRepositoryImpl
|
|
||||||
import tachiyomi.data.history.HistoryRepositoryImpl
|
|
||||||
import tachiyomi.data.manga.MangaRepositoryImpl
|
|
||||||
import tachiyomi.data.release.ReleaseServiceImpl
|
|
||||||
import tachiyomi.data.source.SourceRepositoryImpl
|
|
||||||
import tachiyomi.data.source.StubSourceRepositoryImpl
|
|
||||||
import tachiyomi.data.track.TrackRepositoryImpl
|
|
||||||
import tachiyomi.data.updates.UpdatesRepositoryImpl
|
|
||||||
import tachiyomi.domain.category.interactor.CreateCategoryWithName
|
|
||||||
import tachiyomi.domain.category.interactor.DeleteCategory
|
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
|
||||||
import tachiyomi.domain.category.interactor.RenameCategory
|
|
||||||
import tachiyomi.domain.category.interactor.ReorderCategory
|
|
||||||
import tachiyomi.domain.category.interactor.ResetCategoryFlags
|
|
||||||
import tachiyomi.domain.category.interactor.SetDisplayMode
|
|
||||||
import tachiyomi.domain.category.interactor.SetMangaCategories
|
|
||||||
import tachiyomi.domain.category.interactor.SetSortModeForCategory
|
|
||||||
import tachiyomi.domain.category.repository.CategoryRepository
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetBookmarkedChaptersByMangaId
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapter
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId
|
|
||||||
import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
|
||||||
import tachiyomi.domain.chapter.interactor.SetMangaDefaultChapterFlags
|
|
||||||
import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter
|
|
||||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
|
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
|
||||||
import tachiyomi.domain.history.interactor.GetHistory
|
|
||||||
import tachiyomi.domain.history.interactor.GetNextChapters
|
|
||||||
import tachiyomi.domain.history.interactor.GetTotalReadDuration
|
|
||||||
import tachiyomi.domain.history.interactor.RemoveHistory
|
|
||||||
import tachiyomi.domain.history.interactor.UpsertHistory
|
|
||||||
import tachiyomi.domain.history.repository.HistoryRepository
|
|
||||||
import tachiyomi.domain.manga.interactor.FetchInterval
|
|
||||||
import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
|
||||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
|
||||||
import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId
|
|
||||||
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.UpdateMangaNotes
|
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
|
||||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
|
|
||||||
import tachiyomi.domain.release.service.ReleaseService
|
|
||||||
import tachiyomi.domain.source.interactor.GetRemoteManga
|
|
||||||
import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
|
|
||||||
import tachiyomi.domain.source.repository.SourceRepository
|
|
||||||
import tachiyomi.domain.source.repository.StubSourceRepository
|
|
||||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
|
||||||
import tachiyomi.domain.track.interactor.GetTracks
|
|
||||||
import tachiyomi.domain.track.interactor.GetTracksPerManga
|
|
||||||
import tachiyomi.domain.track.interactor.InsertTrack
|
|
||||||
import tachiyomi.domain.track.repository.TrackRepository
|
|
||||||
import tachiyomi.domain.updates.interactor.GetUpdates
|
|
||||||
import tachiyomi.domain.updates.repository.UpdatesRepository
|
|
||||||
import uy.kohesive.injekt.api.InjektModule
|
|
||||||
import uy.kohesive.injekt.api.InjektRegistrar
|
|
||||||
import uy.kohesive.injekt.api.addFactory
|
|
||||||
import uy.kohesive.injekt.api.addSingletonFactory
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
class DomainModule : InjektModule {
|
|
||||||
|
|
||||||
override fun InjektRegistrar.registerInjectables() {
|
|
||||||
addSingletonFactory<CategoryRepository> { CategoryRepositoryImpl(get()) }
|
|
||||||
addFactory { GetCategories(get()) }
|
|
||||||
addFactory { ResetCategoryFlags(get(), get()) }
|
|
||||||
addFactory { SetDisplayMode(get()) }
|
|
||||||
addFactory { SetSortModeForCategory(get(), get()) }
|
|
||||||
addFactory { CreateCategoryWithName(get(), get()) }
|
|
||||||
addFactory { RenameCategory(get()) }
|
|
||||||
addFactory { ReorderCategory(get()) }
|
|
||||||
addFactory { DeleteCategory(get(), get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<MangaRepository> { MangaRepositoryImpl(get()) }
|
|
||||||
addFactory { GetDuplicateLibraryManga(get()) }
|
|
||||||
addFactory { GetFavorites(get()) }
|
|
||||||
addFactory { GetLibraryManga(get()) }
|
|
||||||
addFactory { GetMangaWithChapters(get(), get()) }
|
|
||||||
addFactory { GetMangaByUrlAndSourceId(get()) }
|
|
||||||
addFactory { GetManga(get()) }
|
|
||||||
addFactory { GetNextChapters(get(), get(), get()) }
|
|
||||||
addFactory { GetUpcomingManga(get()) }
|
|
||||||
addFactory { ResetViewerFlags(get()) }
|
|
||||||
addFactory { SetMangaChapterFlags(get()) }
|
|
||||||
addFactory { FetchInterval(get()) }
|
|
||||||
addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) }
|
|
||||||
addFactory { SetMangaViewerFlags(get()) }
|
|
||||||
addFactory { NetworkToLocalManga(get()) }
|
|
||||||
addFactory { UpdateManga(get(), get()) }
|
|
||||||
addFactory { UpdateMangaNotes(get()) }
|
|
||||||
addFactory { SetMangaCategories(get()) }
|
|
||||||
addFactory { GetExcludedScanlators(get()) }
|
|
||||||
addFactory { SetExcludedScanlators(get()) }
|
|
||||||
addFactory {
|
|
||||||
MigrateMangaUseCase(
|
|
||||||
get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
addSingletonFactory<ReleaseService> { ReleaseServiceImpl(get(), get()) }
|
|
||||||
addFactory { GetApplicationRelease(get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
|
||||||
addFactory { TrackChapter(get(), get(), get(), get()) }
|
|
||||||
addFactory { AddTracks(get(), get(), get(), get()) }
|
|
||||||
addFactory { RefreshTracks(get(), get(), get(), get()) }
|
|
||||||
addFactory { DeleteTrack(get()) }
|
|
||||||
addFactory { GetTracksPerManga(get()) }
|
|
||||||
addFactory { GetTracks(get()) }
|
|
||||||
addFactory { InsertTrack(get()) }
|
|
||||||
addFactory { SyncChapterProgressWithTrack(get(), get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
|
|
||||||
addFactory { GetChapter(get()) }
|
|
||||||
addFactory { GetChaptersByMangaId(get()) }
|
|
||||||
addFactory { GetBookmarkedChaptersByMangaId(get()) }
|
|
||||||
addFactory { GetChapterByUrlAndMangaId(get()) }
|
|
||||||
addFactory { UpdateChapter(get()) }
|
|
||||||
addFactory { SetReadStatus(get(), get(), get(), get()) }
|
|
||||||
addFactory { ShouldUpdateDbChapter() }
|
|
||||||
addFactory { SyncChaptersWithSource(get(), get(), get(), get(), get(), get(), get(), get(), get()) }
|
|
||||||
addFactory { GetAvailableScanlators(get()) }
|
|
||||||
addFactory { FilterChaptersForDownload(get(), get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<HistoryRepository> { HistoryRepositoryImpl(get()) }
|
|
||||||
addFactory { GetHistory(get()) }
|
|
||||||
addFactory { UpsertHistory(get()) }
|
|
||||||
addFactory { RemoveHistory(get()) }
|
|
||||||
addFactory { GetTotalReadDuration(get()) }
|
|
||||||
|
|
||||||
addFactory { DeleteDownload(get(), get()) }
|
|
||||||
|
|
||||||
addFactory { GetExtensionsByType(get(), get()) }
|
|
||||||
addFactory { GetExtensionSources(get()) }
|
|
||||||
addFactory { GetExtensionLanguages(get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<UpdatesRepository> { UpdatesRepositoryImpl(get()) }
|
|
||||||
addFactory { GetUpdates(get()) }
|
|
||||||
|
|
||||||
addSingletonFactory<SourceRepository> { SourceRepositoryImpl(get(), get()) }
|
|
||||||
addSingletonFactory<StubSourceRepository> { StubSourceRepositoryImpl(get()) }
|
|
||||||
addFactory { GetEnabledSources(get(), get()) }
|
|
||||||
addFactory { GetLanguagesWithSources(get(), get()) }
|
|
||||||
addFactory { GetRemoteManga(get()) }
|
|
||||||
addFactory { GetSourcesWithFavoriteCount(get(), get()) }
|
|
||||||
addFactory { GetSourcesWithNonLibraryManga(get()) }
|
|
||||||
addFactory { SetMigrateSorting(get()) }
|
|
||||||
addFactory { ToggleLanguage(get()) }
|
|
||||||
addFactory { ToggleSource(get()) }
|
|
||||||
addFactory { ToggleSourcePin(get()) }
|
|
||||||
addFactory { TrustExtension(get(), get()) }
|
|
||||||
|
|
||||||
addSingletonFactory { ExtensionStoreService(get(), get(), get()) }
|
|
||||||
addSingletonFactory<ExtensionStoreRepository> { ExtensionStoreRepositoryImpl(get(), get()) }
|
|
||||||
addFactory { AddExtensionStore(get()) }
|
|
||||||
addFactory { GetExtensionStoreCountAsFlow(get()) }
|
|
||||||
addFactory { GetExtensionStores(get()) }
|
|
||||||
addFactory { RemoveExtensionStore(get()) }
|
|
||||||
addFactory { UpdateExtensionStores(get()) }
|
|
||||||
|
|
||||||
addFactory { ToggleIncognito(get()) }
|
|
||||||
addFactory { GetIncognitoState(get(), get(), get()) }
|
|
||||||
|
|
||||||
addFactory { UpdateMangaFromRemote(get(), get(), get(), get(), get(), get(), get()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,15 @@ package eu.kanade.domain.base
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import tachiyomi.core.common.preference.Preference
|
import tachiyomi.core.common.preference.Preference
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
import tachiyomi.core.common.preference.PreferenceStore
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class BasePreferences(
|
class BasePreferences(
|
||||||
val context: Context,
|
val context: Context,
|
||||||
preferenceStore: PreferenceStore,
|
preferenceStore: PreferenceStore,
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package eu.kanade.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import tachiyomi.domain.chapter.repository.ChapterRepository
|
import tachiyomi.domain.chapter.repository.ChapterRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetAvailableScanlators(
|
class GetAvailableScanlators(
|
||||||
private val repository: ChapterRepository,
|
private val repository: ChapterRepository,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.download.interactor.DeleteDownload
|
import eu.kanade.domain.download.interactor.DeleteDownload
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
||||||
@@ -11,6 +12,7 @@ import tachiyomi.domain.download.service.DownloadPreferences
|
|||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
class SetReadStatus(
|
class SetReadStatus(
|
||||||
private val downloadPreferences: DownloadPreferences,
|
private val downloadPreferences: DownloadPreferences,
|
||||||
private val deleteDownload: DeleteDownload,
|
private val deleteDownload: DeleteDownload,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.chapter.interactor
|
package eu.kanade.domain.chapter.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.chapter.model.copyFromSChapter
|
import eu.kanade.domain.chapter.model.copyFromSChapter
|
||||||
import eu.kanade.domain.chapter.model.toSChapter
|
import eu.kanade.domain.chapter.model.toSChapter
|
||||||
import eu.kanade.domain.manga.interactor.GetExcludedScanlators
|
import eu.kanade.domain.manga.interactor.GetExcludedScanlators
|
||||||
@@ -29,6 +30,7 @@ import java.lang.Long.max
|
|||||||
import java.util.TreeSet
|
import java.util.TreeSet
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
@Inject
|
||||||
class SyncChaptersWithSource(
|
class SyncChaptersWithSource(
|
||||||
private val downloadManager: DownloadManager,
|
private val downloadManager: DownloadManager,
|
||||||
private val downloadProvider: DownloadProvider,
|
private val downloadProvider: DownloadProvider,
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package eu.kanade.domain.download.interactor
|
package eu.kanade.domain.download.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
import tachiyomi.core.common.util.lang.withNonCancellableContext
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
|
|
||||||
|
@Inject
|
||||||
class DeleteDownload(
|
class DeleteDownload(
|
||||||
private val sourceManager: SourceManager,
|
private val sourceManager: SourceManager,
|
||||||
private val downloadManager: DownloadManager,
|
private val downloadManager: DownloadManager,
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package eu.kanade.domain.extension.interactor
|
package eu.kanade.domain.extension.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetExtensionLanguages(
|
class GetExtensionLanguages(
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
private val extensionManager: ExtensionManager,
|
private val extensionManager: ExtensionManager,
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package eu.kanade.domain.extension.interactor
|
package eu.kanade.domain.extension.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetExtensionSources(
|
class GetExtensionSources(
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.extension.interactor
|
package eu.kanade.domain.extension.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.extension.model.Extensions
|
import eu.kanade.domain.extension.model.Extensions
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
@@ -7,6 +8,7 @@ import eu.kanade.tachiyomi.extension.model.Extension
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetExtensionsByType(
|
class GetExtensionsByType(
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
private val extensionManager: ExtensionManager,
|
private val extensionManager: ExtensionManager,
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package eu.kanade.domain.extension.interactor
|
|||||||
|
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import mihon.domain.extension.repository.ExtensionStoreRepository
|
import mihon.domain.extension.repository.ExtensionStoreRepository
|
||||||
import tachiyomi.core.common.preference.getAndSet
|
import tachiyomi.core.common.preference.getAndSet
|
||||||
|
|
||||||
|
@Inject
|
||||||
class TrustExtension(
|
class TrustExtension(
|
||||||
private val repository: ExtensionStoreRepository,
|
private val repository: ExtensionStoreRepository,
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import app.cash.sqldelight.async.coroutines.awaitAsList
|
import app.cash.sqldelight.async.coroutines.awaitAsList
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import tachiyomi.data.Database
|
import tachiyomi.data.Database
|
||||||
import tachiyomi.data.subscribeToList
|
import tachiyomi.data.subscribeToList
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetExcludedScanlators(
|
class GetExcludedScanlators(
|
||||||
private val database: Database,
|
private val database: Database,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import app.cash.sqldelight.async.coroutines.awaitAsList
|
import app.cash.sqldelight.async.coroutines.awaitAsList
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import tachiyomi.data.Database
|
import tachiyomi.data.Database
|
||||||
|
|
||||||
|
@Inject
|
||||||
class SetExcludedScanlators(
|
class SetExcludedScanlators(
|
||||||
private val database: Database,
|
private val database: Database,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||||
import tachiyomi.domain.manga.model.MangaUpdate
|
import tachiyomi.domain.manga.model.MangaUpdate
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
|
|
||||||
|
@Inject
|
||||||
class SetMangaViewerFlags(
|
class SetMangaViewerFlags(
|
||||||
private val mangaRepository: MangaRepository,
|
private val mangaRepository: MangaRepository,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import kotlinx.datetime.LocalDateTime
|
import kotlinx.datetime.LocalDateTime
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.toLocalDateTime
|
import kotlinx.datetime.toLocalDateTime
|
||||||
@@ -9,6 +10,7 @@ import tachiyomi.domain.manga.model.MangaUpdate
|
|||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
@Inject
|
||||||
class UpdateManga(
|
class UpdateManga(
|
||||||
private val mangaRepository: MangaRepository,
|
private val mangaRepository: MangaRepository,
|
||||||
private val fetchInterval: FetchInterval,
|
private val fetchInterval: FetchInterval,
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package eu.kanade.domain.manga.model
|
package eu.kanade.domain.manga.model
|
||||||
|
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.preference.TriState
|
import tachiyomi.core.common.preference.TriState
|
||||||
import tachiyomi.core.metadata.comicinfo.ComicInfo
|
import tachiyomi.core.metadata.comicinfo.ComicInfo
|
||||||
import tachiyomi.core.metadata.comicinfo.ComicInfoPublishingStatus
|
import tachiyomi.core.metadata.comicinfo.ComicInfoPublishingStatus
|
||||||
@@ -22,7 +23,7 @@ val Manga.readerOrientation: Long
|
|||||||
|
|
||||||
val Manga.downloadedFilter: TriState
|
val Manga.downloadedFilter: TriState
|
||||||
get() {
|
get() {
|
||||||
if (Injekt.get<BasePreferences>().downloadedOnly.get()) return TriState.ENABLED_IS
|
if (Injekt.get<Context>().appGraph.basePreferences.downloadedOnly.get()) return TriState.ENABLED_IS
|
||||||
return when (downloadedFilterRaw) {
|
return when (downloadedFilterRaw) {
|
||||||
Manga.CHAPTER_SHOW_DOWNLOADED -> TriState.ENABLED_IS
|
Manga.CHAPTER_SHOW_DOWNLOADED -> TriState.ENABLED_IS
|
||||||
Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
|
Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
@@ -10,6 +11,7 @@ import tachiyomi.domain.source.model.Source
|
|||||||
import tachiyomi.domain.source.repository.SourceRepository
|
import tachiyomi.domain.source.repository.SourceRepository
|
||||||
import tachiyomi.source.local.isLocal
|
import tachiyomi.source.local.isLocal
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetEnabledSources(
|
class GetEnabledSources(
|
||||||
private val repository: SourceRepository,
|
private val repository: SourceRepository,
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
@@ -7,6 +8,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetIncognitoState(
|
class GetIncognitoState(
|
||||||
private val basePreferences: BasePreferences,
|
private val basePreferences: BasePreferences,
|
||||||
private val sourcePreferences: SourcePreferences,
|
private val sourcePreferences: SourcePreferences,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -8,6 +9,7 @@ import tachiyomi.domain.source.model.Source
|
|||||||
import tachiyomi.domain.source.repository.SourceRepository
|
import tachiyomi.domain.source.repository.SourceRepository
|
||||||
import java.util.SortedMap
|
import java.util.SortedMap
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetLanguagesWithSources(
|
class GetLanguagesWithSources(
|
||||||
private val repository: SourceRepository,
|
private val repository: SourceRepository,
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
@@ -9,6 +10,7 @@ import tachiyomi.domain.source.repository.SourceRepository
|
|||||||
import tachiyomi.source.local.isLocal
|
import tachiyomi.source.local.isLocal
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
|
|
||||||
|
@Inject
|
||||||
class GetSourcesWithFavoriteCount(
|
class GetSourcesWithFavoriteCount(
|
||||||
private val repository: SourceRepository,
|
private val repository: SourceRepository,
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
|
|
||||||
|
@Inject
|
||||||
class SetMigrateSorting(
|
class SetMigrateSorting(
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import tachiyomi.core.common.preference.getAndSet
|
import tachiyomi.core.common.preference.getAndSet
|
||||||
|
|
||||||
|
@Inject
|
||||||
class ToggleIncognito(
|
class ToggleIncognito(
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import tachiyomi.core.common.preference.getAndSet
|
import tachiyomi.core.common.preference.getAndSet
|
||||||
|
|
||||||
|
@Inject
|
||||||
class ToggleLanguage(
|
class ToggleLanguage(
|
||||||
val preferences: SourcePreferences,
|
val preferences: SourcePreferences,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import tachiyomi.core.common.preference.getAndSet
|
import tachiyomi.core.common.preference.getAndSet
|
||||||
import tachiyomi.domain.source.model.Source
|
import tachiyomi.domain.source.model.Source
|
||||||
|
|
||||||
|
@Inject
|
||||||
class ToggleSource(
|
class ToggleSource(
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import tachiyomi.core.common.preference.getAndSet
|
import tachiyomi.core.common.preference.getAndSet
|
||||||
import tachiyomi.domain.source.model.Source
|
import tachiyomi.domain.source.model.Source
|
||||||
|
|
||||||
|
@Inject
|
||||||
class ToggleSourcePin(
|
class ToggleSourcePin(
|
||||||
private val preferences: SourcePreferences,
|
private val preferences: SourcePreferences,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package eu.kanade.domain.source.model
|
package eu.kanade.domain.source.model
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.domain.source.model.Source
|
import tachiyomi.domain.source.model.Source
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
val Source.icon: ImageBitmap?
|
val Source.icon: ImageBitmap?
|
||||||
get() {
|
get() {
|
||||||
return Injekt.get<ExtensionManager>().getAppIconForSource(id)
|
return Injekt.get<Context>().appGraph.extensionManager.getAppIconForSource(id)
|
||||||
?.toBitmap()
|
?.toBitmap()
|
||||||
?.asImageBitmap()
|
?.asImageBitmap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package eu.kanade.domain.source.service
|
package eu.kanade.domain.source.service
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import mihon.domain.migration.models.MigrationFlag
|
import mihon.domain.migration.models.MigrationFlag
|
||||||
@@ -9,6 +12,8 @@ import tachiyomi.core.common.preference.getEnum
|
|||||||
import tachiyomi.core.common.preference.getLongArray
|
import tachiyomi.core.common.preference.getLongArray
|
||||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class SourcePreferences(
|
class SourcePreferences(
|
||||||
preferenceStore: PreferenceStore,
|
preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.track.interactor
|
package eu.kanade.domain.track.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
import eu.kanade.domain.track.model.toDomainTrack
|
import eu.kanade.domain.track.model.toDomainTrack
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
@@ -17,14 +18,14 @@ import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
|
|||||||
import tachiyomi.domain.history.interactor.GetHistory
|
import tachiyomi.domain.history.interactor.GetHistory
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.track.interactor.InsertTrack
|
import tachiyomi.domain.track.interactor.InsertTrack
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class AddTracks(
|
class AddTracks(
|
||||||
private val insertTrack: InsertTrack,
|
private val insertTrack: InsertTrack,
|
||||||
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack,
|
private val syncChapterProgressWithTrack: SyncChapterProgressWithTrack,
|
||||||
private val getChaptersByMangaId: GetChaptersByMangaId,
|
private val getChaptersByMangaId: GetChaptersByMangaId,
|
||||||
private val trackerManager: TrackerManager,
|
private val trackerManager: TrackerManager,
|
||||||
|
private val getHistory: GetHistory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// TODO: update all trackers based on common data
|
// TODO: update all trackers based on common data
|
||||||
@@ -55,7 +56,7 @@ class AddTracks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (track.startDate <= 0) {
|
if (track.startDate <= 0) {
|
||||||
val firstReadChapterDate = Injekt.get<GetHistory>().await(mangaId)
|
val firstReadChapterDate = getHistory.await(mangaId)
|
||||||
.sortedBy { it.readAt }
|
.sortedBy { it.readAt }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
?.readAt
|
?.readAt
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.track.interactor
|
package eu.kanade.domain.track.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
import eu.kanade.domain.track.model.toDomainTrack
|
import eu.kanade.domain.track.model.toDomainTrack
|
||||||
import eu.kanade.tachiyomi.data.track.Tracker
|
import eu.kanade.tachiyomi.data.track.Tracker
|
||||||
@@ -10,6 +11,7 @@ import kotlinx.coroutines.supervisorScope
|
|||||||
import tachiyomi.domain.track.interactor.GetTracks
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
import tachiyomi.domain.track.interactor.InsertTrack
|
import tachiyomi.domain.track.interactor.InsertTrack
|
||||||
|
|
||||||
|
@Inject
|
||||||
class RefreshTracks(
|
class RefreshTracks(
|
||||||
private val getTracks: GetTracks,
|
private val getTracks: GetTracks,
|
||||||
private val trackerManager: TrackerManager,
|
private val trackerManager: TrackerManager,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.domain.track.interactor
|
package eu.kanade.domain.track.interactor
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||||
import eu.kanade.tachiyomi.data.track.Tracker
|
import eu.kanade.tachiyomi.data.track.Tracker
|
||||||
@@ -12,6 +13,7 @@ import tachiyomi.domain.track.interactor.InsertTrack
|
|||||||
import tachiyomi.domain.track.model.Track
|
import tachiyomi.domain.track.model.Track
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
|
@Inject
|
||||||
class SyncChapterProgressWithTrack(
|
class SyncChapterProgressWithTrack(
|
||||||
private val updateChapter: UpdateChapter,
|
private val updateChapter: UpdateChapter,
|
||||||
private val insertTrack: InsertTrack,
|
private val insertTrack: InsertTrack,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.domain.track.interactor
|
package eu.kanade.domain.track.interactor
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
import eu.kanade.domain.track.model.toDomainTrack
|
import eu.kanade.domain.track.model.toDomainTrack
|
||||||
import eu.kanade.domain.track.service.DelayedTrackingUpdateJob
|
import eu.kanade.domain.track.service.DelayedTrackingUpdateJob
|
||||||
@@ -14,6 +15,7 @@ import tachiyomi.core.common.util.system.logcat
|
|||||||
import tachiyomi.domain.track.interactor.GetTracks
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
import tachiyomi.domain.track.interactor.InsertTrack
|
import tachiyomi.domain.track.interactor.InsertTrack
|
||||||
|
|
||||||
|
@Inject
|
||||||
class TrackChapter(
|
class TrackChapter(
|
||||||
private val getTracks: GetTracks,
|
private val getTracks: GetTracks,
|
||||||
private val trackerManager: TrackerManager,
|
private val trackerManager: TrackerManager,
|
||||||
|
|||||||
@@ -8,30 +8,36 @@ import androidx.work.ExistingWorkPolicy
|
|||||||
import androidx.work.NetworkType
|
import androidx.work.NetworkType
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.track.interactor.TrackChapter
|
import eu.kanade.domain.track.interactor.TrackChapter
|
||||||
import eu.kanade.domain.track.store.DelayedTrackingStore
|
import eu.kanade.domain.track.store.DelayedTrackingStore
|
||||||
import eu.kanade.tachiyomi.util.system.workManager
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.AppGraph
|
||||||
|
import mihon.core.metro.metroGraph
|
||||||
import tachiyomi.core.common.util.lang.withIOContext
|
import tachiyomi.core.common.util.lang.withIOContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.domain.track.interactor.GetTracks
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class DelayedTrackingUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
class DelayedTrackingUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
CoroutineWorker(context, workerParams) {
|
CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
|
private val graph: AppGraph = context.metroGraph()
|
||||||
|
|
||||||
|
@Inject lateinit var getTracks: GetTracks
|
||||||
|
|
||||||
|
@Inject lateinit var trackChapter: TrackChapter
|
||||||
|
|
||||||
|
@Inject lateinit var delayedTrackingStore: DelayedTrackingStore
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
|
graph.inject(this)
|
||||||
|
|
||||||
if (runAttemptCount > 3) {
|
if (runAttemptCount > 3) {
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
val getTracks = Injekt.get<GetTracks>()
|
|
||||||
val trackChapter = Injekt.get<TrackChapter>()
|
|
||||||
|
|
||||||
val delayedTrackingStore = Injekt.get<DelayedTrackingStore>()
|
|
||||||
|
|
||||||
withIOContext {
|
withIOContext {
|
||||||
delayedTrackingStore.getItems()
|
delayedTrackingStore.getItems()
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package eu.kanade.domain.track.service
|
package eu.kanade.domain.track.service
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.domain.track.model.AutoTrackState
|
import eu.kanade.domain.track.model.AutoTrackState
|
||||||
import eu.kanade.tachiyomi.data.track.Tracker
|
import eu.kanade.tachiyomi.data.track.Tracker
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||||
@@ -8,6 +11,8 @@ import tachiyomi.core.common.preference.Preference
|
|||||||
import tachiyomi.core.common.preference.PreferenceStore
|
import tachiyomi.core.common.preference.PreferenceStore
|
||||||
import tachiyomi.core.common.preference.getEnum
|
import tachiyomi.core.common.preference.getEnum
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class TrackPreferences(
|
class TrackPreferences(
|
||||||
private val preferenceStore: PreferenceStore,
|
private val preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -2,9 +2,14 @@ package eu.kanade.domain.track.store
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class DelayedTrackingStore(context: Context) {
|
class DelayedTrackingStore(context: Context) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package eu.kanade.domain.ui
|
package eu.kanade.domain.ui
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.domain.ui.model.AppTheme
|
import eu.kanade.domain.ui.model.AppTheme
|
||||||
import eu.kanade.domain.ui.model.TabletUiMode
|
import eu.kanade.domain.ui.model.TabletUiMode
|
||||||
import eu.kanade.domain.ui.model.ThemeMode
|
import eu.kanade.domain.ui.model.ThemeMode
|
||||||
@@ -12,6 +15,8 @@ import java.time.format.DateTimeFormatter
|
|||||||
import java.time.format.FormatStyle
|
import java.time.format.FormatStyle
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class UiPreferences(
|
class UiPreferences(
|
||||||
preferenceStore: PreferenceStore,
|
preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ import eu.kanade.tachiyomi.util.lang.toRelativeString
|
|||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.toLocalDateTime
|
import kotlinx.datetime.toLocalDateTime
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -32,7 +31,7 @@ fun relativeDateText(
|
|||||||
): String {
|
): String {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val preferences = remember { Injekt.get<UiPreferences>() }
|
val preferences = remember { context.appGraph.uiPreferences }
|
||||||
val relativeTime = remember { preferences.relativeTime.get() }
|
val relativeTime = remember { preferences.relativeTime.get() }
|
||||||
val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat.get()) }
|
val dateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat.get()) }
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,15 @@ import androidx.compose.material.icons.outlined.BugReport
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||||
import eu.kanade.presentation.theme.TachiyomiPreviewTheme
|
import eu.kanade.presentation.theme.TachiyomiPreviewTheme
|
||||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
@@ -29,6 +30,7 @@ fun CrashScreen(
|
|||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val crashLogUtil = remember { context.appGraph.crashLogUtil }
|
||||||
|
|
||||||
InfoScreen(
|
InfoScreen(
|
||||||
icon = Icons.Outlined.BugReport,
|
icon = Icons.Outlined.BugReport,
|
||||||
@@ -37,7 +39,7 @@ fun CrashScreen(
|
|||||||
acceptText = stringResource(MR.strings.pref_dump_crash_logs),
|
acceptText = stringResource(MR.strings.pref_dump_crash_logs),
|
||||||
onAcceptClick = {
|
onAcceptClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
CrashLogUtil(context).dumpLogs(exception)
|
crashLogUtil.dumpLogs(exception)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rejectText = stringResource(MR.strings.crash_screen_restart_application),
|
rejectText = stringResource(MR.strings.crash_screen_restart_application),
|
||||||
|
|||||||
@@ -26,11 +26,12 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.domain.base.BasePreferences
|
|
||||||
import eu.kanade.domain.manga.model.downloadedFilter
|
import eu.kanade.domain.manga.model.downloadedFilter
|
||||||
import eu.kanade.presentation.components.TabbedDialog
|
import eu.kanade.presentation.components.TabbedDialog
|
||||||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.preference.TriState
|
import tachiyomi.core.common.preference.TriState
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
@@ -40,8 +41,6 @@ import tachiyomi.presentation.core.components.SortItem
|
|||||||
import tachiyomi.presentation.core.components.TriStateItem
|
import tachiyomi.presentation.core.components.TriStateItem
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.theme.active
|
import tachiyomi.presentation.core.theme.active
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChapterSettingsDialog(
|
fun ChapterSettingsDialog(
|
||||||
@@ -65,7 +64,8 @@ fun ChapterSettingsDialog(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val downloadedOnly = remember { Injekt.get<BasePreferences>().downloadedOnly.get() }
|
val context = LocalContext.current
|
||||||
|
val downloadedOnly = remember { context.appGraph.basePreferences.downloadedOnly.get() }
|
||||||
|
|
||||||
TabbedDialog(
|
TabbedDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
|
|||||||
@@ -63,10 +63,10 @@ import eu.kanade.presentation.more.settings.LocalPreferenceMinHeight
|
|||||||
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
import tachiyomi.domain.manga.model.MangaWithChapterCount
|
||||||
import tachiyomi.domain.source.model.StubSource
|
import tachiyomi.domain.source.model.StubSource
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.Badge
|
import tachiyomi.presentation.core.components.Badge
|
||||||
import tachiyomi.presentation.core.components.BadgeGroup
|
import tachiyomi.presentation.core.components.BadgeGroup
|
||||||
@@ -74,8 +74,6 @@ import tachiyomi.presentation.core.components.material.padding
|
|||||||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DuplicateMangaDialog(
|
fun DuplicateMangaDialog(
|
||||||
@@ -86,7 +84,8 @@ fun DuplicateMangaDialog(
|
|||||||
onMigrate: (manga: Manga) -> Unit,
|
onMigrate: (manga: Manga) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val sourceManager = remember { Injekt.get<SourceManager>() }
|
val context = LocalContext.current
|
||||||
|
val sourceManager = remember { context.appGraph.sourceManager }
|
||||||
val minHeight = LocalPreferenceMinHeight.current
|
val minHeight = LocalPreferenceMinHeight.current
|
||||||
val horizontalPadding = PaddingValues(horizontal = TabbedDialogPaddings.Horizontal)
|
val horizontalPadding = PaddingValues(horizontal = TabbedDialogPaddings.Horizontal)
|
||||||
val horizontalPaddingModifier = Modifier.padding(horizontalPadding)
|
val horizontalPaddingModifier = Modifier.padding(horizontalPadding)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.unit.DpOffset
|
import androidx.compose.ui.unit.DpOffset
|
||||||
@@ -48,7 +49,6 @@ import coil3.imageLoader
|
|||||||
import coil3.request.CachePolicy
|
import coil3.request.CachePolicy
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
import coil3.size.Size
|
import coil3.size.Size
|
||||||
import eu.kanade.domain.base.BasePreferences
|
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
import eu.kanade.presentation.components.DropdownMenu
|
import eu.kanade.presentation.components.DropdownMenu
|
||||||
@@ -57,13 +57,12 @@ import eu.kanade.tachiyomi.data.coil.ImageDecoder
|
|||||||
import eu.kanade.tachiyomi.data.coil.newDecoder
|
import eu.kanade.tachiyomi.data.coil.newDecoder
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaCoverDialog(
|
fun MangaCoverDialog(
|
||||||
@@ -75,7 +74,7 @@ fun MangaCoverDialog(
|
|||||||
onEditClick: ((EditCoverAction) -> Unit)?,
|
onEditClick: ((EditCoverAction) -> Unit)?,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val useNewRenderer = Injekt.get<BasePreferences>().highQualityRenderer.get()
|
val useNewRenderer = LocalContext.current.appGraph.basePreferences.highQualityRenderer.get()
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
|
|
||||||
Dialog(
|
Dialog(
|
||||||
|
|||||||
@@ -86,13 +86,13 @@ import coil3.request.crossfade
|
|||||||
import com.mikepenz.markdown.model.markdownAnnotator
|
import com.mikepenz.markdown.model.markdownAnnotator
|
||||||
import com.mikepenz.markdown.model.markdownAnnotatorConfig
|
import com.mikepenz.markdown.model.markdownAnnotatorConfig
|
||||||
import com.mikepenz.markdown.utils.getUnescapedTextInNode
|
import com.mikepenz.markdown.utils.getUnescapedTextInNode
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
|
||||||
import eu.kanade.presentation.components.DropdownMenu
|
import eu.kanade.presentation.components.DropdownMenu
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.daysUntil
|
import kotlinx.datetime.daysUntil
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import org.intellij.markdown.MarkdownElementTypes
|
import org.intellij.markdown.MarkdownElementTypes
|
||||||
import org.intellij.markdown.MarkdownTokenTypes
|
import org.intellij.markdown.MarkdownTokenTypes
|
||||||
import org.intellij.markdown.ast.findChildOfType
|
import org.intellij.markdown.ast.findChildOfType
|
||||||
@@ -105,8 +105,6 @@ import tachiyomi.presentation.core.i18n.pluralStringResource
|
|||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
@@ -619,7 +617,8 @@ private fun MangaSummary(
|
|||||||
onEditNotesClicked: () -> Unit,
|
onEditNotesClicked: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val preferences = remember { Injekt.get<UiPreferences>() }
|
val context = LocalContext.current
|
||||||
|
val preferences = remember { context.appGraph.uiPreferences }
|
||||||
val loadImages = remember { preferences.imagesInDescription.get() }
|
val loadImages = remember { preferences.imagesInDescription.get() }
|
||||||
val animProgress by animateFloatAsState(
|
val animProgress by animateFloatAsState(
|
||||||
targetValue = if (expanded) 1f else 0f,
|
targetValue = if (expanded) 1f else 0f,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
@@ -36,19 +37,16 @@ import androidx.lifecycle.DefaultLifecycleObserver
|
|||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||||
import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState
|
import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState
|
||||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
|
||||||
import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission
|
import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission
|
||||||
import eu.kanade.tachiyomi.util.system.telemetryIncluded
|
import eu.kanade.tachiyomi.util.system.telemetryIncluded
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
internal class PermissionStep : OnboardingStep {
|
internal class PermissionStep : OnboardingStep {
|
||||||
|
|
||||||
private val privacyPreferences: PrivacyPreferences by injectLazy()
|
|
||||||
|
|
||||||
private var notificationGranted by mutableStateOf(false)
|
private var notificationGranted by mutableStateOf(false)
|
||||||
private var batteryGranted by mutableStateOf(false)
|
private var batteryGranted by mutableStateOf(false)
|
||||||
|
|
||||||
@@ -57,6 +55,7 @@ internal class PermissionStep : OnboardingStep {
|
|||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val privacyPreferences = remember { context.appGraph.privacyPreferences }
|
||||||
val lifecycleOwner = LocalLifecycleOwner.current
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
|
|
||||||
val installGranted = rememberRequestPackageInstallsPermissionState()
|
val installGranted = rememberRequestPackageInstallsPermissionState()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -20,18 +21,14 @@ import androidx.compose.ui.unit.dp
|
|||||||
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import tachiyomi.domain.storage.service.StoragePreferences
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.Button
|
import tachiyomi.presentation.core.components.material.Button
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
internal class StorageStep : OnboardingStep {
|
internal class StorageStep : OnboardingStep {
|
||||||
|
|
||||||
private val storagePref = Injekt.get<StoragePreferences>().baseStorageDirectory
|
|
||||||
|
|
||||||
private var _isComplete by mutableStateOf(false)
|
private var _isComplete by mutableStateOf(false)
|
||||||
|
|
||||||
override val isComplete: Boolean
|
override val isComplete: Boolean
|
||||||
@@ -42,6 +39,7 @@ internal class StorageStep : OnboardingStep {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val handler = LocalUriHandler.current
|
val handler = LocalUriHandler.current
|
||||||
|
|
||||||
|
val storagePref = remember { context.appGraph.storagePreferences.baseStorageDirectory }
|
||||||
val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)
|
val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -3,22 +3,22 @@ package eu.kanade.presentation.more.onboarding
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
||||||
import eu.kanade.presentation.more.settings.widget.AppThemeModePreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.AppThemeModePreferenceWidget
|
||||||
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
internal class ThemeStep : OnboardingStep {
|
internal class ThemeStep : OnboardingStep {
|
||||||
|
|
||||||
override val isComplete: Boolean = true
|
override val isComplete: Boolean = true
|
||||||
|
|
||||||
private val uiPreferences: UiPreferences = Injekt.get()
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val uiPreferences = remember { context.appGraph.uiPreferences }
|
||||||
val themeModePref = uiPreferences.themeMode
|
val themeModePref = uiPreferences.themeMode
|
||||||
val themeMode by themeModePref.collectAsState()
|
val themeMode by themeModePref.collectAsState()
|
||||||
|
|
||||||
|
|||||||
+13
-16
@@ -25,13 +25,10 @@ import androidx.core.net.toUri
|
|||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.extension.interactor.TrustExtension
|
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen
|
import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
|
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadCache
|
|
||||||
import eu.kanade.tachiyomi.data.library.MetadataUpdateJob
|
import eu.kanade.tachiyomi.data.library.MetadataUpdateJob
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
|
||||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.network.PREF_DOH_360
|
import eu.kanade.tachiyomi.network.PREF_DOH_360
|
||||||
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
|
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
|
||||||
@@ -46,26 +43,24 @@ import eu.kanade.tachiyomi.network.PREF_DOH_QUAD101
|
|||||||
import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9
|
import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9
|
||||||
import eu.kanade.tachiyomi.network.PREF_DOH_SHECAN
|
import eu.kanade.tachiyomi.network.PREF_DOH_SHECAN
|
||||||
import eu.kanade.tachiyomi.ui.more.OnboardingScreen
|
import eu.kanade.tachiyomi.ui.more.OnboardingScreen
|
||||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
|
||||||
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
||||||
import eu.kanade.tachiyomi.util.system.isShizukuInstalled
|
import eu.kanade.tachiyomi.util.system.isShizukuInstalled
|
||||||
import eu.kanade.tachiyomi.util.system.powerManager
|
import eu.kanade.tachiyomi.util.system.powerManager
|
||||||
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import tachiyomi.core.common.util.lang.launchNonCancellable
|
import tachiyomi.core.common.util.lang.launchNonCancellable
|
||||||
import tachiyomi.core.common.util.lang.withUIContext
|
import tachiyomi.core.common.util.lang.withUIContext
|
||||||
import tachiyomi.core.common.util.system.ImageUtil
|
import tachiyomi.core.common.util.system.ImageUtil
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.manga.interactor.ResetViewerFlags
|
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object SettingsAdvancedScreen : SearchableSettings {
|
object SettingsAdvancedScreen : SearchableSettings {
|
||||||
@@ -80,9 +75,11 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
val basePreferences = remember { Injekt.get<BasePreferences>() }
|
val graph = remember { context.appGraph }
|
||||||
val networkPreferences = remember { Injekt.get<NetworkPreferences>() }
|
val basePreferences = remember { graph.basePreferences }
|
||||||
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
|
val networkPreferences = remember { graph.networkPreferences }
|
||||||
|
val libraryPreferences = remember { graph.libraryPreferences }
|
||||||
|
val crashLogUtil = remember { graph.crashLogUtil }
|
||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
@@ -90,7 +87,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
subtitle = stringResource(MR.strings.pref_dump_crash_logs_summary),
|
subtitle = stringResource(MR.strings.pref_dump_crash_logs_summary),
|
||||||
onClick = {
|
onClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
CrashLogUtil(context).dumpLogs()
|
crashLogUtil.dumpLogs()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -180,7 +177,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.pref_invalidate_download_cache),
|
title = stringResource(MR.strings.pref_invalidate_download_cache),
|
||||||
subtitle = stringResource(MR.strings.pref_invalidate_download_cache_summary),
|
subtitle = stringResource(MR.strings.pref_invalidate_download_cache_summary),
|
||||||
onClick = {
|
onClick = {
|
||||||
Injekt.get<DownloadCache>().invalidateCache()
|
context.appGraph.downloadCache.invalidateCache()
|
||||||
context.toast(MR.strings.download_cache_invalidated)
|
context.toast(MR.strings.download_cache_invalidated)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -198,7 +195,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
networkPreferences: NetworkPreferences,
|
networkPreferences: NetworkPreferences,
|
||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val networkHelper = remember { Injekt.get<NetworkHelper>() }
|
val networkHelper = remember { context.appGraph.networkHelper }
|
||||||
|
|
||||||
val userAgentPref = networkPreferences.defaultUserAgent
|
val userAgentPref = networkPreferences.defaultUserAgent
|
||||||
val userAgent by userAgentPref.collectAsState()
|
val userAgent by userAgentPref.collectAsState()
|
||||||
@@ -295,14 +292,14 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
preferenceItems = listOf(
|
preferenceItems = listOf(
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(MR.strings.pref_refresh_library_covers),
|
title = stringResource(MR.strings.pref_refresh_library_covers),
|
||||||
onClick = { MetadataUpdateJob.startNow(context) },
|
onClick = { MetadataUpdateJob.startNow(context.workManager) },
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(MR.strings.pref_reset_viewer_flags),
|
title = stringResource(MR.strings.pref_reset_viewer_flags),
|
||||||
subtitle = stringResource(MR.strings.pref_reset_viewer_flags_summary),
|
subtitle = stringResource(MR.strings.pref_reset_viewer_flags_summary),
|
||||||
onClick = {
|
onClick = {
|
||||||
scope.launchNonCancellable {
|
scope.launchNonCancellable {
|
||||||
val success = Injekt.get<ResetViewerFlags>().await()
|
val success = context.appGraph.resetViewerFlags.await()
|
||||||
withUIContext {
|
withUIContext {
|
||||||
val message = if (success) {
|
val message = if (success) {
|
||||||
MR.strings.pref_reset_viewer_flags_success
|
MR.strings.pref_reset_viewer_flags_success
|
||||||
@@ -352,7 +349,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
val extensionInstallerPref = basePreferences.extensionInstaller
|
val extensionInstallerPref = basePreferences.extensionInstaller
|
||||||
var shizukuMissing by rememberSaveable { mutableStateOf(false) }
|
var shizukuMissing by rememberSaveable { mutableStateOf(false) }
|
||||||
val trustExtension = remember { Injekt.get<TrustExtension>() }
|
val trustExtension = remember { context.appGraph.trustExtension }
|
||||||
|
|
||||||
if (shizukuMissing) {
|
if (shizukuMissing) {
|
||||||
val dismiss = { shizukuMissing = false }
|
val dismiss = { shizukuMissing = false }
|
||||||
|
|||||||
+3
-3
@@ -22,11 +22,10 @@ import eu.kanade.tachiyomi.util.system.toast
|
|||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.toJavaLocalDateTime
|
import kotlinx.datetime.toJavaLocalDateTime
|
||||||
import kotlinx.datetime.toLocalDateTime
|
import kotlinx.datetime.toLocalDateTime
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
object SettingsAppearanceScreen : SearchableSettings {
|
object SettingsAppearanceScreen : SearchableSettings {
|
||||||
@@ -37,7 +36,8 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
val context = LocalContext.current
|
||||||
|
val uiPreferences = remember { context.appGraph.uiPreferences }
|
||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
getThemeGroup(uiPreferences = uiPreferences),
|
getThemeGroup(uiPreferences = uiPreferences),
|
||||||
|
|||||||
+3
-6
@@ -9,17 +9,14 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.screen.browse.ExtensionStoresScreen
|
import eu.kanade.presentation.more.settings.screen.browse.ExtensionStoresScreen
|
||||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
|
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
|
||||||
import mihon.domain.extension.interactor.GetExtensionStoreCountAsFlow
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
object SettingsBrowseScreen : SearchableSettings {
|
object SettingsBrowseScreen : SearchableSettings {
|
||||||
|
|
||||||
@@ -32,8 +29,8 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
|
val sourcePreferences = remember { context.appGraph.sourcePreferences }
|
||||||
val getExtensionStoreCountAsFlow = remember { Injekt.get<GetExtensionStoreCountAsFlow>() }
|
val getExtensionStoreCountAsFlow = remember { context.appGraph.getExtensionStoreCountAsFlow }
|
||||||
|
|
||||||
val reposCount by getExtensionStoreCountAsFlow().collectAsState(0)
|
val reposCount by getExtensionStoreCountAsFlow().collectAsState(0)
|
||||||
|
|
||||||
|
|||||||
+9
-11
@@ -51,30 +51,27 @@ import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding
|
|||||||
import eu.kanade.presentation.util.relativeTimeSpanString
|
import eu.kanade.presentation.util.relativeTimeSpanString
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
|
||||||
import eu.kanade.tachiyomi.data.export.LibraryExporter
|
import eu.kanade.tachiyomi.data.export.LibraryExporter
|
||||||
import eu.kanade.tachiyomi.data.export.LibraryExporter.ExportOptions
|
import eu.kanade.tachiyomi.data.export.LibraryExporter.ExportOptions
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.storage.displayablePath
|
import tachiyomi.core.common.storage.displayablePath
|
||||||
import tachiyomi.core.common.util.lang.launchNonCancellable
|
import tachiyomi.core.common.util.lang.launchNonCancellable
|
||||||
import tachiyomi.core.common.util.lang.withUIContext
|
import tachiyomi.core.common.util.lang.withUIContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.domain.backup.service.BackupPreferences
|
import tachiyomi.domain.backup.service.BackupPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
|
||||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.storage.service.StoragePreferences
|
import tachiyomi.domain.storage.service.StoragePreferences
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.TextButton
|
import tachiyomi.presentation.core.components.material.TextButton
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
object SettingsDataScreen : SearchableSettings {
|
object SettingsDataScreen : SearchableSettings {
|
||||||
|
|
||||||
@@ -98,8 +95,9 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val backupPreferences = Injekt.get<BackupPreferences>()
|
val context = LocalContext.current
|
||||||
val storagePreferences = Injekt.get<StoragePreferences>()
|
val backupPreferences = remember { context.appGraph.backupPreferences }
|
||||||
|
val storagePreferences = remember { context.appGraph.storagePreferences }
|
||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
getStorageLocationPref(storagePreferences = storagePreferences),
|
getStorageLocationPref(storagePreferences = storagePreferences),
|
||||||
@@ -230,7 +228,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
modifier = Modifier.fillMaxHeight(),
|
modifier = Modifier.fillMaxHeight(),
|
||||||
checked = false,
|
checked = false,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
if (!BackupRestoreJob.isRunning(context)) {
|
if (!BackupRestoreJob.isRunning(context.workManager)) {
|
||||||
if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
|
if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
|
||||||
context.toast(MR.strings.restore_miui_warning)
|
context.toast(MR.strings.restore_miui_warning)
|
||||||
}
|
}
|
||||||
@@ -279,9 +277,9 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
private fun getDataGroup(): Preference.PreferenceGroup {
|
private fun getDataGroup(): Preference.PreferenceGroup {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
|
val libraryPreferences = remember { context.appGraph.libraryPreferences }
|
||||||
|
|
||||||
val chapterCache = remember { Injekt.get<ChapterCache>() }
|
val chapterCache = remember { context.appGraph.chapterCache }
|
||||||
var cacheReadableSizeSema by remember { mutableIntStateOf(0) }
|
var cacheReadableSizeSema by remember { mutableIntStateOf(0) }
|
||||||
val cacheReadableSize = remember(cacheReadableSizeSema) { chapterCache.readableSize }
|
val cacheReadableSize = remember(cacheReadableSizeSema) { chapterCache.readableSize }
|
||||||
|
|
||||||
@@ -341,7 +339,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val getFavorites = remember { Injekt.get<GetFavorites>() }
|
val getFavorites = remember { context.appGraph.getFavorites }
|
||||||
var favorites by remember { mutableStateOf<List<Manga>>(emptyList()) }
|
var favorites by remember { mutableStateOf<List<Manga>>(emptyList()) }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
favorites = getFavorites.await()
|
favorites = getFavorites.await()
|
||||||
|
|||||||
+5
-5
@@ -8,19 +8,18 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.util.fastMap
|
import androidx.compose.ui.util.fastMap
|
||||||
import eu.kanade.presentation.category.visualName
|
import eu.kanade.presentation.category.visualName
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.widget.TriStateListDialog
|
import eu.kanade.presentation.more.settings.widget.TriStateListDialog
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.domain.download.service.DownloadPreferences
|
import tachiyomi.domain.download.service.DownloadPreferences
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
object SettingsDownloadScreen : SearchableSettings {
|
object SettingsDownloadScreen : SearchableSettings {
|
||||||
|
|
||||||
@@ -30,10 +29,11 @@ object SettingsDownloadScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val getCategories = remember { Injekt.get<GetCategories>() }
|
val context = LocalContext.current
|
||||||
|
val getCategories = remember { context.appGraph.getCategories }
|
||||||
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
||||||
|
|
||||||
val downloadPreferences = remember { Injekt.get<DownloadPreferences>() }
|
val downloadPreferences = remember { context.appGraph.downloadPreferences }
|
||||||
val parallelSourceLimit by downloadPreferences.parallelSourceLimit.collectAsState()
|
val parallelSourceLimit by downloadPreferences.parallelSourceLimit.collectAsState()
|
||||||
val parallelPageLimit by downloadPreferences.parallelPageLimit.collectAsState()
|
val parallelPageLimit by downloadPreferences.parallelPageLimit.collectAsState()
|
||||||
return listOf(
|
return listOf(
|
||||||
|
|||||||
+9
-8
@@ -21,8 +21,7 @@ import eu.kanade.presentation.more.settings.widget.TriStateListDialog
|
|||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
import eu.kanade.tachiyomi.ui.category.CategoryScreen
|
import eu.kanade.tachiyomi.ui.category.CategoryScreen
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.domain.category.interactor.ResetCategoryFlags
|
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEVICE_CHARGING
|
import tachiyomi.domain.library.service.LibraryPreferences.Companion.DEVICE_CHARGING
|
||||||
@@ -38,8 +37,6 @@ import tachiyomi.i18n.MR
|
|||||||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
object SettingsLibraryScreen : SearchableSettings {
|
object SettingsLibraryScreen : SearchableSettings {
|
||||||
|
|
||||||
@@ -49,8 +46,9 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val getCategories = remember { Injekt.get<GetCategories>() }
|
val context = LocalContext.current
|
||||||
val libraryPreferences = remember { Injekt.get<LibraryPreferences>() }
|
val getCategories = remember { context.appGraph.getCategories }
|
||||||
|
val libraryPreferences = remember { context.appGraph.libraryPreferences }
|
||||||
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
val allCategories by getCategories.subscribe().collectAsState(initial = emptyList())
|
||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
@@ -66,6 +64,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
allCategories: List<Category>,
|
allCategories: List<Category>,
|
||||||
libraryPreferences: LibraryPreferences,
|
libraryPreferences: LibraryPreferences,
|
||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size
|
val userCategoriesCount = allCategories.filterNot(Category::isSystemCategory).size
|
||||||
|
|
||||||
@@ -98,7 +97,7 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
if (!it) {
|
if (!it) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
Injekt.get<ResetCategoryFlags>().await()
|
context.appGraph.resetCategoryFlags.await()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@@ -172,7 +171,9 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
enabled = autoUpdateInterval > 0,
|
enabled = autoUpdateInterval > 0,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
// Post to event looper to allow the preference to be updated.
|
// Post to event looper to allow the preference to be updated.
|
||||||
ContextCompat.getMainExecutor(context).execute { LibraryUpdateJob.setupTask(context) }
|
ContextCompat.getMainExecutor(context).execute {
|
||||||
|
LibraryUpdateJob.setupTask(context)
|
||||||
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
+4
-3
@@ -4,18 +4,18 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||||
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
|
|
||||||
object SettingsReaderScreen : SearchableSettings {
|
object SettingsReaderScreen : SearchableSettings {
|
||||||
@@ -26,7 +26,8 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val readerPref = remember { Injekt.get<ReaderPreferences>() }
|
val context = LocalContext.current
|
||||||
|
val readerPref = remember { context.appGraph.readerPreferences }
|
||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
|
|||||||
+4
-4
@@ -12,13 +12,12 @@ import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
|||||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
|
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
|
||||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.isAuthenticationSupported
|
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.isAuthenticationSupported
|
||||||
import eu.kanade.tachiyomi.util.system.telemetryIncluded
|
import eu.kanade.tachiyomi.util.system.telemetryIncluded
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.pluralStringResource
|
import tachiyomi.presentation.core.i18n.pluralStringResource
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
object SettingsSecurityScreen : SearchableSettings {
|
object SettingsSecurityScreen : SearchableSettings {
|
||||||
|
|
||||||
@@ -28,8 +27,9 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val securityPreferences = remember { Injekt.get<SecurityPreferences>() }
|
val context = LocalContext.current
|
||||||
val privacyPreferences = remember { Injekt.get<PrivacyPreferences>() }
|
val securityPreferences = remember { context.appGraph.securityPreferences }
|
||||||
|
val privacyPreferences = remember { context.appGraph.privacyPreferences }
|
||||||
return buildList(2) {
|
return buildList(2) {
|
||||||
add(getSecurityGroup(securityPreferences))
|
add(getSecurityGroup(securityPreferences))
|
||||||
if (!telemetryIncluded) return@buildList
|
if (!telemetryIncluded) return@buildList
|
||||||
|
|||||||
+4
-8
@@ -44,11 +44,9 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
import eu.kanade.domain.track.model.AutoTrackState
|
import eu.kanade.domain.track.model.AutoTrackState
|
||||||
import eu.kanade.domain.track.service.TrackPreferences
|
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||||
import eu.kanade.tachiyomi.data.track.Tracker
|
import eu.kanade.tachiyomi.data.track.Tracker
|
||||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.AnilistApi
|
import eu.kanade.tachiyomi.data.track.anilist.AnilistApi
|
||||||
import eu.kanade.tachiyomi.data.track.bangumi.BangumiApi
|
import eu.kanade.tachiyomi.data.track.bangumi.BangumiApi
|
||||||
import eu.kanade.tachiyomi.data.track.hikka.HikkaApi
|
import eu.kanade.tachiyomi.data.track.hikka.HikkaApi
|
||||||
@@ -57,14 +55,12 @@ import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeListApi
|
|||||||
import eu.kanade.tachiyomi.data.track.shikimori.ShikimoriApi
|
import eu.kanade.tachiyomi.data.track.shikimori.ShikimoriApi
|
||||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.core.common.util.lang.withUIContext
|
import tachiyomi.core.common.util.lang.withUIContext
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
object SettingsTrackingScreen : SearchableSettings {
|
object SettingsTrackingScreen : SearchableSettings {
|
||||||
|
|
||||||
@@ -86,9 +82,9 @@ object SettingsTrackingScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val trackPreferences = remember { Injekt.get<TrackPreferences>() }
|
val trackPreferences = remember { context.appGraph.trackPreferences }
|
||||||
val trackerManager = remember { Injekt.get<TrackerManager>() }
|
val trackerManager = remember { context.appGraph.trackerManager }
|
||||||
val sourceManager = remember { Injekt.get<SourceManager>() }
|
val sourceManager = remember { context.appGraph.sourceManager }
|
||||||
|
|
||||||
var dialog by remember { mutableStateOf<Any?>(null) }
|
var dialog by remember { mutableStateOf<Any?>(null) }
|
||||||
dialog?.run {
|
dialog?.run {
|
||||||
|
|||||||
@@ -30,10 +30,8 @@ import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
|||||||
import eu.kanade.presentation.util.LocalBackPress
|
import eu.kanade.presentation.util.LocalBackPress
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
|
|
||||||
import eu.kanade.tachiyomi.data.updater.RELEASE_URL
|
import eu.kanade.tachiyomi.data.updater.RELEASE_URL
|
||||||
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
|
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
|
||||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
|
||||||
import eu.kanade.tachiyomi.util.lang.toDateTimestampString
|
import eu.kanade.tachiyomi.util.lang.toDateTimestampString
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import eu.kanade.tachiyomi.util.system.isFossBuildType
|
import eu.kanade.tachiyomi.util.system.isFossBuildType
|
||||||
@@ -44,6 +42,7 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.toLocalDateTime
|
import kotlinx.datetime.toLocalDateTime
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.Constants
|
import tachiyomi.core.common.Constants
|
||||||
import tachiyomi.core.common.util.lang.withIOContext
|
import tachiyomi.core.common.util.lang.withIOContext
|
||||||
import tachiyomi.core.common.util.lang.withUIContext
|
import tachiyomi.core.common.util.lang.withUIContext
|
||||||
@@ -74,6 +73,7 @@ object AboutScreen : Screen() {
|
|||||||
val handleBack = LocalBackPress.current
|
val handleBack = LocalBackPress.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
var isCheckingUpdates by remember { mutableStateOf(false) }
|
var isCheckingUpdates by remember { mutableStateOf(false) }
|
||||||
|
val crashLogUtil = remember { context.appGraph.crashLogUtil }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
@@ -98,7 +98,7 @@ object AboutScreen : Screen() {
|
|||||||
title = stringResource(MR.strings.version),
|
title = stringResource(MR.strings.version),
|
||||||
subtitle = getVersionName(withBuildDate = true),
|
subtitle = getVersionName(withBuildDate = true),
|
||||||
onPreferenceClick = {
|
onPreferenceClick = {
|
||||||
val deviceInfo = CrashLogUtil(context).getDebugInfo()
|
val deviceInfo = crashLogUtil.getDebugInfo()
|
||||||
context.copyToClipboard("Debug information", deviceInfo)
|
context.copyToClipboard("Debug information", deviceInfo)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -217,7 +217,7 @@ object AboutScreen : Screen() {
|
|||||||
onAvailableUpdate: (GetApplicationRelease.Result.NewUpdate) -> Unit,
|
onAvailableUpdate: (GetApplicationRelease.Result.NewUpdate) -> Unit,
|
||||||
onFinish: () -> Unit,
|
onFinish: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val updateChecker = AppUpdateChecker()
|
val updateChecker = context.appGraph.updateChecker
|
||||||
withUIContext {
|
withUIContext {
|
||||||
try {
|
try {
|
||||||
when (val result = withIOContext { updateChecker.checkForUpdate(forceCheck = true) }) {
|
when (val result = withIOContext { updateChecker.checkForUpdate(forceCheck = true) }) {
|
||||||
@@ -279,7 +279,7 @@ object AboutScreen : Screen() {
|
|||||||
.toLocalDateTime(TimeZone.currentSystemDefault())
|
.toLocalDateTime(TimeZone.currentSystemDefault())
|
||||||
.toDateTimestampString(
|
.toDateTimestampString(
|
||||||
UiPreferences.dateFormat(
|
UiPreferences.dateFormat(
|
||||||
Injekt.get<UiPreferences>().dateFormat.get(),
|
Injekt.get<Context>().appGraph.uiPreferences.dateFormat.get(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
|
|||||||
+14
-8
@@ -32,9 +32,14 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.util.fastMap
|
import androidx.compose.ui.util.fastMap
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesIntoMap
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.binding
|
||||||
|
import dev.zacsweers.metrox.viewmodel.ViewModelKey
|
||||||
|
import dev.zacsweers.metrox.viewmodel.metroViewModel
|
||||||
import eu.kanade.presentation.browse.components.SourceIcon
|
import eu.kanade.presentation.browse.components.SourceIcon
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
@@ -60,8 +65,6 @@ import tachiyomi.presentation.core.i18n.stringResource
|
|||||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||||
import tachiyomi.presentation.core.util.selectedBackground
|
import tachiyomi.presentation.core.util.selectedBackground
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
class ClearDatabaseScreen : Screen() {
|
class ClearDatabaseScreen : Screen() {
|
||||||
|
|
||||||
@@ -69,7 +72,7 @@ class ClearDatabaseScreen : Screen() {
|
|||||||
override fun Content() {
|
override fun Content() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val viewModel = viewModel<ClearDatabaseViewModel>()
|
val viewModel = metroViewModel<ClearDatabaseViewModel>()
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
@@ -222,14 +225,17 @@ class ClearDatabaseScreen : Screen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClearDatabaseViewModel : ViewModel() {
|
@Inject
|
||||||
|
@ViewModelKey
|
||||||
|
@ContributesIntoMap(AppScope::class, binding = binding<ViewModel>())
|
||||||
|
class ClearDatabaseViewModel(
|
||||||
|
private val database: Database,
|
||||||
|
private val getSourcesWithNonLibraryManga: GetSourcesWithNonLibraryManga,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
val state: StateFlow<ClearDatabaseViewModel.State>
|
val state: StateFlow<ClearDatabaseViewModel.State>
|
||||||
field = MutableStateFlow<ClearDatabaseViewModel.State>(State.Loading)
|
field = MutableStateFlow<ClearDatabaseViewModel.State>(State.Loading)
|
||||||
|
|
||||||
private val getSourcesWithNonLibraryManga: GetSourcesWithNonLibraryManga = Injekt.get()
|
|
||||||
private val database: Database = Injekt.get()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
getSourcesWithNonLibraryManga.subscribe()
|
getSourcesWithNonLibraryManga.subscribe()
|
||||||
|
|||||||
+2
-1
@@ -8,6 +8,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import dev.zacsweers.metrox.viewmodel.metroViewModel
|
||||||
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionStoreConfirmDialog
|
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionStoreConfirmDialog
|
||||||
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionStoreCreateDialog
|
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionStoreCreateDialog
|
||||||
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionStoreDeleteDialog
|
import eu.kanade.presentation.more.settings.screen.browse.components.ExtensionStoreDeleteDialog
|
||||||
@@ -26,7 +27,7 @@ class ExtensionStoresScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
val viewModel = viewModel<ExtensionStoresViewModel>()
|
val viewModel = metroViewModel<ExtensionStoresViewModel>()
|
||||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
LaunchedEffect(url) {
|
LaunchedEffect(url) {
|
||||||
|
|||||||
+13
-7
@@ -3,6 +3,11 @@ package eu.kanade.presentation.more.settings.screen.browse
|
|||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesIntoMap
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.binding
|
||||||
|
import dev.zacsweers.metrox.viewmodel.ViewModelKey
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -20,16 +25,17 @@ import mihon.domain.extension.interactor.RemoveExtensionStore
|
|||||||
import mihon.domain.extension.interactor.UpdateExtensionStores
|
import mihon.domain.extension.interactor.UpdateExtensionStores
|
||||||
import mihon.domain.extension.model.ExtensionStore
|
import mihon.domain.extension.model.ExtensionStore
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@ViewModelKey
|
||||||
|
@ContributesIntoMap(AppScope::class, binding = binding<ViewModel>())
|
||||||
class ExtensionStoresViewModel(
|
class ExtensionStoresViewModel(
|
||||||
private val getExtensionStores: GetExtensionStores = Injekt.get(),
|
private val getExtensionStores: GetExtensionStores,
|
||||||
private val addExtensionStore: AddExtensionStore = Injekt.get(),
|
private val addExtensionStore: AddExtensionStore,
|
||||||
private val removeExtensionStore: RemoveExtensionStore = Injekt.get(),
|
private val removeExtensionStore: RemoveExtensionStore,
|
||||||
private val updateExtensionStores: UpdateExtensionStores = Injekt.get(),
|
private val updateExtensionStores: UpdateExtensionStores,
|
||||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
private val extensionManager: ExtensionManager,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val dialog = MutableStateFlow<ExtensionStoreDialog?>(null)
|
private val dialog = MutableStateFlow<ExtensionStoreDialog?>(null)
|
||||||
|
|||||||
+11
-3
@@ -12,9 +12,14 @@ import androidx.compose.runtime.collectAsState
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesIntoMap
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.binding
|
||||||
|
import dev.zacsweers.metrox.viewmodel.ViewModelKey
|
||||||
|
import dev.zacsweers.metrox.viewmodel.metroViewModel
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.WarningBanner
|
import eu.kanade.presentation.components.WarningBanner
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
@@ -39,7 +44,7 @@ class CreateBackupScreen : Screen() {
|
|||||||
override fun Content() {
|
override fun Content() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val viewModel = viewModel<CreateBackupViewModel>()
|
val viewModel = metroViewModel<CreateBackupViewModel>()
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
|
|
||||||
val chooseBackupDir = rememberLauncherForActivityResult(
|
val chooseBackupDir = rememberLauncherForActivityResult(
|
||||||
@@ -73,7 +78,7 @@ class CreateBackupScreen : Screen() {
|
|||||||
if (!BackupCreateJob.isManualJobRunning(context)) {
|
if (!BackupCreateJob.isManualJobRunning(context)) {
|
||||||
try {
|
try {
|
||||||
chooseBackupDir.launch(BackupCreator.getFilename())
|
chooseBackupDir.launch(BackupCreator.getFilename())
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (_: ActivityNotFoundException) {
|
||||||
context.toast(MR.strings.file_picker_error)
|
context.toast(MR.strings.file_picker_error)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -121,6 +126,9 @@ class CreateBackupScreen : Screen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@ViewModelKey
|
||||||
|
@ContributesIntoMap(AppScope::class, binding = binding<ViewModel>())
|
||||||
class CreateBackupViewModel : ViewModel() {
|
class CreateBackupViewModel : ViewModel() {
|
||||||
|
|
||||||
val state: StateFlow<CreateBackupViewModel.State>
|
val state: StateFlow<CreateBackupViewModel.State>
|
||||||
|
|||||||
+21
-27
@@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen.data
|
package eu.kanade.presentation.more.settings.screen.data
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -21,12 +20,16 @@ import androidx.compose.ui.text.font.FontWeight
|
|||||||
import androidx.compose.ui.text.withStyle
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewmodel.CreationExtras
|
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.lifecycle.viewmodel.initializer
|
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Assisted
|
||||||
|
import dev.zacsweers.metro.AssistedFactory
|
||||||
|
import dev.zacsweers.metro.AssistedInject
|
||||||
|
import dev.zacsweers.metro.ContributesIntoMap
|
||||||
|
import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactory
|
||||||
|
import dev.zacsweers.metrox.viewmodel.ManualViewModelAssistedFactoryKey
|
||||||
|
import dev.zacsweers.metrox.viewmodel.assistedMetroViewModel
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.WarningBanner
|
import eu.kanade.presentation.components.WarningBanner
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
@@ -34,6 +37,7 @@ import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
|||||||
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.RestoreOptions
|
import eu.kanade.tachiyomi.data.backup.restore.RestoreOptions
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
@@ -44,8 +48,6 @@ import tachiyomi.presentation.core.components.SectionCard
|
|||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
class RestoreBackupScreen(
|
class RestoreBackupScreen(
|
||||||
private val uri: String,
|
private val uri: String,
|
||||||
@@ -54,12 +56,8 @@ class RestoreBackupScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val viewModel = viewModel<RestoreBackupViewModel>(
|
val viewModel =
|
||||||
factory = RestoreBackupViewModel.Factory,
|
assistedMetroViewModel<RestoreBackupViewModel, RestoreBackupViewModel.Factory> { create(uri = uri) }
|
||||||
extras = CreationExtras {
|
|
||||||
set(RestoreBackupViewModel.URI_KEY, uri)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -175,25 +173,21 @@ class RestoreBackupScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AssistedInject
|
||||||
class RestoreBackupViewModel(
|
class RestoreBackupViewModel(
|
||||||
|
@Assisted private val uri: String,
|
||||||
|
private val backupFileValidator: BackupFileValidator,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val uri: String,
|
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val state: StateFlow<RestoreBackupViewModel.State>
|
val state: StateFlow<RestoreBackupViewModel.State>
|
||||||
field = MutableStateFlow<RestoreBackupViewModel.State>(State())
|
field = MutableStateFlow<RestoreBackupViewModel.State>(State())
|
||||||
|
|
||||||
companion object {
|
@AssistedFactory
|
||||||
val URI_KEY = CreationExtras.Key<String>()
|
@ManualViewModelAssistedFactoryKey
|
||||||
|
@ContributesIntoMap(AppScope::class)
|
||||||
val Factory = viewModelFactory {
|
interface Factory : ManualViewModelAssistedFactory {
|
||||||
initializer {
|
fun create(uri: String): RestoreBackupViewModel
|
||||||
RestoreBackupViewModel(
|
|
||||||
context = Injekt.get<Application>(),
|
|
||||||
uri = get(URI_KEY)!!,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -210,7 +204,7 @@ class RestoreBackupViewModel(
|
|||||||
|
|
||||||
fun startRestore() {
|
fun startRestore() {
|
||||||
BackupRestoreJob.start(
|
BackupRestoreJob.start(
|
||||||
context = context,
|
workManager = context.workManager,
|
||||||
uri = uri.toUri(),
|
uri = uri.toUri(),
|
||||||
options = state.value.options,
|
options = state.value.options,
|
||||||
)
|
)
|
||||||
@@ -218,7 +212,7 @@ class RestoreBackupViewModel(
|
|||||||
|
|
||||||
private fun validate(uri: Uri) {
|
private fun validate(uri: Uri) {
|
||||||
val results = try {
|
val results = try {
|
||||||
BackupFileValidator(context).validate(uri)
|
backupFileValidator.validate(uri)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
setError(
|
setError(
|
||||||
error = InvalidRestore(uri, e.message.toString()),
|
error = InvalidRestore(uri, e.message.toString()),
|
||||||
|
|||||||
+2
-4
@@ -16,7 +16,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.profileinstaller.ProfileVerifier
|
import androidx.profileinstaller.ProfileVerifier
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.base.BasePreferences
|
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
||||||
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||||
@@ -26,11 +25,10 @@ import eu.kanade.tachiyomi.util.system.WebViewUtil
|
|||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import kotlinx.coroutines.guava.await
|
import kotlinx.coroutines.guava.await
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import mihon.core.common.FeatureFlags
|
import mihon.core.common.FeatureFlags
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
class DebugInfoScreen : Screen() {
|
class DebugInfoScreen : Screen() {
|
||||||
|
|
||||||
@@ -62,7 +60,7 @@ class DebugInfoScreen : Screen() {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val installationIdPref = remember { Injekt.get<BasePreferences>().installationId }
|
val installationIdPref = remember { context.appGraph.basePreferences.installationId }
|
||||||
val installationId by installationIdPref.collectAsState()
|
val installationId by installationIdPref.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
|
|||||||
+12
-18
@@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen.debug
|
package eu.kanade.presentation.more.settings.screen.debug
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.foundation.horizontalScroll
|
import androidx.compose.foundation.horizontalScroll
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -21,13 +20,15 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.util.fastForEach
|
import androidx.compose.ui.util.fastForEach
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import androidx.lifecycle.viewmodel.initializer
|
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
|
||||||
import androidx.work.WorkInfo
|
import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkQuery
|
import androidx.work.WorkQuery
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesIntoMap
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metrox.viewmodel.ViewModelKey
|
||||||
|
import dev.zacsweers.metrox.viewmodel.metroViewModel
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
@@ -40,11 +41,11 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.toLocalDateTime
|
import kotlinx.datetime.toLocalDateTime
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.plus
|
import tachiyomi.presentation.core.util.plus
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ class WorkerInfoScreen : Screen() {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
val viewModel = viewModel<WorkerInfoViewModel>(factory = WorkerInfoViewModel.Factory)
|
val viewModel = metroViewModel<WorkerInfoViewModel>()
|
||||||
val enqueued by viewModel.enqueued.collectAsState()
|
val enqueued by viewModel.enqueued.collectAsState()
|
||||||
val finished by viewModel.finished.collectAsState()
|
val finished by viewModel.finished.collectAsState()
|
||||||
val running by viewModel.running.collectAsState()
|
val running by viewModel.running.collectAsState()
|
||||||
@@ -120,20 +121,13 @@ class WorkerInfoScreen : Screen() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@ViewModelKey
|
||||||
|
@ContributesIntoMap(AppScope::class)
|
||||||
class WorkerInfoViewModel(
|
class WorkerInfoViewModel(
|
||||||
context: Context,
|
private val context: Context,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
companion object {
|
|
||||||
val Factory = viewModelFactory {
|
|
||||||
initializer {
|
|
||||||
WorkerInfoViewModel(
|
|
||||||
context = Injekt.get<Application>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val workManager = context.workManager
|
private val workManager = context.workManager
|
||||||
|
|
||||||
val finished = workManager
|
val finished = workManager
|
||||||
@@ -169,7 +163,7 @@ class WorkerInfoScreen : Screen() {
|
|||||||
.toLocalDateTime(TimeZone.currentSystemDefault())
|
.toLocalDateTime(TimeZone.currentSystemDefault())
|
||||||
.toDateTimestampString(
|
.toDateTimestampString(
|
||||||
UiPreferences.dateFormat(
|
UiPreferences.dateFormat(
|
||||||
Injekt.get<UiPreferences>().dateFormat.get(),
|
context.appGraph.uiPreferences.dateFormat.get(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
appendLine("Next scheduled run: $timestamp")
|
appendLine("Next scheduled run: $timestamp")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.presentation.reader
|
package eu.kanade.presentation.reader
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -13,6 +14,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@@ -22,7 +24,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
|||||||
class DisplayRefreshHost {
|
class DisplayRefreshHost {
|
||||||
|
|
||||||
internal var currentDisplayRefresh by mutableStateOf(false)
|
internal var currentDisplayRefresh by mutableStateOf(false)
|
||||||
private val readerPreferences = Injekt.get<ReaderPreferences>()
|
private val readerPreferences = Injekt.get<Context>().appGraph.readerPreferences
|
||||||
|
|
||||||
internal val flashMillis = readerPreferences.flashDurationMillis
|
internal val flashMillis = readerPreferences.flashDurationMillis
|
||||||
internal val flashMode = readerPreferences.flashColor
|
internal val flashMode = readerPreferences.flashColor
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import eu.kanade.domain.manga.model.readerOrientation
|
import eu.kanade.domain.manga.model.readerOrientation
|
||||||
import eu.kanade.domain.manga.model.readingMode
|
import eu.kanade.domain.manga.model.readingMode
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
||||||
@@ -16,6 +17,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsViewModel
|
|||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.webgpu.WebGpuViewer
|
import eu.kanade.tachiyomi.ui.reader.viewer.webgpu.WebGpuViewer
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.CheckboxItem
|
import tachiyomi.presentation.core.components.CheckboxItem
|
||||||
import tachiyomi.presentation.core.components.HeadingItem
|
import tachiyomi.presentation.core.components.HeadingItem
|
||||||
@@ -23,8 +25,6 @@ import tachiyomi.presentation.core.components.SettingsChipRow
|
|||||||
import tachiyomi.presentation.core.components.SliderItem
|
import tachiyomi.presentation.core.components.SliderItem
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.util.collectAsState
|
import tachiyomi.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -43,7 +43,7 @@ internal fun ColumnScope.ReadingModePage(viewModel: ReaderSettingsViewModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val default = Injekt.get<ReaderPreferences>().defaultReadingMode.get()
|
val default = LocalContext.current.appGraph.readerPreferences.defaultReadingMode.get()
|
||||||
val resolved = ReadingMode.fromPreference(
|
val resolved = ReadingMode.fromPreference(
|
||||||
when {
|
when {
|
||||||
readingMode == ReadingMode.DEFAULT -> default
|
readingMode == ReadingMode.DEFAULT -> default
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import androidx.compose.material3.MaterialExpressiveTheme
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
|
||||||
import eu.kanade.domain.ui.model.AppTheme
|
import eu.kanade.domain.ui.model.AppTheme
|
||||||
import eu.kanade.presentation.theme.colorscheme.BaseColorScheme
|
import eu.kanade.presentation.theme.colorscheme.BaseColorScheme
|
||||||
import eu.kanade.presentation.theme.colorscheme.CatppuccinColorScheme
|
import eu.kanade.presentation.theme.colorscheme.CatppuccinColorScheme
|
||||||
@@ -25,8 +24,7 @@ import eu.kanade.presentation.theme.colorscheme.TidalWaveColorScheme
|
|||||||
import eu.kanade.presentation.theme.colorscheme.TokyoNightColorScheme
|
import eu.kanade.presentation.theme.colorscheme.TokyoNightColorScheme
|
||||||
import eu.kanade.presentation.theme.colorscheme.YinYangColorScheme
|
import eu.kanade.presentation.theme.colorscheme.YinYangColorScheme
|
||||||
import eu.kanade.presentation.theme.colorscheme.YotsubaColorScheme
|
import eu.kanade.presentation.theme.colorscheme.YotsubaColorScheme
|
||||||
import uy.kohesive.injekt.Injekt
|
import mihon.app.di.appGraph
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TachiyomiTheme(
|
fun TachiyomiTheme(
|
||||||
@@ -34,7 +32,8 @@ fun TachiyomiTheme(
|
|||||||
amoled: Boolean? = null,
|
amoled: Boolean? = null,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
val uiPreferences = Injekt.get<UiPreferences>()
|
val context = LocalContext.current
|
||||||
|
val uiPreferences = remember { context.appGraph.uiPreferences }
|
||||||
BaseTachiyomiTheme(
|
BaseTachiyomiTheme(
|
||||||
appTheme = appTheme ?: uiPreferences.appTheme.get(),
|
appTheme = appTheme ?: uiPreferences.appTheme.get(),
|
||||||
isAmoled = amoled ?: uiPreferences.themeDarkAmoled.get(),
|
isAmoled = amoled ?: uiPreferences.themeDarkAmoled.get(),
|
||||||
|
|||||||
@@ -22,21 +22,21 @@ import coil3.request.allowRgb565
|
|||||||
import coil3.request.crossfade
|
import coil3.request.crossfade
|
||||||
import coil3.util.DebugLogger
|
import coil3.util.DebugLogger
|
||||||
import dev.mihon.injekt.patchInjekt
|
import dev.mihon.injekt.patchInjekt
|
||||||
import eu.kanade.domain.DomainModule
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.createGraphFactory
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
||||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||||
import eu.kanade.tachiyomi.crash.CrashActivity
|
import eu.kanade.tachiyomi.crash.CrashActivity
|
||||||
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
||||||
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.coil.BufferedSourceFetcher
|
import eu.kanade.tachiyomi.data.coil.BufferedSourceFetcher
|
||||||
import eu.kanade.tachiyomi.data.coil.ImageDecoder
|
import eu.kanade.tachiyomi.data.coil.ImageDecoder
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaKeyer
|
import eu.kanade.tachiyomi.data.coil.MangaKeyer
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.di.AppModule
|
|
||||||
import eu.kanade.tachiyomi.di.PreferenceModule
|
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
||||||
@@ -44,6 +44,7 @@ import eu.kanade.tachiyomi.util.system.DeviceUtil
|
|||||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||||
import eu.kanade.tachiyomi.util.system.cancelNotification
|
import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||||
|
import eu.kanade.tachiyomi.util.system.isDebugBuildType
|
||||||
import eu.kanade.tachiyomi.util.system.notify
|
import eu.kanade.tachiyomi.util.system.notify
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -51,34 +52,68 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import logcat.AndroidLogcatLogger
|
import logcat.AndroidLogcatLogger
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import logcat.LogcatLogger
|
import logcat.LogcatLogger
|
||||||
|
import mihon.app.di.AppGraph
|
||||||
|
import mihon.app.di.injekt.MetroInteropModule
|
||||||
|
import mihon.core.metro.GraphProvider
|
||||||
|
import mihon.core.migration.Migration
|
||||||
import mihon.core.migration.Migrator
|
import mihon.core.migration.Migrator
|
||||||
import mihon.core.migration.migrations.migrations
|
|
||||||
import mihon.telemetry.TelemetryConfig
|
import mihon.telemetry.TelemetryConfig
|
||||||
import org.conscrypt.Conscrypt
|
import org.conscrypt.Conscrypt
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.preference.Preference
|
import tachiyomi.core.common.preference.Preference
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
import tachiyomi.core.common.preference.PreferenceStore
|
||||||
import tachiyomi.core.common.util.system.ImageUtil
|
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.widget.WidgetManager
|
import tachiyomi.presentation.widget.WidgetManager
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.addSingleton
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.security.Security
|
import java.security.Security
|
||||||
|
|
||||||
class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factory {
|
class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factory, GraphProvider<AppGraph> {
|
||||||
|
|
||||||
private val basePreferences: BasePreferences by injectLazy()
|
override val graph: AppGraph by lazy {
|
||||||
private val privacyPreferences: PrivacyPreferences by injectLazy()
|
createGraphFactory<AppGraph.Factory>().create(context = this, isDebugBuild = isDebugBuildType)
|
||||||
private val networkPreferences: NetworkPreferences by injectLazy()
|
}
|
||||||
|
|
||||||
|
@Inject private lateinit var preferenceStore: PreferenceStore
|
||||||
|
|
||||||
|
@Inject private lateinit var basePreferences: BasePreferences
|
||||||
|
|
||||||
|
@Inject private lateinit var privacyPreferences: PrivacyPreferences
|
||||||
|
|
||||||
|
@Inject private lateinit var networkPreferences: NetworkPreferences
|
||||||
|
|
||||||
|
@Inject private lateinit var uiPreferences: UiPreferences
|
||||||
|
|
||||||
|
@Inject private lateinit var coverCache: CoverCache
|
||||||
|
|
||||||
|
@Inject private lateinit var networkHelper: NetworkHelper
|
||||||
|
|
||||||
|
@Inject private lateinit var sourceManager: SourceManager
|
||||||
|
|
||||||
|
@Inject private lateinit var widgetManager: WidgetManager
|
||||||
|
|
||||||
|
@Inject private lateinit var injektMetroInteropModule: MetroInteropModule
|
||||||
|
|
||||||
|
@Inject private lateinit var migrations: Set<Migration>
|
||||||
|
|
||||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||||
|
|
||||||
@SuppressLint("LaunchActivityFromNotification")
|
@SuppressLint("LaunchActivityFromNotification")
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super<Application>.onCreate()
|
super<Application>.onCreate()
|
||||||
patchInjekt()
|
|
||||||
|
// Must run before the graph is built, since injecting dependencies initializes WebView and the
|
||||||
|
// suffix can't be set once a provider exists in the process. Secondary processes die otherwise.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
val process = getProcessName()
|
||||||
|
if (packageName != process) WebView.setDataDirectorySuffix(process)
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.inject(this)
|
||||||
|
setupInjekt()
|
||||||
|
|
||||||
TelemetryConfig.init(applicationContext)
|
TelemetryConfig.init(applicationContext)
|
||||||
|
|
||||||
GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java)
|
GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java)
|
||||||
@@ -88,16 +123,6 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid potential crashes
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
||||||
val process = getProcessName()
|
|
||||||
if (packageName != process) WebView.setDataDirectorySuffix(process)
|
|
||||||
}
|
|
||||||
|
|
||||||
Injekt.importModule(PreferenceModule(this))
|
|
||||||
Injekt.importModule(AppModule(this))
|
|
||||||
Injekt.importModule(DomainModule())
|
|
||||||
|
|
||||||
setupNotificationChannels()
|
setupNotificationChannels()
|
||||||
|
|
||||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||||
@@ -143,10 +168,10 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
.onEach(TelemetryConfig::setCrashlyticsEnabled)
|
.onEach(TelemetryConfig::setCrashlyticsEnabled)
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode.get())
|
setAppCompatDelegateThemeMode(uiPreferences.themeMode.get())
|
||||||
|
|
||||||
// Updates widget update
|
// Updates widget update
|
||||||
WidgetManager(Injekt.get(), Injekt.get()).apply { init(scope) }
|
widgetManager.init(scope)
|
||||||
|
|
||||||
if (!LogcatLogger.isInstalled) {
|
if (!LogcatLogger.isInstalled) {
|
||||||
val minLogPriority = when {
|
val minLogPriority = when {
|
||||||
@@ -161,14 +186,22 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
initializeMigrator()
|
initializeMigrator()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupInjekt() {
|
||||||
|
patchInjekt()
|
||||||
|
Injekt.addSingleton<Application>(this)
|
||||||
|
Injekt.addSingleton<Context>(this)
|
||||||
|
Injekt.importModule(injektMetroInteropModule)
|
||||||
|
}
|
||||||
|
|
||||||
private fun initializeMigrator() {
|
private fun initializeMigrator() {
|
||||||
val preferenceStore = Injekt.get<PreferenceStore>()
|
|
||||||
val preference = preferenceStore.getInt(Preference.appStateKey("last_version_code"), 0)
|
val preference = preferenceStore.getInt(Preference.appStateKey("last_version_code"), 0)
|
||||||
logcat { "Migration from ${preference.get()} to ${BuildConfig.VERSION_CODE}" }
|
logcat {
|
||||||
|
"Migration from ${preference.get()} to ${BuildConfig.VERSION_CODE} with ${migrations.size} migration(s)"
|
||||||
|
}
|
||||||
Migrator.initialize(
|
Migrator.initialize(
|
||||||
old = preference.get(),
|
old = preference.get(),
|
||||||
new = BuildConfig.VERSION_CODE,
|
new = BuildConfig.VERSION_CODE,
|
||||||
migrations = migrations,
|
migrations = migrations.toList(),
|
||||||
onMigrationComplete = {
|
onMigrationComplete = {
|
||||||
logcat { "Updating last version to ${BuildConfig.VERSION_CODE}" }
|
logcat { "Updating last version to ${BuildConfig.VERSION_CODE}" }
|
||||||
preference.set(BuildConfig.VERSION_CODE)
|
preference.set(BuildConfig.VERSION_CODE)
|
||||||
@@ -178,7 +211,7 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
|
|
||||||
override fun newImageLoader(context: Context): ImageLoader {
|
override fun newImageLoader(context: Context): ImageLoader {
|
||||||
return ImageLoader.Builder(this).apply {
|
return ImageLoader.Builder(this).apply {
|
||||||
val callFactoryLazy = lazy { Injekt.get<NetworkHelper>().client }
|
val callFactoryLazy = lazy { networkHelper.client }
|
||||||
components {
|
components {
|
||||||
// NetworkFetcher.Factory
|
// NetworkFetcher.Factory
|
||||||
add(OkHttpNetworkFetcherFactory(callFactoryLazy::value))
|
add(OkHttpNetworkFetcherFactory(callFactoryLazy::value))
|
||||||
@@ -186,10 +219,10 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
add(ImageDecoder.Factory())
|
add(ImageDecoder.Factory())
|
||||||
// Fetcher.Factory
|
// Fetcher.Factory
|
||||||
add(BufferedSourceFetcher.Factory())
|
add(BufferedSourceFetcher.Factory())
|
||||||
add(MangaCoverFetcher.MangaCoverFactory(callFactoryLazy))
|
add(MangaCoverFetcher.MangaCoverFactory(callFactoryLazy, coverCache, sourceManager))
|
||||||
add(MangaCoverFetcher.MangaFactory(callFactoryLazy))
|
add(MangaCoverFetcher.MangaFactory(callFactoryLazy, coverCache, sourceManager))
|
||||||
// Keyer
|
// Keyer
|
||||||
add(MangaCoverKeyer())
|
add(MangaCoverKeyer(coverCache))
|
||||||
add(MangaKeyer())
|
add(MangaKeyer())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,11 +244,11 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart(owner: LifecycleOwner) {
|
override fun onStart(owner: LifecycleOwner) {
|
||||||
SecureActivityDelegate.onApplicationStart()
|
SecureActivityDelegate.onApplicationStart(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop(owner: LifecycleOwner) {
|
override fun onStop(owner: LifecycleOwner) {
|
||||||
SecureActivityDelegate.onApplicationStopped()
|
SecureActivityDelegate.onApplicationStopped(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPackageName(): String {
|
override fun getPackageName(): String {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.protobuf.ProtoBuf
|
import kotlinx.serialization.protobuf.ProtoBuf
|
||||||
@@ -10,13 +11,12 @@ import okio.gzip
|
|||||||
import okio.source
|
import okio.source
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
|
@Inject
|
||||||
class BackupDecoder(
|
class BackupDecoder(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val parser: ProtoBuf = Injekt.get(),
|
private val parser: ProtoBuf,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Decode a potentially-gzipped backup.
|
* Decode a potentially-gzipped backup.
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup
|
package eu.kanade.tachiyomi.data.backup
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class BackupFileValidator(
|
class BackupFileValidator(
|
||||||
private val context: Context,
|
private val sourceManager: SourceManager,
|
||||||
|
private val trackerManager: TrackerManager,
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val backupDecoder: BackupDecoder,
|
||||||
private val trackerManager: TrackerManager = Injekt.get(),
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,7 +19,7 @@ class BackupFileValidator(
|
|||||||
*/
|
*/
|
||||||
fun validate(uri: Uri): Results {
|
fun validate(uri: Uri): Results {
|
||||||
val backup = try {
|
val backup = try {
|
||||||
BackupDecoder(context).decode(uri)
|
backupDecoder.decode(uri)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw IllegalStateException(e)
|
throw IllegalStateException(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
@@ -16,14 +17,14 @@ import tachiyomi.core.common.i18n.pluralStringResource
|
|||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.storage.displayablePath
|
import tachiyomi.core.common.storage.displayablePath
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
class BackupNotifier(private val context: Context) {
|
@Inject
|
||||||
|
class BackupNotifier(
|
||||||
private val preferences: SecurityPreferences by injectLazy()
|
private val context: Context,
|
||||||
|
private val preferences: SecurityPreferences,
|
||||||
|
) {
|
||||||
private val progressNotificationBuilder = context.notificationBuilder(
|
private val progressNotificationBuilder = context.notificationBuilder(
|
||||||
Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS,
|
Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.work.PeriodicWorkRequestBuilder
|
|||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
@@ -24,22 +25,33 @@ import eu.kanade.tachiyomi.util.system.isRunning
|
|||||||
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
||||||
import eu.kanade.tachiyomi.util.system.workManager
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.AppGraph
|
||||||
|
import mihon.app.di.appGraph
|
||||||
|
import mihon.core.metro.metroGraph
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.domain.backup.service.BackupPreferences
|
|
||||||
import tachiyomi.domain.storage.service.StorageManager
|
import tachiyomi.domain.storage.service.StorageManager
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class BackupCreateJob(private val context: Context, workerParams: WorkerParameters) :
|
class BackupCreateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
CoroutineWorker(context, workerParams) {
|
CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
private val notifier = BackupNotifier(context)
|
private val graph: AppGraph = context.metroGraph()
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private lateinit var backupCreatorFactory: BackupCreator.Factory
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private lateinit var storageManager: StorageManager
|
||||||
|
|
||||||
|
@Inject private lateinit var notifier: BackupNotifier
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
|
graph.inject(this)
|
||||||
|
|
||||||
val isAutoBackup = inputData.getBoolean(IS_AUTO_BACKUP_KEY, true)
|
val isAutoBackup = inputData.getBoolean(IS_AUTO_BACKUP_KEY, true)
|
||||||
|
|
||||||
if (isAutoBackup && BackupRestoreJob.isRunning(context)) return Result.retry()
|
if (isAutoBackup && BackupRestoreJob.isRunning(context.workManager)) return Result.retry()
|
||||||
|
|
||||||
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
||||||
?: getAutomaticBackupLocation()
|
?: getAutomaticBackupLocation()
|
||||||
@@ -51,7 +63,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
|
|||||||
?: BackupOptions()
|
?: BackupOptions()
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
val location = BackupCreator(context, isAutoBackup).backup(uri, options)
|
val location = backupCreatorFactory.create(isAutoBackup = isAutoBackup).backup(uri, options)
|
||||||
if (!isAutoBackup) {
|
if (!isAutoBackup) {
|
||||||
notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())!!)
|
notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())!!)
|
||||||
}
|
}
|
||||||
@@ -78,7 +90,6 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getAutomaticBackupLocation(): Uri? {
|
private fun getAutomaticBackupLocation(): Uri? {
|
||||||
val storageManager = Injekt.get<StorageManager>()
|
|
||||||
return storageManager.getAutomaticBackupsDirectory()?.uri
|
return storageManager.getAutomaticBackupsDirectory()?.uri
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +99,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setupTask(context: Context, prefInterval: Int? = null) {
|
fun setupTask(context: Context, prefInterval: Int? = null) {
|
||||||
val backupPreferences = Injekt.get<BackupPreferences>()
|
val backupPreferences = context.appGraph.backupPreferences
|
||||||
val interval = prefInterval ?: backupPreferences.backupInterval.get()
|
val interval = prefInterval ?: backupPreferences.backupInterval.get()
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val constraints = Constraints(
|
val constraints = Constraints(
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package eu.kanade.tachiyomi.data.backup.create
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import dev.zacsweers.metro.Assisted
|
||||||
|
import dev.zacsweers.metro.AssistedFactory
|
||||||
|
import dev.zacsweers.metro.AssistedInject
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
||||||
import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator
|
import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator
|
||||||
@@ -29,29 +32,31 @@ import tachiyomi.domain.manga.interactor.GetFavorites
|
|||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.repository.MangaRepository
|
import tachiyomi.domain.manga.repository.MangaRepository
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
@AssistedInject
|
||||||
class BackupCreator(
|
class BackupCreator(
|
||||||
|
@Assisted private val isAutoBackup: Boolean,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val isAutoBackup: Boolean,
|
private val parser: ProtoBuf,
|
||||||
|
private val getFavorites: GetFavorites,
|
||||||
private val parser: ProtoBuf = Injekt.get(),
|
private val backupPreferences: BackupPreferences,
|
||||||
private val getFavorites: GetFavorites = Injekt.get(),
|
private val mangaRepository: MangaRepository,
|
||||||
private val backupPreferences: BackupPreferences = Injekt.get(),
|
private val categoriesBackupCreator: CategoriesBackupCreator,
|
||||||
private val mangaRepository: MangaRepository = Injekt.get(),
|
private val mangaBackupCreator: MangaBackupCreator,
|
||||||
|
private val preferenceBackupCreator: PreferenceBackupCreator,
|
||||||
private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(),
|
private val extensionStoresBackupCreator: ExtensionStoresBackupCreator,
|
||||||
private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(),
|
private val sourcesBackupCreator: SourcesBackupCreator,
|
||||||
private val preferenceBackupCreator: PreferenceBackupCreator = PreferenceBackupCreator(),
|
private val backupFileValidator: BackupFileValidator,
|
||||||
private val extensionStoresBackupCreator: ExtensionStoresBackupCreator = ExtensionStoresBackupCreator(),
|
|
||||||
private val sourcesBackupCreator: SourcesBackupCreator = SourcesBackupCreator(),
|
|
||||||
) {
|
) {
|
||||||
|
@AssistedFactory
|
||||||
|
fun interface Factory {
|
||||||
|
fun create(isAutoBackup: Boolean): BackupCreator
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun backup(uri: Uri, options: BackupOptions): String {
|
suspend fun backup(uri: Uri, options: BackupOptions): String {
|
||||||
var file: UniFile? = null
|
var file: UniFile? = null
|
||||||
@@ -105,7 +110,7 @@ class BackupCreator(
|
|||||||
val fileUri = file.uri
|
val fileUri = file.uri
|
||||||
|
|
||||||
// Make sure it's a valid backup file
|
// Make sure it's a valid backup file
|
||||||
BackupFileValidator(context).validate(fileUri)
|
backupFileValidator.validate(fileUri)
|
||||||
|
|
||||||
if (isAutoBackup) {
|
if (isAutoBackup) {
|
||||||
backupPreferences.lastAutoBackupTimestamp.set(Clock.System.now().toEpochMilliseconds())
|
backupPreferences.lastAutoBackupTimestamp.set(Clock.System.now().toEpochMilliseconds())
|
||||||
|
|||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.create.creators
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper
|
import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class CategoriesBackupCreator(
|
class CategoriesBackupCreator(
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(): List<BackupCategory> {
|
suspend operator fun invoke(): List<BackupCategory> {
|
||||||
|
|||||||
+3
-3
@@ -1,13 +1,13 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.create.creators
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
||||||
import eu.kanade.tachiyomi.data.backup.models.backupExtensionStoreMapper
|
import eu.kanade.tachiyomi.data.backup.models.backupExtensionStoreMapper
|
||||||
import mihon.domain.extension.interactor.GetExtensionStores
|
import mihon.domain.extension.interactor.GetExtensionStores
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class ExtensionStoresBackupCreator(
|
class ExtensionStoresBackupCreator(
|
||||||
private val getExtensionStores: GetExtensionStores = Injekt.get(),
|
private val getExtensionStores: GetExtensionStores,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(): List<BackupExtensionStore> {
|
suspend operator fun invoke(): List<BackupExtensionStore> {
|
||||||
|
|||||||
+5
-5
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup.create.creators
|
|||||||
|
|
||||||
import app.cash.sqldelight.async.coroutines.awaitAsList
|
import app.cash.sqldelight.async.coroutines.awaitAsList
|
||||||
import app.cash.sqldelight.async.coroutines.awaitAsOne
|
import app.cash.sqldelight.async.coroutines.awaitAsOne
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupOptions
|
import eu.kanade.tachiyomi.data.backup.create.BackupOptions
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
|
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
|
||||||
@@ -14,13 +15,12 @@ import tachiyomi.data.MemoColumnAdapter
|
|||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
import tachiyomi.domain.history.interactor.GetHistory
|
import tachiyomi.domain.history.interactor.GetHistory
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class MangaBackupCreator(
|
class MangaBackupCreator(
|
||||||
private val database: Database = Injekt.get(),
|
private val database: Database,
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories,
|
||||||
private val getHistory: GetHistory = Injekt.get(),
|
private val getHistory: GetHistory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
suspend operator fun invoke(mangas: List<Manga>, options: BackupOptions): List<BackupManga> {
|
||||||
|
|||||||
+4
-4
@@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.create.creators
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue
|
import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue
|
||||||
@@ -14,12 +15,11 @@ import eu.kanade.tachiyomi.source.sourcePreferences
|
|||||||
import tachiyomi.core.common.preference.Preference
|
import tachiyomi.core.common.preference.Preference
|
||||||
import tachiyomi.core.common.preference.PreferenceStore
|
import tachiyomi.core.common.preference.PreferenceStore
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class PreferenceBackupCreator(
|
class PreferenceBackupCreator(
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager,
|
||||||
private val preferenceStore: PreferenceStore = Injekt.get(),
|
private val preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun createApp(includePrivatePreferences: Boolean): List<BackupPreference> {
|
fun createApp(includePrivatePreferences: Boolean): List<BackupPreference> {
|
||||||
|
|||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.create.creators
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class SourcesBackupCreator(
|
class SourcesBackupCreator(
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
operator fun invoke(mangas: List<BackupManga>): List<BackupSource> {
|
operator fun invoke(mangas: List<BackupManga>): List<BackupSource> {
|
||||||
|
|||||||
@@ -9,16 +9,19 @@ import androidx.work.CoroutineWorker
|
|||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.util.system.cancelNotification
|
import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||||
import eu.kanade.tachiyomi.util.system.isRunning
|
import eu.kanade.tachiyomi.util.system.isRunning
|
||||||
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
||||||
import eu.kanade.tachiyomi.util.system.workManager
|
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.AppGraph
|
||||||
|
import mihon.core.metro.metroGraph
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
@@ -26,9 +29,15 @@ import tachiyomi.i18n.MR
|
|||||||
class BackupRestoreJob(private val context: Context, workerParams: WorkerParameters) :
|
class BackupRestoreJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
CoroutineWorker(context, workerParams) {
|
CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
private val notifier = BackupNotifier(context)
|
private val graph: AppGraph = context.metroGraph()
|
||||||
|
|
||||||
|
@Inject private lateinit var backupRestorerFactory: BackupRestorer.Factory
|
||||||
|
|
||||||
|
@Inject private lateinit var notifier: BackupNotifier
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
|
graph.inject(this)
|
||||||
|
|
||||||
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
||||||
val options = inputData.getBooleanArray(OPTIONS_KEY)?.let { RestoreOptions.fromBooleanArray(it) }
|
val options = inputData.getBooleanArray(OPTIONS_KEY)?.let { RestoreOptions.fromBooleanArray(it) }
|
||||||
|
|
||||||
@@ -41,7 +50,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
setForegroundSafely()
|
setForegroundSafely()
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
BackupRestorer(context, notifier, isSync).restore(uri, options)
|
backupRestorerFactory.create(notifier = notifier, isSync = isSync).restore(uri, options)
|
||||||
Result.success()
|
Result.success()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is CancellationException) {
|
if (e is CancellationException) {
|
||||||
@@ -70,12 +79,12 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun isRunning(context: Context): Boolean {
|
fun isRunning(workManager: WorkManager): Boolean {
|
||||||
return context.workManager.isRunning(TAG)
|
return workManager.isRunning(TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun start(
|
fun start(
|
||||||
context: Context,
|
workManager: WorkManager,
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
options: RestoreOptions,
|
options: RestoreOptions,
|
||||||
sync: Boolean = false,
|
sync: Boolean = false,
|
||||||
@@ -89,11 +98,11 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.setInputData(inputData)
|
.setInputData(inputData)
|
||||||
.build()
|
.build()
|
||||||
context.workManager.enqueueUniqueWork(TAG, ExistingWorkPolicy.KEEP, request)
|
workManager.enqueueUniqueWork(TAG, ExistingWorkPolicy.KEEP, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop(context: Context) {
|
fun stop(workManager: WorkManager) {
|
||||||
context.workManager.cancelUniqueWork(TAG)
|
workManager.cancelUniqueWork(TAG)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.data.backup.restore
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import dev.zacsweers.metro.Assisted
|
||||||
|
import dev.zacsweers.metro.AssistedFactory
|
||||||
|
import dev.zacsweers.metro.AssistedInject
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupDecoder
|
import eu.kanade.tachiyomi.data.backup.BackupDecoder
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
@@ -24,8 +27,6 @@ import tachiyomi.core.common.i18n.stringResource
|
|||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.data.Database
|
import tachiyomi.data.Database
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@@ -36,18 +37,25 @@ import kotlin.concurrent.atomics.ExperimentalAtomicApi
|
|||||||
import kotlin.concurrent.atomics.incrementAndFetch
|
import kotlin.concurrent.atomics.incrementAndFetch
|
||||||
|
|
||||||
@OptIn(ExperimentalAtomicApi::class)
|
@OptIn(ExperimentalAtomicApi::class)
|
||||||
|
@AssistedInject
|
||||||
class BackupRestorer(
|
class BackupRestorer(
|
||||||
|
@Assisted private val notifier: BackupNotifier,
|
||||||
|
@Assisted private val isSync: Boolean,
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val notifier: BackupNotifier,
|
private val database: Database,
|
||||||
private val isSync: Boolean,
|
private val downloadCache: DownloadCache,
|
||||||
|
private val categoriesRestorer: CategoriesRestorer,
|
||||||
private val database: Database = Injekt.get(),
|
private val preferenceRestorer: PreferenceRestorer,
|
||||||
private val categoriesRestorer: CategoriesRestorer = CategoriesRestorer(),
|
private val extensionStoreRestorer: ExtensionStoreRestorer,
|
||||||
private val preferenceRestorer: PreferenceRestorer = PreferenceRestorer(context),
|
private val mangaRestorer: MangaRestorer,
|
||||||
private val extensionStoreRestorer: ExtensionStoreRestorer = ExtensionStoreRestorer(),
|
private val backupDecoder: BackupDecoder,
|
||||||
private val mangaRestorer: MangaRestorer = MangaRestorer(),
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
fun interface Factory {
|
||||||
|
fun create(notifier: BackupNotifier, isSync: Boolean): BackupRestorer
|
||||||
|
}
|
||||||
|
|
||||||
private var restoreAmount = 0
|
private var restoreAmount = 0
|
||||||
private val restoreProgress = AtomicInt(0)
|
private val restoreProgress = AtomicInt(0)
|
||||||
private val errors = CopyOnWriteArrayList<Pair<Date, String>>()
|
private val errors = CopyOnWriteArrayList<Pair<Date, String>>()
|
||||||
@@ -65,7 +73,7 @@ class BackupRestorer(
|
|||||||
// Invalidate download cache to ensure UI reflects any restored downloads
|
// Invalidate download cache to ensure UI reflects any restored downloads
|
||||||
if (options.libraryEntries) {
|
if (options.libraryEntries) {
|
||||||
try {
|
try {
|
||||||
Injekt.get<DownloadCache>().invalidateCache()
|
downloadCache.invalidateCache()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logcat(LogPriority.ERROR, e) { "Failed to invalidate download cache after restore" }
|
logcat(LogPriority.ERROR, e) { "Failed to invalidate download cache after restore" }
|
||||||
}
|
}
|
||||||
@@ -85,7 +93,7 @@ class BackupRestorer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun restoreFromFile(uri: Uri, options: RestoreOptions) {
|
private suspend fun restoreFromFile(uri: Uri, options: RestoreOptions) {
|
||||||
val backup = BackupDecoder(context).decode(uri)
|
val backup = backupDecoder.decode(uri)
|
||||||
|
|
||||||
// Store source mapping for error messages
|
// Store source mapping for error messages
|
||||||
val backupMaps = backup.backupSources
|
val backupMaps = backup.backupSources
|
||||||
|
|||||||
+5
-5
@@ -1,16 +1,16 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
import tachiyomi.data.Database
|
import tachiyomi.data.Database
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class CategoriesRestorer(
|
class CategoriesRestorer(
|
||||||
private val database: Database = Injekt.get(),
|
private val database: Database,
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories,
|
||||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
private val libraryPreferences: LibraryPreferences,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(backupCategories: List<BackupCategory>) {
|
suspend operator fun invoke(backupCategories: List<BackupCategory>) {
|
||||||
|
|||||||
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
||||||
import tachiyomi.data.Database
|
import tachiyomi.data.Database
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class ExtensionStoreRestorer(
|
class ExtensionStoreRestorer(
|
||||||
private val database: Database = Injekt.get(),
|
private val database: Database,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(
|
suspend operator fun invoke(
|
||||||
|
|||||||
+10
-10
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers
|
|||||||
import app.cash.sqldelight.async.coroutines.awaitAsList
|
import app.cash.sqldelight.async.coroutines.awaitAsList
|
||||||
import app.cash.sqldelight.async.coroutines.awaitAsOne
|
import app.cash.sqldelight.async.coroutines.awaitAsOne
|
||||||
import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull
|
import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
||||||
@@ -23,21 +24,20 @@ import tachiyomi.domain.manga.model.Manga
|
|||||||
import tachiyomi.domain.track.interactor.GetTracks
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
import tachiyomi.domain.track.interactor.InsertTrack
|
import tachiyomi.domain.track.interactor.InsertTrack
|
||||||
import tachiyomi.domain.track.model.Track
|
import tachiyomi.domain.track.model.Track
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
@Inject
|
||||||
class MangaRestorer(
|
class MangaRestorer(
|
||||||
private val database: Database = Injekt.get(),
|
private val database: Database,
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories,
|
||||||
private val getMangaByUrlAndSourceId: GetMangaByUrlAndSourceId = Injekt.get(),
|
private val getMangaByUrlAndSourceId: GetMangaByUrlAndSourceId,
|
||||||
private val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get(),
|
private val getChaptersByMangaId: GetChaptersByMangaId,
|
||||||
private val updateManga: UpdateManga = Injekt.get(),
|
private val updateManga: UpdateManga,
|
||||||
private val getTracks: GetTracks = Injekt.get(),
|
private val getTracks: GetTracks,
|
||||||
private val insertTrack: InsertTrack = Injekt.get(),
|
private val insertTrack: InsertTrack,
|
||||||
fetchInterval: FetchInterval = Injekt.get(),
|
fetchInterval: FetchInterval,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val timeZone = TimeZone.currentSystemDefault()
|
private val timeZone = TimeZone.currentSystemDefault()
|
||||||
|
|||||||
+5
-5
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||||
@@ -21,13 +22,12 @@ import tachiyomi.domain.category.interactor.GetCategories
|
|||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.domain.download.service.DownloadPreferences
|
import tachiyomi.domain.download.service.DownloadPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
|
@Inject
|
||||||
class PreferenceRestorer(
|
class PreferenceRestorer(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories,
|
||||||
private val preferenceStore: PreferenceStore = Injekt.get(),
|
private val preferenceStore: PreferenceStore,
|
||||||
) {
|
) {
|
||||||
suspend fun restoreApp(
|
suspend fun restoreApp(
|
||||||
preferences: List<BackupPreference>,
|
preferences: List<BackupPreference>,
|
||||||
@@ -45,7 +45,7 @@ class PreferenceRestorer(
|
|||||||
|
|
||||||
suspend fun restoreSource(preferences: List<BackupSourcePreferences>) {
|
suspend fun restoreSource(preferences: List<BackupSourcePreferences>) {
|
||||||
preferences.forEach {
|
preferences.forEach {
|
||||||
val sourcePrefs = AndroidPreferenceStore(context, sourcePreferences(it.sourceKey))
|
val sourcePrefs = AndroidPreferenceStore(sourcePreferences(it.sourceKey))
|
||||||
restorePreferences(it.prefs, sourcePrefs)
|
restorePreferences(it.prefs, sourcePrefs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package eu.kanade.tachiyomi.data.cache
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.format.Formatter
|
import android.text.format.Formatter
|
||||||
import com.jakewharton.disklrucache.DiskLruCache
|
import com.jakewharton.disklrucache.DiskLruCache
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||||
@@ -24,6 +27,8 @@ import java.io.IOException
|
|||||||
*
|
*
|
||||||
* @param context the application context.
|
* @param context the application context.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class ChapterCache(
|
class ChapterCache(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val json: Json,
|
private val json: Json,
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package eu.kanade.tachiyomi.data.cache
|
package eu.kanade.tachiyomi.data.cache
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -15,6 +18,8 @@ import java.io.InputStream
|
|||||||
* @param context the application context.
|
* @param context the application context.
|
||||||
* @constructor creates an instance of the cover cache.
|
* @constructor creates an instance of the cover cache.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class CoverCache(private val context: Context) {
|
class CoverCache(private val context: Context) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import tachiyomi.core.common.util.system.logcat
|
|||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.MangaCover
|
import tachiyomi.domain.manga.model.MangaCover
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@@ -299,11 +298,10 @@ class MangaCoverFetcher(
|
|||||||
|
|
||||||
class MangaFactory(
|
class MangaFactory(
|
||||||
private val callFactoryLazy: Lazy<Call.Factory>,
|
private val callFactoryLazy: Lazy<Call.Factory>,
|
||||||
|
private val coverCache: CoverCache,
|
||||||
|
private val sourceManager: SourceManager,
|
||||||
) : Fetcher.Factory<Manga> {
|
) : Fetcher.Factory<Manga> {
|
||||||
|
|
||||||
private val coverCache: CoverCache by injectLazy()
|
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
|
||||||
|
|
||||||
override fun create(data: Manga, options: Options, imageLoader: ImageLoader): Fetcher {
|
override fun create(data: Manga, options: Options, imageLoader: ImageLoader): Fetcher {
|
||||||
return MangaCoverFetcher(
|
return MangaCoverFetcher(
|
||||||
url = data.thumbnailUrl,
|
url = data.thumbnailUrl,
|
||||||
@@ -321,11 +319,10 @@ class MangaCoverFetcher(
|
|||||||
|
|
||||||
class MangaCoverFactory(
|
class MangaCoverFactory(
|
||||||
private val callFactoryLazy: Lazy<Call.Factory>,
|
private val callFactoryLazy: Lazy<Call.Factory>,
|
||||||
|
private val coverCache: CoverCache,
|
||||||
|
private val sourceManager: SourceManager,
|
||||||
) : Fetcher.Factory<MangaCover> {
|
) : Fetcher.Factory<MangaCover> {
|
||||||
|
|
||||||
private val coverCache: CoverCache by injectLazy()
|
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
|
||||||
|
|
||||||
override fun create(data: MangaCover, options: Options, imageLoader: ImageLoader): Fetcher {
|
override fun create(data: MangaCover, options: Options, imageLoader: ImageLoader): Fetcher {
|
||||||
return MangaCoverFetcher(
|
return MangaCoverFetcher(
|
||||||
url = data.url,
|
url = data.url,
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import coil3.request.Options
|
|||||||
import eu.kanade.domain.manga.model.hasCustomCover
|
import eu.kanade.domain.manga.model.hasCustomCover
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import tachiyomi.domain.manga.model.MangaCover
|
import tachiyomi.domain.manga.model.MangaCover
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import tachiyomi.domain.manga.model.Manga as DomainManga
|
import tachiyomi.domain.manga.model.Manga as DomainManga
|
||||||
|
|
||||||
class MangaKeyer : Keyer<DomainManga> {
|
class MangaKeyer : Keyer<DomainManga> {
|
||||||
@@ -20,7 +18,7 @@ class MangaKeyer : Keyer<DomainManga> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MangaCoverKeyer(
|
class MangaCoverKeyer(
|
||||||
private val coverCache: CoverCache = Injekt.get(),
|
private val coverCache: CoverCache,
|
||||||
) : Keyer<MangaCover> {
|
) : Keyer<MangaCover> {
|
||||||
override fun key(data: MangaCover, options: Options): String {
|
override fun key(data: MangaCover, options: Options): String {
|
||||||
return if (coverCache.getCustomCoverFile(data.mangaId).exists()) {
|
return if (coverCache.getCustomCoverFile(data.mangaId).exists()) {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package eu.kanade.tachiyomi.data.download
|
package eu.kanade.tachiyomi.data.download
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
@@ -61,12 +63,14 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
* defined in [renewInterval] as we don't have any control over the filesystem and the user can
|
* defined in [renewInterval] as we don't have any control over the filesystem and the user can
|
||||||
* delete the folders at any time without the app noticing.
|
* delete the folders at any time without the app noticing.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class DownloadCache(
|
class DownloadCache(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val provider: DownloadProvider = Injekt.get(),
|
private val provider: DownloadProvider,
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager,
|
||||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
private val extensionManager: ExtensionManager,
|
||||||
private val storageManager: StorageManager = Injekt.get(),
|
private val storageManager: StorageManager,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
@@ -492,7 +496,7 @@ private object UniFileAsStringSerializer : KSerializer<UniFile?> {
|
|||||||
|
|
||||||
override fun deserialize(decoder: Decoder): UniFile? {
|
override fun deserialize(decoder: Decoder): UniFile? {
|
||||||
return if (decoder.decodeNotNullMark()) {
|
return if (decoder.decodeNotNullMark()) {
|
||||||
UniFile.fromUri(Injekt.get<Application>(), decoder.decodeString().toUri())
|
UniFile.fromUri(Injekt.get<Context>(), decoder.decodeString().toUri())
|
||||||
} else {
|
} else {
|
||||||
decoder.decodeNull()
|
decoder.decodeNull()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import androidx.work.OneTimeWorkRequestBuilder
|
|||||||
import androidx.work.WorkInfo
|
import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.util.system.NetworkState
|
import eu.kanade.tachiyomi.util.system.NetworkState
|
||||||
@@ -24,9 +25,9 @@ import kotlinx.coroutines.flow.combineTransform
|
|||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import mihon.app.di.AppGraph
|
||||||
|
import mihon.core.metro.metroGraph
|
||||||
import tachiyomi.domain.download.service.DownloadPreferences
|
import tachiyomi.domain.download.service.DownloadPreferences
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This worker is used to manage the downloader. The system can decide to stop the worker, in
|
* This worker is used to manage the downloader. The system can decide to stop the worker, in
|
||||||
@@ -34,8 +35,15 @@ import uy.kohesive.injekt.api.get
|
|||||||
*/
|
*/
|
||||||
class DownloadJob(context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {
|
class DownloadJob(context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
private val downloadManager: DownloadManager = Injekt.get()
|
private val graph: AppGraph = context.metroGraph()
|
||||||
private val downloadPreferences: DownloadPreferences = Injekt.get()
|
|
||||||
|
@Inject private lateinit var downloadManager: DownloadManager
|
||||||
|
|
||||||
|
@Inject private lateinit var downloadPreferences: DownloadPreferences
|
||||||
|
|
||||||
|
init {
|
||||||
|
graph.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||||
val notification = applicationContext.notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
|
val notification = applicationContext.notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package eu.kanade.tachiyomi.data.download
|
package eu.kanade.tachiyomi.data.download
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
@@ -20,41 +24,37 @@ import tachiyomi.core.common.util.lang.launchIO
|
|||||||
import tachiyomi.core.common.util.system.ImageUtil
|
import tachiyomi.core.common.util.system.ImageUtil
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
|
import tachiyomi.domain.chapter.interactor.GetChapter
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.download.service.DownloadPreferences
|
import tachiyomi.domain.download.service.DownloadPreferences
|
||||||
|
import tachiyomi.domain.manga.interactor.GetManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to manage chapter downloads in the application. It must be instantiated once
|
* This class is used to manage chapter downloads in the application. It must be instantiated once
|
||||||
* and retrieved through dependency injection. You can use this class to queue new chapters or query
|
* and retrieved through dependency injection. You can use this class to queue new chapters or query
|
||||||
* downloaded chapters.
|
* downloaded chapters.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class DownloadManager(
|
class DownloadManager(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val provider: DownloadProvider = Injekt.get(),
|
private val provider: DownloadProvider,
|
||||||
private val cache: DownloadCache = Injekt.get(),
|
private val cache: DownloadCache,
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories,
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val getManga: GetManga,
|
||||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
private val getChapter: GetChapter,
|
||||||
|
private val sourceManager: SourceManager,
|
||||||
|
private val downloadPreferences: DownloadPreferences,
|
||||||
|
private val downloader: Downloader,
|
||||||
|
private val pendingDeleter: DownloadPendingDeleter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloader whose only task is to download chapters.
|
|
||||||
*/
|
|
||||||
private val downloader = Downloader(context, provider, cache)
|
|
||||||
|
|
||||||
val isRunning: Boolean
|
val isRunning: Boolean
|
||||||
get() = downloader.isRunning
|
get() = downloader.isRunning
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue to delay the deletion of a list of chapters until triggered.
|
|
||||||
*/
|
|
||||||
private val pendingDeleter = DownloadPendingDeleter(context)
|
|
||||||
|
|
||||||
val queueState
|
val queueState
|
||||||
get() = downloader.queueState
|
get() = downloader.queueState
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ class DownloadManager(
|
|||||||
fun startDownloadNow(chapterId: Long) {
|
fun startDownloadNow(chapterId: Long) {
|
||||||
val existingDownload = getQueuedDownloadOrNull(chapterId)
|
val existingDownload = getQueuedDownloadOrNull(chapterId)
|
||||||
// If not in queue try to start a new download
|
// If not in queue try to start a new download
|
||||||
val toAdd = existingDownload ?: runBlocking { Download.fromChapterId(chapterId) } ?: return
|
val toAdd = existingDownload ?: runBlocking { downloadFromChapterId(chapterId) } ?: return
|
||||||
queueState.value.toMutableList().apply {
|
queueState.value.toMutableList().apply {
|
||||||
existingDownload?.let { remove(it) }
|
existingDownload?.let { remove(it) }
|
||||||
add(0, toAdd)
|
add(0, toAdd)
|
||||||
@@ -116,6 +116,14 @@ class DownloadManager(
|
|||||||
startDownloads()
|
startDownloads()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun downloadFromChapterId(chapterId: Long): Download? {
|
||||||
|
val chapter = getChapter.await(chapterId) ?: return null
|
||||||
|
val manga = getManga.await(chapter.mangaId) ?: return null
|
||||||
|
val source = sourceManager.get(manga.source) as? HttpSource ?: return null
|
||||||
|
|
||||||
|
return Download(source, manga, chapter)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reorders the download queue.
|
* Reorders the download queue.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.PendingIntent
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
@@ -16,7 +17,6 @@ import eu.kanade.tachiyomi.util.system.notificationBuilder
|
|||||||
import eu.kanade.tachiyomi.util.system.notify
|
import eu.kanade.tachiyomi.util.system.notify
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,9 +24,11 @@ import java.util.regex.Pattern
|
|||||||
*
|
*
|
||||||
* @param context context of application
|
* @param context context of application
|
||||||
*/
|
*/
|
||||||
internal class DownloadNotifier(private val context: Context) {
|
@Inject
|
||||||
|
class DownloadNotifier(
|
||||||
private val preferences: SecurityPreferences by injectLazy()
|
private val context: Context,
|
||||||
|
private val preferences: SecurityPreferences,
|
||||||
|
) {
|
||||||
|
|
||||||
private val progressNotificationBuilder by lazy {
|
private val progressNotificationBuilder by lazy {
|
||||||
context.notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
|
context.notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
|
||||||
|
|||||||
@@ -2,21 +2,24 @@ package eu.kanade.tachiyomi.data.download
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to keep a list of chapters for future deletion.
|
* Class used to keep a list of chapters for future deletion.
|
||||||
*
|
*
|
||||||
* @param context the application context.
|
* @param context the application context.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class DownloadPendingDeleter(
|
class DownloadPendingDeleter(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val json: Json = Injekt.get(),
|
private val json: Json,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.data.download
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.util.lang.Hash.md5
|
import eu.kanade.tachiyomi.util.lang.Hash.md5
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
@@ -14,8 +17,6 @@ import tachiyomi.domain.library.service.LibraryPreferences
|
|||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.storage.service.StorageManager
|
import tachiyomi.domain.storage.service.StorageManager
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,10 +25,12 @@ import java.io.IOException
|
|||||||
*
|
*
|
||||||
* @param context the application context.
|
* @param context the application context.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class DownloadProvider(
|
class DownloadProvider(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val storageManager: StorageManager = Injekt.get(),
|
private val storageManager: StorageManager,
|
||||||
private val libraryPreferences: LibraryPreferences = Injekt.get(),
|
private val libraryPreferences: LibraryPreferences,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val downloadsDir: UniFile?
|
private val downloadsDir: UniFile?
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.data.download
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@@ -11,18 +14,18 @@ import tachiyomi.domain.chapter.interactor.GetChapter
|
|||||||
import tachiyomi.domain.manga.interactor.GetManga
|
import tachiyomi.domain.manga.interactor.GetManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used to persist active downloads across application restarts.
|
* This class is used to persist active downloads across application restarts.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class DownloadStore(
|
class DownloadStore(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager,
|
||||||
private val json: Json = Injekt.get(),
|
private val json: Json,
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga,
|
||||||
private val getChapter: GetChapter = Injekt.get(),
|
private val getChapter: GetChapter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.data.download
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.domain.chapter.model.toSChapter
|
import eu.kanade.domain.chapter.model.toSChapter
|
||||||
import eu.kanade.domain.manga.model.getComicInfo
|
import eu.kanade.domain.manga.model.getComicInfo
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
@@ -57,8 +60,6 @@ import tachiyomi.domain.manga.model.Manga
|
|||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.domain.track.interactor.GetTracks
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
@@ -68,34 +69,27 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
*
|
*
|
||||||
* Its queue contains the list of chapters to download.
|
* Its queue contains the list of chapters to download.
|
||||||
*/
|
*/
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class Downloader(
|
class Downloader(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val provider: DownloadProvider,
|
private val provider: DownloadProvider,
|
||||||
private val cache: DownloadCache,
|
private val cache: DownloadCache,
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager,
|
||||||
private val chapterCache: ChapterCache = Injekt.get(),
|
private val chapterCache: ChapterCache,
|
||||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
private val downloadPreferences: DownloadPreferences,
|
||||||
private val xml: XML = Injekt.get(),
|
private val xml: XML,
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories,
|
||||||
private val getTracks: GetTracks = Injekt.get(),
|
private val getTracks: GetTracks,
|
||||||
|
private val store: DownloadStore,
|
||||||
|
private val notifier: DownloadNotifier,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
|
||||||
* Store for persisting downloads across restarts.
|
|
||||||
*/
|
|
||||||
private val store = DownloadStore(context)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue where active downloads are kept.
|
* Queue where active downloads are kept.
|
||||||
*/
|
*/
|
||||||
private val _queueState = MutableStateFlow<List<Download>>(emptyList())
|
private val _queueState = MutableStateFlow<List<Download>>(emptyList())
|
||||||
val queueState = _queueState.asStateFlow()
|
val queueState = _queueState.asStateFlow()
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifier for the downloader state and progress.
|
|
||||||
*/
|
|
||||||
private val notifier by lazy { DownloadNotifier(context) }
|
|
||||||
|
|
||||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
private var downloaderJob: Job? = null
|
private var downloaderJob: Job? = null
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,8 @@ import kotlinx.coroutines.flow.debounce
|
|||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.emitAll
|
import kotlinx.coroutines.flow.emitAll
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapter
|
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.manga.interactor.GetManga
|
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
data class Download(
|
data class Download(
|
||||||
@@ -71,19 +66,4 @@ data class Download(
|
|||||||
DOWNLOADED(3),
|
DOWNLOADED(3),
|
||||||
ERROR(4),
|
ERROR(4),
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
suspend fun fromChapterId(
|
|
||||||
chapterId: Long,
|
|
||||||
getChapter: GetChapter = Injekt.get(),
|
|
||||||
getManga: GetManga = Injekt.get(),
|
|
||||||
sourceManager: SourceManager = Injekt.get(),
|
|
||||||
): Download? {
|
|
||||||
val chapter = getChapter.await(chapterId) ?: return null
|
|
||||||
val manga = getManga.await(chapter.mangaId) ?: return null
|
|
||||||
val source = sourceManager.get(manga.source) as? HttpSource ?: return null
|
|
||||||
|
|
||||||
return Download(source, manga, chapter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,11 @@ import androidx.work.NetworkType
|
|||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
import androidx.work.WorkInfo
|
import androidx.work.WorkInfo
|
||||||
|
import androidx.work.WorkManager
|
||||||
import androidx.work.WorkQuery
|
import androidx.work.WorkQuery
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
@@ -38,6 +40,9 @@ import kotlinx.coroutines.sync.withPermit
|
|||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.toLocalDateTime
|
import kotlinx.datetime.toLocalDateTime
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.AppGraph
|
||||||
|
import mihon.app.di.appGraph
|
||||||
|
import mihon.core.metro.metroGraph
|
||||||
import mihon.domain.chapter.interactor.FilterChaptersForDownload
|
import mihon.domain.chapter.interactor.FilterChaptersForDownload
|
||||||
import mihon.domain.source.interactor.UpdateMangaFromRemote
|
import mihon.domain.source.interactor.UpdateMangaFromRemote
|
||||||
import tachiyomi.core.common.i18n.stringResource
|
import tachiyomi.core.common.i18n.stringResource
|
||||||
@@ -63,8 +68,6 @@ import tachiyomi.domain.manga.model.Manga
|
|||||||
import tachiyomi.domain.source.model.SourceNotInstalledException
|
import tachiyomi.domain.source.model.SourceNotInstalledException
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@@ -78,24 +81,34 @@ import kotlin.time.Clock
|
|||||||
class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
CoroutineWorker(context, workerParams) {
|
CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
private val sourceManager: SourceManager = Injekt.get()
|
private val graph: AppGraph = context.metroGraph()
|
||||||
private val libraryPreferences: LibraryPreferences = Injekt.get()
|
|
||||||
private val downloadManager: DownloadManager = Injekt.get()
|
|
||||||
private val getLibraryManga: GetLibraryManga = Injekt.get()
|
|
||||||
private val getManga: GetManga = Injekt.get()
|
|
||||||
private val fetchInterval: FetchInterval = Injekt.get()
|
|
||||||
private val filterChaptersForDownload: FilterChaptersForDownload = Injekt.get()
|
|
||||||
private val updateMangaFromRemote: UpdateMangaFromRemote = Injekt.get()
|
|
||||||
|
|
||||||
private val notifier = LibraryUpdateNotifier(context)
|
@Inject private lateinit var sourceManager: SourceManager
|
||||||
|
|
||||||
|
@Inject private lateinit var libraryPreferences: LibraryPreferences
|
||||||
|
|
||||||
|
@Inject private lateinit var downloadManager: DownloadManager
|
||||||
|
|
||||||
|
@Inject private lateinit var getLibraryManga: GetLibraryManga
|
||||||
|
|
||||||
|
@Inject private lateinit var getManga: GetManga
|
||||||
|
|
||||||
|
@Inject private lateinit var fetchInterval: FetchInterval
|
||||||
|
|
||||||
|
@Inject private lateinit var filterChaptersForDownload: FilterChaptersForDownload
|
||||||
|
|
||||||
|
@Inject private lateinit var updateMangaFromRemote: UpdateMangaFromRemote
|
||||||
|
|
||||||
|
@Inject private lateinit var notifier: LibraryUpdateNotifier
|
||||||
|
|
||||||
private var mangaToUpdate: List<LibraryManga> = mutableListOf()
|
private var mangaToUpdate: List<LibraryManga> = mutableListOf()
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
|
graph.inject(this)
|
||||||
|
|
||||||
if (tags.contains(WORK_NAME_AUTO)) {
|
if (tags.contains(WORK_NAME_AUTO)) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||||
val preferences = Injekt.get<LibraryPreferences>()
|
val restrictions = libraryPreferences.autoUpdateDeviceRestrictions.get()
|
||||||
val restrictions = preferences.autoUpdateDeviceRestrictions.get()
|
|
||||||
if ((DEVICE_ONLY_ON_WIFI in restrictions) && !context.isConnectedToWifi()) {
|
if ((DEVICE_ONLY_ON_WIFI in restrictions) && !context.isConnectedToWifi()) {
|
||||||
return Result.retry()
|
return Result.retry()
|
||||||
}
|
}
|
||||||
@@ -133,7 +146,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||||
val notifier = LibraryUpdateNotifier(context)
|
|
||||||
return ForegroundInfo(
|
return ForegroundInfo(
|
||||||
Notifications.ID_LIBRARY_PROGRESS,
|
Notifications.ID_LIBRARY_PROGRESS,
|
||||||
notifier.progressNotificationBuilder.build(),
|
notifier.progressNotificationBuilder.build(),
|
||||||
@@ -420,7 +432,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
context: Context,
|
context: Context,
|
||||||
prefInterval: Int? = null,
|
prefInterval: Int? = null,
|
||||||
) {
|
) {
|
||||||
val preferences = Injekt.get<LibraryPreferences>()
|
val preferences = context.appGraph.libraryPreferences
|
||||||
val interval = prefInterval ?: preferences.autoUpdateInterval.get()
|
val interval = prefInterval ?: preferences.autoUpdateInterval.get()
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
val restrictions = preferences.autoUpdateDeviceRestrictions.get()
|
val restrictions = preferences.autoUpdateDeviceRestrictions.get()
|
||||||
@@ -469,11 +481,10 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun startNow(
|
fun startNow(
|
||||||
context: Context,
|
workManager: WorkManager,
|
||||||
category: Category? = null,
|
category: Category? = null,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val wm = context.workManager
|
if (workManager.isRunning(TAG)) {
|
||||||
if (wm.isRunning(TAG)) {
|
|
||||||
// Already running either as a scheduled or manual job
|
// Already running either as a scheduled or manual job
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -486,20 +497,20 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
.addTag(WORK_NAME_MANUAL)
|
.addTag(WORK_NAME_MANUAL)
|
||||||
.setInputData(inputData)
|
.setInputData(inputData)
|
||||||
.build()
|
.build()
|
||||||
wm.enqueueUniqueWork(WORK_NAME_MANUAL, ExistingWorkPolicy.KEEP, request)
|
workManager.enqueueUniqueWork(WORK_NAME_MANUAL, ExistingWorkPolicy.KEEP, request)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop(context: Context) {
|
fun stop(context: Context) {
|
||||||
val wm = context.workManager
|
val workManager = context.workManager
|
||||||
val workQuery = WorkQuery.Builder.fromTags(listOf(TAG))
|
val workQuery = WorkQuery.Builder.fromTags(listOf(TAG))
|
||||||
.addStates(listOf(WorkInfo.State.RUNNING))
|
.addStates(listOf(WorkInfo.State.RUNNING))
|
||||||
.build()
|
.build()
|
||||||
wm.getWorkInfos(workQuery).get()
|
workManager.getWorkInfos(workQuery).get()
|
||||||
// Should only return one work but just in case
|
// Should only return one work but just in case
|
||||||
.forEach {
|
.forEach {
|
||||||
wm.cancelWorkById(it.id)
|
workManager.cancelWorkById(it.id)
|
||||||
|
|
||||||
// Re-enqueue cancelled scheduled work
|
// Re-enqueue cancelled scheduled work
|
||||||
if (it.tags.contains(WORK_NAME_AUTO)) {
|
if (it.tags.contains(WORK_NAME_AUTO)) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import coil3.imageLoader
|
|||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
import coil3.request.transformations
|
import coil3.request.transformations
|
||||||
import coil3.transform.CircleCropTransformation
|
import coil3.transform.CircleCropTransformation
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.presentation.util.formatChapterNumber
|
import eu.kanade.presentation.util.formatChapterNumber
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||||
@@ -37,15 +38,14 @@ import tachiyomi.domain.library.model.LibraryManga
|
|||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
|
|
||||||
|
@Inject
|
||||||
class LibraryUpdateNotifier(
|
class LibraryUpdateNotifier(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val securityPreferences: SecurityPreferences = Injekt.get(),
|
private val securityPreferences: SecurityPreferences,
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val percentFormatter = NumberFormat.getPercentInstance().apply {
|
private val percentFormatter = NumberFormat.getPercentInstance().apply {
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ import androidx.work.CoroutineWorker
|
|||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.WorkInfo
|
import androidx.work.WorkManager
|
||||||
import androidx.work.WorkQuery
|
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.util.system.isRunning
|
import eu.kanade.tachiyomi.util.system.isRunning
|
||||||
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
import eu.kanade.tachiyomi.util.system.setForegroundSafely
|
||||||
import eu.kanade.tachiyomi.util.system.workManager
|
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
@@ -22,6 +21,8 @@ import kotlinx.coroutines.ensureActive
|
|||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlinx.coroutines.sync.withPermit
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import mihon.app.di.AppGraph
|
||||||
|
import mihon.core.metro.metroGraph
|
||||||
import mihon.domain.source.interactor.UpdateMangaFromRemote
|
import mihon.domain.source.interactor.UpdateMangaFromRemote
|
||||||
import tachiyomi.core.common.util.lang.withIOContext
|
import tachiyomi.core.common.util.lang.withIOContext
|
||||||
import tachiyomi.core.common.util.system.logcat
|
import tachiyomi.core.common.util.system.logcat
|
||||||
@@ -29,8 +30,6 @@ import tachiyomi.domain.library.model.LibraryManga
|
|||||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
import kotlin.concurrent.atomics.AtomicInt
|
import kotlin.concurrent.atomics.AtomicInt
|
||||||
import kotlin.concurrent.atomics.ExperimentalAtomicApi
|
import kotlin.concurrent.atomics.ExperimentalAtomicApi
|
||||||
@@ -40,15 +39,21 @@ import kotlin.concurrent.atomics.fetchAndIncrement
|
|||||||
class MetadataUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
class MetadataUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
CoroutineWorker(context, workerParams) {
|
CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
private val sourceManager: SourceManager = Injekt.get()
|
private val graph: AppGraph = context.metroGraph()
|
||||||
private val getLibraryManga: GetLibraryManga = Injekt.get()
|
|
||||||
private val updateMangaFromRemote: UpdateMangaFromRemote = Injekt.get()
|
|
||||||
|
|
||||||
private val notifier = LibraryUpdateNotifier(context)
|
@Inject private lateinit var sourceManager: SourceManager
|
||||||
|
|
||||||
|
@Inject private lateinit var getLibraryManga: GetLibraryManga
|
||||||
|
|
||||||
|
@Inject private lateinit var updateMangaFromRemote: UpdateMangaFromRemote
|
||||||
|
|
||||||
|
@Inject private lateinit var notifier: LibraryUpdateNotifier
|
||||||
|
|
||||||
private var mangaToUpdate: List<LibraryManga> = mutableListOf()
|
private var mangaToUpdate: List<LibraryManga> = mutableListOf()
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
|
graph.inject(this)
|
||||||
|
|
||||||
setForegroundSafely()
|
setForegroundSafely()
|
||||||
|
|
||||||
addMangaToQueue()
|
addMangaToQueue()
|
||||||
@@ -72,7 +77,6 @@ class MetadataUpdateJob(private val context: Context, workerParams: WorkerParame
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||||
val notifier = LibraryUpdateNotifier(context)
|
|
||||||
return ForegroundInfo(
|
return ForegroundInfo(
|
||||||
Notifications.ID_LIBRARY_PROGRESS,
|
Notifications.ID_LIBRARY_PROGRESS,
|
||||||
notifier.progressNotificationBuilder.build(),
|
notifier.progressNotificationBuilder.build(),
|
||||||
@@ -168,9 +172,8 @@ class MetadataUpdateJob(private val context: Context, workerParams: WorkerParame
|
|||||||
|
|
||||||
private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60
|
private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60
|
||||||
|
|
||||||
fun startNow(context: Context): Boolean {
|
fun startNow(workManager: WorkManager): Boolean {
|
||||||
val wm = context.workManager
|
if (workManager.isRunning(TAG)) {
|
||||||
if (wm.isRunning(TAG)) {
|
|
||||||
// Already running either as a scheduled or manual job
|
// Already running either as a scheduled or manual job
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -178,21 +181,9 @@ class MetadataUpdateJob(private val context: Context, workerParams: WorkerParame
|
|||||||
.addTag(TAG)
|
.addTag(TAG)
|
||||||
.addTag(WORK_NAME_MANUAL)
|
.addTag(WORK_NAME_MANUAL)
|
||||||
.build()
|
.build()
|
||||||
wm.enqueueUniqueWork(WORK_NAME_MANUAL, ExistingWorkPolicy.KEEP, request)
|
workManager.enqueueUniqueWork(WORK_NAME_MANUAL, ExistingWorkPolicy.KEEP, request)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop(context: Context) {
|
|
||||||
val wm = context.workManager
|
|
||||||
val workQuery = WorkQuery.Builder.fromTags(listOf(TAG))
|
|
||||||
.addStates(listOf(WorkInfo.State.RUNNING))
|
|
||||||
.build()
|
|
||||||
wm.getWorkInfos(workQuery).get()
|
|
||||||
// Should only return one work but just in case
|
|
||||||
.forEach {
|
|
||||||
wm.cancelWorkById(it.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
@@ -16,7 +17,9 @@ import eu.kanade.tachiyomi.util.system.getParcelableExtraCompat
|
|||||||
import eu.kanade.tachiyomi.util.system.notificationManager
|
import eu.kanade.tachiyomi.util.system.notificationManager
|
||||||
import eu.kanade.tachiyomi.util.system.toShareIntent
|
import eu.kanade.tachiyomi.util.system.toShareIntent
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import mihon.app.di.appGraph
|
||||||
import tachiyomi.core.common.Constants
|
import tachiyomi.core.common.Constants
|
||||||
import tachiyomi.core.common.util.lang.launchIO
|
import tachiyomi.core.common.util.lang.launchIO
|
||||||
import tachiyomi.domain.chapter.interactor.GetChapter
|
import tachiyomi.domain.chapter.interactor.GetChapter
|
||||||
@@ -28,9 +31,6 @@ import tachiyomi.domain.manga.interactor.GetManga
|
|||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,12 +40,21 @@ import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
|||||||
*/
|
*/
|
||||||
class NotificationReceiver : BroadcastReceiver() {
|
class NotificationReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
private val getManga: GetManga by injectLazy()
|
@Inject private lateinit var getManga: GetManga
|
||||||
private val getChapter: GetChapter by injectLazy()
|
|
||||||
private val updateChapter: UpdateChapter by injectLazy()
|
@Inject private lateinit var getChapter: GetChapter
|
||||||
private val downloadManager: DownloadManager by injectLazy()
|
|
||||||
|
@Inject private lateinit var updateChapter: UpdateChapter
|
||||||
|
|
||||||
|
@Inject private lateinit var downloadManager: DownloadManager
|
||||||
|
|
||||||
|
@Inject private lateinit var downloadPreferences: DownloadPreferences
|
||||||
|
|
||||||
|
@Inject private lateinit var sourceManager: SourceManager
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
context.appGraph.inject(this)
|
||||||
|
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
// Dismiss notification
|
// Dismiss notification
|
||||||
ACTION_DISMISS_NOTIFICATION -> dismissNotification(context, intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
ACTION_DISMISS_NOTIFICATION -> dismissNotification(context, intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
||||||
@@ -161,7 +170,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param context context of application
|
* @param context context of application
|
||||||
*/
|
*/
|
||||||
private fun cancelRestore(context: Context) {
|
private fun cancelRestore(context: Context) {
|
||||||
BackupRestoreJob.stop(context)
|
BackupRestoreJob.stop(context.workManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,9 +189,6 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param mangaId id of manga
|
* @param mangaId id of manga
|
||||||
*/
|
*/
|
||||||
private fun markAsRead(chapterUrls: Array<String>, mangaId: Long) {
|
private fun markAsRead(chapterUrls: Array<String>, mangaId: Long) {
|
||||||
val downloadPreferences: DownloadPreferences = Injekt.get()
|
|
||||||
val sourceManager: SourceManager = Injekt.get()
|
|
||||||
|
|
||||||
launchIO {
|
launchIO {
|
||||||
val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) }
|
val toUpdate = chapterUrls.mapNotNull { getChapter.await(it, mangaId) }
|
||||||
.map {
|
.map {
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import android.webkit.MimeTypeMap
|
|||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.contentValuesOf
|
import androidx.core.content.contentValuesOf
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.Inject
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
||||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||||
@@ -26,6 +29,8 @@ import java.io.File
|
|||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
class ImageSaver(
|
class ImageSaver(
|
||||||
val context: Context,
|
val context: Context,
|
||||||
) {
|
) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user