Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3dd1a2b
Update actions/dependency-review-action action to v4.9.0 (#3036)
renovate-bot Mar 6, 2026
3a1963f
Update dependency com.materialkolor:material-kolor to v5.0.0-alpha07 …
renovate-bot Mar 6, 2026
639dfa7
Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8.…
renovate-bot Mar 6, 2026
e3f8146
Update dependency com.google.firebase:firebase-bom to v34.10.0 (#3006)
renovate-bot Mar 6, 2026
e8226e5
Update dependency androidx.compose:compose-bom to v2026.02.01 (#3009)
renovate-bot Mar 6, 2026
d8bea1e
Add installation id for feature flags (#3052)
AntsyLich Mar 10, 2026
c5a7263
Bump workflows JDK to 21 (#3053)
AntsyLich Mar 14, 2026
a3f8158
Update dependency androidx.compose:compose-bom to v2026.03.00 (#3066)
renovate-bot Mar 15, 2026
bdc5de2
Update dependency androidx.core:core-ktx to v1.18.0 (#3067)
renovate-bot Mar 15, 2026
1314464
Update dependency androidx.activity:activity-compose to v1.13.0 (#3065)
renovate-bot Mar 15, 2026
d7fc331
Update softprops/action-gh-release action to v2.5.3 (#3064)
renovate-bot Mar 15, 2026
37526b8
Update dependency com.squareup.okio:okio to v3.17.0 (#3070)
renovate-bot Mar 15, 2026
470f975
Update moko to v0.26.1 (#3068)
renovate-bot Mar 16, 2026
ffcccb4
Update dependency io.kotest:kotest-assertions-core to v6.1.7 (#3062)
renovate-bot Mar 16, 2026
9260112
Update sqldelight to v2.3.1 (#3071)
renovate-bot Mar 16, 2026
36d0fd1
Address bundleOf deprecation (#3073)
MajorTanya Mar 18, 2026
13da2ca
Update sqldelight to v2.3.2 (#3077)
renovate-bot Mar 18, 2026
c0cc012
Update kotlin monorepo to v2.3.20 (#3074)
renovate-bot Mar 18, 2026
d0ab992
Update paging.version to v3.4.2 (#3063)
renovate-bot Mar 18, 2026
9128468
Update softprops/action-gh-release action to v2.6.1 (#3072)
renovate-bot Mar 18, 2026
99c8566
Switch to AndroidX bundled sqlite driver
Secozzi Mar 20, 2026
248916a
Update dependency com.diffplug.spotless:spotless-plugin-gradle to v8.…
renovate-bot Mar 19, 2026
8aa6d54
Fix tracker-induced duplicate key crash in duplicate detection
Secozzi Mar 20, 2026
0de1c1b
Fix WebView JavaScript dialogs popup after screen is closed (#3041)
leodyversemilla07 Mar 19, 2026
40c2fc0
Fix extension actions disappearing after installing and uninstalling …
Secozzi Mar 20, 2026
182c6fc
Replace preference getter functions with properties
Secozzi Mar 20, 2026
194be0e
Update dependency com.google.firebase:firebase-bom to v34.11.0 (#3094)
renovate-bot Mar 20, 2026
682de19
Fix wrong exception being caught after 8c480c6355 migration
AntsyLich Mar 23, 2026
d4cfb95
Potentially fix 'database is locked' crash
Secozzi Mar 30, 2026
15ce5eb
Fix occasional crash when mass installing/uninstalling extension usin…
AntsyLich Mar 23, 2026
446a010
Fix app crash on startup on some Android TV
AntsyLich Mar 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/.java-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
21
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ jobs:

- name: Dependency Review
if: github.event_name == 'pull_request'
uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0

- name: Set up JDK
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
java-version: 17
java-version-file: .github/.java-version
distribution: temurin

- name: Set up Gradle
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
java-version: 17
java-version-file: .github/.java-version
distribution: temurin

# AM (SYNC_DRIVE) -->
Expand Down Expand Up @@ -110,7 +110,7 @@ jobs:
Animiru

- name: Create GitHub Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
tag_name: ${{ needs.get_tag.outputs.tag }}
name: Animiru ${{ needs.get_tag.outputs.tag }}
Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ dependencies {
implementation(androidx.paging.runtime)
implementation(androidx.paging.compose)

implementation(libs.bundles.sqlite)
implementation(androidx.sqlite.bundled)

implementation(kotlinx.reflect)
implementation(kotlinx.immutables)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class UpdateAnime(

// if the anime isn't a favorite (or 'update titles' preference is enabled), set its title from source and update in db
val title =
if (remoteTitle.isNotEmpty() && (!localAnime.favorite || libraryPreferences.updateAnimeTitles().get())) {
if (remoteTitle.isNotEmpty() && (!localAnime.favorite || libraryPreferences.updateAnimeTitles.get())) {
remoteTitle
} else {
null
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/eu/kanade/domain/anime/model/Anime.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import uy.kohesive.injekt.api.get
// TODO: move these into the domain model
val Anime.downloadedFilter: TriState
get() {
if (Injekt.get<BasePreferences>().downloadedOnly().get()) return TriState.ENABLED_IS
if (Injekt.get<BasePreferences>().downloadedOnly.get()) return TriState.ENABLED_IS
return when (downloadedFilterRaw) {
Anime.EPISODE_SHOW_DOWNLOADED -> TriState.ENABLED_IS
Anime.EPISODE_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
Expand All @@ -23,7 +23,7 @@ val Anime.downloadedFilter: TriState
// AY -->
val Anime.seasonDownloadedFilter: TriState
get() {
if (Injekt.get<BasePreferences>().downloadedOnly().get()) return TriState.ENABLED_IS
if (Injekt.get<BasePreferences>().downloadedOnly.get()) return TriState.ENABLED_IS
return when (seasonDownloadedFilterRaw) {
Anime.SEASON_SHOW_DOWNLOADED -> TriState.ENABLED_IS
Anime.SEASON_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
Expand Down
15 changes: 10 additions & 5 deletions app/src/main/java/eu/kanade/domain/base/BasePreferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,35 @@ import tachiyomi.i18n.MR

class BasePreferences(
val context: Context,
private val preferenceStore: PreferenceStore,
preferenceStore: PreferenceStore,
) {

fun downloadedOnly() = preferenceStore.getBoolean(
val downloadedOnly: Preference<Boolean> = preferenceStore.getBoolean(
Preference.appStateKey("pref_downloaded_only"),
false,
)

fun incognitoMode() = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)
val incognitoMode: Preference<Boolean> = preferenceStore.getBoolean(Preference.appStateKey("incognito_mode"), false)

fun extensionInstaller() = ExtensionInstallerPreference(context, preferenceStore)
val extensionInstaller: ExtensionInstallerPreference = ExtensionInstallerPreference(context, preferenceStore)

// AY -->
fun deviceHasPip() = context.packageManager.hasSystemFeature(
PackageManager.FEATURE_PICTURE_IN_PICTURE,
)
// <-- AY

fun shownOnboardingFlow() = preferenceStore.getBoolean(Preference.appStateKey("onboarding_complete"), false)
val shownOnboardingFlow: Preference<Boolean> = preferenceStore.getBoolean(
Preference.appStateKey("onboarding_complete"),
false,
)

enum class ExtensionInstaller(val titleRes: StringResource, val requiresSystemPermission: Boolean) {
LEGACY(MR.strings.ext_installer_legacy, true),
PACKAGEINSTALLER(MR.strings.ext_installer_packageinstaller, true),
SHIZUKU(MR.strings.ext_installer_shizuku, false),
PRIVATE(MR.strings.ext_installer_private, false),
}

val installationId: Preference<String> = preferenceStore.getString(Preference.appStateKey("installation_id"), "")
}
19 changes: 11 additions & 8 deletions app/src/main/java/eu/kanade/domain/connection/SyncPreferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,31 @@ class SyncPreferences(
private val preferenceStore: PreferenceStore,
) {
// AM (SYNC_YOMI) -->
fun clientHost() = preferenceStore.getString("connection_sync_client_host", "https://sync.animiru.net")
fun clientAPIKey() = preferenceStore.getString("connection_sync_client_api_key", "")
val clientHost: Preference<String> = preferenceStore.getString(
"connection_sync_client_host",
"https://sync.animiru.net",
)
val clientAPIKey: Preference<String> = preferenceStore.getString("connection_sync_client_api_key", "")
// <-- AM (SYNC_YOMI)

fun lastSyncTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_sync_timestamp"), 0L)
val lastSyncTimestamp: Preference<Long> = preferenceStore.getLong(Preference.appStateKey("last_sync_timestamp"), 0L)

fun lastSyncEtag() = preferenceStore.getString("sync_etag", "")
val lastSyncEtag: Preference<String> = preferenceStore.getString("sync_etag", "")

fun syncInterval() = preferenceStore.getInt("sync_interval", 0)
val syncInterval: Preference<Int> = preferenceStore.getInt("sync_interval", 0)

// AM (SYNC_DRIVE) -->
fun googleDriveAccessToken() = preferenceStore.getString(
val googleDriveAccessToken: Preference<String> = preferenceStore.getString(
Preference.appStateKey("connection_google_drive_access_token"),
"",
)
fun googleDriveRefreshToken() = preferenceStore.getString(
val googleDriveRefreshToken: Preference<String> = preferenceStore.getString(
Preference.appStateKey("connection_google_drive_refresh_token"),
"",
)
// <-- AM (SYNC_DRIVE)

fun isSyncEnabled() = googleDriveRefreshToken().get().isNotBlank() || clientAPIKey().get().isNotBlank()
fun isSyncEnabled() = googleDriveRefreshToken.get().isNotBlank() || clientAPIKey.get().isNotBlank()

fun uniqueDeviceID(): String {
val uniqueIDPreference = preferenceStore.getString("unique_device_id", "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package eu.kanade.domain.connection.service

import eu.kanade.tachiyomi.data.connection.Connection
import tachiyomi.core.common.preference.Preference
import tachiyomi.core.common.preference.PreferenceStore

class ConnectionPreferences(
Expand All @@ -25,13 +26,16 @@ class ConnectionPreferences(
fun connectionToken(connection: Connection) = preferenceStore.getString(connectionToken(connection.id), "")

// AM (DISCORD_RPC) -->
fun enableDiscordRPC() = preferenceStore.getBoolean("pref_enable_discord_rpc", false)
val enableDiscordRPC: Preference<Boolean> = preferenceStore.getBoolean("pref_enable_discord_rpc", false)

fun discordRPCStatus() = preferenceStore.getInt("pref_discord_rpc_status", 1)
val discordRPCStatus: Preference<Int> = preferenceStore.getInt("pref_discord_rpc_status", 1)

fun discordRPCIncognito() = preferenceStore.getBoolean("pref_discord_rpc_incognito", false)
val discordRPCIncognito: Preference<Boolean> = preferenceStore.getBoolean("pref_discord_rpc_incognito", false)

fun discordRPCIncognitoCategories() = preferenceStore.getStringSet("discord_rpc_incognito_categories", emptySet())
val discordRPCIncognitoCategories: Preference<Set<String>> = preferenceStore.getStringSet(
"discord_rpc_incognito_categories",
emptySet(),
)
// <-- AM (DISCORD_RPC)

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class SetSeenStatus(
return@withNonCancellableContext Result.InternalError(e)
}

if (seen && downloadPreferences.removeAfterMarkedAsSeen().get()) {
if (seen && downloadPreferences.removeAfterMarkedAsSeen.get()) {
episodesToUpdate
.groupBy { it.animeId }
.forEach { (animeId, episodes) ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class SyncEpisodesWithSource(
val deletedEpisodeNumberDateFetchMap = removedEpisodes.sortedByDescending { it.dateFetch }
.associate { it.episodeNumber to it.dateFetch }

val markDuplicateAsSeen = libraryPreferences.markDuplicateSeenEpisodeAsSeen().get()
val markDuplicateAsSeen = libraryPreferences.markDuplicateSeenEpisodeAsSeen.get()
.contains(LibraryPreferences.MARK_DUPLICATE_EPISODE_SEEN_NEW)

// Date fetch is set in such a way that the upper ones will have bigger value than the lower ones
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class GetExtensionLanguages(
) {
fun subscribe(): Flow<List<String>> {
return combine(
preferences.enabledLanguages().changes(),
preferences.enabledLanguages.changes(),
extensionManager.availableExtensionsFlow,
) { enabledLanguage, availableExtensions ->
availableExtensions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class GetExtensionSources(
val isMultiLangSingleSource =
isMultiSource && extension.sources.map { it.name }.distinct().size == 1

return preferences.disabledSources().changes().map { disabledSources ->
return preferences.disabledSources.changes().map { disabledSources ->
fun AnimeSource.isEnabled() = id.toString() !in disabledSources

extension.sources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ class GetExtensionsByType(
) {

fun subscribe(): Flow<Extensions> {
val showNsfwSources = preferences.showNsfwSource().get()
val showNsfwSources = preferences.showNsfwSource.get()

return combine(
preferences.enabledLanguages().changes(),
preferences.enabledLanguages.changes(),
extensionManager.installedExtensionsFlow,
extensionManager.untrustedExtensionsFlow,
extensionManager.availableExtensionsFlow,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ class TrustExtension(
suspend fun isTrusted(pkgInfo: PackageInfo, fingerprints: List<String>): Boolean {
val trustedFingerprints = extensionRepoRepository.getAll().map { it.signingKeyFingerprint }.toHashSet()
val key = "${pkgInfo.packageName}:${PackageInfoCompat.getLongVersionCode(pkgInfo)}:${fingerprints.last()}"
return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions().get()
return trustedFingerprints.any { fingerprints.contains(it) } || key in preferences.trustedExtensions.get()
}

fun trust(pkgName: String, versionCode: Long, signatureHash: String) {
preferences.trustedExtensions().getAndSet { exts ->
preferences.trustedExtensions.getAndSet { exts ->
// Remove previously trusted versions
val removed = exts.filterNot { it.startsWith("$pkgName:") }.toMutableSet()

Expand All @@ -27,6 +27,6 @@ class TrustExtension(
}

fun revokeAll() {
preferences.trustedExtensions().delete()
preferences.trustedExtensions.delete()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class GetEnabledSources(

fun subscribe(): Flow<List<Source>> {
return combine(
preferences.pinnedSources().changes(),
preferences.enabledLanguages().changes(),
preferences.disabledSources().changes(),
preferences.lastUsedSource().changes(),
preferences.pinnedSources.changes(),
preferences.enabledLanguages.changes(),
preferences.disabledSources.changes(),
preferences.lastUsedSource.changes(),
repository.getSources(),
) { pinnedSourceIds, enabledLanguages, disabledSources, lastUsedSource, sources ->
sources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ class GetIncognitoState(
private val extensionManager: ExtensionManager,
) {
fun await(sourceId: Long?): Boolean {
if (basePreferences.incognitoMode().get()) return true
if (basePreferences.incognitoMode.get()) return true
if (sourceId == null) return false
val extensionPackage = extensionManager.getExtensionPackage(sourceId) ?: return false

return extensionPackage in sourcePreferences.incognitoExtensions().get()
return extensionPackage in sourcePreferences.incognitoExtensions.get()
}

fun subscribe(sourceId: Long?): Flow<Boolean> {
if (sourceId == null) return basePreferences.incognitoMode().changes()
if (sourceId == null) return basePreferences.incognitoMode.changes()

return combine(
basePreferences.incognitoMode().changes(),
sourcePreferences.incognitoExtensions().changes(),
basePreferences.incognitoMode.changes(),
sourcePreferences.incognitoExtensions.changes(),
extensionManager.getExtensionPackageAsFlow(sourceId),
) { incognito, incognitoExtensions, extensionPackage ->
incognito || (extensionPackage in incognitoExtensions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class GetLanguagesWithSources(

fun subscribe(): Flow<SortedMap<String, List<Source>>> {
return combine(
preferences.enabledLanguages().changes(),
preferences.disabledSources().changes(),
preferences.enabledLanguages.changes(),
preferences.disabledSources.changes(),
repository.getOnlineSources(),
) { enabledLanguage, disabledSource, onlineSources ->
val sortedSources = onlineSources.sortedWith(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class GetSourcesWithFavoriteCount(

fun subscribe(): Flow<List<Pair<Source, Long>>> {
return combine(
preferences.migrationSortingDirection().changes(),
preferences.migrationSortingMode().changes(),
preferences.migrationSortingDirection.changes(),
preferences.migrationSortingMode.changes(),
repository.getSourcesWithFavoriteCount(),
) { direction, mode, list ->
list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ class SetMigrateSorting(
) {

fun await(mode: Mode, direction: Direction) {
preferences.migrationSortingMode().set(mode)
preferences.migrationSortingDirection().set(direction)
preferences.migrationSortingMode.set(mode)
preferences.migrationSortingDirection.set(direction)
}

enum class Mode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ToggleIncognito(
private val preferences: SourcePreferences,
) {
fun await(extensions: String, enable: Boolean) {
preferences.incognitoExtensions().getAndSet {
preferences.incognitoExtensions.getAndSet {
if (enable) it.plus(extensions) else it.minus(extensions)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class ToggleLanguage(
) {

fun await(language: String) {
val isEnabled = language in preferences.enabledLanguages().get()
preferences.enabledLanguages().getAndSet { enabled ->
val isEnabled = language in preferences.enabledLanguages.get()
preferences.enabledLanguages.getAndSet { enabled ->
if (isEnabled) enabled.minus(language) else enabled.plus(language)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ class ToggleSource(
}

fun await(sourceId: Long, enable: Boolean = isEnabled(sourceId)) {
preferences.disabledSources().getAndSet { disabled ->
preferences.disabledSources.getAndSet { disabled ->
if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
}
}

fun await(sourceIds: List<Long>, enable: Boolean) {
val transformedSourceIds = sourceIds.map { it.toString() }
preferences.disabledSources().getAndSet { disabled ->
preferences.disabledSources.getAndSet { disabled ->
if (enable) disabled.minus(transformedSourceIds) else disabled.plus(transformedSourceIds)
}
}

private fun isEnabled(sourceId: Long): Boolean {
return sourceId.toString() in preferences.disabledSources().get()
return sourceId.toString() in preferences.disabledSources.get()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class ToggleSourcePin(
) {

fun await(source: Source) {
val isPinned = source.id.toString() in preferences.pinnedSources().get()
preferences.pinnedSources().getAndSet { pinned ->
val isPinned = source.id.toString() in preferences.pinnedSources.get()
preferences.pinnedSources.getAndSet { pinned ->
if (isPinned) pinned.minus("${source.id}") else pinned.plus("${source.id}")
}
}
Expand Down
Loading
Loading