Add option to opt out of Analytics and Crashlytics (#1237)
(cherry picked from commit 7c7af72f8cb12decc06b76c36852dcc54696236d) # Conflicts: # app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt # app/src/standard/AndroidManifest.xml
This commit is contained in:
parent
f6d2d0bd48
commit
2bd9a914c1
9
app/src/dev/java/mihon/core/firebase/Firebase.kt
Normal file
9
app/src/dev/java/mihon/core/firebase/Firebase.kt
Normal file
@ -0,0 +1,9 @@
|
||||
package mihon.core.firebase
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
object Firebase {
|
||||
fun setup(context: Context, preference: PrivacyPreferences, scope: CoroutineScope) = Unit
|
||||
}
|
@ -268,6 +268,14 @@
|
||||
android:name="android.webkit.WebView.MetricsOptOut"
|
||||
android:value="true" />
|
||||
|
||||
<!-- Disable for manual opt-in -->
|
||||
<meta-data
|
||||
android:name="firebase_analytics_collection_enabled"
|
||||
android:value="false" />
|
||||
<meta-data
|
||||
android:name="firebase_crashlytics_collection_enabled"
|
||||
android:value="false" />
|
||||
|
||||
<!-- Disable advertising ID collection for Firebase -->
|
||||
<meta-data
|
||||
android:name="google_analytics_adid_collection_enabled"
|
||||
|
@ -14,11 +14,13 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@ -34,13 +36,18 @@ import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.presentation.core.util.secondaryItemAlpha
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
internal class PermissionStep : OnboardingStep {
|
||||
|
||||
private val privacyPreferences: PrivacyPreferences by injectLazy()
|
||||
|
||||
private var notificationGranted by mutableStateOf(false)
|
||||
private var batteryGranted by mutableStateOf(false)
|
||||
|
||||
@ -73,7 +80,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
}
|
||||
|
||||
Column {
|
||||
PermissionItem(
|
||||
PermissionCheckbox(
|
||||
title = stringResource(MR.strings.onboarding_permission_install_apps),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_install_apps_description),
|
||||
granted = installGranted,
|
||||
@ -89,7 +96,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
// no-op. resulting checks is being done on resume
|
||||
},
|
||||
)
|
||||
PermissionItem(
|
||||
PermissionCheckbox(
|
||||
title = stringResource(MR.strings.onboarding_permission_notifications),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_notifications_description),
|
||||
granted = notificationGranted,
|
||||
@ -97,7 +104,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
)
|
||||
}
|
||||
|
||||
PermissionItem(
|
||||
PermissionCheckbox(
|
||||
title = stringResource(MR.strings.onboarding_permission_ignore_battery_opts),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_ignore_battery_opts_description),
|
||||
granted = batteryGranted,
|
||||
@ -109,6 +116,29 @@ internal class PermissionStep : OnboardingStep {
|
||||
context.startActivity(intent)
|
||||
},
|
||||
)
|
||||
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
)
|
||||
|
||||
val crashlyticsPref = privacyPreferences.crashlytics()
|
||||
val crashlytics by crashlyticsPref.collectAsState()
|
||||
PermissionSwitch(
|
||||
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_crashlytics_description),
|
||||
granted = crashlytics,
|
||||
onToggleChange = crashlyticsPref::set,
|
||||
)
|
||||
|
||||
val analyticsPref = privacyPreferences.analytics()
|
||||
val analytics by analyticsPref.collectAsState()
|
||||
PermissionSwitch(
|
||||
title = stringResource(MR.strings.onboarding_permission_analytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_analytics_description),
|
||||
granted = analytics,
|
||||
onToggleChange = analyticsPref::set,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +157,7 @@ internal class PermissionStep : OnboardingStep {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PermissionItem(
|
||||
private fun PermissionCheckbox(
|
||||
title: String,
|
||||
subtitle: String,
|
||||
granted: Boolean,
|
||||
@ -157,4 +187,26 @@ internal class PermissionStep : OnboardingStep {
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PermissionSwitch(
|
||||
title: String,
|
||||
subtitle: String,
|
||||
granted: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
onToggleChange: (Boolean) -> Unit,
|
||||
) {
|
||||
ListItem(
|
||||
modifier = modifier,
|
||||
headlineContent = { Text(text = title) },
|
||||
supportingContent = { Text(text = subtitle) },
|
||||
trailingContent = {
|
||||
Switch(
|
||||
checked = granted,
|
||||
onCheckedChange = onToggleChange,
|
||||
)
|
||||
},
|
||||
colors = ListItemDefaults.colors(containerColor = Color.Transparent),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
||||
import eu.kanade.tachiyomi.ui.category.biometric.BiometricTimesScreen
|
||||
@ -70,10 +71,20 @@ object SettingsSecurityScreen : SearchableSettings {
|
||||
|
||||
@Composable
|
||||
override fun getPreferences(): List<Preference> {
|
||||
val context = LocalContext.current
|
||||
val securityPreferences = remember { Injekt.get<SecurityPreferences>() }
|
||||
val authSupported = remember { context.isAuthenticationSupported() }
|
||||
val privacyPreferences = remember { Injekt.get<PrivacyPreferences>() }
|
||||
return listOf(
|
||||
getSecurityGroup(securityPreferences),
|
||||
getFirebaseGroup(privacyPreferences),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSecurityGroup(
|
||||
securityPreferences: SecurityPreferences,
|
||||
): Preference.PreferenceGroup {
|
||||
val context = LocalContext.current
|
||||
val authSupported = remember { context.isAuthenticationSupported() }
|
||||
val useAuthPref = securityPreferences.useAuthenticator()
|
||||
val useAuth by useAuthPref.collectAsState()
|
||||
|
||||
@ -81,129 +92,132 @@ object SettingsSecurityScreen : SearchableSettings {
|
||||
val isCbzPasswordSet by remember { CbzCrypto.isPasswordSetState(scope) }.collectAsState()
|
||||
val passwordProtectDownloads by securityPreferences.passwordProtectDownloads().collectAsState()
|
||||
|
||||
return listOf(
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = useAuthPref,
|
||||
title = stringResource(MR.strings.lock_with_biometrics),
|
||||
enabled = authSupported,
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_with_biometrics),
|
||||
)
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.lockAppAfter(),
|
||||
title = stringResource(MR.strings.lock_when_idle),
|
||||
enabled = authSupported && useAuth,
|
||||
entries = LockAfterValues
|
||||
.associateWith {
|
||||
when (it) {
|
||||
-1 -> stringResource(MR.strings.lock_never)
|
||||
0 -> stringResource(MR.strings.lock_always)
|
||||
else -> pluralStringResource(MR.plurals.lock_after_mins, count = it, it)
|
||||
return Preference.PreferenceGroup(
|
||||
title = stringResource(MR.strings.pref_security),
|
||||
preferenceItems = persistentListOf(
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = useAuthPref,
|
||||
title = stringResource(MR.strings.lock_with_biometrics),
|
||||
enabled = authSupported,
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_with_biometrics),
|
||||
)
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.lockAppAfter(),
|
||||
title = stringResource(MR.strings.lock_when_idle),
|
||||
enabled = authSupported && useAuth,
|
||||
entries = LockAfterValues
|
||||
.associateWith {
|
||||
when (it) {
|
||||
-1 -> stringResource(MR.strings.lock_never)
|
||||
0 -> stringResource(MR.strings.lock_always)
|
||||
else -> pluralStringResource(MR.plurals.lock_after_mins, count = it, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
.toImmutableMap(),
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_when_idle),
|
||||
)
|
||||
},
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = securityPreferences.hideNotificationContent(),
|
||||
title = stringResource(MR.strings.hide_notification_content),
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.secureScreen(),
|
||||
title = stringResource(MR.strings.secure_screen),
|
||||
entries = SecurityPreferences.SecureScreenMode.entries
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toImmutableMap(),
|
||||
),
|
||||
// SY -->
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = securityPreferences.passwordProtectDownloads(),
|
||||
title = stringResource(SYMR.strings.password_protect_downloads),
|
||||
subtitle = stringResource(SYMR.strings.password_protect_downloads_summary),
|
||||
enabled = isCbzPasswordSet,
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.encryptionType(),
|
||||
title = stringResource(SYMR.strings.encryption_type),
|
||||
entries = SecurityPreferences.EncryptionType.entries
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toImmutableMap(),
|
||||
enabled = passwordProtectDownloads,
|
||||
|
||||
),
|
||||
kotlin.run {
|
||||
var dialogOpen by remember { mutableStateOf(false) }
|
||||
if (dialogOpen) {
|
||||
PasswordDialog(
|
||||
onDismissRequest = { dialogOpen = false },
|
||||
onReturnPassword = { password ->
|
||||
dialogOpen = false
|
||||
|
||||
CbzCrypto.deleteKeyCbz()
|
||||
securityPreferences.cbzPassword().set(CbzCrypto.encryptCbz(password.replace("\n", "")))
|
||||
},
|
||||
)
|
||||
}
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(SYMR.strings.set_cbz_zip_password),
|
||||
onClick = {
|
||||
dialogOpen = true
|
||||
.toImmutableMap(),
|
||||
onValueChanged = {
|
||||
(context as FragmentActivity).authenticate(
|
||||
title = context.stringResource(MR.strings.lock_when_idle),
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(SYMR.strings.delete_cbz_archive_password),
|
||||
onClick = {
|
||||
CbzCrypto.deleteKeyCbz()
|
||||
securityPreferences.cbzPassword().set("")
|
||||
},
|
||||
enabled = isCbzPasswordSet,
|
||||
),
|
||||
kotlin.run {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val count by securityPreferences.authenticatorTimeRanges().collectAsState()
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(SYMR.strings.action_edit_biometric_lock_times),
|
||||
subtitle = pluralStringResource(
|
||||
SYMR.plurals.num_lock_times,
|
||||
count.size,
|
||||
count.size,
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = securityPreferences.hideNotificationContent(),
|
||||
title = stringResource(MR.strings.hide_notification_content),
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.secureScreen(),
|
||||
title = stringResource(MR.strings.secure_screen),
|
||||
entries = SecurityPreferences.SecureScreenMode.entries
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toImmutableMap(),
|
||||
),
|
||||
// SY -->
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = securityPreferences.passwordProtectDownloads(),
|
||||
title = stringResource(SYMR.strings.password_protect_downloads),
|
||||
subtitle = stringResource(SYMR.strings.password_protect_downloads_summary),
|
||||
enabled = isCbzPasswordSet,
|
||||
),
|
||||
Preference.PreferenceItem.ListPreference(
|
||||
pref = securityPreferences.encryptionType(),
|
||||
title = stringResource(SYMR.strings.encryption_type),
|
||||
entries = SecurityPreferences.EncryptionType.entries
|
||||
.associateWith { stringResource(it.titleRes) }
|
||||
.toImmutableMap(),
|
||||
enabled = passwordProtectDownloads,
|
||||
|
||||
),
|
||||
onClick = {
|
||||
navigator.push(BiometricTimesScreen())
|
||||
},
|
||||
enabled = useAuth,
|
||||
)
|
||||
},
|
||||
kotlin.run {
|
||||
val selection by securityPreferences.authenticatorDays().collectAsState()
|
||||
var dialogOpen by remember { mutableStateOf(false) }
|
||||
if (dialogOpen) {
|
||||
SetLockedDaysDialog(
|
||||
onDismissRequest = { dialogOpen = false },
|
||||
initialSelection = selection,
|
||||
onDaysSelected = {
|
||||
dialogOpen = false
|
||||
securityPreferences.authenticatorDays().set(it)
|
||||
kotlin.run {
|
||||
var dialogOpen by remember { mutableStateOf(false) }
|
||||
if (dialogOpen) {
|
||||
PasswordDialog(
|
||||
onDismissRequest = { dialogOpen = false },
|
||||
onReturnPassword = { password ->
|
||||
dialogOpen = false
|
||||
|
||||
CbzCrypto.deleteKeyCbz()
|
||||
securityPreferences.cbzPassword().set(CbzCrypto.encryptCbz(password.replace("\n", "")))
|
||||
},
|
||||
)
|
||||
}
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(SYMR.strings.set_cbz_zip_password),
|
||||
onClick = {
|
||||
dialogOpen = true
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(SYMR.strings.biometric_lock_days),
|
||||
subtitle = stringResource(SYMR.strings.biometric_lock_days_summary),
|
||||
onClick = { dialogOpen = true },
|
||||
enabled = useAuth,
|
||||
)
|
||||
},
|
||||
// SY <--
|
||||
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.secure_screen_summary)),
|
||||
title = stringResource(SYMR.strings.delete_cbz_archive_password),
|
||||
onClick = {
|
||||
CbzCrypto.deleteKeyCbz()
|
||||
securityPreferences.cbzPassword().set("")
|
||||
},
|
||||
enabled = isCbzPasswordSet,
|
||||
),
|
||||
kotlin.run {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val count by securityPreferences.authenticatorTimeRanges().collectAsState()
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(SYMR.strings.action_edit_biometric_lock_times),
|
||||
subtitle = pluralStringResource(
|
||||
SYMR.plurals.num_lock_times,
|
||||
count.size,
|
||||
count.size,
|
||||
),
|
||||
onClick = {
|
||||
navigator.push(BiometricTimesScreen())
|
||||
},
|
||||
enabled = useAuth,
|
||||
)
|
||||
},
|
||||
kotlin.run {
|
||||
val selection by securityPreferences.authenticatorDays().collectAsState()
|
||||
var dialogOpen by remember { mutableStateOf(false) }
|
||||
if (dialogOpen) {
|
||||
SetLockedDaysDialog(
|
||||
onDismissRequest = { dialogOpen = false },
|
||||
initialSelection = selection,
|
||||
onDaysSelected = {
|
||||
dialogOpen = false
|
||||
securityPreferences.authenticatorDays().set(it)
|
||||
},
|
||||
)
|
||||
}
|
||||
Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(SYMR.strings.biometric_lock_days),
|
||||
subtitle = stringResource(SYMR.strings.biometric_lock_days_summary),
|
||||
onClick = { dialogOpen = true },
|
||||
enabled = useAuth,
|
||||
)
|
||||
},
|
||||
// SY <--
|
||||
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.secure_screen_summary)),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -361,6 +375,28 @@ object SettingsSecurityScreen : SearchableSettings {
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
|
||||
@Composable
|
||||
private fun getFirebaseGroup(
|
||||
privacyPreferences: PrivacyPreferences,
|
||||
): Preference.PreferenceGroup {
|
||||
return Preference.PreferenceGroup(
|
||||
title = stringResource(MR.strings.pref_firebase),
|
||||
preferenceItems = persistentListOf(
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = privacyPreferences.crashlytics(),
|
||||
title = stringResource(MR.strings.onboarding_permission_crashlytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_crashlytics_description),
|
||||
),
|
||||
Preference.PreferenceItem.SwitchPreference(
|
||||
pref = privacyPreferences.analytics(),
|
||||
title = stringResource(MR.strings.onboarding_permission_analytics),
|
||||
subtitle = stringResource(MR.strings.onboarding_permission_analytics_description),
|
||||
),
|
||||
Preference.PreferenceItem.InfoPreference(stringResource(MR.strings.firebase_summary)),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val LockAfterValues = persistentListOf(
|
||||
|
@ -28,14 +28,13 @@ import com.elvishew.xlog.printer.AndroidPrinter
|
||||
import com.elvishew.xlog.printer.Printer
|
||||
import com.elvishew.xlog.printer.file.backup.NeverBackupStrategy
|
||||
import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator
|
||||
import com.google.firebase.crashlytics.ktx.crashlytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import eu.kanade.domain.DomainModule
|
||||
import eu.kanade.domain.SYDomainModule
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.domain.sync.SyncPreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.crash.CrashActivity
|
||||
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
||||
import eu.kanade.tachiyomi.data.coil.BufferedSourceFetcher
|
||||
@ -60,8 +59,6 @@ import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.WebViewUtil
|
||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||
import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
||||
import eu.kanade.tachiyomi.util.system.notify
|
||||
import exh.log.CrashlyticsPrinter
|
||||
import exh.log.EHLogLevel
|
||||
@ -74,6 +71,7 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import logcat.LogPriority
|
||||
import logcat.LogcatLogger
|
||||
import mihon.core.firebase.Firebase
|
||||
import mihon.core.migration.Migrator
|
||||
import mihon.core.migration.migrations.migrations
|
||||
import org.conscrypt.Conscrypt
|
||||
@ -94,6 +92,7 @@ import java.util.Locale
|
||||
class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factory {
|
||||
|
||||
private val basePreferences: BasePreferences by injectLazy()
|
||||
private val privacyPreferences: PrivacyPreferences by injectLazy()
|
||||
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||
|
||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||
@ -102,11 +101,6 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
||||
override fun onCreate() {
|
||||
super<Application>.onCreate()
|
||||
|
||||
// SY -->
|
||||
if (!isDevFlavor) {
|
||||
Firebase.crashlytics.setCrashlyticsCollectionEnabled(isReleaseBuildType)
|
||||
}
|
||||
// SY <--
|
||||
GlobalExceptionHandler.initialize(applicationContext, CrashActivity::class.java)
|
||||
|
||||
// TLS 1.3 support for Android < 10
|
||||
@ -133,6 +127,8 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor
|
||||
setupExhLogging() // EXH logging
|
||||
LogcatLogger.install(XLogLogcatLogger()) // SY Redirect Logcat to XLog
|
||||
|
||||
Firebase.setup(applicationContext, privacyPreferences, ProcessLifecycleOwner.get().lifecycleScope)
|
||||
|
||||
setupNotificationChannels()
|
||||
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
|
@ -6,6 +6,7 @@ import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.domain.sync.SyncPreferences
|
||||
import eu.kanade.domain.track.service.TrackPreferences
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
@ -37,6 +38,9 @@ class PreferenceModule(val app: Application) : InjektModule {
|
||||
addSingletonFactory {
|
||||
SecurityPreferences(get())
|
||||
}
|
||||
addSingletonFactory {
|
||||
PrivacyPreferences(get())
|
||||
}
|
||||
addSingletonFactory {
|
||||
LibraryPreferences(get())
|
||||
}
|
||||
|
20
app/src/standard/java/mihon/core/firebase/Firebase.kt
Normal file
20
app/src/standard/java/mihon/core/firebase/Firebase.kt
Normal file
@ -0,0 +1,20 @@
|
||||
package mihon.core.firebase
|
||||
|
||||
import android.content.Context
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import eu.kanade.tachiyomi.core.security.PrivacyPreferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
object Firebase {
|
||||
fun setup(context: Context, preference: PrivacyPreferences, scope: CoroutineScope) {
|
||||
preference.analytics().changes().onEach { enabled ->
|
||||
FirebaseAnalytics.getInstance(context).setAnalyticsCollectionEnabled(enabled)
|
||||
}.launchIn(scope)
|
||||
preference.crashlytics().changes().onEach { enabled ->
|
||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enabled)
|
||||
}.launchIn(scope)
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package eu.kanade.tachiyomi.core.security
|
||||
|
||||
import tachiyomi.core.common.preference.PreferenceStore
|
||||
|
||||
class PrivacyPreferences(
|
||||
private val preferenceStore: PreferenceStore,
|
||||
) {
|
||||
fun crashlytics() = preferenceStore.getBoolean("crashlytics", true)
|
||||
|
||||
fun analytics() = preferenceStore.getBoolean("analytics", true)
|
||||
}
|
@ -190,6 +190,10 @@
|
||||
<string name="onboarding_permission_notifications_description">Get notified for library updates and more.</string>
|
||||
<string name="onboarding_permission_ignore_battery_opts">Background battery usage</string>
|
||||
<string name="onboarding_permission_ignore_battery_opts_description">Avoid interruptions to long-running library updates, downloads, and backup restores.</string>
|
||||
<string name="onboarding_permission_crashlytics">Send crash logs</string>
|
||||
<string name="onboarding_permission_crashlytics_description">Send anonymized crash logs to the developers.</string>
|
||||
<string name="onboarding_permission_analytics">Allow analytics</string>
|
||||
<string name="onboarding_permission_analytics_description">Send anonymized usage data to improve app features.</string>
|
||||
<string name="onboarding_permission_action_grant">Grant</string>
|
||||
<string name="onboarding_guides_new_user">New to %s? We recommend checking out the getting started guide.</string>
|
||||
<string name="onboarding_guides_returning_user">Reinstalling %s?</string>
|
||||
@ -242,6 +246,9 @@
|
||||
<string name="pref_app_language">App language</string>
|
||||
|
||||
<string name="pref_category_security">Security and privacy</string>
|
||||
<string name="pref_security">Security</string>
|
||||
<string name="pref_firebase">Analytics and Crash logs</string>
|
||||
|
||||
<string name="lock_with_biometrics">Require unlock</string>
|
||||
<string name="lock_when_idle">Lock when idle</string>
|
||||
<string name="lock_always">Always</string>
|
||||
@ -249,6 +256,7 @@
|
||||
<string name="hide_notification_content">Hide notification content</string>
|
||||
<string name="secure_screen">Secure screen</string>
|
||||
<string name="secure_screen_summary">Secure screen hides app contents when switching apps and block screenshots</string>
|
||||
<string name="firebase_summary">Sending crash logs and analytics will allow us to identify and fix issues, improve performance, and make future updates more relevant to your needs</string>
|
||||
|
||||
<string name="pref_category_nsfw_content">NSFW (18+) sources</string>
|
||||
<string name="pref_show_nsfw_source">Show in sources and extensions lists</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user