summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorAlexandre Roux <alexandre.roux.danzi@lostpod.me>2022-04-25 15:16:25 +0000
committerAlexandre Roux <alexandre.roux.danzi@lostpod.me>2022-04-25 15:16:25 +0000
commitf3c01e7bbf130c7f304b6bf50510c3800b8586f6 (patch)
treed9bee5a2fbcbe43bc0bbc121b4fd7dcc259ef8a3 /app
parent27dbc4ea2c3357481f93c765008a3d66a1d51a22 (diff)
parent3ca4c651aff84c551101337984bf1d457d892a1a (diff)
Merge branch '5311_main_toggle_wording' into 'main'
5311 main toggle wording, 5321 default settings See merge request e/privacy-central/privacycentralapp!43
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt5
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/data/repositories/LocalStateRepository.kt38
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/entities/QuickPrivacyState.kt24
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/FakeLocationStateUseCase.kt13
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/GetQuickPrivacyStateUseCase.kt55
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/IpScramblingStateUseCase.kt8
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStateUseCase.kt12
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt55
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFragment.kt43
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardViewModel.kt14
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt30
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt2
-rw-r--r--app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt38
-rw-r--r--app/src/main/res/drawable-night/ic_shield_off.xml19
-rw-r--r--app/src/main/res/drawable-night/ic_shield_on.xml18
-rw-r--r--app/src/main/res/drawable/ic_shield_off.xml25
-rw-r--r--app/src/main/res/drawable/ic_shield_off_white.xml19
-rw-r--r--app/src/main/res/drawable/ic_shield_on.xml25
-rw-r--r--app/src/main/res/drawable/ic_shield_on_white.xml18
-rw-r--r--app/src/main/res/values/strings.xml3
20 files changed, 302 insertions, 162 deletions
diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
index fa4a3e3..4a790c6 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
@@ -104,7 +104,7 @@ class DependencyContainer(val app: Application) {
// ViewModelFactories
val dashBoardViewModelFactory by lazy {
- DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase, trackersStateUseCase, fakeLocationStateUseCase)
+ DashBoardViewModelFactory(getQuickPrivacyStateUseCase, trackersStatisticsUseCase)
}
val fakeLocationViewModelFactory by lazy {
@@ -138,10 +138,7 @@ class DependencyContainer(val app: Application) {
Widget.startListening(
context,
getQuickPrivacyStateUseCase,
- ipScramblingStateUseCase,
trackersStatisticsUseCase,
- trackersStateUseCase,
- fakeLocationStateUseCase
)
}
}
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 9a7fd15..136b20f 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
@@ -18,6 +18,8 @@
package foundation.e.privacycentralapp.data.repositories
import android.content.Context
+import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode
+import foundation.e.privacycentralapp.domain.entities.LocationMode
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -26,6 +28,7 @@ class LocalStateRepository(context: Context) {
private const val SHARED_PREFS_FILE = "localState"
private const val KEY_QUICK_PRIVACY = "quickPrivacy"
private const val KEY_IP_SCRAMBLING = "ipScrambling"
+ private const val KEY_FAKE_LOCATION = "fakeLocation"
private const val KEY_FAKE_LATITUDE = "fakeLatitude"
private const val KEY_FAKE_LONGITUDE = "fakeLongitude"
private const val KEY_FIRST_BOOT = "firstBoot"
@@ -35,43 +38,52 @@ class LocalStateRepository(context: Context) {
private val quickPrivacyEnabledMutableFlow =
MutableStateFlow<Boolean>(sharedPref.getBoolean(KEY_QUICK_PRIVACY, false))
- var isQuickPrivacyEnabled: Boolean
- get() = quickPrivacyEnabledMutableFlow.value
- set(value) {
- set(KEY_QUICK_PRIVACY, value)
- quickPrivacyEnabledMutableFlow.value = value
- }
+ val isQuickPrivacyEnabled: Boolean get() = quickPrivacyEnabledMutableFlow.value
+
+ fun setQuickPrivacyReturnIsFirstActivation(value: Boolean): Boolean {
+ val isFirstActivation = value && !sharedPref.contains(KEY_QUICK_PRIVACY)
+ set(KEY_QUICK_PRIVACY, value)
+ quickPrivacyEnabledMutableFlow.value = value
+ return isFirstActivation
+ }
var quickPrivacyEnabledFlow: Flow<Boolean> = quickPrivacyEnabledMutableFlow
+ val areAllTrackersBlocked: MutableStateFlow<Boolean> = MutableStateFlow(false)
+
var fakeLocation: Pair<Float, Float>?
- get() = if (sharedPref.contains(KEY_FAKE_LATITUDE) && sharedPref.contains(
- KEY_FAKE_LONGITUDE
- )
- )
+ get() = if (sharedPref.getBoolean(KEY_FAKE_LOCATION, true))
Pair(
- sharedPref.getFloat(KEY_FAKE_LATITUDE, 0f),
- sharedPref.getFloat(KEY_FAKE_LONGITUDE, 0f)
+ // Initial default value is Quezon City
+ sharedPref.getFloat(KEY_FAKE_LATITUDE, 14.6760f),
+ sharedPref.getFloat(KEY_FAKE_LONGITUDE, 121.0437f)
)
else null
+
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()
}
}
+ val locationMode: MutableStateFlow<LocationMode> = MutableStateFlow(LocationMode.REAL_LOCATION)
+
var isIpScramblingEnabled: Boolean
- get() = sharedPref.getBoolean(KEY_IP_SCRAMBLING, false)
+ get() = sharedPref.getBoolean(KEY_IP_SCRAMBLING, true)
set(value) = set(KEY_IP_SCRAMBLING, value)
+ val internetPrivacyMode: MutableStateFlow<InternetPrivacyMode> = MutableStateFlow(InternetPrivacyMode.REAL_IP)
+
var firstBoot: Boolean
get() = sharedPref.getBoolean(KEY_FIRST_BOOT, true)
set(value) = set(KEY_FIRST_BOOT, value)
diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/entities/QuickPrivacyState.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/QuickPrivacyState.kt
new file mode 100644
index 0000000..3257402
--- /dev/null
+++ b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/QuickPrivacyState.kt
@@ -0,0 +1,24 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+package foundation.e.privacycentralapp.domain.entities
+
+enum class QuickPrivacyState {
+ DISABLED, ENABLED, FULL_ENABLED;
+
+ fun isEnabled(): Boolean = this != DISABLED
+}
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 32affe0..c07657a 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
@@ -33,7 +33,6 @@ import foundation.e.privacymodules.permissions.data.AppOpModes
import foundation.e.privacymodules.permissions.data.ApplicationDescription
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlin.random.Random
@@ -47,8 +46,8 @@ class FakeLocationStateUseCase(
private val appContext: Context,
private val coroutineScope: CoroutineScope
) {
- private val _locationMode = MutableStateFlow(LocationMode.REAL_LOCATION)
- val locationMode: StateFlow<LocationMode> = _locationMode
+ // private val _locationMode = MutableStateFlow(LocationMode.REAL_LOCATION)
+ // val locationMode: StateFlow<LocationMode> = _locationMode
init {
coroutineScope.launch {
@@ -63,14 +62,14 @@ class FakeLocationStateUseCase(
fun getLocationMode(): Triple<LocationMode, Float?, Float?> {
val fakeLocation = localStateRepository.fakeLocation
- return if (fakeLocation != null && _locationMode.value == LocationMode.SPECIFIC_LOCATION) {
+ return if (fakeLocation != null && localStateRepository.locationMode.value == LocationMode.SPECIFIC_LOCATION) {
Triple(
LocationMode.SPECIFIC_LOCATION,
fakeLocation.first,
fakeLocation.second
)
} else {
- Triple(_locationMode.value, null, null)
+ Triple(localStateRepository.locationMode.value, null, null)
}
}
@@ -97,11 +96,11 @@ class FakeLocationStateUseCase(
}
fakeLocationModule.startFakeLocation()
fakeLocationModule.setFakeLocation(fakeLocation.first.toDouble(), fakeLocation.second.toDouble())
- _locationMode.value = if (fakeLocation in citiesRepository.citiesLocationsList) LocationMode.RANDOM_LOCATION
+ localStateRepository.locationMode.value = if (fakeLocation in citiesRepository.citiesLocationsList) LocationMode.RANDOM_LOCATION
else LocationMode.SPECIFIC_LOCATION
} else {
fakeLocationModule.stopFakeLocation()
- _locationMode.value = LocationMode.REAL_LOCATION
+ localStateRepository.locationMode.value = LocationMode.REAL_LOCATION
}
}
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 db6f312..fd9430c 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
@@ -18,14 +18,63 @@
package foundation.e.privacycentralapp.domain.usecases
import foundation.e.privacycentralapp.data.repositories.LocalStateRepository
+import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode
+import foundation.e.privacycentralapp.domain.entities.LocationMode
+import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
class GetQuickPrivacyStateUseCase(private val localStateRepository: LocalStateRepository) {
val quickPrivacyEnabledFlow = localStateRepository.quickPrivacyEnabledFlow
val isQuickPrivacyEnabled get() = localStateRepository.isQuickPrivacyEnabled
- fun toggle(): Boolean {
+ val quickPrivacyState = combine(
+ localStateRepository.quickPrivacyEnabledFlow,
+ localStateRepository.areAllTrackersBlocked,
+ localStateRepository.locationMode,
+ localStateRepository.internetPrivacyMode
+ ) { isQuickPrivacyEnabled, isAllTrackersBlocked, locationMode, internetPrivacyMode ->
+ when {
+ !isQuickPrivacyEnabled -> QuickPrivacyState.DISABLED
+ isAllTrackersBlocked &&
+ locationMode != LocationMode.REAL_LOCATION &&
+ internetPrivacyMode in listOf(
+ InternetPrivacyMode.HIDE_IP,
+ InternetPrivacyMode.HIDE_IP_LOADING
+ ) -> QuickPrivacyState.FULL_ENABLED
+ else -> QuickPrivacyState.ENABLED
+ }
+ }
+
+ val isTrackersDenied = combine(
+ localStateRepository.quickPrivacyEnabledFlow,
+ localStateRepository.areAllTrackersBlocked
+ ) { isQuickPrivacyEnabled, isAllTrackersBlocked ->
+ isQuickPrivacyEnabled && isAllTrackersBlocked
+ }
+
+ val isLocationHidden = combine(
+ localStateRepository.quickPrivacyEnabledFlow,
+ localStateRepository.locationMode
+ ) { isQuickPrivacyEnabled, locationMode ->
+ isQuickPrivacyEnabled && locationMode != LocationMode.REAL_LOCATION
+ }
+
+ val locationMode: StateFlow<LocationMode> = localStateRepository.locationMode
+
+ val isIpHidden = combine(
+ localStateRepository.quickPrivacyEnabledFlow,
+ localStateRepository.internetPrivacyMode
+ ) { isQuickPrivacyEnabled, internetPrivacyMode ->
+ when {
+ !isQuickPrivacyEnabled || internetPrivacyMode == InternetPrivacyMode.REAL_IP -> false
+ internetPrivacyMode == InternetPrivacyMode.HIDE_IP -> true
+ else -> null
+ }
+ }
+
+ fun toggleReturnIsFirstActivation(): Boolean {
val newState = !localStateRepository.isQuickPrivacyEnabled
- localStateRepository.isQuickPrivacyEnabled = newState
- return newState
+ return localStateRepository.setQuickPrivacyReturnIsFirstActivation(newState)
}
}
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 6cc8e4a..a701eec 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
@@ -71,6 +71,10 @@ class IpScramblingStateUseCase(
applySettings(it, localStateRepository.isIpScramblingEnabled)
}
}
+
+ coroutineScope.launch {
+ internetPrivacyMode.collect { localStateRepository.internetPrivacyMode.value = it }
+ }
}
fun toggle(hideIp: Boolean) {
@@ -119,7 +123,7 @@ class IpScramblingStateUseCase(
private fun applySettings(isQuickPrivacyEnabled: Boolean, isIpScramblingEnabled: Boolean) {
when {
- isQuickPrivacyEnabled && isIpScramblingEnabled -> when (internetPrivacyMode.value) {
+ isQuickPrivacyEnabled && isIpScramblingEnabled -> when (localStateRepository.internetPrivacyMode.value) {
InternetPrivacyMode.REAL_IP, InternetPrivacyMode.REAL_IP_LOADING -> {
val intent = ipScramblerModule.prepareAndroidVpn()
if (intent != null) {
@@ -129,7 +133,7 @@ class IpScramblingStateUseCase(
}
else -> {}
}
- else -> when (internetPrivacyMode.value) {
+ else -> when (localStateRepository.internetPrivacyMode.value) {
InternetPrivacyMode.HIDE_IP, InternetPrivacyMode.HIDE_IP_LOADING -> ipScramblerModule.stop()
else -> {}
}
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 a589509..5263559 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
@@ -26,9 +26,6 @@ import foundation.e.privacymodules.trackers.IBlockTrackersPrivacyModule
import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule
import foundation.e.privacymodules.trackers.Tracker
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@@ -41,13 +38,6 @@ class TrackersStateUseCase(
private val appListsRepository: AppListsRepository,
private val coroutineScope: CoroutineScope
) {
-
- private val _areAllTrackersBlocked = MutableStateFlow(
- blockTrackersPrivacyModule.isBlockingEnabled() &&
- blockTrackersPrivacyModule.isWhiteListEmpty()
- )
- val areAllTrackersBlocked: StateFlow<Boolean> = _areAllTrackersBlocked
-
init {
trackersPrivacyModule.start(trackersRepository.trackers, enableNotification = false)
coroutineScope.launch {
@@ -63,7 +53,7 @@ class TrackersStateUseCase(
}
private fun updateAllTrackersBlockedState() {
- _areAllTrackersBlocked.value = blockTrackersPrivacyModule.isBlockingEnabled() &&
+ localStateRepository.areAllTrackersBlocked.value = blockTrackersPrivacyModule.isBlockingEnabled() &&
blockTrackersPrivacyModule.isWhiteListEmpty()
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt
index ca45393..95726db 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/DashboardFeature.kt
@@ -22,14 +22,13 @@ import foundation.e.flowmvi.Actor
import foundation.e.flowmvi.Reducer
import foundation.e.flowmvi.SingleEventProducer
import foundation.e.flowmvi.feature.BaseFeature
-import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode
+import foundation.e.privacycentralapp.R
import foundation.e.privacycentralapp.domain.entities.LocationMode
-import foundation.e.privacycentralapp.domain.usecases.FakeLocationStateUseCase
+import foundation.e.privacycentralapp.domain.entities.QuickPrivacyState
import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase
-import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase
-import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase
import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -49,10 +48,11 @@ class DashboardFeature(
singleEventProducer
) {
data class State(
- val isQuickPrivacyEnabled: Boolean = false,
- val isAllTrackersBlocked: Boolean = false,
+ val quickPrivacyState: QuickPrivacyState = QuickPrivacyState.DISABLED,
+ val isTrackersDenied: Boolean = false,
+ val isLocationHidden: Boolean = false,
+ val isIpHidden: Boolean? = false,
val locationMode: LocationMode = LocationMode.REAL_LOCATION,
- val internetPrivacyMode: InternetPrivacyMode = InternetPrivacyMode.REAL_IP,
val leakedTrackersCount: Int? = null,
val trackersCount: Int? = null,
val activeTrackersCount: Int? = null,
@@ -66,6 +66,7 @@ class DashboardFeature(
object NavigateToLocationSingleEvent : SingleEvent()
object NavigateToPermissionsSingleEvent : SingleEvent()
object NewStatisticsAvailableSingleEvent : SingleEvent()
+ data class ToastMessageSingleEvent(val message: Int) : SingleEvent()
}
sealed class Action {
@@ -80,8 +81,8 @@ class DashboardFeature(
sealed class Effect {
object NoEffect : Effect()
- data class UpdateStateEffect(val isEnabled: Boolean) : Effect()
- data class IpScramblingModeUpdatedEffect(val mode: InternetPrivacyMode) : Effect()
+ data class UpdateStateEffect(val state: QuickPrivacyState) : Effect()
+ data class IpScramblingModeUpdatedEffect(val isIpHidden: Boolean?) : Effect()
data class TrackersStatisticsUpdatedEffect(
val dayStatistics: List<Pair<Int, Int>>,
val dayLabels: List<String>,
@@ -96,24 +97,23 @@ class DashboardFeature(
object OpenAppsPermissionsEffect : Effect()
object OpenTrackersEffect : Effect()
object NewStatisticsAvailablesEffect : Effect()
+ object FirstIPTrackerActivationEffect : Effect()
+ data class LocationHiddenUpdatedEffect(val isLocationHidden: Boolean) : Effect()
}
companion object {
fun create(
coroutineScope: CoroutineScope,
getPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
- ipScramblingStateUseCase: IpScramblingStateUseCase,
trackersStatisticsUseCase: TrackersStatisticsUseCase,
- trackersStateUseCase: TrackersStateUseCase,
- fakeLocationStateUseCase: FakeLocationStateUseCase
): DashboardFeature =
DashboardFeature(
initialState = State(),
coroutineScope,
reducer = { state, effect ->
when (effect) {
- is Effect.UpdateStateEffect -> state.copy(isQuickPrivacyEnabled = effect.isEnabled)
- is Effect.IpScramblingModeUpdatedEffect -> state.copy(internetPrivacyMode = effect.mode)
+ is Effect.UpdateStateEffect -> state.copy(quickPrivacyState = effect.state)
+ is Effect.IpScramblingModeUpdatedEffect -> state.copy(isIpHidden = effect.isIpHidden)
is Effect.TrackersStatisticsUpdatedEffect -> state.copy(
dayStatistics = effect.dayStatistics,
dayLabels = effect.dayLabels,
@@ -123,7 +123,10 @@ class DashboardFeature(
)
is Effect.TrackersBlockedUpdatedEffect -> state.copy(
- isAllTrackersBlocked = effect.areAllTrackersBlocked
+ isTrackersDenied = effect.areAllTrackersBlocked
+ )
+ is Effect.LocationHiddenUpdatedEffect -> state.copy(
+ isLocationHidden = effect.isLocationHidden
)
is Effect.UpdateLocationModeEffect -> state.copy(locationMode = effect.mode)
@@ -133,24 +136,30 @@ class DashboardFeature(
actor = { _: State, action: Action ->
when (action) {
Action.TogglePrivacyAction -> {
- getPrivacyStateUseCase.toggle()
- flowOf(Effect.NewStatisticsAvailablesEffect)
+ val isFirstActivation = getPrivacyStateUseCase.toggleReturnIsFirstActivation()
+ flow {
+ emit(Effect.NewStatisticsAvailablesEffect)
+ if (isFirstActivation) emit(Effect.FirstIPTrackerActivationEffect)
+ }
}
Action.InitAction -> merge(
- getPrivacyStateUseCase.quickPrivacyEnabledFlow.map {
+ getPrivacyStateUseCase.quickPrivacyState.map {
Effect.UpdateStateEffect(it)
},
- ipScramblingStateUseCase.internetPrivacyMode.map {
+ getPrivacyStateUseCase.isIpHidden.map {
Effect.IpScramblingModeUpdatedEffect(it)
},
trackersStatisticsUseCase.listenUpdates().map {
Effect.NewStatisticsAvailablesEffect
},
- trackersStateUseCase.areAllTrackersBlocked.map {
+ getPrivacyStateUseCase.isTrackersDenied.map {
Effect.TrackersBlockedUpdatedEffect(it)
},
- fakeLocationStateUseCase.locationMode.map {
+ getPrivacyStateUseCase.isLocationHidden.map {
+ Effect.LocationHiddenUpdatedEffect(it)
+ },
+ getPrivacyStateUseCase.locationMode.map {
Effect.UpdateLocationModeEffect(it)
}
)
@@ -188,6 +197,10 @@ class DashboardFeature(
SingleEvent.NavigateToTrackersSingleEvent
is Effect.NewStatisticsAvailablesEffect ->
SingleEvent.NewStatisticsAvailableSingleEvent
+ is Effect.FirstIPTrackerActivationEffect ->
+ SingleEvent.ToastMessageSingleEvent(
+ message = R.string.dashboard_first_ipscrambling_activation
+ )
else -> null
}
}
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 96ace56..588eedd 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
@@ -22,6 +22,7 @@ import android.os.Bundle
import android.text.Html
import android.text.Html.FROM_HTML_MODE_LEGACY
import android.view.View
+import android.widget.Toast
import androidx.core.content.ContextCompat.getColor
import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels
@@ -35,8 +36,8 @@ import foundation.e.privacycentralapp.R
import foundation.e.privacycentralapp.common.GraphHolder
import foundation.e.privacycentralapp.common.NavToolbarFragment
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.extensions.viewModelProviderFactoryOf
import foundation.e.privacycentralapp.features.dashboard.DashboardFeature.State
import foundation.e.privacycentralapp.features.internetprivacy.InternetPrivacyFragment
@@ -104,6 +105,9 @@ class DashboardFragment :
DashboardFeature.SingleEvent.NewStatisticsAvailableSingleEvent -> {
viewModel.submitAction(DashboardFeature.Action.FetchStatistics)
}
+ is DashboardFeature.SingleEvent.ToastMessageSingleEvent ->
+ Toast.makeText(requireContext(), event.message, Toast.LENGTH_LONG)
+ .show()
}
}
}
@@ -159,50 +163,48 @@ class DashboardFragment :
override fun render(state: State) {
binding.stateLabel.text = getString(
- if (state.isQuickPrivacyEnabled) R.string.dashboard_state_title_on
- else R.string.dashboard_state_title_off
+ when (state.quickPrivacyState) {
+ QuickPrivacyState.DISABLED -> R.string.dashboard_state_title_off
+ QuickPrivacyState.FULL_ENABLED -> R.string.dashboard_state_title_on
+ QuickPrivacyState.ENABLED -> R.string.dashboard_state_title_custom
+ }
)
binding.stateIcon.setImageResource(
- if (state.isQuickPrivacyEnabled) R.drawable.ic_shield_on
+ if (state.quickPrivacyState.isEnabled()) R.drawable.ic_shield_on
else R.drawable.ic_shield_off
)
- binding.togglePrivacyCentral.isChecked = state.isQuickPrivacyEnabled
+ binding.togglePrivacyCentral.isChecked = state.quickPrivacyState.isEnabled()
- val trackersEnabled = state.isQuickPrivacyEnabled && state.isAllTrackersBlocked
binding.stateTrackers.text = getString(
- if (trackersEnabled) R.string.dashboard_state_trackers_on
+ if (state.isTrackersDenied) R.string.dashboard_state_trackers_on
else R.string.dashboard_state_trackers_off
)
binding.stateTrackers.setTextColor(
getColor(
requireContext(),
- if (trackersEnabled) R.color.green_valid
+ if (state.isTrackersDenied) R.color.green_valid
else R.color.red_off
)
)
- val geolocEnabled = state.isQuickPrivacyEnabled && state.locationMode != LocationMode.REAL_LOCATION
binding.stateGeolocation.text = getString(
- if (geolocEnabled) R.string.dashboard_state_geolocation_on
+ if (state.isLocationHidden) R.string.dashboard_state_geolocation_on
else R.string.dashboard_state_geolocation_off
)
binding.stateGeolocation.setTextColor(
getColor(
requireContext(),
- if (geolocEnabled) R.color.green_valid
+ if (state.isLocationHidden) R.color.green_valid
else R.color.red_off
)
)
- val ipAddressEnabled = state.isQuickPrivacyEnabled && state.internetPrivacyMode != InternetPrivacyMode.REAL_IP
- val isLoading = state.isQuickPrivacyEnabled && state.internetPrivacyMode in listOf(
- InternetPrivacyMode.HIDE_IP_LOADING,
- InternetPrivacyMode.REAL_IP_LOADING
- )
+ val isLoading = state.isIpHidden == null
+
binding.stateIpAddress.text = getString(
- if (ipAddressEnabled) R.string.dashboard_state_ipaddress_on
+ if (state.isIpHidden == true) R.string.dashboard_state_ipaddress_on
else R.string.dashboard_state_ipaddress_off
)
@@ -212,7 +214,7 @@ class DashboardFragment :
binding.stateIpAddress.setTextColor(
getColor(
requireContext(),
- if (ipAddressEnabled) R.color.green_valid
+ if (state.isIpHidden == true) R.color.green_valid
else R.color.red_off
)
)
@@ -252,10 +254,7 @@ class DashboardFragment :
)
binding.internetActivityPrivacy.subTitle = getString(
- if (state.isQuickPrivacyEnabled &&
- state.internetPrivacyMode != InternetPrivacyMode.REAL_IP
- )
- R.string.dashboard_internet_activity_privacy_subtitle_on
+ if (state.isIpHidden == true) R.string.dashboard_internet_activity_privacy_subtitle_on
else R.string.dashboard_internet_activity_privacy_subtitle_off
)
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 0dbcdda..ffd7951 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
@@ -20,10 +20,7 @@ package foundation.e.privacycentralapp.features.dashboard
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import foundation.e.privacycentralapp.common.Factory
-import foundation.e.privacycentralapp.domain.usecases.FakeLocationStateUseCase
import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase
-import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase
-import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase
import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
@@ -31,10 +28,7 @@ import kotlinx.coroutines.launch
class DashboardViewModel(
private val getPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
- private val ipScramblingStateUseCase: IpScramblingStateUseCase,
private val trackersStatisticsUseCase: TrackersStatisticsUseCase,
- private val trackersStateUseCase: TrackersStateUseCase,
- private val fakeLocationStateUseCase: FakeLocationStateUseCase
) : ViewModel() {
private val _actions = MutableSharedFlow<DashboardFeature.Action>()
@@ -44,10 +38,7 @@ class DashboardViewModel(
DashboardFeature.create(
coroutineScope = viewModelScope,
getPrivacyStateUseCase = getPrivacyStateUseCase,
- ipScramblingStateUseCase = ipScramblingStateUseCase,
trackersStatisticsUseCase = trackersStatisticsUseCase,
- trackersStateUseCase = trackersStateUseCase,
- fakeLocationStateUseCase = fakeLocationStateUseCase
)
}
@@ -60,12 +51,9 @@ class DashboardViewModel(
class DashBoardViewModelFactory(
private val getPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
- private val ipScramblingStateUseCase: IpScramblingStateUseCase,
private val trackersStatisticsUseCase: TrackersStatisticsUseCase,
- private val trackersStateUseCase: TrackersStateUseCase,
- private val fakeLocationStateUseCase: FakeLocationStateUseCase
) : Factory<DashboardViewModel> {
override fun create(): DashboardViewModel {
- return DashboardViewModel(getPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase, trackersStateUseCase, fakeLocationStateUseCase)
+ return DashboardViewModel(getPrivacyStateUseCase, trackersStatisticsUseCase)
}
}
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 1969fe5..7efb6b0 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt
@@ -20,10 +20,7 @@ package foundation.e.privacycentralapp
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
-import foundation.e.privacycentralapp.domain.usecases.FakeLocationStateUseCase
import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase
-import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase
-import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase
import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase
import foundation.e.privacycentralapp.widget.State
import foundation.e.privacycentralapp.widget.render
@@ -72,25 +69,22 @@ class Widget : AppWidgetProvider() {
private fun initState(
getPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
- ipScramblingStateUseCase: IpScramblingStateUseCase,
trackersStatisticsUseCase: TrackersStatisticsUseCase,
- trackersStateUseCase: TrackersStateUseCase,
- fakeLocationStateUseCase: FakeLocationStateUseCase,
coroutineScope: CoroutineScope
): StateFlow<State> {
return combine(
- getPrivacyStateUseCase.quickPrivacyEnabledFlow,
- trackersStateUseCase.areAllTrackersBlocked,
- fakeLocationStateUseCase.locationMode,
- ipScramblingStateUseCase.internetPrivacyMode
- ) { isQuickPrivacyEnabled, isAllTrackersBlocked, locationMode, internetPrivacyMode ->
+ getPrivacyStateUseCase.quickPrivacyState,
+ getPrivacyStateUseCase.isTrackersDenied,
+ getPrivacyStateUseCase.isLocationHidden,
+ getPrivacyStateUseCase.isIpHidden,
+ ) { quickPrivacyState, isTrackersDenied, isLocationHidden, isIpHidden ->
State(
- isQuickPrivacyEnabled = isQuickPrivacyEnabled,
- isAllTrackersBlocked = isAllTrackersBlocked,
- locationMode = locationMode,
- internetPrivacyMode = internetPrivacyMode
+ quickPrivacyState = quickPrivacyState,
+ isTrackersDenied = isTrackersDenied,
+ isLocationHidden = isLocationHidden,
+ isIpHidden = isIpHidden
)
}.sample(50)
.combine(
@@ -112,17 +106,11 @@ class Widget : AppWidgetProvider() {
fun startListening(
appContext: Context,
getPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
- ipScramblingStateUseCase: IpScramblingStateUseCase,
trackersStatisticsUseCase: TrackersStatisticsUseCase,
- trackersStateUseCase: TrackersStateUseCase,
- fakeLocationStateUseCase: FakeLocationStateUseCase
) {
state = initState(
getPrivacyStateUseCase,
- ipScramblingStateUseCase,
trackersStatisticsUseCase,
- trackersStateUseCase,
- fakeLocationStateUseCase,
GlobalScope
)
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 87e88df..a4e3079 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt
@@ -27,7 +27,7 @@ class WidgetCommandReceiver : BroadcastReceiver() {
when (intent?.action) {
ACTION_TOGGLE_PRIVACY -> {
(context?.applicationContext as? PrivacyCentralApplication)
- ?.dependencyContainer?.getQuickPrivacyStateUseCase?.toggle()
+ ?.dependencyContainer?.getQuickPrivacyStateUseCase?.toggleReturnIsFirstActivation()
}
else -> {}
}
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 2529f6c..57ddd0c 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt
@@ -27,24 +27,20 @@ import android.view.View
import android.widget.RemoteViews
import foundation.e.privacycentralapp.R
import foundation.e.privacycentralapp.Widget
-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.extensions.dpToPxF
import foundation.e.privacycentralapp.main.MainActivity
import foundation.e.privacycentralapp.widget.WidgetCommandReceiver.Companion.ACTION_TOGGLE_PRIVACY
import kotlinx.coroutines.FlowPreview
data class State(
- val isQuickPrivacyEnabled: Boolean = false,
- val isAllTrackersBlocked: Boolean = false,
- val locationMode: LocationMode = LocationMode.REAL_LOCATION,
- val internetPrivacyMode: InternetPrivacyMode = InternetPrivacyMode.REAL_IP,
+ val quickPrivacyState: QuickPrivacyState = QuickPrivacyState.DISABLED,
+ val isTrackersDenied: Boolean = false,
+ val isLocationHidden: Boolean = false,
+ val isIpHidden: Boolean? = false,
val dayStatistics: List<Pair<Int, Int>> = emptyList(),
val activeTrackersCount: Int = 0,
-) {
- val isTrackersDenied get() = isQuickPrivacyEnabled && isAllTrackersBlocked
- val isLocationHidden get() = isQuickPrivacyEnabled && locationMode != LocationMode.REAL_LOCATION
-}
+)
@FlowPreview
fun render(
@@ -62,18 +58,22 @@ fun render(
setImageViewResource(
R.id.state_icon,
- if (state.isQuickPrivacyEnabled) R.drawable.ic_shield_on else R.drawable.ic_shield_off
+ if (state.quickPrivacyState.isEnabled()) R.drawable.ic_shield_on_white
+ else R.drawable.ic_shield_off_white
)
setTextViewText(
R.id.state_label,
context.getString(
- if (state.isQuickPrivacyEnabled) R.string.widget_state_title_on
- else R.string.widget_state_title_off
+ when (state.quickPrivacyState) {
+ QuickPrivacyState.DISABLED -> R.string.widget_state_title_off
+ QuickPrivacyState.FULL_ENABLED -> R.string.widget_state_title_on
+ QuickPrivacyState.ENABLED -> R.string.widget_state_title_custom
+ }
)
)
setImageViewResource(
R.id.toggle_privacy_central,
- if (state.isQuickPrivacyEnabled) R.drawable.ic_switch_enabled
+ if (state.quickPrivacyState.isEnabled()) R.drawable.ic_switch_enabled
else R.drawable.ic_switch_disabled
)
@@ -108,16 +108,12 @@ fun render(
setTextViewText(
R.id.state_ip_address,
context.getString(
- if (state.internetPrivacyMode != InternetPrivacyMode.HIDE_IP)
- R.string.widget_state_ipaddress_off
- else R.string.widget_state_ipaddress_on
+ if (state.isIpHidden == true) R.string.widget_state_ipaddress_on
+ else R.string.widget_state_ipaddress_off
)
)
- val loading = state.internetPrivacyMode in listOf(
- InternetPrivacyMode.HIDE_IP_LOADING,
- InternetPrivacyMode.REAL_IP_LOADING
- )
+ val loading = state.isIpHidden == null
setViewVisibility(R.id.state_ip_address, if (loading) View.GONE else View.VISIBLE)
diff --git a/app/src/main/res/drawable-night/ic_shield_off.xml b/app/src/main/res/drawable-night/ic_shield_off.xml
new file mode 100644
index 0000000..f45fd98
--- /dev/null
+++ b/app/src/main/res/drawable-night/ic_shield_off.xml
@@ -0,0 +1,19 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="25dp"
+ android:height="24dp"
+ android:viewportWidth="25"
+ android:viewportHeight="24">
+ <group>
+ <clip-path
+ android:pathData="M12.0183,1L3.0183,5V11C3.0183,16.55 6.8583,21.74 12.0183,23C17.1783,21.74 21.0183,16.55 21.0183,11V5L12.0183,1Z"/>
+ <path
+ android:pathData="M12.0183,1L12.8306,-0.8276L12.0183,-1.1886L11.206,-0.8276L12.0183,1ZM3.0183,5L2.206,3.1724L1.0183,3.7002V5H3.0183ZM12.0183,23L11.5439,24.9429L12.0183,25.0588L12.4927,24.9429L12.0183,23ZM21.0183,5H23.0183V3.7002L21.8306,3.1724L21.0183,5ZM11.206,-0.8276L2.206,3.1724L3.8306,6.8276L12.8306,2.8276L11.206,-0.8276ZM1.0183,5V11H5.0183V5H1.0183ZM1.0183,11C1.0183,17.3888 5.4102,23.4452 11.5439,24.9429L12.4927,21.0571C8.3064,20.0348 5.0183,15.7112 5.0183,11H1.0183ZM12.4927,24.9429C18.6264,23.4452 23.0183,17.3888 23.0183,11H19.0183C19.0183,15.7112 15.7302,20.0348 11.5439,21.0571L12.4927,24.9429ZM23.0183,11V5H19.0183V11H23.0183ZM21.8306,3.1724L12.8306,-0.8276L11.206,2.8276L20.206,6.8276L21.8306,3.1724Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"/>
+ </group>
+ <path
+ android:pathData="M15.1396,10.1213L15.8467,9.4142L14.4325,8L13.7254,8.7071L11.9325,10.5L10.1396,8.7071L9.4325,8L8.0183,9.4142L8.7254,10.1213L10.5183,11.9142L8.7254,13.7071L8.0183,14.4142L9.4325,15.8284L10.1396,15.1213L11.9325,13.3284L13.7254,15.1213L14.4325,15.8284L15.8467,14.4142L15.1396,13.7071L13.3467,11.9142L15.1396,10.1213Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/app/src/main/res/drawable-night/ic_shield_on.xml b/app/src/main/res/drawable-night/ic_shield_on.xml
new file mode 100644
index 0000000..ecc27b4
--- /dev/null
+++ b/app/src/main/res/drawable-night/ic_shield_on.xml
@@ -0,0 +1,18 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="25dp"
+ android:viewportWidth="24"
+ android:viewportHeight="25">
+ <group>
+ <clip-path
+ android:pathData="M12,1.5796L3,5.5796V11.5796C3,17.1296 6.84,22.3196 12,23.5796C17.16,22.3196 21,17.1296 21,11.5796V5.5796L12,1.5796Z"/>
+ <path
+ android:pathData="M12,1.5796L12.8123,-0.248L12,-0.609L11.1877,-0.248L12,1.5796ZM3,5.5796L2.1877,3.752L1,4.2798V5.5796H3ZM12,23.5796L11.5256,25.5225L12,25.6384L12.4744,25.5225L12,23.5796ZM21,5.5796H23V4.2798L21.8123,3.752L21,5.5796ZM11.1877,-0.248L2.1877,3.752L3.8123,7.4072L12.8123,3.4072L11.1877,-0.248ZM1,5.5796V11.5796H5V5.5796H1ZM1,11.5796C1,17.9684 5.3919,24.0247 11.5256,25.5225L12.4744,21.6367C8.2881,20.6144 5,16.2907 5,11.5796H1ZM12.4744,25.5225C18.6081,24.0247 23,17.9684 23,11.5796H19C19,16.2907 15.7119,20.6144 11.5256,21.6367L12.4744,25.5225ZM23,11.5796V5.5796H19V11.5796H23ZM21.8123,3.752L12.8123,-0.248L11.1877,3.4072L20.1877,7.4072L21.8123,3.752Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"/>
+ </group>
+ <path
+ android:pathData="M10.6951,14.5796L10.0141,15.3118L10.6948,15.9449L11.3758,15.3122L10.6951,14.5796ZM9.681,12.2708L8.9488,11.5897L7.5867,13.0542L8.319,13.7353L9.681,12.2708ZM15.6807,11.3122L16.4133,10.6315L15.0519,9.1663L14.3193,9.847L15.6807,11.3122ZM11.3762,13.8473L9.681,12.2708L8.319,13.7353L10.0141,15.3118L11.3762,13.8473ZM14.3193,9.847L10.0144,13.847L11.3758,15.3122L15.6807,11.3122L14.3193,9.847Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_shield_off.xml b/app/src/main/res/drawable/ic_shield_off.xml
index 8f811a2..cd60ba4 100644
--- a/app/src/main/res/drawable/ic_shield_off.xml
+++ b/app/src/main/res/drawable/ic_shield_off.xml
@@ -1,16 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
+ android:width="25dp"
android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="@color/red_off">
+ android:viewportWidth="25"
+ android:viewportHeight="24">
+ <group>
+ <clip-path
+ android:pathData="M12.5,1L3.5,5V11C3.5,16.55 7.34,21.74 12.5,23C17.66,21.74 21.5,16.55 21.5,11V5L12.5,1Z"/>
<path
- android:pathData="M4,11V5.6499L12,2.0943L20,5.6499V11C20,16.0434 16.556,20.7257 12,21.9673C7.444,20.7257 4,16.0434 4,11Z"
- android:strokeWidth="2"
- android:fillColor="#00000000"
- android:strokeColor="#000000"/>
- <path
- android:pathData="M15.1213,10.1213L15.8284,9.4142L14.4142,8L13.7071,8.7071L11.9142,10.5L10.1213,8.7071L9.4142,8L8,9.4142L8.7071,10.1213L10.5,11.9142L8.7071,13.7071L8,14.4142L9.4142,15.8284L10.1213,15.1213L11.9142,13.3284L13.7071,15.1213L14.4142,15.8284L15.8284,14.4142L15.1213,13.7071L13.3284,11.9142L15.1213,10.1213Z"
+ android:pathData="M12.5,1L13.3123,-0.8276L12.5,-1.1886L11.6877,-0.8276L12.5,1ZM3.5,5L2.6877,3.1724L1.5,3.7002V5H3.5ZM12.5,23L12.0256,24.9429L12.5,25.0588L12.9744,24.9429L12.5,23ZM21.5,5H23.5V3.7002L22.3123,3.1724L21.5,5ZM11.6877,-0.8276L2.6877,3.1724L4.3123,6.8276L13.3123,2.8276L11.6877,-0.8276ZM1.5,5V11H5.5V5H1.5ZM1.5,11C1.5,17.3888 5.8919,23.4452 12.0256,24.9429L12.9744,21.0571C8.7881,20.0348 5.5,15.7112 5.5,11H1.5ZM12.9744,24.9429C19.1081,23.4452 23.5,17.3888 23.5,11H19.5C19.5,15.7112 16.2119,20.0348 12.0256,21.0571L12.9744,24.9429ZM23.5,11V5H19.5V11H23.5ZM22.3123,3.1724L13.3123,-0.8276L11.6877,2.8276L20.6877,6.8276L22.3123,3.1724Z"
android:fillColor="#000000"
- android:fillType="evenOdd"/>
+ android:fillAlpha="0.87"/>
+ </group>
+ <path
+ android:pathData="M15.6213,10.1213L16.3284,9.4142L14.9142,8L14.2071,8.7071L12.4142,10.5L10.6213,8.7071L9.9142,8L8.5,9.4142L9.2071,10.1213L11,11.9142L9.2071,13.7071L8.5,14.4142L9.9142,15.8284L10.6213,15.1213L12.4142,13.3284L14.2071,15.1213L14.9142,15.8284L16.3284,14.4142L15.6213,13.7071L13.8284,11.9142L15.6213,10.1213Z"
+ android:fillColor="#000000"
+ android:fillAlpha="0.87"
+ android:fillType="evenOdd"/>
</vector>
diff --git a/app/src/main/res/drawable/ic_shield_off_white.xml b/app/src/main/res/drawable/ic_shield_off_white.xml
new file mode 100644
index 0000000..f45fd98
--- /dev/null
+++ b/app/src/main/res/drawable/ic_shield_off_white.xml
@@ -0,0 +1,19 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="25dp"
+ android:height="24dp"
+ android:viewportWidth="25"
+ android:viewportHeight="24">
+ <group>
+ <clip-path
+ android:pathData="M12.0183,1L3.0183,5V11C3.0183,16.55 6.8583,21.74 12.0183,23C17.1783,21.74 21.0183,16.55 21.0183,11V5L12.0183,1Z"/>
+ <path
+ android:pathData="M12.0183,1L12.8306,-0.8276L12.0183,-1.1886L11.206,-0.8276L12.0183,1ZM3.0183,5L2.206,3.1724L1.0183,3.7002V5H3.0183ZM12.0183,23L11.5439,24.9429L12.0183,25.0588L12.4927,24.9429L12.0183,23ZM21.0183,5H23.0183V3.7002L21.8306,3.1724L21.0183,5ZM11.206,-0.8276L2.206,3.1724L3.8306,6.8276L12.8306,2.8276L11.206,-0.8276ZM1.0183,5V11H5.0183V5H1.0183ZM1.0183,11C1.0183,17.3888 5.4102,23.4452 11.5439,24.9429L12.4927,21.0571C8.3064,20.0348 5.0183,15.7112 5.0183,11H1.0183ZM12.4927,24.9429C18.6264,23.4452 23.0183,17.3888 23.0183,11H19.0183C19.0183,15.7112 15.7302,20.0348 11.5439,21.0571L12.4927,24.9429ZM23.0183,11V5H19.0183V11H23.0183ZM21.8306,3.1724L12.8306,-0.8276L11.206,2.8276L20.206,6.8276L21.8306,3.1724Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"/>
+ </group>
+ <path
+ android:pathData="M15.1396,10.1213L15.8467,9.4142L14.4325,8L13.7254,8.7071L11.9325,10.5L10.1396,8.7071L9.4325,8L8.0183,9.4142L8.7254,10.1213L10.5183,11.9142L8.7254,13.7071L8.0183,14.4142L9.4325,15.8284L10.1396,15.1213L11.9325,13.3284L13.7254,15.1213L14.4325,15.8284L15.8467,14.4142L15.1396,13.7071L13.3467,11.9142L15.1396,10.1213Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_shield_on.xml b/app/src/main/res/drawable/ic_shield_on.xml
index b70dc6e..e29f766 100644
--- a/app/src/main/res/drawable/ic_shield_on.xml
+++ b/app/src/main/res/drawable/ic_shield_on.xml
@@ -1,17 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
+ android:width="25dp"
android:height="25dp"
- android:viewportWidth="24"
+ android:viewportWidth="25"
android:viewportHeight="25">
+ <group>
+ <clip-path
+ android:pathData="M12.5,1.5L3.5,5.5V11.5C3.5,17.05 7.34,22.24 12.5,23.5C17.66,22.24 21.5,17.05 21.5,11.5V5.5L12.5,1.5Z"/>
<path
- android:pathData="M4,11.5V6.1499L12,2.5943L20,6.1499V11.5C20,16.5434 16.556,21.2257 12,22.4673C7.444,21.2257 4,16.5434 4,11.5Z"
- android:strokeWidth="2"
- android:fillColor="#00000000"
- android:strokeColor="#2CC766"/>
- <path
- android:pathData="M9,12.9234L10.6951,14.5L15,10.5"
- android:strokeWidth="2"
- android:fillColor="#00000000"
- android:strokeColor="#2CC766"
- android:strokeLineCap="square"/>
+ android:pathData="M12.5,1.5L13.3123,-0.3276L12.5,-0.6886L11.6877,-0.3276L12.5,1.5ZM3.5,5.5L2.6877,3.6724L1.5,4.2003V5.5H3.5ZM12.5,23.5L12.0256,25.4429L12.5,25.5588L12.9744,25.4429L12.5,23.5ZM21.5,5.5H23.5V4.2003L22.3123,3.6724L21.5,5.5ZM11.6877,-0.3276L2.6877,3.6724L4.3123,7.3276L13.3123,3.3276L11.6877,-0.3276ZM1.5,5.5V11.5H5.5V5.5H1.5ZM1.5,11.5C1.5,17.8888 5.8919,23.9452 12.0256,25.4429L12.9744,21.5571C8.7881,20.5348 5.5,16.2112 5.5,11.5H1.5ZM12.9744,25.4429C19.1081,23.9452 23.5,17.8888 23.5,11.5H19.5C19.5,16.2112 16.2119,20.5348 12.0256,21.5571L12.9744,25.4429ZM23.5,11.5V5.5H19.5V11.5H23.5ZM22.3123,3.6724L13.3123,-0.3276L11.6877,3.3276L20.6877,7.3276L22.3123,3.6724Z"
+ android:fillColor="#000000"
+ android:fillAlpha="0.87"/>
+ </group>
+ <path
+ android:pathData="M11.1951,14.5L10.5141,15.2323L11.1948,15.8654L11.8758,15.2326L11.1951,14.5ZM10.181,12.1912L9.4488,11.5102L8.0867,12.9747L8.819,13.6557L10.181,12.1912ZM16.1807,11.2326L16.9133,10.5519L15.5519,9.0867L14.8193,9.7674L16.1807,11.2326ZM11.8762,13.7677L10.181,12.1912L8.819,13.6557L10.5141,15.2323L11.8762,13.7677ZM14.8193,9.7674L10.5144,13.7674L11.8758,15.2326L16.1807,11.2326L14.8193,9.7674Z"
+ android:fillColor="#000000"
+ android:fillAlpha="0.87"/>
</vector>
diff --git a/app/src/main/res/drawable/ic_shield_on_white.xml b/app/src/main/res/drawable/ic_shield_on_white.xml
new file mode 100644
index 0000000..ecc27b4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_shield_on_white.xml
@@ -0,0 +1,18 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="25dp"
+ android:viewportWidth="24"
+ android:viewportHeight="25">
+ <group>
+ <clip-path
+ android:pathData="M12,1.5796L3,5.5796V11.5796C3,17.1296 6.84,22.3196 12,23.5796C17.16,22.3196 21,17.1296 21,11.5796V5.5796L12,1.5796Z"/>
+ <path
+ android:pathData="M12,1.5796L12.8123,-0.248L12,-0.609L11.1877,-0.248L12,1.5796ZM3,5.5796L2.1877,3.752L1,4.2798V5.5796H3ZM12,23.5796L11.5256,25.5225L12,25.6384L12.4744,25.5225L12,23.5796ZM21,5.5796H23V4.2798L21.8123,3.752L21,5.5796ZM11.1877,-0.248L2.1877,3.752L3.8123,7.4072L12.8123,3.4072L11.1877,-0.248ZM1,5.5796V11.5796H5V5.5796H1ZM1,11.5796C1,17.9684 5.3919,24.0247 11.5256,25.5225L12.4744,21.6367C8.2881,20.6144 5,16.2907 5,11.5796H1ZM12.4744,25.5225C18.6081,24.0247 23,17.9684 23,11.5796H19C19,16.2907 15.7119,20.6144 11.5256,21.6367L12.4744,25.5225ZM23,11.5796V5.5796H19V11.5796H23ZM21.8123,3.752L12.8123,-0.248L11.1877,3.4072L20.1877,7.4072L21.8123,3.752Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"/>
+ </group>
+ <path
+ android:pathData="M10.6951,14.5796L10.0141,15.3118L10.6948,15.9449L11.3758,15.3122L10.6951,14.5796ZM9.681,12.2708L8.9488,11.5897L7.5867,13.0542L8.319,13.7353L9.681,12.2708ZM15.6807,11.3122L16.4133,10.6315L15.0519,9.1663L14.3193,9.847L15.6807,11.3122ZM11.3762,13.8473L9.681,12.2708L8.319,13.7353L10.0141,15.3118L11.3762,13.8473ZM14.3193,9.847L10.0144,13.847L11.3758,15.3122L15.6807,11.3122L14.3193,9.847Z"
+ android:fillColor="#ffffff"
+ android:fillAlpha="0.87"/>
+</vector>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index cf293e1..1fc7841 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -13,6 +13,7 @@
<string name="dashboard_title">@string/app_name</string>
<string name="dashboard_state_title_on">Your online privacy is protected</string>
<string name="dashboard_state_title_off">Your online privacy is unprotected</string>
+ <string name="dashboard_state_title_custom">Custom privacy settings applied</string>
<string name="dashboard_state_trackers_label">Trackers:</string>
<string name="dashboard_state_trackers_off">Vulnerable</string>
<string name="dashboard_state_trackers_on">Denied</string>
@@ -25,6 +26,7 @@
<string name="dashboard_graph_label">Personal data leakage:</string>
<string name="dashboard_graph_period">Today</string>
<string name="dashboard_graph_trackers_legend">%s trackers have profiled you in the last 24 hours</string>
+ <string name="dashboard_first_ipscrambling_activation">While your IP is faked, your internet speed is likely to be reduced.</string>
<string name="dashboard_am_i_tracked_title">Manage apps\' trackers</string>
<string name="dashboard_am_i_tracked_subtitle">%1$d app trackers, %2$d active trackers</string>
@@ -126,6 +128,7 @@
<string name="widget_title">@string/app_name</string>
<string name="widget_state_title_on">Your online privacy is protected</string>
<string name="widget_state_title_off">Your online privacy is unprotected</string>
+ <string name="widget_state_title_custom">Custom privacy settings applied</string>
<string name="widget_state_trackers_label">@string/dashboard_state_trackers_label</string>
<string name="widget_state_trackers_off">@string/dashboard_state_trackers_off</string>
<string name="widget_state_trackers_on">@string/dashboard_state_trackers_on</string>