diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/Sync.kt b/AnkiDroid/src/main/java/com/ichi2/anki/Sync.kt index 7de0978624..3982373c81 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/Sync.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/Sync.kt @@ -33,6 +33,7 @@ import com.ichi2.anki.dialogs.SyncErrorDialog import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.anki.snackbar.showSnackbar import com.ichi2.anki.worker.SyncMediaWorker +import com.ichi2.libanki.ChangeManager.notifySubscribersAllValuesChanged import com.ichi2.libanki.createBackup import com.ichi2.libanki.fullUploadOrDownload import com.ichi2.libanki.syncCollection @@ -161,6 +162,7 @@ fun DeckPicker.handleNewSync( throw exc } withCol { notetypes.clearCache() } + notifySubscribersAllValuesChanged(deckPicker) setLastSyncTimeToNow() refreshState() } diff --git a/AnkiDroid/src/main/java/com/ichi2/libanki/ChangeManager.kt b/AnkiDroid/src/main/java/com/ichi2/libanki/ChangeManager.kt index cf827a716a..d8372eff33 100644 --- a/AnkiDroid/src/main/java/com/ichi2/libanki/ChangeManager.kt +++ b/AnkiDroid/src/main/java/com/ichi2/libanki/ChangeManager.kt @@ -33,6 +33,7 @@ import anki.collection.OpChangesAfterUndo import anki.collection.OpChangesOnly import anki.collection.OpChangesWithCount import anki.collection.OpChangesWithId +import anki.collection.opChanges import anki.import_export.ImportResponse import com.ichi2.anki.CollectionManager.withCol import com.ichi2.anki.CrashReportService @@ -103,6 +104,29 @@ object ChangeManager { } notifySubscribers(opChanges, initiator) } + + fun notifySubscribersAllValuesChanged(handler: Any? = null) { + notifySubscribers(ALL, handler) + } + + /** + * An OpChanges that ensures that all data should be considered as potentially changed. + */ + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal val ALL = opChanges { + card = true + note = true + deck = true + tag = true + notetype = true + config = true + deckConfig = true + mtime = true + browserTable = true + browserSidebar = true + noteText = true + studyQueues = true + } } /** Wrap a routine that returns OpChanges* or similar undo info with this diff --git a/AnkiDroid/src/test/java/com/ichi2/libanki/ChangeManagerTest.kt b/AnkiDroid/src/test/java/com/ichi2/libanki/ChangeManagerTest.kt new file mode 100644 index 0000000000..69a2267a18 --- /dev/null +++ b/AnkiDroid/src/test/java/com/ichi2/libanki/ChangeManagerTest.kt @@ -0,0 +1,63 @@ +/* + Copyright (c) 2024 David Allison + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 3 of the License, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + this program. If not, see . + */ +package com.ichi2.libanki + +import anki.collection.OpChanges +import com.ichi2.testutils.JvmTest +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.greaterThan +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized +import kotlin.collections.Collection +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.memberProperties +import kotlin.reflect.javaType +import kotlin.reflect.jvm.isAccessible + +@RunWith(Parameterized::class) +class ChangeManagerTest : JvmTest() { + + @JvmField // required for Parameter + @Parameterized.Parameter + var property: KProperty1? = null + + @JvmField // required for Parameter + @Parameterized.Parameter(1) + var name: String? = null + + @Test + fun `Property is set in ALL object`() { + assertThat(name, property!!.call(ChangeManager.ALL), equalTo(true)) + } + + companion object { + @Parameterized.Parameters(name = "{1}") + @OptIn(ExperimentalStdlibApi::class) + @JvmStatic // required for initParameters + fun initParameters(): Collection> { + val props = + OpChanges::class.memberProperties.filter { it.returnType.javaType == Boolean::class.java } + assertThat(props.size, greaterThan(0)) + + props.forEach { it.isAccessible = true } + return props.map { + arrayOf(it, it.name) + } + } + } +}