From 2ee502ad3dbfd42c09a88212f5bd179fc531e2e6 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Fri, 18 Nov 2022 07:21:49 +0000 Subject: 568: individuals buttons to activate trackers control, fake location and Hide my ip --- app/build.gradle | 2 +- .../e/privacycentralapp/DependencyContainer.kt | 2 +- .../common/QuickPrivacyDisabledSnackbar.kt | 36 ---------- .../data/repositories/LocalStateRepository.kt | 78 +++++++++------------- .../domain/entities/InternetPrivacyMode.kt | 6 +- .../domain/usecases/FakeLocationStateUseCase.kt | 41 +++++------- .../domain/usecases/GetQuickPrivacyStateUseCase.kt | 71 ++++++++------------ .../domain/usecases/IpScramblingStateUseCase.kt | 35 ++++------ .../domain/usecases/TrackersStateUseCase.kt | 9 +-- .../features/dashboard/DashboardFragment.kt | 36 +++++----- .../features/dashboard/DashboardState.kt | 4 +- .../features/dashboard/DashboardViewModel.kt | 29 ++++---- .../internetprivacy/InternetPrivacyFragment.kt | 12 ---- .../internetprivacy/InternetPrivacyState.kt | 1 - .../internetprivacy/InternetPrivacyViewModel.kt | 19 +----- .../features/location/FakeLocationFragment.kt | 12 ---- .../features/location/FakeLocationState.kt | 1 - .../features/location/FakeLocationViewModel.kt | 6 -- .../features/trackers/TrackersFragment.kt | 11 --- .../features/trackers/TrackersState.kt | 1 - .../features/trackers/TrackersViewModel.kt | 7 -- .../trackers/apptrackers/AppTrackersFragment.kt | 17 ++--- .../trackers/apptrackers/AppTrackersState.kt | 4 +- .../trackers/apptrackers/AppTrackersViewModel.kt | 19 +++--- .../e/privacycentralapp/main/MainActivity.kt | 6 -- .../e/privacycentralapp/widget/Widget.kt | 6 +- .../widget/WidgetCommandReceiver.kt | 13 ++-- .../e/privacycentralapp/widget/WidgetUI.kt | 65 +++++++++++++++--- app/src/main/res/layout/fragment_dashboard.xml | 31 ++++++--- app/src/main/res/layout/widget.xml | 50 +++++++++----- app/src/main/res/values-de/strings.xml | 7 +- app/src/main/res/values-es/strings.xml | 6 +- app/src/main/res/values-fi/strings.xml | 7 +- app/src/main/res/values-fr/strings.xml | 7 +- app/src/main/res/values-it/strings.xml | 7 +- app/src/main/res/values/strings.xml | 8 +-- 36 files changed, 296 insertions(+), 376 deletions(-) delete mode 100644 app/src/main/java/foundation/e/privacycentralapp/common/QuickPrivacyDisabledSnackbar.kt diff --git a/app/build.gradle b/app/build.gradle index 82717d3..323a118 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -132,7 +132,7 @@ dependencies { implementation project(':trackers') - implementation 'foundation.e:privacymodule.tor:1.3.0-orbot-16.6.2' + implementation 'foundation.e:privacymodule.tor:1.6.0-dev-orbot-16.6.2' implementation 'foundation.e:elib:0.0.1-alpha11' diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt index 670b81e..345307c 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt @@ -82,7 +82,7 @@ class DependencyContainer(val app: Application) { // Usecases val getQuickPrivacyStateUseCase by lazy { - GetQuickPrivacyStateUseCase(localStateRepository, GlobalScope) + GetQuickPrivacyStateUseCase(localStateRepository) } private val ipScramblingStateUseCase by lazy { IpScramblingStateUseCase( diff --git a/app/src/main/java/foundation/e/privacycentralapp/common/QuickPrivacyDisabledSnackbar.kt b/app/src/main/java/foundation/e/privacycentralapp/common/QuickPrivacyDisabledSnackbar.kt deleted file mode 100644 index 705f65d..0000000 --- a/app/src/main/java/foundation/e/privacycentralapp/common/QuickPrivacyDisabledSnackbar.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2022 E FOUNDATION - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package foundation.e.privacycentralapp.common - -import android.view.View -import com.google.android.material.snackbar.BaseTransientBottomBar -import com.google.android.material.snackbar.Snackbar -import foundation.e.privacycentralapp.R - -fun initQuickPrivacySnackbar(view: View, onDismiss: () -> Unit): Snackbar { - val snackbar = Snackbar.make(view, R.string.quickprivacy_disabled_message, Snackbar.LENGTH_INDEFINITE) - snackbar.setAction(R.string.close) { onDismiss() } - - snackbar.addCallback(object : BaseTransientBottomBar.BaseCallback() { - override fun onDismissed(transientBottomBar: Snackbar?, event: Int) { - super.onDismissed(transientBottomBar, event) - if (event == DISMISS_EVENT_SWIPE) onDismiss() - } - }) - return snackbar -} diff --git a/app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt b/app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt index d39ee43..92ee0c1 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt @@ -24,14 +24,13 @@ import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update class LocalStateRepository(context: Context) { companion object { private const val SHARED_PREFS_FILE = "localState" - private const val KEY_QUICK_PRIVACY = "quickPrivacy" + private const val KEY_BLOCK_TRACKERS = "blockTrackers" private const val KEY_IP_SCRAMBLING = "ipScrambling" private const val KEY_FAKE_LOCATION = "fakeLocation" private const val KEY_FAKE_LATITUDE = "fakeLatitude" @@ -41,58 +40,48 @@ class LocalStateRepository(context: Context) { private val sharedPref = context.getSharedPreferences(SHARED_PREFS_FILE, Context.MODE_PRIVATE) - private val quickPrivacyEnabledMutableFlow = - MutableStateFlow(sharedPref.getBoolean(KEY_QUICK_PRIVACY, false)) - val isQuickPrivacyEnabled: Boolean get() = quickPrivacyEnabledMutableFlow.value + private val _blockTrackers = MutableStateFlow(sharedPref.getBoolean(KEY_BLOCK_TRACKERS, true)) + val blockTrackers = _blockTrackers.asStateFlow() - fun setQuickPrivacyReturnIsFirstActivation(value: Boolean): Boolean { - val isFirstActivation = value && !sharedPref.contains(KEY_QUICK_PRIVACY) - set(KEY_QUICK_PRIVACY, value) - quickPrivacyEnabledMutableFlow.value = value - return isFirstActivation + fun setBlockTrackers(enabled: Boolean) { + set(KEY_BLOCK_TRACKERS, enabled) + _blockTrackers.update { enabled } } - private val _otherVpnRunning = MutableSharedFlow() - suspend fun emitOtherVpnRunning(appDesc: ApplicationDescription) { - _otherVpnRunning.emit(appDesc) - } + val areAllTrackersBlocked: MutableStateFlow = MutableStateFlow(false) - val otherVpnRunning: SharedFlow = _otherVpnRunning + private val _fakeLocationEnabled = MutableStateFlow(sharedPref.getBoolean(KEY_FAKE_LOCATION, true)) - var quickPrivacyEnabledFlow: StateFlow = quickPrivacyEnabledMutableFlow + val fakeLocationEnabled = _fakeLocationEnabled.asStateFlow() - val areAllTrackersBlocked: MutableStateFlow = MutableStateFlow(false) + fun setFakeLocationEnabled(enabled: Boolean) { + set(KEY_FAKE_LOCATION, enabled) + _fakeLocationEnabled.update { enabled } + } - var fakeLocation: Pair? - get() = if (sharedPref.getBoolean(KEY_FAKE_LOCATION, true)) - Pair( - // Initial default value is Quezon City - sharedPref.getFloat(KEY_FAKE_LATITUDE, 14.6760f), - sharedPref.getFloat(KEY_FAKE_LONGITUDE, 121.0437f) - ) - else null + var fakeLocation: Pair + get() = Pair( + // Initial default value is Quezon City + sharedPref.getFloat(KEY_FAKE_LATITUDE, 14.6760f), + sharedPref.getFloat(KEY_FAKE_LONGITUDE, 121.0437f) + ) set(value) { - if (value == null) { - sharedPref.edit() - .putBoolean(KEY_FAKE_LOCATION, false) - .remove(KEY_FAKE_LATITUDE) - .remove(KEY_FAKE_LONGITUDE) - .commit() - } else { - sharedPref.edit() - .putBoolean(KEY_FAKE_LOCATION, true) - .putFloat(KEY_FAKE_LATITUDE, value.first) - .putFloat(KEY_FAKE_LONGITUDE, value.second) - .commit() - } + sharedPref.edit() + .putFloat(KEY_FAKE_LATITUDE, value.first) + .putFloat(KEY_FAKE_LONGITUDE, value.second) + .apply() } val locationMode: MutableStateFlow = MutableStateFlow(LocationMode.REAL_LOCATION) - private val _ipScramblingSetting = MutableStateFlow(sharedPref.getBoolean(KEY_IP_SCRAMBLING, true)) + private val _ipScramblingSetting = MutableStateFlow(sharedPref.getBoolean(KEY_IP_SCRAMBLING, false)) val ipScramblingSetting = _ipScramblingSetting.asStateFlow() + fun isIpScramblingFirstActivation(enabled: Boolean): Boolean { + return enabled && !sharedPref.contains(KEY_IP_SCRAMBLING) + } + fun setIpScramblingSetting(enabled: Boolean) { set(KEY_IP_SCRAMBLING, enabled) _ipScramblingSetting.update { enabled } @@ -100,18 +89,17 @@ class LocalStateRepository(context: Context) { val internetPrivacyMode: MutableStateFlow = MutableStateFlow(InternetPrivacyMode.REAL_IP) - private val _showQuickPrivacyDisabledMessage = MutableStateFlow(false) - val showQuickPrivacyDisabledMessage: StateFlow = _showQuickPrivacyDisabledMessage - - fun setShowQuickPrivacyDisabledMessage(show: Boolean) { - _showQuickPrivacyDisabledMessage.value = show + private val _otherVpnRunning = MutableSharedFlow() + suspend fun emitOtherVpnRunning(appDesc: ApplicationDescription) { + _otherVpnRunning.emit(appDesc) } + val otherVpnRunning: SharedFlow = _otherVpnRunning var firstBoot: Boolean get() = sharedPref.getBoolean(KEY_FIRST_BOOT, true) set(value) = set(KEY_FIRST_BOOT, value) private fun set(key: String, value: Boolean) { - sharedPref.edit().putBoolean(key, value).commit() + sharedPref.edit().putBoolean(key, value).apply() } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/entities/InternetPrivacyMode.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/InternetPrivacyMode.kt index 534bb2f..f849d57 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/domain/entities/InternetPrivacyMode.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/InternetPrivacyMode.kt @@ -21,5 +21,9 @@ enum class InternetPrivacyMode { REAL_IP, HIDE_IP, HIDE_IP_LOADING, - REAL_IP_LOADING + REAL_IP_LOADING; + + val isChecked get() = this == HIDE_IP || this == HIDE_IP_LOADING + + val isLoading get() = this == HIDE_IP_LOADING || this == REAL_IP_LOADING } diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt index e9da855..2910f26 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt @@ -57,7 +57,7 @@ class FakeLocationStateUseCase( init { coroutineScope.launch { - localStateRepository.quickPrivacyEnabledFlow.collect { + localStateRepository.fakeLocationEnabled.collect { applySettings(it, localStateRepository.fakeLocation) } } @@ -71,10 +71,10 @@ class FakeLocationStateUseCase( permissionsModule.toggleDangerousPermission(appDesc, android.Manifest.permission.ACCESS_FINE_LOCATION, true) } - private fun applySettings(isQuickPrivacyEnabled: Boolean, fakeLocation: Pair?, isSpecificLocation: Boolean = false) { - _configuredLocationMode.value = computeLocationMode(fakeLocation, isSpecificLocation) + private fun applySettings(isEnabled: Boolean, fakeLocation: Pair, isSpecificLocation: Boolean = false) { + _configuredLocationMode.value = computeLocationMode(isEnabled, fakeLocation, isSpecificLocation) - if (isQuickPrivacyEnabled && fakeLocation != null && hasAcquireMockLocationPermission()) { + if (isEnabled && hasAcquireMockLocationPermission()) { fakeLocationModule.startFakeLocation() fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble()) localStateRepository.locationMode.value = configuredLocationMode.value.first @@ -90,18 +90,10 @@ class FakeLocationStateUseCase( } fun setSpecificLocation(latitude: Float, longitude: Float) { - if (!localStateRepository.isQuickPrivacyEnabled) { - localStateRepository.setShowQuickPrivacyDisabledMessage(true) - } - setFakeLocation(latitude to longitude, true) } fun setRandomLocation() { - if (!localStateRepository.isQuickPrivacyEnabled) { - localStateRepository.setShowQuickPrivacyDisabledMessage(true) - } - val randomIndex = Random.nextInt(citiesRepository.citiesLocationsList.size) val location = citiesRepository.citiesLocationsList[randomIndex] @@ -110,26 +102,29 @@ class FakeLocationStateUseCase( private fun setFakeLocation(location: Pair, isSpecificLocation: Boolean = false) { localStateRepository.fakeLocation = location - applySettings(localStateRepository.isQuickPrivacyEnabled, location, isSpecificLocation) + localStateRepository.setFakeLocationEnabled(true) + applySettings(true, location, isSpecificLocation) } fun stopFakeLocation() { - if (!localStateRepository.isQuickPrivacyEnabled) { - localStateRepository.setShowQuickPrivacyDisabledMessage(true) - } - - localStateRepository.fakeLocation = null - applySettings(localStateRepository.isQuickPrivacyEnabled, null) + localStateRepository.setFakeLocationEnabled(false) + applySettings(false, localStateRepository.fakeLocation) } - private fun computeLocationMode(fakeLocation: Pair?, isSpecificLocation: Boolean = false): Triple { + private fun computeLocationMode( + isFakeLocationEnabled: Boolean, + fakeLocation: Pair, + isSpecificLocation: Boolean = false, + ): Triple { return Triple( when { - fakeLocation == null -> LocationMode.REAL_LOCATION - fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation -> LocationMode.RANDOM_LOCATION + !isFakeLocationEnabled -> LocationMode.REAL_LOCATION + (fakeLocation in citiesRepository.citiesLocationsList && !isSpecificLocation) -> + LocationMode.RANDOM_LOCATION else -> LocationMode.SPECIFIC_LOCATION }, - fakeLocation?.first, fakeLocation?.second + fakeLocation.first, + fakeLocation.second ) } diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/GetQuickPrivacyStateUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/GetQuickPrivacyStateUseCase.kt index 46e054e..85410d0 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/GetQuickPrivacyStateUseCase.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/GetQuickPrivacyStateUseCase.kt @@ -23,88 +23,69 @@ import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState import foundation.e.privacycentralapp.domain.entities.TrackerMode import foundation.e.privacymodules.permissions.data.ApplicationDescription -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.map class GetQuickPrivacyStateUseCase( - private val localStateRepository: LocalStateRepository, - coroutineScope: CoroutineScope + private val localStateRepository: LocalStateRepository ) { - - init { - coroutineScope.launch { - localStateRepository.quickPrivacyEnabledFlow.collect { - if (it) resetQuickPrivacyDisabledMessage() - } - } - } - - val quickPrivacyEnabledFlow: Flow = localStateRepository.quickPrivacyEnabledFlow - - val isQuickPrivacyEnabled: Boolean get() = localStateRepository.isQuickPrivacyEnabled - val quickPrivacyState: Flow = combine( - localStateRepository.quickPrivacyEnabledFlow, + localStateRepository.blockTrackers, localStateRepository.areAllTrackersBlocked, localStateRepository.locationMode, localStateRepository.internetPrivacyMode - ) { isQuickPrivacyEnabled, isAllTrackersBlocked, locationMode, internetPrivacyMode -> + ) { isBlockTrackers, isAllTrackersBlocked, locationMode, internetPrivacyMode -> when { - !isQuickPrivacyEnabled -> QuickPrivacyState.DISABLED + !isBlockTrackers && + locationMode == LocationMode.REAL_LOCATION && + internetPrivacyMode == InternetPrivacyMode.REAL_IP -> QuickPrivacyState.DISABLED + isAllTrackersBlocked && locationMode != LocationMode.REAL_LOCATION && internetPrivacyMode in listOf( InternetPrivacyMode.HIDE_IP, InternetPrivacyMode.HIDE_IP_LOADING ) -> QuickPrivacyState.FULL_ENABLED + else -> QuickPrivacyState.ENABLED } } val trackerMode: Flow = combine( - localStateRepository.quickPrivacyEnabledFlow, + localStateRepository.blockTrackers, localStateRepository.areAllTrackersBlocked - ) { isQuickPrivacyEnabled, isAllTrackersBlocked -> + ) { isBlockTrackers, isAllTrackersBlocked -> when { - isQuickPrivacyEnabled && isAllTrackersBlocked -> TrackerMode.DENIED - isQuickPrivacyEnabled && !isAllTrackersBlocked -> TrackerMode.CUSTOM + isBlockTrackers && isAllTrackersBlocked -> TrackerMode.DENIED + isBlockTrackers && !isAllTrackersBlocked -> TrackerMode.CUSTOM else -> TrackerMode.VULNERABLE } } - val isLocationHidden: Flow = combine( - localStateRepository.quickPrivacyEnabledFlow, - localStateRepository.locationMode - ) { isQuickPrivacyEnabled, locationMode -> - isQuickPrivacyEnabled && locationMode != LocationMode.REAL_LOCATION + val isLocationHidden: Flow = localStateRepository.locationMode.map { locationMode -> + locationMode != LocationMode.REAL_LOCATION } val locationMode: StateFlow = localStateRepository.locationMode - val isIpHidden: Flow = combine( - localStateRepository.quickPrivacyEnabledFlow, - localStateRepository.internetPrivacyMode - ) { isQuickPrivacyEnabled, internetPrivacyMode -> - when { - !isQuickPrivacyEnabled || internetPrivacyMode == InternetPrivacyMode.REAL_IP -> false - internetPrivacyMode == InternetPrivacyMode.HIDE_IP -> true - else -> null - } - } + val ipScramblingMode: Flow = localStateRepository.internetPrivacyMode - fun toggleReturnIsFirstActivation(): Boolean { - val newState = !localStateRepository.isQuickPrivacyEnabled - return localStateRepository.setQuickPrivacyReturnIsFirstActivation(newState) + fun toggleTrackers() { + localStateRepository.setBlockTrackers(!localStateRepository.blockTrackers.value) } - val showQuickPrivacyDisabledMessage: StateFlow = localStateRepository.showQuickPrivacyDisabledMessage + fun toggleLocation() { + localStateRepository.setFakeLocationEnabled(!localStateRepository.fakeLocationEnabled.value) + } - fun resetQuickPrivacyDisabledMessage() { - localStateRepository.setShowQuickPrivacyDisabledMessage(false) + fun toggleIpScramblingIsFirstActivation(): Boolean { + val enabled = !localStateRepository.ipScramblingSetting.value + val firstActivation = localStateRepository.isIpScramblingFirstActivation(enabled) + localStateRepository.setIpScramblingSetting(enabled) + return firstActivation } val otherVpnRunning: SharedFlow = localStateRepository.otherVpnRunning diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt index cb9fcd5..9216233 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt @@ -28,6 +28,7 @@ import foundation.e.privacymodules.ipscramblermodule.IIpScramblerModule import foundation.e.privacymodules.permissions.IPermissionsPrivacyModule import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -43,9 +44,6 @@ class IpScramblingStateUseCase( private val appListsRepository: AppListsRepository, private val coroutineScope: CoroutineScope ) { - - val configuredMode: StateFlow = localStateRepository.ipScramblingSetting - val internetPrivacyMode: StateFlow = callbackFlow { val listener = object : IIpScramblerModule.Listener { override fun onStatusChanged(newStatus: IIpScramblerModule.Status) { @@ -67,13 +65,13 @@ class IpScramblingStateUseCase( }.stateIn( scope = coroutineScope, started = SharingStarted.Eagerly, - initialValue = InternetPrivacyMode.REAL_IP + initialValue = REAL_IP ) init { - coroutineScope.launch { - localStateRepository.quickPrivacyEnabledFlow.collect { - applySettings(it, localStateRepository.ipScramblingSetting.value) + coroutineScope.launch(Dispatchers.Default) { + localStateRepository.ipScramblingSetting.collect { + applySettings(it) } } @@ -84,12 +82,7 @@ class IpScramblingStateUseCase( fun toggle(hideIp: Boolean) { localStateRepository.setIpScramblingSetting(enabled = hideIp) - - if (!localStateRepository.isQuickPrivacyEnabled) { - localStateRepository.setShowQuickPrivacyDisabledMessage(true) - } else { - applySettings(true, hideIp) - } + applySettings(hideIp) } private fun getHiddenPackageNames(): List { @@ -129,15 +122,13 @@ class IpScramblingStateUseCase( ipScramblerModule.appList = rawList } - private fun applySettings(isQuickPrivacyEnabled: Boolean, isIpScramblingEnabled: Boolean) { - val settingEnabled = isQuickPrivacyEnabled && isIpScramblingEnabled + private fun applySettings(isIpScramblingEnabled: Boolean) { val currentMode = localStateRepository.internetPrivacyMode.value - when { - settingEnabled && currentMode in setOf(REAL_IP, REAL_IP_LOADING) -> + isIpScramblingEnabled && currentMode in setOf(REAL_IP, REAL_IP_LOADING) -> applyStartIpScrambling() - !settingEnabled && currentMode in setOf(HIDE_IP, HIDE_IP_LOADING) -> + !isIpScramblingEnabled && currentMode in setOf(HIDE_IP, HIDE_IP_LOADING) -> ipScramblerModule.stop() else -> {} @@ -162,11 +153,11 @@ class IpScramblingStateUseCase( private fun map(status: IIpScramblerModule.Status): InternetPrivacyMode { return when (status) { - IIpScramblerModule.Status.OFF -> InternetPrivacyMode.REAL_IP - IIpScramblerModule.Status.ON -> InternetPrivacyMode.HIDE_IP - IIpScramblerModule.Status.STARTING -> InternetPrivacyMode.HIDE_IP_LOADING + IIpScramblerModule.Status.OFF -> REAL_IP + IIpScramblerModule.Status.ON -> HIDE_IP + IIpScramblerModule.Status.STARTING -> HIDE_IP_LOADING IIpScramblerModule.Status.STOPPING, - IIpScramblerModule.Status.START_DISABLED -> InternetPrivacyMode.REAL_IP_LOADING + IIpScramblerModule.Status.START_DISABLED -> REAL_IP_LOADING } } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt index 17e5096..8b37152 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt @@ -38,7 +38,7 @@ class TrackersStateUseCase( init { trackersPrivacyModule.start(trackersRepository.trackers, enableNotification = false) coroutineScope.launch { - localStateRepository.quickPrivacyEnabledFlow.collect { enabled -> + localStateRepository.blockTrackers.collect { enabled -> if (enabled) { blockTrackersPrivacyModule.enableBlocking() } else { @@ -76,10 +76,6 @@ class TrackersStateUseCase( } fun toggleAppWhitelist(appUid: Int, isWhitelisted: Boolean) { - if (!localStateRepository.isQuickPrivacyEnabled) { - localStateRepository.setShowQuickPrivacyDisabledMessage(true) - } - if (appUid == appListsRepository.dummySystemApp.uid) { appListsRepository.getHiddenSystemApps().forEach { blockTrackersPrivacyModule.setWhiteListed(it.uid, isWhitelisted) @@ -90,9 +86,6 @@ class TrackersStateUseCase( } fun blockTracker(appUid: Int, tracker: Tracker, isBlocked: Boolean) { - if (!localStateRepository.isQuickPrivacyEnabled) { - localStateRepository.setShowQuickPrivacyDisabledMessage(true) - } if (appUid == appListsRepository.dummySystemApp.uid) { appListsRepository.getHiddenSystemApps().forEach { blockTrackersPrivacyModule.setWhiteListed(tracker, it.uid, !isBlocked) diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt index 6cd259e..8a0a3d4 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt @@ -32,14 +32,13 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import com.google.android.material.snackbar.Snackbar import foundation.e.privacycentralapp.DependencyContainer import foundation.e.privacycentralapp.PrivacyCentralApplication import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.common.GraphHolder import foundation.e.privacycentralapp.common.NavToolbarFragment -import foundation.e.privacycentralapp.common.initQuickPrivacySnackbar import foundation.e.privacycentralapp.databinding.FragmentDashboardBinding +import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState import foundation.e.privacycentralapp.domain.entities.TrackerMode @@ -72,8 +71,6 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { private var _binding: FragmentDashboardBinding? = null private val binding get() = _binding!! - private var qpDisabledSnackbar: Snackbar? = null - private var highlightIndexOnStart: Int? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -91,8 +88,14 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { binding.leakingAppButton.setOnClickListener { viewModel.submitAction(Action.ShowMostLeakedApp) } - binding.togglePrivacyCentral.setOnClickListener { - viewModel.submitAction(Action.TogglePrivacyAction) + binding.toggleTrackers.setOnClickListener { + viewModel.submitAction(Action.ToggleTrackers) + } + binding.toggleLocation.setOnClickListener { + viewModel.submitAction(Action.ToggleLocation) + } + binding.toggleIpscrambling.setOnClickListener { + viewModel.submitAction(Action.ToggleIpScrambling) } binding.myLocation.container.setOnClickListener { viewModel.submitAction(Action.ShowFakeMyLocationAction) @@ -108,10 +111,6 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { viewModel.submitAction(Action.ShowTrackers) } - qpDisabledSnackbar = initQuickPrivacySnackbar(binding.root) { - viewModel.submitAction(Action.CloseQuickPrivacyDisabledMessage) - } - viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { render(viewModel.state.value) @@ -185,9 +184,6 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { } private fun render(state: DashboardState) { - if (state.showQuickPrivacyDisabledMessage) qpDisabledSnackbar?.show() - else qpDisabledSnackbar?.dismiss() - binding.stateLabel.text = getString( when (state.quickPrivacyState) { QuickPrivacyState.DISABLED -> R.string.dashboard_state_title_off @@ -201,7 +197,7 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { else R.drawable.ic_shield_off ) - binding.togglePrivacyCentral.isChecked = state.quickPrivacyState.isEnabled() + binding.toggleTrackers.isChecked = state.trackerMode != TrackerMode.VULNERABLE binding.stateTrackers.text = getString( when (state.trackerMode) { @@ -218,6 +214,8 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { ) ) + binding.toggleLocation.isChecked = state.isLocationHidden + binding.stateGeolocation.text = getString( if (state.isLocationHidden) R.string.dashboard_state_geolocation_on else R.string.dashboard_state_geolocation_off @@ -230,10 +228,11 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { ) ) - val isLoading = state.isIpHidden == null + binding.toggleIpscrambling.isChecked = state.ipScramblingMode.isChecked + val isLoading = state.ipScramblingMode.isLoading binding.stateIpAddress.text = getString( - if (state.isIpHidden == true) R.string.dashboard_state_ipaddress_on + if (state.ipScramblingMode == InternetPrivacyMode.HIDE_IP) R.string.dashboard_state_ipaddress_on else R.string.dashboard_state_ipaddress_off ) @@ -243,7 +242,7 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { binding.stateIpAddress.setTextColor( getColor( requireContext(), - if (state.isIpHidden == true) R.color.green_valid + if (state.ipScramblingMode == InternetPrivacyMode.HIDE_IP) R.color.green_valid else R.color.red_off ) ) @@ -292,7 +291,7 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { ) binding.internetActivityPrivacy.subTitle = getString( - if (state.isIpHidden == true) R.string.dashboard_internet_activity_privacy_subtitle_on + if (state.ipScramblingMode == InternetPrivacyMode.HIDE_IP) R.string.dashboard_internet_activity_privacy_subtitle_on else R.string.dashboard_internet_activity_privacy_subtitle_off ) @@ -301,7 +300,6 @@ class DashboardFragment : NavToolbarFragment(R.layout.fragment_dashboard) { override fun onDestroyView() { super.onDestroyView() - qpDisabledSnackbar = null graphHolder = null _binding = null } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardState.kt b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardState.kt index 04b7ae8..937fa22 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardState.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardState.kt @@ -17,6 +17,7 @@ package foundation.e.privacycentralapp.features.dashboard +import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState import foundation.e.privacycentralapp.domain.entities.TrackerMode @@ -25,12 +26,11 @@ data class DashboardState( val quickPrivacyState: QuickPrivacyState = QuickPrivacyState.DISABLED, val trackerMode: TrackerMode = TrackerMode.VULNERABLE, val isLocationHidden: Boolean = false, - val isIpHidden: Boolean? = false, + val ipScramblingMode: InternetPrivacyMode = InternetPrivacyMode.REAL_IP_LOADING, val locationMode: LocationMode = LocationMode.REAL_LOCATION, val leakedTrackersCount: Int? = null, val trackersCount: Int? = null, val allowedTrackersCount: Int? = null, val dayStatistics: List>? = null, val dayLabels: List? = null, - val showQuickPrivacyDisabledMessage: Boolean = false ) diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardViewModel.kt b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardViewModel.kt index d7d74c6..57e7790 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardViewModel.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardViewModel.kt @@ -25,6 +25,7 @@ import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCas import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase import foundation.e.privacymodules.permissions.data.ApplicationDescription import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -58,8 +59,8 @@ class DashboardViewModel( getPrivacyStateUseCase.quickPrivacyState.map { _state.update { s -> s.copy(quickPrivacyState = it) } }, - getPrivacyStateUseCase.isIpHidden.map { - _state.update { s -> s.copy(isIpHidden = it) } + getPrivacyStateUseCase.ipScramblingMode.map { + _state.update { s -> s.copy(ipScramblingMode = it) } }, trackersStatisticsUseCase.listenUpdates().flatMapLatest { fetchStatistics() @@ -73,9 +74,6 @@ class DashboardViewModel( getPrivacyStateUseCase.locationMode.map { _state.update { s -> s.copy(locationMode = it) } }, - getPrivacyStateUseCase.showQuickPrivacyDisabledMessage.map { - _state.update { s -> s.copy(showQuickPrivacyDisabledMessage = it) } - }, getPrivacyStateUseCase.otherVpnRunning.map { _singleEvents.emit( SingleEvent.ToastMessageSingleEvent( @@ -89,7 +87,14 @@ class DashboardViewModel( fun submitAction(action: Action) = viewModelScope.launch { when (action) { - is Action.TogglePrivacyAction -> actionTogglePrivacy() + is Action.ToggleTrackers -> { + getPrivacyStateUseCase.toggleTrackers() + // Add delay here to prevent race condition with trackers state. + delay(200) + fetchStatistics().first() + } + is Action.ToggleLocation -> getPrivacyStateUseCase.toggleLocation() + is Action.ToggleIpScrambling -> actionToggleIpScrambling() is Action.ShowFakeMyLocationAction -> _singleEvents.emit(SingleEvent.NavigateToLocationSingleEvent) is Action.ShowAppsPermissions -> @@ -98,8 +103,6 @@ class DashboardViewModel( _singleEvents.emit(SingleEvent.NavigateToInternetActivityPrivacySingleEvent) is Action.ShowTrackers -> _singleEvents.emit(SingleEvent.NavigateToTrackersSingleEvent) - is Action.CloseQuickPrivacyDisabledMessage -> - getPrivacyStateUseCase.resetQuickPrivacyDisabledMessage() is Action.ShowMostLeakedApp -> actionShowMostLeakedApp() } } @@ -120,9 +123,8 @@ class DashboardViewModel( } } - private suspend fun actionTogglePrivacy() = withContext(Dispatchers.IO) { - val isFirstActivation = getPrivacyStateUseCase.toggleReturnIsFirstActivation() - fetchStatistics().first() + private suspend fun actionToggleIpScrambling() = withContext(Dispatchers.IO) { + val isFirstActivation = getPrivacyStateUseCase.toggleIpScramblingIsFirstActivation() if (isFirstActivation) _singleEvents.emit( SingleEvent.ToastMessageSingleEvent( @@ -152,12 +154,13 @@ class DashboardViewModel( } sealed class Action { - object TogglePrivacyAction : Action() + object ToggleTrackers : Action() + object ToggleLocation : Action() + object ToggleIpScrambling : Action() object ShowFakeMyLocationAction : Action() object ShowInternetActivityPrivacyAction : Action() object ShowAppsPermissions : Action() object ShowTrackers : Action() - object CloseQuickPrivacyDisabledMessage : Action() object ShowMostLeakedApp : Action() } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFragment.kt index 99aa217..afef986 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFragment.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFragment.kt @@ -27,13 +27,11 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.snackbar.Snackbar import foundation.e.privacycentralapp.DependencyContainer import foundation.e.privacycentralapp.PrivacyCentralApplication import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.common.NavToolbarFragment import foundation.e.privacycentralapp.common.ToggleAppsAdapter -import foundation.e.privacycentralapp.common.initQuickPrivacySnackbar import foundation.e.privacycentralapp.common.setToolTipForAsterisk import foundation.e.privacycentralapp.databinding.FragmentInternetActivityPolicyBinding import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode @@ -53,8 +51,6 @@ class InternetPrivacyFragment : NavToolbarFragment(R.layout.fragment_internet_ac private var _binding: FragmentInternetActivityPolicyBinding? = null private val binding get() = _binding!! - private var qpDisabledSnackbar: Snackbar? = null - private fun displayToast(message: String) { Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT) .show() @@ -120,10 +116,6 @@ class InternetPrivacyFragment : NavToolbarFragment(R.layout.fragment_internet_ac } } - qpDisabledSnackbar = initQuickPrivacySnackbar(binding.root) { - viewModel.submitAction(InternetPrivacyViewModel.Action.CloseQuickPrivacyDisabledMessage) - } - viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { render(viewModel.state.value) @@ -152,9 +144,6 @@ class InternetPrivacyFragment : NavToolbarFragment(R.layout.fragment_internet_ac override fun getTitle(): String = getString(R.string.ipscrambling_title) private fun render(state: InternetPrivacyState) { - if (state.showQuickPrivacyDisabledMessage) qpDisabledSnackbar?.show() - else qpDisabledSnackbar?.dismiss() - binding.radioUseHiddenIp.radiobutton.apply { isChecked = state.mode in listOf( InternetPrivacyMode.HIDE_IP, @@ -207,7 +196,6 @@ class InternetPrivacyFragment : NavToolbarFragment(R.layout.fragment_internet_ac override fun onDestroyView() { super.onDestroyView() - qpDisabledSnackbar = null _binding = null } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyState.kt b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyState.kt index 6991196..54b7e01 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyState.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyState.kt @@ -27,7 +27,6 @@ data class InternetPrivacyState( val selectedLocation: String = "", val availableLocationIds: List = emptyList(), val forceRedraw: Boolean = false, - val showQuickPrivacyDisabledMessage: Boolean = false ) { fun getApps(): List> { return availableApps.map { it to (it.packageName !in bypassTorApps) } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyViewModel.kt b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyViewModel.kt index be6cd4d..bbd6239 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyViewModel.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyViewModel.kt @@ -73,9 +73,6 @@ class InternetPrivacyViewModel( suspend fun doOnStartedState() = withContext(Dispatchers.IO) { launch { merge( - getQuickPrivacyStateUseCase.showQuickPrivacyDisabledMessage.map { - _state.update { s -> s.copy(showQuickPrivacyDisabledMessage = it) } - }, appListUseCase.getAppsUsingInternet().map { apps -> _state.update { s -> s.copy( @@ -84,17 +81,8 @@ class InternetPrivacyViewModel( ) } }, - if (getQuickPrivacyStateUseCase.isQuickPrivacyEnabled) - ipScramblingStateUseCase.internetPrivacyMode.map { - _state.update { s -> s.copy(mode = it) } - } - else ipScramblingStateUseCase.configuredMode.map { - _state.update { s -> - s.copy( - mode = if (it) InternetPrivacyMode.HIDE_IP - else InternetPrivacyMode.REAL_IP - ) - } + ipScramblingStateUseCase.internetPrivacyMode.map { + _state.update { s -> s.copy(mode = it) } } ).collect {} } @@ -129,8 +117,6 @@ class InternetPrivacyViewModel( is Action.UseHiddenIPAction -> actionUseHiddenIP() is Action.ToggleAppIpScrambled -> actionToggleAppIpScrambled(action) is Action.SelectLocationAction -> actionSelectLocation(action) - is Action.CloseQuickPrivacyDisabledMessage -> - getQuickPrivacyStateUseCase.resetQuickPrivacyDisabledMessage() } } @@ -167,6 +153,5 @@ class InternetPrivacyViewModel( object UseHiddenIPAction : Action() data class ToggleAppIpScrambled(val packageName: String) : Action() data class SelectLocationAction(val position: Int) : Action() - object CloseQuickPrivacyDisabledMessage : Action() } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt index 537d0b6..9e3f854 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationFragment.kt @@ -33,7 +33,6 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import com.google.android.material.snackbar.Snackbar import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout.END_ICON_CUSTOM @@ -52,7 +51,6 @@ import foundation.e.privacycentralapp.DependencyContainer import foundation.e.privacycentralapp.PrivacyCentralApplication import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.common.NavToolbarFragment -import foundation.e.privacycentralapp.common.initQuickPrivacySnackbar import foundation.e.privacycentralapp.databinding.FragmentFakeLocationBinding import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.features.location.FakeLocationViewModel.Action @@ -79,8 +77,6 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) private var mapboxMap: MapboxMap? = null private var locationComponent: LocationComponent? = null - private var qpDisabledSnackbar: Snackbar? = null - private var inputJob: Job? = null private val locationPermissionRequest = registerForActivityResult( @@ -147,10 +143,6 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) } } - qpDisabledSnackbar = initQuickPrivacySnackbar(binding.root) { - viewModel.submitAction(Action.CloseQuickPrivacyDisabledMessage) - } - viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { render(viewModel.state.value) @@ -266,9 +258,6 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) @SuppressLint("MissingPermission") private fun render(state: FakeLocationState) { - if (state.showQuickPrivacyDisabledMessage) qpDisabledSnackbar?.show() - else qpDisabledSnackbar?.dismiss() - binding.radioUseRandomLocation.isChecked = state.mode == LocationMode.RANDOM_LOCATION binding.radioUseSpecificLocation.isChecked = state.mode == LocationMode.SPECIFIC_LOCATION @@ -379,7 +368,6 @@ class FakeLocationFragment : NavToolbarFragment(R.layout.fragment_fake_location) override fun onDestroyView() { super.onDestroyView() binding.mapView.onDestroy() - qpDisabledSnackbar = null mapboxMap = null locationComponent = null inputJob = null diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationState.kt b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationState.kt index 9513f77..50d7a14 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationState.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationState.kt @@ -26,5 +26,4 @@ data class FakeLocationState( val specificLatitude: Float? = null, val specificLongitude: Float? = null, val forceRefresh: Boolean = false, - val showQuickPrivacyDisabledMessage: Boolean = false ) diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationViewModel.kt b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationViewModel.kt index 8db3537..1cdf9f4 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationViewModel.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/location/FakeLocationViewModel.kt @@ -66,9 +66,6 @@ class FakeLocationViewModel( ) } }, - getQuickPrivacyStateUseCase.showQuickPrivacyDisabledMessage.map { - _state.update { s -> s.copy(showQuickPrivacyDisabledMessage = it) } - }, specificLocationInputFlow .debounce(SET_SPECIFIC_LOCATION_DELAY).map { action -> fakeLocationStateUseCase.setSpecificLocation(action.latitude, action.longitude) @@ -96,8 +93,6 @@ class FakeLocationViewModel( is Action.UseRandomLocationAction -> fakeLocationStateUseCase.setRandomLocation() is Action.UseRealLocationAction -> fakeLocationStateUseCase.stopFakeLocation() - is Action.CloseQuickPrivacyDisabledMessage -> - getQuickPrivacyStateUseCase.resetQuickPrivacyDisabledMessage() } } @@ -127,6 +122,5 @@ class FakeLocationViewModel( val latitude: Float, val longitude: Float ) : Action() - object CloseQuickPrivacyDisabledMessage : Action() } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt index 491f625..8adf256 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFragment.kt @@ -28,14 +28,12 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.snackbar.Snackbar import foundation.e.privacycentralapp.DependencyContainer import foundation.e.privacycentralapp.PrivacyCentralApplication import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.common.AppsAdapter import foundation.e.privacycentralapp.common.GraphHolder import foundation.e.privacycentralapp.common.NavToolbarFragment -import foundation.e.privacycentralapp.common.initQuickPrivacySnackbar import foundation.e.privacycentralapp.common.setToolTipForAsterisk import foundation.e.privacycentralapp.databinding.FragmentTrackersBinding import foundation.e.privacycentralapp.databinding.TrackersItemGraphBinding @@ -58,7 +56,6 @@ class TrackersFragment : private var dayGraphHolder: GraphHolder? = null private var monthGraphHolder: GraphHolder? = null private var yearGraphHolder: GraphHolder? = null - private var qpDisabledSnackbar: Snackbar? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -79,10 +76,6 @@ class TrackersFragment : } } - qpDisabledSnackbar = initQuickPrivacySnackbar(binding.root) { - viewModel.submitAction(TrackersViewModel.Action.CloseQuickPrivacyDisabledMessage) - } - setToolTipForAsterisk( textView = binding.trackersAppsListTitle, textId = R.string.trackers_applist_title, @@ -137,9 +130,6 @@ class TrackersFragment : override fun getTitle() = getString(R.string.trackers_title) private fun render(state: TrackersState) { - if (state.showQuickPrivacyDisabledMessage) qpDisabledSnackbar?.show() - else qpDisabledSnackbar?.dismiss() - state.dayStatistics?.let { renderGraph(it, dayGraphHolder!!, binding.graphDay) } state.monthStatistics?.let { renderGraph(it, monthGraphHolder!!, binding.graphMonth) } state.yearStatistics?.let { renderGraph(it, yearGraphHolder!!, binding.graphYear) } @@ -171,7 +161,6 @@ class TrackersFragment : override fun onDestroyView() { super.onDestroyView() - qpDisabledSnackbar = null dayGraphHolder = null monthGraphHolder = null yearGraphHolder = null diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersState.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersState.kt index 2437366..a3bb80a 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersState.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersState.kt @@ -25,5 +25,4 @@ data class TrackersState( val monthStatistics: TrackersPeriodicStatistics? = null, val yearStatistics: TrackersPeriodicStatistics? = null, val apps: List? = null, - val showQuickPrivacyDisabledMessage: Boolean = false ) diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt index 3869c39..07828f8 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersViewModel.kt @@ -46,9 +46,6 @@ class TrackersViewModel( suspend fun doOnStartedState() = withContext(Dispatchers.IO) { merge( - getQuickPrivacyStateUseCase.showQuickPrivacyDisabledMessage.map { - _state.update { s -> s.copy(showQuickPrivacyDisabledMessage = it) } - }, trackersStatisticsUseCase.listenUpdates().map { trackersStatisticsUseCase.getDayMonthYearStatistics() .let { (day, month, year) -> @@ -70,9 +67,6 @@ class TrackersViewModel( fun submitAction(action: Action) = viewModelScope.launch { when (action) { is Action.ClickAppAction -> actionClickApp(action) - is Action.CloseQuickPrivacyDisabledMessage -> { - getQuickPrivacyStateUseCase.resetQuickPrivacyDisabledMessage() - } } } @@ -89,6 +83,5 @@ class TrackersViewModel( sealed class Action { data class ClickAppAction(val packageName: String) : Action() - object CloseQuickPrivacyDisabledMessage : Action() } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt index cd4f6b2..6aeac8e 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFragment.kt @@ -34,7 +34,6 @@ import foundation.e.privacycentralapp.DependencyContainer import foundation.e.privacycentralapp.PrivacyCentralApplication import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.common.NavToolbarFragment -import foundation.e.privacycentralapp.common.initQuickPrivacySnackbar import foundation.e.privacycentralapp.databinding.ApptrackersFragmentBinding import kotlinx.coroutines.launch @@ -63,8 +62,6 @@ class AppTrackersFragment : NavToolbarFragment(R.layout.apptrackers_fragment) { private var _binding: ApptrackersFragmentBinding? = null private val binding get() = _binding!! - private var qpDisabledSnackbar: Snackbar? = null - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments == null || @@ -101,10 +98,6 @@ class AppTrackersFragment : NavToolbarFragment(R.layout.apptrackers_fragment) { ) } - qpDisabledSnackbar = initQuickPrivacySnackbar(binding.root) { - viewModel.submitAction(AppTrackersViewModel.Action.CloseQuickPrivacyDisabledMessage) - } - viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.singleEvents.collect { event -> @@ -117,6 +110,12 @@ class AppTrackersFragment : NavToolbarFragment(R.layout.apptrackers_fragment) { } catch (e: ActivityNotFoundException) { displayToast("No application to see webpages") } + is AppTrackersViewModel.SingleEvent.ToastTrackersControlDisabled -> + Snackbar.make( + binding.root, + R.string.apptrackers_tracker_control_disabled_message, + Snackbar.LENGTH_LONG + ).show() } } } @@ -137,9 +136,6 @@ class AppTrackersFragment : NavToolbarFragment(R.layout.apptrackers_fragment) { } private fun render(state: AppTrackersState) { - if (state.showQuickPrivacyDisabledMessage) qpDisabledSnackbar?.show() - else qpDisabledSnackbar?.dismiss() - binding.trackersCountSummary.text = if (state.getTrackersCount() == 0) "" else getString( R.string.apptrackers_trackers_count_summary, @@ -176,7 +172,6 @@ class AppTrackersFragment : NavToolbarFragment(R.layout.apptrackers_fragment) { override fun onDestroyView() { super.onDestroyView() - qpDisabledSnackbar = null _binding = null } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersState.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersState.kt index d6d0858..8088443 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersState.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersState.kt @@ -26,7 +26,7 @@ data class AppTrackersState( val trackersWithWhiteList: List>? = null, val leaked: Int = 0, val blocked: Int = 0, - val isQuickPrivacyEnabled: Boolean = false, + val isTrackersBlockingEnabled: Boolean = false, val showQuickPrivacyDisabledMessage: Boolean = false, ) { fun getTrackersStatus(): List>? { @@ -34,7 +34,7 @@ data class AppTrackersState( } fun getTrackersCount() = trackersWithWhiteList?.size ?: 0 - fun getBlockedTrackersCount(): Int = if (isQuickPrivacyEnabled && isBlockingActivated) + fun getBlockedTrackersCount(): Int = if (isTrackersBlockingEnabled && isBlockingActivated) trackersWithWhiteList?.count { !it.second } ?: 0 else 0 } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersViewModel.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersViewModel.kt index 52ef2c4..1a33844 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersViewModel.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersViewModel.kt @@ -21,6 +21,7 @@ import android.net.Uri import androidx.annotation.StringRes import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import foundation.e.privacycentralapp.domain.entities.TrackerMode import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase @@ -66,11 +67,8 @@ class AppTrackersViewModel( suspend fun doOnStartedState() = withContext(Dispatchers.IO) { merge( - getQuickPrivacyStateUseCase.quickPrivacyEnabledFlow.map { - _state.update { s -> s.copy(isQuickPrivacyEnabled = it) } - }, - getQuickPrivacyStateUseCase.showQuickPrivacyDisabledMessage.map { - _state.update { s -> s.copy(showQuickPrivacyDisabledMessage = it) } + getQuickPrivacyStateUseCase.trackerMode.map { + _state.update { s -> s.copy(isTrackersBlockingEnabled = it != TrackerMode.VULNERABLE) } }, trackersStatisticsUseCase.listenUpdates().map { fetchStatistics() } ).collect { } @@ -81,13 +79,14 @@ class AppTrackersViewModel( is Action.BlockAllToggleAction -> blockAllToggleAction(action) is Action.ToggleTrackerAction -> toggleTrackerAction(action) is Action.ClickTracker -> actionClickTracker(action) - is Action.CloseQuickPrivacyDisabledMessage -> - getQuickPrivacyStateUseCase.resetQuickPrivacyDisabledMessage() } } private suspend fun blockAllToggleAction(action: Action.BlockAllToggleAction) { withContext(Dispatchers.IO) { + if (!state.value.isTrackersBlockingEnabled) { + _singleEvents.emit(SingleEvent.ToastTrackersControlDisabled) + } trackersStateUseCase.toggleAppWhitelist(appUid, !action.isBlocked) _state.update { it.copy( @@ -99,6 +98,10 @@ class AppTrackersViewModel( private suspend fun toggleTrackerAction(action: Action.ToggleTrackerAction) { withContext(Dispatchers.IO) { + if (!state.value.isTrackersBlockingEnabled) { + _singleEvents.emit(SingleEvent.ToastTrackersControlDisabled) + } + if (state.value.isBlockingActivated) { trackersStateUseCase.blockTracker(appUid, action.tracker, action.isBlocked) _state.update { @@ -141,12 +144,12 @@ class AppTrackersViewModel( sealed class SingleEvent { data class ErrorEvent(@StringRes val errorResId: Int) : SingleEvent() data class OpenUrl(val url: Uri) : SingleEvent() + object ToastTrackersControlDisabled : SingleEvent() } sealed class Action { data class BlockAllToggleAction(val isBlocked: Boolean) : Action() data class ToggleTrackerAction(val tracker: Tracker, val isBlocked: Boolean) : Action() data class ClickTracker(val tracker: Tracker) : Action() - object CloseQuickPrivacyDisabledMessage : Action() } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt b/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt index 58ac797..a81f5b5 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt @@ -24,7 +24,6 @@ import android.os.Bundle import androidx.fragment.app.FragmentActivity import androidx.fragment.app.add import androidx.fragment.app.commit -import foundation.e.privacycentralapp.PrivacyCentralApplication import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.features.dashboard.DashboardFragment import foundation.e.privacycentralapp.features.trackers.TrackersFragment @@ -37,11 +36,6 @@ open class MainActivity : FragmentActivity(R.layout.activity_main) { override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) - - (application as? PrivacyCentralApplication) - ?.dependencyContainer?.getQuickPrivacyStateUseCase - ?.resetQuickPrivacyDisabledMessage() - handleIntent(intent) } diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt index ddfcc2e..3abe21b 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt @@ -85,14 +85,14 @@ class Widget : AppWidgetProvider() { getPrivacyStateUseCase.quickPrivacyState, getPrivacyStateUseCase.trackerMode, getPrivacyStateUseCase.isLocationHidden, - getPrivacyStateUseCase.isIpHidden, - ) { quickPrivacyState, trackerMode, isLocationHidden, isIpHidden -> + getPrivacyStateUseCase.ipScramblingMode, + ) { quickPrivacyState, trackerMode, isLocationHidden, ipScramblingMode -> State( quickPrivacyState = quickPrivacyState, trackerMode = trackerMode, isLocationHidden = isLocationHidden, - isIpHidden = isIpHidden + ipScramblingMode = ipScramblingMode ) }.sample(50) .combine( diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt index 831c06f..4a103e0 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt @@ -26,10 +26,13 @@ import foundation.e.privacycentralapp.R class WidgetCommandReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { - val privacyCentralApplication = (context?.applicationContext as? PrivacyCentralApplication) + val getQuickPrivacyStateUseCase = (context?.applicationContext as? PrivacyCentralApplication)?.dependencyContainer?.getQuickPrivacyStateUseCase + when (intent?.action) { - ACTION_TOGGLE_PRIVACY -> { - if (privacyCentralApplication?.dependencyContainer?.getQuickPrivacyStateUseCase?.toggleReturnIsFirstActivation() == true) { + ACTION_TOGGLE_TRACKERS -> getQuickPrivacyStateUseCase?.toggleTrackers() + ACTION_TOGGLE_LOCATION -> getQuickPrivacyStateUseCase?.toggleLocation() + ACTION_TOGGLE_IPSCRAMBLING -> { + if (getQuickPrivacyStateUseCase?.toggleIpScramblingIsFirstActivation() == true) { Toast.makeText( context, context.getString(R.string.dashboard_first_ipscrambling_activation), @@ -42,6 +45,8 @@ class WidgetCommandReceiver : BroadcastReceiver() { } companion object { - const val ACTION_TOGGLE_PRIVACY = "toggle_privacy" + const val ACTION_TOGGLE_TRACKERS = "toggle_trackers" + const val ACTION_TOGGLE_LOCATION = "toggle_location" + const val ACTION_TOGGLE_IPSCRAMBLING = "toggle_ipscrambling" } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt index 682e5cc..4fdbb03 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt @@ -30,16 +30,19 @@ import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.Widget import foundation.e.privacycentralapp.Widget.Companion.isDarkText import foundation.e.privacycentralapp.common.extensions.dpToPxF +import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState import foundation.e.privacycentralapp.domain.entities.TrackerMode import foundation.e.privacycentralapp.main.MainActivity -import foundation.e.privacycentralapp.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_PRIVACY +import foundation.e.privacycentralapp.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_IPSCRAMBLING +import foundation.e.privacycentralapp.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_LOCATION +import foundation.e.privacycentralapp.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_TRACKERS data class State( val quickPrivacyState: QuickPrivacyState = QuickPrivacyState.DISABLED, val trackerMode: TrackerMode = TrackerMode.VULNERABLE, val isLocationHidden: Boolean = false, - val isIpHidden: Boolean? = false, + val ipScramblingMode: InternetPrivacyMode = InternetPrivacyMode.REAL_IP_LOADING, val dayStatistics: List> = emptyList(), val activeTrackersCount: Int = 0, ) @@ -71,19 +74,21 @@ fun render( } ) ) + setImageViewResource( - R.id.toggle_privacy_central, - if (state.quickPrivacyState.isEnabled()) R.drawable.ic_switch_enabled - else R.drawable.ic_switch_disabled + R.id.toggle_trackers, + if (state.trackerMode == TrackerMode.VULNERABLE) + R.drawable.ic_switch_disabled + else R.drawable.ic_switch_enabled ) setOnClickPendingIntent( - R.id.toggle_privacy_central, + R.id.toggle_trackers, PendingIntent.getBroadcast( context, - REQUEST_CODE_TOGGLE, + REQUEST_CODE_TOGGLE_TRACKERS, Intent(context, WidgetCommandReceiver::class.java).apply { - action = ACTION_TOGGLE_PRIVACY + action = ACTION_TOGGLE_TRACKERS }, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT ) @@ -100,6 +105,24 @@ fun render( ) ) + setImageViewResource( + R.id.toggle_location, + if (state.isLocationHidden) R.drawable.ic_switch_enabled + else R.drawable.ic_switch_disabled + ) + + setOnClickPendingIntent( + R.id.toggle_location, + PendingIntent.getBroadcast( + context, + REQUEST_CODE_TOGGLE_LOCATION, + Intent(context, WidgetCommandReceiver::class.java).apply { + action = ACTION_TOGGLE_LOCATION + }, + FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT + ) + ) + setTextViewText( R.id.state_geolocation, context.getString( @@ -108,15 +131,33 @@ fun render( ) ) + setImageViewResource( + R.id.toggle_ipscrambling, + if (state.ipScramblingMode.isChecked) R.drawable.ic_switch_enabled + else R.drawable.ic_switch_disabled + ) + + setOnClickPendingIntent( + R.id.toggle_ipscrambling, + PendingIntent.getBroadcast( + context, + REQUEST_CODE_TOGGLE_IPSCRAMBLING, + Intent(context, WidgetCommandReceiver::class.java).apply { + action = ACTION_TOGGLE_IPSCRAMBLING + }, + FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT + ) + ) + setTextViewText( R.id.state_ip_address, context.getString( - if (state.isIpHidden == true) R.string.widget_state_ipaddress_on + if (state.ipScramblingMode == InternetPrivacyMode.HIDE_IP) R.string.widget_state_ipaddress_on else R.string.widget_state_ipaddress_off ) ) - val loading = state.isIpHidden == null + val loading = state.ipScramblingMode.isLoading setViewVisibility(R.id.state_ip_address, if (loading) View.GONE else View.VISIBLE) @@ -265,8 +306,10 @@ private val leakedBarIds = listOf( ) private const val REQUEST_CODE_DASHBOARD = 1 -private const val REQUEST_CODE_TOGGLE = 2 private const val REQUEST_CODE_TRACKERS = 3 +private const val REQUEST_CODE_TOGGLE_TRACKERS = 4 +private const val REQUEST_CODE_TOGGLE_LOCATION = 5 +private const val REQUEST_CODE_TOGGLE_IPSCRAMBLING = 6 private const val REQUEST_CODE_HIGHLIGHT = 100 fun applyDarkText(context: Context, state: State, views: RemoteViews) { diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml index 8b8792b..cedf569 100644 --- a/app/src/main/res/layout/fragment_dashboard.xml +++ b/app/src/main/res/layout/fragment_dashboard.xml @@ -42,12 +42,6 @@ android:textSize="14sp" android:textColor="@color/secondary_text" /> - + + + + diff --git a/app/src/main/res/layout/widget.xml b/app/src/main/res/layout/widget.xml index 60cbffa..1e78bc7 100644 --- a/app/src/main/res/layout/widget.xml +++ b/app/src/main/res/layout/widget.xml @@ -72,13 +72,6 @@ android:textSize="12sp" android:textColor="@color/on_primary_medium_emphasis" /> - - + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index cda8aa8..ea0bacd 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,12 +1,12 @@ Dein Online-Datenschutz ist nicht gewährleistet - Tracker (Verfolger): + Tracker (Verfolger) Verletzlich Abgelehnt - Standort: + Standort Verschleiert - Echte IP-Adresse: + Echte IP-Adresse Verschleiert Datenlecks (Nutzerdaten): Heute @@ -110,7 +110,6 @@ Tippe auf die Balken für weitere Informationen. Tippe, um herauszufinden, wie Tracker einfach blockiert, dein Standort gefälscht und deine IP-Adresse verschleiert werden kann. Benutzerdefinierte Datenschutz-Einstellungen werden angewendet - Die Änderungen werden erst beim Aktivieren des Datenschutz-Schalters angewandt. Schließen Das Verschleiern deiner IP wird möglicherweise die Internetgeschwindigkeit verlangsamen. Benutzerdefinierte Datenschutz-Einstellungen werden angewandt diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9cbe21c..213a9d7 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,12 +1,12 @@ - Rastreadores: + Rastreadores Vulnerable Denegado - Ubicación: + Ubicación Expuesto Falso - Direccion IP real: + Direccion IP real Expuesto Oculto Filtración de datos personales diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 0964d3f..b5932de 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -90,17 +90,16 @@ Henkilötietojen vuoto: Piilotettu Paljastettu - Todellinen IP-osoite: + Todellinen IP-osoite Väärennetty Paljastettu - Sijainti: + Sijainti Estetty Haavoittuvainen - Seuraimet: + Seuraimet Sovelletaan mukautettuja yksityisyysasetuksia Yksityisyytesi verkossa on suojattu Sulje - Muutokset tulevat voimaan vain, kun yksityisyydensuojan kytkin on käytössä. Napauta palkkeja saadaksesi lisätietoja. Sallittuja tietovuotoja Estettyjä tietovuotoja diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 628cff3..b4db80f 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -2,13 +2,13 @@ Votre vie privée en ligne est protégée Votre vie privée en ligne n\'est pas protégée - Trackers : + Trackers Vulnérable Refusé - Localisation : + Localisation Exposé Faux - Adresse IP réelle : + Adresse IP réelle Exposé Fuite de données personnelles : Aujourd\'hui @@ -96,7 +96,6 @@ - Tous les pisteurs sont désactivés. \n- Votre géolocalisation sera falsifiée. \n- Votre adresse IP réelle sera masquée. - Les modifications seront effectives uniquement quand la protection de la confidentialité sera activée. Votre vitesse Internet risque d\'être réduite tant que votre adresse IP est masquée. Fuites autorisées Fuites bloquées diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 9f8d02d..316aa4f 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,13 +1,13 @@ La tua privacy online non è protetta - Tracker: + Tracker Vulnerabile Negato - Posizione: + Posizione Esposta Fasulla - Indirizzo IP reale: + Indirizzo IP reale Esposto Nascosto Fuga di dati personali: @@ -110,7 +110,6 @@ Guarda Impostazioni della privacy personalizzate applicate Chiudi - I cambiamenti avranno efficacia solo dopo l\'abilitazione del pulsante protezione privacy. Tocca le barre per maggiori informazioni. Perdite di dati ammesse Perdite di dati bloccate diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8705ac5..a4d1040 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,21 +8,20 @@ Blocked leaks Allowed leaks Tap on the bars for more information. - Changes will only be effective when privacy protection toggle is enabled. Close @string/app_name Your online privacy is protected Your online privacy is unprotected Custom privacy settings applied - Trackers: + Trackers Vulnerable Denied Custom - Location: + Location Exposed Fake - Real IP address: + Real IP address Exposed Hidden Personal data leakage: @@ -87,6 +86,7 @@ Enable Quick Privacy to be able to activate/deactivate trackers. %1$d blocked trackers out of %2$d detected trackers, %3$d blocked leaks and %4$d allowed leaks. App not installed. + Changes will take effect when tracker blocker is on. Quick protection enables these settings when turned on - All trackers are turned off.\n- Your geolocation will be faked.\n- Your real IP address will be hidden. -- cgit v1.2.1