Add installation id for feature flags (#3052)

# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt
#	app/src/main/java/mihon/core/migration/migrations/Migrations.kt
This commit is contained in:
AntsyLich
2026-03-10 23:53:11 +06:00
committed by Jobobby04
parent 8b1fd30902
commit b7d6cc8dd0
9 changed files with 81 additions and 1 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "eu.kanade.tachiyomi.sy" applicationId = "eu.kanade.tachiyomi.sy"
versionCode = 76 versionCode = 77
versionName = "1.12.0" versionName = "1.12.0"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
@@ -35,4 +35,6 @@ class BasePreferences(
fun hardwareBitmapThreshold() = preferenceStore.getInt("pref_hardware_bitmap_threshold", GLUtil.SAFE_TEXTURE_LIMIT) fun hardwareBitmapThreshold() = preferenceStore.getInt("pref_hardware_bitmap_threshold", GLUtil.SAFE_TEXTURE_LIMIT)
fun alwaysDecodeLongStripWithSSIV() = preferenceStore.getBoolean("pref_always_decode_long_strip_with_ssiv", false) fun alwaysDecodeLongStripWithSSIV() = preferenceStore.getBoolean("pref_always_decode_long_strip_with_ssiv", false)
fun installationId() = preferenceStore.getString(Preference.appStateKey("installation_id"), "")
} }
@@ -30,6 +30,7 @@ sealed class Preference {
override val title: String, override val title: String,
override val subtitle: CharSequence? = null, override val subtitle: CharSequence? = null,
override val enabled: Boolean = true, override val enabled: Boolean = true,
val widget: @Composable (() -> Unit)? = null,
val onClick: (() -> Unit)? = null, val onClick: (() -> Unit)? = null,
) : PreferenceItem<String, Unit>() { ) : PreferenceItem<String, Unit>() {
override val icon: ImageVector? = null override val icon: ImageVector? = null
@@ -147,6 +147,7 @@ internal fun PreferenceItem(
title = item.title, title = item.title,
subtitle = item.subtitle, subtitle = item.subtitle,
icon = item.icon, icon = item.icon,
widget = item.widget,
onPreferenceClick = item.onClick, onPreferenceClick = item.onClick,
) )
} }
@@ -1,24 +1,38 @@
package eu.kanade.presentation.more.settings.screen.debug package eu.kanade.presentation.more.settings.screen.debug
import android.os.Build import android.os.Build
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Autorenew
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable 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.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext 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
import eu.kanade.presentation.util.Screen import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.util.system.DeviceUtil 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.copyToClipboard
import kotlinx.collections.immutable.mutate import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.guava.await import kotlinx.coroutines.guava.await
import kotlinx.coroutines.launch
import mihon.core.common.FeatureFlags
import tachiyomi.i18n.MR import tachiyomi.i18n.MR
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class DebugInfoScreen : Screen() { class DebugInfoScreen : Screen() {
@@ -47,6 +61,12 @@ class DebugInfoScreen : Screen() {
@Composable @Composable
private fun getAppInfoGroup(): Preference.PreferenceGroup { private fun getAppInfoGroup(): Preference.PreferenceGroup {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val installationIdPref = remember { Injekt.get<BasePreferences>().installationId() }
val installationId by installationIdPref.collectAsState()
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
title = "App info", title = "App info",
preferenceItems = persistentListOf( preferenceItems = persistentListOf(
@@ -58,6 +78,28 @@ class DebugInfoScreen : Screen() {
title = "Build time", title = "Build time",
subtitle = AboutScreen.getFormattedBuildTime(), subtitle = AboutScreen.getFormattedBuildTime(),
), ),
Preference.PreferenceItem.TextPreference(
title = "Installation ID",
subtitle = installationId,
widget = {
IconButton(
onClick = {
scope.launch {
installationIdPref.set(FeatureFlags.newInstallationId())
}
},
) {
Icon(
imageVector = Icons.Outlined.Autorenew,
tint = MaterialTheme.colorScheme.primary,
contentDescription = null,
)
}
},
onClick = {
context.copyToClipboard(installationId, installationId)
},
),
getProfileVerifierPreference(), getProfileVerifierPreference(),
Preference.PreferenceItem.TextPreference( Preference.PreferenceItem.TextPreference(
title = "WebView version", title = "WebView version",
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.util
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.util.storage.getUriCompat import eu.kanade.tachiyomi.util.storage.getUriCompat
@@ -20,6 +21,7 @@ import java.time.ZoneId
class CrashLogUtil( class CrashLogUtil(
private val context: Context, private val context: Context,
private val extensionManager: ExtensionManager = Injekt.get(), private val extensionManager: ExtensionManager = Injekt.get(),
private val preferences: BasePreferences = Injekt.get(),
) { ) {
suspend fun dumpLogs(exception: Throwable? = null) = withNonCancellableContext { suspend fun dumpLogs(exception: Throwable? = null) = withNonCancellableContext {
@@ -44,6 +46,7 @@ class CrashLogUtil(
App ID: ${BuildConfig.APPLICATION_ID} App ID: ${BuildConfig.APPLICATION_ID}
App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}, ${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE}, ${BuildConfig.BUILD_TIME}) App version: ${BuildConfig.VERSION_NAME} (${BuildConfig.FLAVOR}, ${BuildConfig.COMMIT_SHA}, ${BuildConfig.VERSION_CODE}, ${BuildConfig.BUILD_TIME})
Preview build: $syDebugVersion Preview build: $syDebugVersion
Installation ID: ${preferences.installationId().get()}
Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT}; build ${Build.DISPLAY}) Android version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT}; build ${Build.DISPLAY})
Device brand: ${Build.BRAND} Device brand: ${Build.BRAND}
Device manufacturer: ${Build.MANUFACTURER} Device manufacturer: ${Build.MANUFACTURER}
@@ -0,0 +1,18 @@
package mihon.core.migration.migrations
import eu.kanade.domain.base.BasePreferences
import mihon.core.common.FeatureFlags
import mihon.core.migration.Migration
import mihon.core.migration.MigrationContext
import kotlin.uuid.ExperimentalUuidApi
class InstallationIdMigration : Migration {
override val version: Float = Migration.ALWAYS
@OptIn(ExperimentalUuidApi::class)
override suspend fun invoke(migrationContext: MigrationContext): Boolean {
val installationId = migrationContext.get<BasePreferences>()?.installationId() ?: return false
if (!installationId.isSet()) installationId.set(FeatureFlags.newInstallationId())
return true
}
}
@@ -47,4 +47,5 @@ val migrations: List<Migration>
TrustExtensionRepositoryMigration(), TrustExtensionRepositoryMigration(),
CategoryPreferencesCleanupMigration(), CategoryPreferencesCleanupMigration(),
RemoveDuplicateReaderPreferenceMigration(), RemoveDuplicateReaderPreferenceMigration(),
InstallationIdMigration(),
) )
@@ -0,0 +1,12 @@
package mihon.core.common
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
object FeatureFlags {
@OptIn(ExperimentalUuidApi::class)
fun newInstallationId(): String {
return Uuid.random().toHexDashString()
}
}