From d94e8043e82b3402689c229acef8d8ccf2959c36 Mon Sep 17 00:00:00 2001
From: Guillaume Jacquart <guillaume.jacquart@hoodbrains.com>
Date: Wed, 10 May 2023 23:02:11 +0200
Subject: 1222: tight toggle feature to UI switch state.

---
 .../domain/usecases/GetQuickPrivacyStateUseCase.kt  | 21 +++++++++++++++------
 .../domain/usecases/IpScramblingStateUseCase.kt     | 14 ++++++++++++--
 .../features/dashboard/DashboardFragment.kt         | 21 ++++++++++++++++++---
 .../features/dashboard/DashboardViewModel.kt        | 13 +++++++------
 .../advancedprivacy/widget/WidgetCommandReceiver.kt | 12 +++++++++---
 .../foundation/e/advancedprivacy/widget/WidgetUI.kt |  9 ++++++---
 6 files changed, 67 insertions(+), 23 deletions(-)

(limited to 'app/src')

diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt
index 475c05d..b82918e 100644
--- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt
+++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/GetQuickPrivacyStateUseCase.kt
@@ -73,16 +73,25 @@ class GetQuickPrivacyStateUseCase(
 
     val ipScramblingMode: Flow<InternetPrivacyMode> = localStateRepository.internetPrivacyMode
 
-    fun toggleTrackers() {
-        localStateRepository.setBlockTrackers(!localStateRepository.blockTrackers.value)
+    fun toggleTrackers(enabled: Boolean?) {
+        val value = enabled ?: !localStateRepository.blockTrackers.value
+        if (value != localStateRepository.blockTrackers.value) {
+            localStateRepository.setBlockTrackers(value)
+        }
     }
 
-    fun toggleLocation() {
-        localStateRepository.setFakeLocationEnabled(!localStateRepository.fakeLocationEnabled.value)
+    fun toggleLocation(enabled: Boolean?) {
+        val value = enabled ?: !localStateRepository.fakeLocationEnabled.value
+        if (value != localStateRepository.fakeLocationEnabled.value) {
+            localStateRepository.setFakeLocationEnabled(value)
+        }
     }
 
-    fun toggleIpScrambling() {
-        localStateRepository.setIpScramblingSetting(!localStateRepository.ipScramblingSetting.value)
+    fun toggleIpScrambling(enabled: Boolean?) {
+        val value = enabled ?: !localStateRepository.ipScramblingSetting.value
+        if (value != localStateRepository.ipScramblingSetting.value) {
+            localStateRepository.setIpScramblingSetting(value)
+        }
     }
 
     val otherVpnRunning: SharedFlow<ApplicationDescription> = localStateRepository.otherVpnRunning
diff --git a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt
index 8c94602..6ae0746 100644
--- a/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt
+++ b/app/src/main/java/foundation/e/advancedprivacy/domain/usecases/IpScramblingStateUseCase.kt
@@ -30,6 +30,7 @@ import foundation.e.privacymodules.permissions.data.ApplicationDescription
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.callbackFlow
@@ -75,8 +76,17 @@ class IpScramblingStateUseCase(
             }
         }
 
-        coroutineScope.launch {
-            internetPrivacyMode.collect { localStateRepository.internetPrivacyMode.value = it }
+        coroutineScope.launch(Dispatchers.IO) {
+            internetPrivacyMode.collect {
+                if (
+                    it == REAL_IP &&
+                    localStateRepository.internetPrivacyMode.value == REAL_IP_LOADING
+                ) {
+                    // Wait for orbot to relax before allowing user to reactivate it.
+                    delay(1000)
+                }
+                localStateRepository.internetPrivacyMode.value = it
+            }
         }
     }
 
diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt
index b30935c..02fd1ad 100644
--- a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt
+++ b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardFragment.kt
@@ -89,13 +89,25 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) {
             viewModel.submitAction(Action.ShowMostLeakedApp)
         }
         binding.toggleTrackers.setOnClickListener {
-            viewModel.submitAction(Action.ToggleTrackers)
+            viewModel.submitAction(
+                Action.ToggleTrackers(
+                    enabled = binding.toggleTrackers.isChecked
+                )
+            )
         }
         binding.toggleLocation.setOnClickListener {
-            viewModel.submitAction(Action.ToggleLocation)
+            viewModel.submitAction(
+                Action.ToggleLocation(
+                    enabled = binding.toggleLocation.isChecked
+                )
+            )
         }
         binding.toggleIpscrambling.setOnClickListener {
-            viewModel.submitAction(Action.ToggleIpScrambling)
+            viewModel.submitAction(
+                Action.ToggleIpScrambling(
+                    enabled = binding.toggleIpscrambling.isChecked
+                )
+            )
         }
         binding.myLocation.container.setOnClickListener {
             viewModel.submitAction(Action.ShowFakeMyLocationAction)
@@ -230,6 +242,9 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) {
 
         binding.toggleIpscrambling.isChecked = state.ipScramblingMode.isChecked
         val isLoading = state.ipScramblingMode.isLoading
+        binding.toggleIpscrambling.isEnabled = (
+            state.ipScramblingMode != InternetPrivacyMode.REAL_IP_LOADING
+            )
 
         binding.stateIpAddress.text = getString(
             if (state.ipScramblingMode == InternetPrivacyMode.HIDE_IP) R.string.dashboard_state_ipaddress_on
diff --git a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt
index d82b073..cc1263b 100644
--- a/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt
+++ b/app/src/main/java/foundation/e/advancedprivacy/features/dashboard/DashboardViewModel.kt
@@ -89,13 +89,14 @@ class DashboardViewModel(
     fun submitAction(action: Action) = viewModelScope.launch {
         when (action) {
             is Action.ToggleTrackers -> {
-                getPrivacyStateUseCase.toggleTrackers()
+                getPrivacyStateUseCase.toggleTrackers(action.enabled)
                 // Add delay here to prevent race condition with trackers state.
                 delay(200)
                 fetchStatistics().first()
             }
-            is Action.ToggleLocation -> getPrivacyStateUseCase.toggleLocation()
-            is Action.ToggleIpScrambling -> getPrivacyStateUseCase.toggleIpScrambling()
+            is Action.ToggleLocation -> getPrivacyStateUseCase.toggleLocation(action.enabled)
+            is Action.ToggleIpScrambling ->
+                getPrivacyStateUseCase.toggleIpScrambling(action.enabled)
             is Action.ShowFakeMyLocationAction ->
                 _singleEvents.emit(SingleEvent.NavigateToLocationSingleEvent)
             is Action.ShowAppsPermissions ->
@@ -146,9 +147,9 @@ class DashboardViewModel(
     }
 
     sealed class Action {
-        object ToggleTrackers : Action()
-        object ToggleLocation : Action()
-        object ToggleIpScrambling : Action()
+        data class ToggleTrackers(val enabled: Boolean) : Action()
+        data class ToggleLocation(val enabled: Boolean) : Action()
+        data class ToggleIpScrambling(val enabled: Boolean) : Action()
         object ShowFakeMyLocationAction : Action()
         object ShowInternetActivityPrivacyAction : Action()
         object ShowAppsPermissions : Action()
diff --git a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt
index f68a59c..9021125 100644
--- a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt
+++ b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetCommandReceiver.kt
@@ -26,10 +26,15 @@ class WidgetCommandReceiver : BroadcastReceiver() {
     override fun onReceive(context: Context?, intent: Intent?) {
         val getQuickPrivacyStateUseCase = (context?.applicationContext as? AdvancedPrivacyApplication)?.dependencyContainer?.getQuickPrivacyStateUseCase
 
+        val featureEnabled = intent?.extras?.let { bundle ->
+            if (bundle.containsKey(PARAM_FEATURE_ENABLED))
+                bundle.getBoolean(PARAM_FEATURE_ENABLED)
+            else null
+        }
         when (intent?.action) {
-            ACTION_TOGGLE_TRACKERS -> getQuickPrivacyStateUseCase?.toggleTrackers()
-            ACTION_TOGGLE_LOCATION -> getQuickPrivacyStateUseCase?.toggleLocation()
-            ACTION_TOGGLE_IPSCRAMBLING -> getQuickPrivacyStateUseCase?.toggleIpScrambling()
+            ACTION_TOGGLE_TRACKERS -> getQuickPrivacyStateUseCase?.toggleTrackers(featureEnabled)
+            ACTION_TOGGLE_LOCATION -> getQuickPrivacyStateUseCase?.toggleLocation(featureEnabled)
+            ACTION_TOGGLE_IPSCRAMBLING -> getQuickPrivacyStateUseCase?.toggleIpScrambling(featureEnabled)
             else -> {}
         }
     }
@@ -38,5 +43,6 @@ class WidgetCommandReceiver : BroadcastReceiver() {
         const val ACTION_TOGGLE_TRACKERS = "toggle_trackers"
         const val ACTION_TOGGLE_LOCATION = "toggle_location"
         const val ACTION_TOGGLE_IPSCRAMBLING = "toggle_ipscrambling"
+        const val PARAM_FEATURE_ENABLED = "param_feature_enabled"
     }
 }
diff --git a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt
index cb7fe5c..f1edb36 100644
--- a/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt
+++ b/app/src/main/java/foundation/e/advancedprivacy/widget/WidgetUI.kt
@@ -37,6 +37,7 @@ import foundation.e.advancedprivacy.main.MainActivity
 import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_IPSCRAMBLING
 import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_LOCATION
 import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_TRACKERS
+import foundation.e.advancedprivacy.widget.WidgetCommandReceiver.Companion.PARAM_FEATURE_ENABLED
 
 data class State(
     val quickPrivacyState: QuickPrivacyState = QuickPrivacyState.DISABLED,
@@ -75,11 +76,10 @@ fun render(
             )
         )
 
+        val trackersEnabled = state.trackerMode != TrackerMode.VULNERABLE
         setImageViewResource(
             R.id.toggle_trackers,
-            if (state.trackerMode == TrackerMode.VULNERABLE)
-                R.drawable.ic_switch_disabled
-            else R.drawable.ic_switch_enabled
+            if (trackersEnabled) R.drawable.ic_switch_enabled else R.drawable.ic_switch_disabled
         )
 
         setOnClickPendingIntent(
@@ -89,6 +89,7 @@ fun render(
                 REQUEST_CODE_TOGGLE_TRACKERS,
                 Intent(context, WidgetCommandReceiver::class.java).apply {
                     action = ACTION_TOGGLE_TRACKERS
+                    putExtra(PARAM_FEATURE_ENABLED, !trackersEnabled)
                 },
                 FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
             )
@@ -118,6 +119,7 @@ fun render(
                 REQUEST_CODE_TOGGLE_LOCATION,
                 Intent(context, WidgetCommandReceiver::class.java).apply {
                     action = ACTION_TOGGLE_LOCATION
+                    putExtra(PARAM_FEATURE_ENABLED, !state.isLocationHidden)
                 },
                 FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
             )
@@ -144,6 +146,7 @@ fun render(
                 REQUEST_CODE_TOGGLE_IPSCRAMBLING,
                 Intent(context, WidgetCommandReceiver::class.java).apply {
                     action = ACTION_TOGGLE_IPSCRAMBLING
+                    putExtra(PARAM_FEATURE_ENABLED, !state.ipScramblingMode.isChecked)
                 },
                 FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT
             )
-- 
cgit v1.2.3