Show notification to disable Incognito Mode when it's enabled (#4976)

* Show notification to disable Incognito Mode when it's enabled

* Finish ReaderActivity and BrowseSourceController when incognito is disabled

* CLeanup strings

* Only register DisableIncognitoReceiver when needed

(cherry picked from commit cb203ef02cc3c078d5e5717b98ef1db1cf570586)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/App.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt
This commit is contained in:
Ivan Iskandar 2021-05-01 09:36:54 +07:00 committed by Jobobby04
parent 6dad90e19c
commit 4f02f652d9
7 changed files with 101 additions and 6 deletions

View File

@ -2,16 +2,22 @@ package eu.kanade.tachiyomi
import android.app.ActivityManager import android.app.ActivityManager
import android.app.Application import android.app.Application
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.multidex.MultiDex import androidx.multidex.MultiDex
import coil.ImageLoader import coil.ImageLoader
import coil.ImageLoaderFactory import coil.ImageLoaderFactory
@ -39,6 +45,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.util.system.notification
import exh.debug.DebugToggles import exh.debug.DebugToggles
import exh.log.CrashlyticsPrinter import exh.log.CrashlyticsPrinter
import exh.log.EHDebugModeOverlay import exh.log.EHDebugModeOverlay
@ -49,6 +56,8 @@ import exh.log.xLogD
import exh.log.xLogE import exh.log.xLogE
import exh.syDebugVersion import exh.syDebugVersion
import io.realm.Realm import io.realm.Realm
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.conscrypt.Conscrypt import org.conscrypt.Conscrypt
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -67,6 +76,8 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory {
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
private val disableIncognitoReceiver = DisableIncognitoReceiver()
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
// if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) // if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
@ -95,6 +106,34 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory {
// Reset Incognito Mode on relaunch // Reset Incognito Mode on relaunch
preferences.incognitoMode().set(false) preferences.incognitoMode().set(false)
// 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) {
setContentTitle(getString(R.string.pref_incognito_mode))
setContentText(getString(R.string.notification_incognito_text))
setSmallIcon(R.drawable.ic_glasses_black_24dp)
setOngoing(true)
val pendingIntent = PendingIntent.getBroadcast(
this@App,
0,
Intent(ACTION_DISABLE_INCOGNITO_MODE),
PendingIntent.FLAG_ONE_SHOT
)
setContentIntent(pendingIntent)
}
notificationManager.notify(Notifications.ID_INCOGNITO_MODE, notification)
} else {
disableIncognitoReceiver.unregister()
notificationManager.cancel(Notifications.ID_INCOGNITO_MODE)
}
}
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
} }
override fun attachBaseContext(base: Context) { override fun attachBaseContext(base: Context) {
@ -245,4 +284,30 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory {
xLogE("Failed to initialize debug overlay, app in background?", e) xLogE("Failed to initialize debug overlay, app in background?", e)
} }
} }
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
}
}
}
companion object {
private const val ACTION_DISABLE_INCOGNITO_MODE = "tachi.action.DISABLE_INCOGNITO_MODE"
}
} }

View File

