Browse Source

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
Ivan Iskandar 3 years ago
parent
commit
cb203ef02c

+ 65 - 0
app/src/main/java/eu/kanade/tachiyomi/App.kt

@@ -2,14 +2,20 @@ package eu.kanade.tachiyomi
 
 import android.app.ActivityManager
 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.content.res.Configuration
 import android.os.Build
+import androidx.core.app.NotificationManagerCompat
 import androidx.core.content.getSystemService
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleObserver
 import androidx.lifecycle.OnLifecycleEvent
 import androidx.lifecycle.ProcessLifecycleOwner
+import androidx.lifecycle.lifecycleScope
 import androidx.multidex.MultiDex
 import coil.ImageLoader
 import coil.ImageLoaderFactory
@@ -22,6 +28,9 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.network.NetworkHelper
 import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
 import eu.kanade.tachiyomi.util.system.LocaleHelper
+import eu.kanade.tachiyomi.util.system.notification
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 import org.acra.ACRA
 import org.acra.annotation.AcraCore
 import org.acra.annotation.AcraHttpSender
@@ -45,6 +54,8 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory {
 
     private val preferences: PreferencesHelper by injectLazy()
 
+    private val disableIncognitoReceiver = DisableIncognitoReceiver()
+
     override fun onCreate() {
         super.onCreate()
         if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
@@ -65,6 +76,34 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory {
 
         // Reset Incognito Mode on relaunch
         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) {
@@ -111,4 +150,30 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory {
     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
+            }
+        }
+    }
+
+    companion object {
+        private const val ACTION_DISABLE_INCOGNITO_MODE = "tachi.action.DISABLE_INCOGNITO_MODE"
+    }
 }

+ 11 - 0
app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt

@@ -68,6 +68,12 @@ object Notifications {
     const val CHANNEL_CRASH_LOGS = "crash_logs_channel"
     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
+
     private val deprecatedChannels = listOf(
         "downloader_channel",
         "backup_restore_complete_channel"
@@ -154,6 +160,11 @@ object Notifications {
                 CHANNEL_CRASH_LOGS,
                 context.getString(R.string.channel_crash_logs),
                 NotificationManager.IMPORTANCE_HIGH
+            ),
+            NotificationChannel(
+                CHANNEL_INCOGNITO_MODE,
+                context.getString(R.string.pref_incognito_mode),
+                NotificationManager.IMPORTANCE_LOW
             )
         ).forEach(context.notificationManager::createNotificationChannel)
 

+ 12 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -41,6 +41,7 @@ import eu.kanade.tachiyomi.ui.base.controller.TabbedController
 import eu.kanade.tachiyomi.ui.base.controller.ToolbarLiftOnScrollController
 import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 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.download.DownloadController
 import eu.kanade.tachiyomi.ui.library.LibraryController
@@ -224,7 +225,17 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
             .launchIn(lifecycleScope)
 
         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)
     }
 

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt

@@ -127,7 +127,7 @@ class MangaController :
     var source: Source? = null
         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 coverCache: CoverCache by injectLazy()

+ 6 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt

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

+ 5 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt

@@ -144,6 +144,8 @@ class ReaderPresenter(
         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
      * was restored.
@@ -375,7 +377,7 @@ class ReaderPresenter(
 
         // Save last page read and mark as read if needed
         selectedChapter.chapter.last_page_read = page.index
-        val shouldTrack = !preferences.incognitoMode().get() || hasTrackers
+        val shouldTrack = !incognitoMode || hasTrackers
         if (selectedChapter.pages?.lastIndex == page.index && shouldTrack) {
             selectedChapter.chapter.read = true
             updateTrackChapterRead(selectedChapter)
@@ -430,7 +432,7 @@ class ReaderPresenter(
      * If incognito mode isn't on or has at least 1 tracker
      */
     private fun saveChapterProgress(chapter: ReaderChapter) {
-        if (!preferences.incognitoMode().get() || hasTrackers) {
+        if (!incognitoMode || hasTrackers) {
             db.updateChapterProgress(chapter.chapter).asRxCompletable()
                 .onErrorComplete()
                 .subscribeOn(Schedulers.io())
@@ -442,7 +444,7 @@ class ReaderPresenter(
      * Saves this [chapter] last read history if incognito mode isn't on.
      */
     private fun saveChapterHistory(chapter: ReaderChapter) {
-        if (!preferences.incognitoMode().get()) {
+        if (!incognitoMode) {
             val history = History.create(chapter.chapter).apply { last_read = Date().time }
             db.updateHistoryLastRead(history).asRxCompletable()
                 .onErrorComplete()

+ 1 - 1
app/src/main/res/values/strings.xml

@@ -467,6 +467,7 @@
     <string name="label_downloaded_only">Downloaded only</string>
     <string name="pref_incognito_mode">Incognito mode</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>
     <plurals name="download_queue_summary">
         <item quantity="one">1 remaining</item>
@@ -776,5 +777,4 @@
     <!-- S Pen actions -->
     <string name="spen_previous_page">Previous page</string>
     <string name="spen_next_page">Next page</string>
-
 </resources>