summaryrefslogtreecommitdiff
path: root/app/src/main/java/foundation
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/foundation')
-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
13 files changed, 198 insertions, 139 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)