yokai/app/src/main/java/eu/kanade/tachiyomi/App.kt

175 lines
6.4 KiB
Kotlin

package eu.kanade.tachiyomi
import android.annotation.SuppressLint
import android.app.Application
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.webkit.WebView
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.NotificationManagerCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.multidex.MultiDex
import eu.kanade.tachiyomi.data.image.coil.CoilSetup
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
import eu.kanade.tachiyomi.ui.recents.RecentsPresenter
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.ui.source.SourcePresenter
import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
import eu.kanade.tachiyomi.util.system.notification
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.acra.ACRA
import org.acra.config.httpSender
import org.acra.data.StringFormat
import org.acra.ktx.initAcra
import org.conscrypt.Conscrypt
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektScope
import uy.kohesive.injekt.injectLazy
import uy.kohesive.injekt.registry.default.DefaultRegistrar
import java.security.Security
// @ReportsCrashes(
// formUri = "https://collector.tracepot.com/e90773ff",
// reportType = org.acra.sender.HttpSender.Type.JSON,
// httpMethod = org.acra.sender.HttpSender.Method.PUT,
// buildConfigClass = BuildConfig::class,
// excludeMatchingSharedPreferencesKeys = [".*username.*", ".*password.*", ".*token.*"]
// )
open class App : Application(), DefaultLifecycleObserver {
val preferences: PreferencesHelper by injectLazy()
private val disableIncognitoReceiver = DisableIncognitoReceiver()
@SuppressLint("LaunchActivityFromNotification")
override fun onCreate() {
super<Application>.onCreate()
if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
// TLS 1.3 support for Android 10 and below
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Security.insertProviderAt(Conscrypt.newProvider(), 1)
}
// Avoid potential crashes
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val process = getProcessName()
if (packageName != process) WebView.setDataDirectorySuffix(process)
}
Injekt = InjektScope(DefaultRegistrar())
Injekt.importModule(AppModule(this))
CoilSetup(this)
setupAcra()
setupNotificationChannels()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
MangaCoverMetadata.load()
preferences.nightMode()
.asImmediateFlow { AppCompatDelegate.setDefaultNightMode(it) }
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
// Show notification to disable Incognito Mode when it's enabled
preferences.incognitoMode().asFlow()
.onEach { enabled ->
val notificationManager = NotificationManagerCompat.from(this)
if (enabled) {
disableIncognitoReceiver.register()
val notification = notification(Notifications.CHANNEL_INCOGNITO_MODE) {
val incogText = getString(R.string.incognito_mode)
setContentTitle(incogText)
setContentText(getString(R.string.turn_off_, incogText))
setSmallIcon(R.drawable.ic_incognito_24dp)
setOngoing(true)
val pendingIntent = PendingIntent.getBroadcast(
this@App,
0,
Intent(ACTION_DISABLE_INCOGNITO_MODE),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
)
setContentIntent(pendingIntent)
}
notificationManager.notify(Notifications.ID_INCOGNITO_MODE, notification)
} else {
disableIncognitoReceiver.unregister()
notificationManager.cancel(Notifications.ID_INCOGNITO_MODE)
}
}
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
}
override fun onPause(owner: LifecycleOwner) {
if (!AuthenticatorUtil.isAuthenticating && preferences.lockAfter().get() >= 0) {
SecureActivityDelegate.locked = true
}
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
override fun onLowMemory() {
super.onLowMemory()
LibraryPresenter.onLowMemory()
RecentsPresenter.onLowMemory()
SourcePresenter.onLowMemory()
}
protected open fun setupAcra() {
initAcra {
reportFormat = StringFormat.JSON
buildConfigClass = BuildConfig::class.java
excludeMatchingSharedPreferencesKeys = arrayOf(".*username.*", ".*password.*", ".*token.*")
httpSender {
uri = "https://collector.tracepot.com/e90773ff"
httpMethod = org.acra.sender.HttpSender.Method.PUT
}
}
ACRA.init(this)
}
protected open fun setupNotificationChannels() {
Notifications.createChannels(this)
}
private inner class DisableIncognitoReceiver : BroadcastReceiver() {
private var registered = false
override fun onReceive(context: Context, intent: Intent) {
preferences.incognitoMode().set(false)
}
fun register() {
if (!registered) {
registerReceiver(this, IntentFilter(ACTION_DISABLE_INCOGNITO_MODE))
registered = true
}
}
fun unregister() {
if (registered) {
unregisterReceiver(this)
registered = false
}
}
}
}
private const val ACTION_DISABLE_INCOGNITO_MODE = "tachi.action.DISABLE_INCOGNITO_MODE"