@ -68,6 +68,12 @@ object Notifications {
const val CHANNEL_CRASH_LOGS = "crash_logs_channel" const val CHANNEL_CRASH_LOGS = "crash_logs_channel"
const val ID_CRASH_LOGS = -601 const val ID_CRASH_LOGS = -601
/**
* Notification channel used for Incognito Mode
*/
const val CHANNEL_INCOGNITO_MODE = "incognito_mode_channel"
const val ID_INCOGNITO_MODE = -701
// SY --> // SY -->
/** /**
* Notification channel and ids used for backup and restore. * Notification channel and ids used for backup and restore.
@ -164,6 +170,11 @@ object Notifications {
context.getString(R.string.channel_crash_logs), context.getString(R.string.channel_crash_logs),
NotificationManager.IMPORTANCE_HIGH NotificationManager.IMPORTANCE_HIGH
), ),
NotificationChannel(
CHANNEL_INCOGNITO_MODE,
context.getString(R.string.pref_incognito_mode),
NotificationManager.IMPORTANCE_LOW
),
NotificationChannel( NotificationChannel(
CHANNEL_SIMILAR, CHANNEL_SIMILAR,
context.getString(R.string.similar_manga), context.getString(R.string.similar_manga),

View File

@ -40,6 +40,7 @@ import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.ToolbarLiftOnScrollController import eu.kanade.tachiyomi.ui.base.controller.ToolbarLiftOnScrollController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.BrowseController import eu.kanade.tachiyomi.ui.browse.BrowseController
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
import eu.kanade.tachiyomi.ui.download.DownloadController import eu.kanade.tachiyomi.ui.download.DownloadController
import eu.kanade.tachiyomi.ui.library.LibraryController import eu.kanade.tachiyomi.ui.library.LibraryController
@ -277,7 +278,17 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.incognitoMode() preferences.incognitoMode()
.asImmediateFlow { binding.incognitoMode.isVisible = it } .asImmediateFlow {
binding.incognitoMode.isVisible = it
// Close BrowseSourceController and its MangaController child when incognito mode is disabled
if (!it) {
val fg = router.backstack.last().controller()
if (fg is BrowseSourceController || fg is MangaController && fg.fromSource) {
router.popToRoot()
}
}
}
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
} }

View File

@ -181,7 +181,7 @@ class MangaController :
var source: Source? = null var source: Source? = null
private set private set
private val fromSource = args.getBoolean(FROM_SOURCE_EXTRA, false) val fromSource = args.getBoolean(FROM_SOURCE_EXTRA, false)
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
private val coverCache: CoverCache by injectLazy() private val coverCache: CoverCache by injectLazy()

View File

@ -202,6 +202,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
window.decorView.setOnSystemUiVisibilityChangeListener { window.decorView.setOnSystemUiVisibilityChangeListener {
setMenuVisibility(menuVisible, animate = false) setMenuVisibility(menuVisible, animate = false)
} }
// Finish when incognito mode is disabled
preferences.incognitoMode().asFlow()
.drop(1)
.onEach { if (!it) finish() }
.launchIn(lifecycleScope)
} }
// SY --> // SY -->

View File

@ -177,6 +177,8 @@ class ReaderPresenter(
hasTrackers = tracks.size > 0 hasTrackers = tracks.size > 0
} }
private val incognitoMode = preferences.incognitoMode().get()
/** /**
* Called when the presenter is created. It retrieves the saved active chapter if the process * Called when the presenter is created. It retrieves the saved active chapter if the process
* was restored. * was restored.
@ -454,7 +456,7 @@ class ReaderPresenter(
// Save last page read and mark as read if needed // Save last page read and mark as read if needed
selectedChapter.chapter.last_page_read = page.index selectedChapter.chapter.last_page_read = page.index
val shouldTrack = !preferences.incognitoMode().get() || hasTrackers val shouldTrack = !incognitoMode || hasTrackers
if (selectedChapter.pages?.lastIndex == page.index && shouldTrack) { if (selectedChapter.pages?.lastIndex == page.index && shouldTrack) {
selectedChapter.chapter.read = true selectedChapter.chapter.read = true
// SY --> // SY -->
@ -527,7 +529,7 @@ class ReaderPresenter(
* If incognito mode isn't on or has at least 1 tracker * If incognito mode isn't on or has at least 1 tracker
*/ */
private fun saveChapterProgress(chapter: ReaderChapter) { private fun saveChapterProgress(chapter: ReaderChapter) {
if (!preferences.incognitoMode().get() || hasTrackers) { if (!incognitoMode || hasTrackers) {
db.updateChapterProgress(chapter.chapter).asRxCompletable() db.updateChapterProgress(chapter.chapter).asRxCompletable()
.onErrorComplete() .onErrorComplete()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@ -539,7 +541,7 @@ class ReaderPresenter(
* Saves this [chapter] last read history if incognito mode isn't on. * Saves this [chapter] last read history if incognito mode isn't on.
*/ */
private fun saveChapterHistory(chapter: ReaderChapter) { private fun saveChapterHistory(chapter: ReaderChapter) {
if (!preferences.incognitoMode().get()) { if (!incognitoMode) {
val history = History.create(chapter.chapter).apply { last_read = Date().time } val history = History.create(chapter.chapter).apply { last_read = Date().time }
db.updateHistoryLastRead(history).asRxCompletable() db.updateHistoryLastRead(history).asRxCompletable()
.onErrorComplete() .onErrorComplete()

View File

@ -468,6 +468,7 @@
<string name="label_downloaded_only">Downloaded only</string> <string name="label_downloaded_only">Downloaded only</string>
<string name="pref_incognito_mode">Incognito mode</string> <string name="pref_incognito_mode">Incognito mode</string>
<string name="pref_incognito_mode_summary">Pauses reading history</string> <string name="pref_incognito_mode_summary">Pauses reading history</string>
<string name="notification_incognito_text">Disable incognito mode</string>
<string name="downloaded_only_summary">Filters all manga in your library</string> <string name="downloaded_only_summary">Filters all manga in your library</string>
<plurals name="download_queue_summary"> <plurals name="download_queue_summary">
<item quantity="one">1 remaining</item> <item quantity="one">1 remaining</item>
@ -777,5 +778,4 @@
<!-- S Pen actions --> <!-- S Pen actions -->
<string name="spen_previous_page">Previous page</string> <string name="spen_previous_page">Previous page</string>
<string name="spen_next_page">Next page</string> <string name="spen_next_page">Next page</string>
</resources> </resources>