mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-15 15:02:49 +01:00
feat: added triggers for syncing.
Experimental for now, but works fine so far, I don't know about google api limit but I think it's pretty generous. Signed-off-by: KaiserBh <kaiserbh@proton.me>
This commit is contained in:
parent
cc5e14088c
commit
178b00280b
@ -34,6 +34,7 @@ import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen
|
||||
import eu.kanade.presentation.more.settings.screen.data.SyncOptionsScreen
|
||||
import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget
|
||||
import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding
|
||||
import eu.kanade.presentation.util.relativeTimeSpanString
|
||||
@ -559,6 +560,7 @@ private fun getSyncNowPref(): Preference.PreferenceGroup {
|
||||
return Preference.PreferenceGroup(
|
||||
title = stringResource(MR.strings.pref_sync_now_group_title),
|
||||
preferenceItems = listOf(
|
||||
getSyncOptionsPref(),
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(MR.strings.pref_sync_now),
|
||||
subtitle = stringResource(MR.strings.pref_sync_now_subtitle),
|
||||
@ -570,6 +572,16 @@ private fun getSyncNowPref(): Preference.PreferenceGroup {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSyncOptionsPref(): Preference.PreferenceItem.TextPreference {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
return Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(MR.strings.pref_sync_options),
|
||||
subtitle = stringResource(MR.strings.pref_sync_options_summ),
|
||||
onClick = { navigator.push(SyncOptionsScreen()) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getAutomaticSyncGroup(syncPreferences: SyncPreferences): Preference.PreferenceGroup {
|
||||
val context = LocalContext.current
|
||||
|
@ -0,0 +1,125 @@
|
||||
package eu.kanade.presentation.more.settings.screen.data
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import kotlinx.collections.immutable.PersistentSet
|
||||
import kotlinx.collections.immutable.minus
|
||||
import kotlinx.collections.immutable.plus
|
||||
import kotlinx.collections.immutable.toPersistentSet
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import androidx.compose.runtime.getValue
|
||||
import tachiyomi.domain.sync.SyncPreferences
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class SyncOptionsScreen : Screen() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val model = rememberScreenModel { SyncOptionsScreenModel() }
|
||||
val state by model.state.collectAsState()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppBar(
|
||||
title = stringResource(MR.strings.pref_sync_options),
|
||||
navigateUp = navigator::pop,
|
||||
scrollBehavior = it,
|
||||
)
|
||||
},
|
||||
) { contentPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = MaterialTheme.padding.medium),
|
||||
) {
|
||||
SyncChoices.forEach { (k, v) ->
|
||||
item {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(v),
|
||||
checked = state.flags.contains(k),
|
||||
onCheckedChange = {
|
||||
model.toggleOptionFlag(k)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SyncOptionsScreenModel : StateScreenModel<SyncOptionsScreenModel.State>(State()) {
|
||||
private val syncPreferences = Injekt.get<SyncPreferences>()
|
||||
|
||||
init {
|
||||
loadInitialFlags()
|
||||
}
|
||||
|
||||
private fun loadInitialFlags() {
|
||||
val savedFlags = syncPreferences.syncFlags().get()
|
||||
val flagSet = SyncPreferences.Flags.values().filter { flag ->
|
||||
savedFlags and flag > 0
|
||||
}.toSet().toPersistentSet()
|
||||
|
||||
mutableState.update { State(flags = flagSet) }
|
||||
}
|
||||
|
||||
fun toggleOptionFlag(option: Int) {
|
||||
mutableState.update { currentState ->
|
||||
val newFlags = if (currentState.flags.contains(option)) {
|
||||
currentState.flags - option
|
||||
} else {
|
||||
currentState.flags + option
|
||||
}
|
||||
saveFlags(newFlags)
|
||||
currentState.copy(flags = newFlags)
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveFlags(flags: PersistentSet<Int>) {
|
||||
val flagsInt = flags.fold(0) { acc, flag -> acc or flag }
|
||||
syncPreferences.syncFlags().set(flagsInt)
|
||||
}
|
||||
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val flags: PersistentSet<Int> = SyncChoices.keys.toPersistentSet(),
|
||||
)
|
||||
}
|
||||
|
||||
private val SyncChoices = mapOf(
|
||||
SyncPreferences.Flags.SYNC_ON_CHAPTER_READ to MR.strings.sync_on_chapter_read,
|
||||
SyncPreferences.Flags.SYNC_ON_CHAPTER_OPEN to MR.strings.sync_on_chapter_open,
|
||||
SyncPreferences.Flags.SYNC_ON_APP_START to MR.strings.sync_on_app_start,
|
||||
)
|
||||
|
@ -32,6 +32,7 @@ import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
||||
import eu.kanade.tachiyomi.data.coil.MangaKeyer
|
||||
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.sync.SyncDataJob
|
||||
import eu.kanade.tachiyomi.di.AppModule
|
||||
import eu.kanade.tachiyomi.di.PreferenceModule
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
@ -56,6 +57,7 @@ import org.acra.sender.HttpSender
|
||||
import org.conscrypt.Conscrypt
|
||||
import tachiyomi.core.i18n.stringResource
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.sync.SyncPreferences
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.widget.WidgetManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@ -168,6 +170,13 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
|
||||
override fun onStart(owner: LifecycleOwner) {
|
||||
SecureActivityDelegate.onApplicationStart()
|
||||
|
||||
val syncPreferences: SyncPreferences by injectLazy()
|
||||
val syncFlags = syncPreferences.syncFlags().get()
|
||||
if (syncPreferences.syncService().get() != 0 && syncFlags and SyncPreferences.Flags.SYNC_ON_APP_START == SyncPreferences.Flags.SYNC_ON_APP_START) {
|
||||
SyncDataJob.startNow(this@App)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
|
@ -21,6 +21,7 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.saver.Image
|
||||
import eu.kanade.tachiyomi.data.saver.ImageSaver
|
||||
import eu.kanade.tachiyomi.data.saver.Location
|
||||
import eu.kanade.tachiyomi.data.sync.SyncDataJob
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
||||
@ -71,6 +72,7 @@ import tachiyomi.domain.history.model.HistoryUpdate
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.sync.SyncPreferences
|
||||
import tachiyomi.source.local.isLocal
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@ -98,6 +100,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
||||
private val upsertHistory: UpsertHistory = Injekt.get(),
|
||||
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||
private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(),
|
||||
private val syncPreferences: SyncPreferences = Injekt.get()
|
||||
) : ViewModel() {
|
||||
|
||||
private val mutableState = MutableStateFlow(State())
|
||||
@ -513,6 +516,7 @@ class ReaderViewModel @JvmOverloads constructor(
|
||||
*/
|
||||
private suspend fun updateChapterProgress(readerChapter: ReaderChapter, page: Page) {
|
||||
val pageIndex = page.index
|
||||
val syncFlags = syncPreferences.syncFlags().get()
|
||||
|
||||
mutableState.update {
|
||||
it.copy(currentPage = pageIndex + 1)
|
||||
@ -527,6 +531,12 @@ class ReaderViewModel @JvmOverloads constructor(
|
||||
readerChapter.chapter.read = true
|
||||
updateTrackChapterRead(readerChapter)
|
||||
deleteChapterIfNeeded(readerChapter)
|
||||
|
||||
// Check if syncing is enabled for chapter read:
|
||||
if (syncPreferences.syncService().get() != 0 &&
|
||||
syncFlags and SyncPreferences.Flags.SYNC_ON_CHAPTER_READ == SyncPreferences.Flags.SYNC_ON_CHAPTER_READ) {
|
||||
SyncDataJob.startNow(Injekt.get<Application>())
|
||||
}
|
||||
}
|
||||
|
||||
updateChapter.await(
|
||||
@ -536,6 +546,12 @@ class ReaderViewModel @JvmOverloads constructor(
|
||||
lastPageRead = readerChapter.chapter.last_page_read.toLong(),
|
||||
),
|
||||
)
|
||||
|
||||
// Check if syncing is enabled for chapter open:
|
||||
if (syncPreferences.syncService().get() != 0 &&
|
||||
syncFlags and SyncPreferences.Flags.SYNC_ON_CHAPTER_OPEN == SyncPreferences.Flags.SYNC_ON_CHAPTER_OPEN) {
|
||||
SyncDataJob.startNow(Injekt.get<Application>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,18 @@ import tachiyomi.core.preference.PreferenceStore
|
||||
class SyncPreferences(
|
||||
private val preferenceStore: PreferenceStore,
|
||||
) {
|
||||
object Flags {
|
||||
const val NONE = 0x0
|
||||
const val SYNC_ON_CHAPTER_READ = 0x1
|
||||
const val SYNC_ON_CHAPTER_OPEN = 0x2
|
||||
const val SYNC_ON_APP_START = 0x4
|
||||
|
||||
const val Defaults = NONE
|
||||
|
||||
fun values() = listOf(NONE, SYNC_ON_CHAPTER_READ, SYNC_ON_CHAPTER_OPEN, SYNC_ON_APP_START)
|
||||
}
|
||||
|
||||
|
||||
fun syncHost() = preferenceStore.getString("sync_host", "https://sync.tachiyomi.org")
|
||||
fun syncAPIKey() = preferenceStore.getString("sync_api_key", "")
|
||||
fun lastSyncTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_sync_timestamp"), 0L)
|
||||
@ -22,4 +34,6 @@ class SyncPreferences(
|
||||
Preference.appStateKey("google_drive_refresh_token"),
|
||||
"",
|
||||
)
|
||||
|
||||
fun syncFlags() = preferenceStore.getInt("sync_flags", Flags.Defaults)
|
||||
}
|
||||
|
@ -566,7 +566,11 @@
|
||||
<string name="google_drive_not_signed_in">Not signed in to Google Drive</string>
|
||||
<string name="pref_purge_confirmation_title">Purge confirmation</string>
|
||||
<string name="pref_purge_confirmation_message">Purging sync data will delete all your sync data from Google Drive. Are you sure you want to continue?</string>
|
||||
|
||||
<string name="pref_sync_options">Create sync triggers</string>
|
||||
<string name="pref_sync_options_summ">Can be used to set sync triggers</string>
|
||||
<string name="sync_on_chapter_read">On chapter read</string>
|
||||
<string name="sync_on_chapter_open">On every open chapter page (EXPERIMENTAL NOT RECOMMENDED, everytime you go to next page it or previous it will sync.)</string>
|
||||
<string name="sync_on_app_start">On app start</string>
|
||||
|
||||
<!-- Advanced section -->
|
||||
<string name="label_network">Networking</string>
|
||||
|
Loading…
Reference in New Issue
Block a user