From 650a067529cdf65cc9a9130c91511adfb4b64c98 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquart Date: Thu, 24 Feb 2022 07:46:23 +0000 Subject: Access trackers list when QP disabled: #4591, #4596, #4601 --- .../e/privacycentralapp/DependencyContainer.kt | 6 +-- .../domain/entities/TrackersPeriodicStatistics.kt | 24 +++++++++ .../domain/usecases/FakeLocationStateUseCase.kt | 4 -- .../domain/usecases/IpScramblingStateUseCase.kt | 10 +--- .../domain/usecases/TrackersStatisticsUseCase.kt | 23 +++++---- .../e/privacycentralapp/extensions/AnyExtension.kt | 26 ++++++++++ .../features/dashboard/DashboardFeature.kt | 4 +- .../internetprivacy/InternetPrivacyFeature.kt | 5 +- .../internetprivacy/InternetPrivacyFragment.kt | 3 +- .../features/location/FakeLocationFragment.kt | 2 - .../features/trackers/TrackersFeature.kt | 12 ++--- .../features/trackers/TrackersFragment.kt | 2 +- .../features/trackers/TrackersViewModel.kt | 9 +--- .../trackers/apptrackers/AppTrackersFeature.kt | 60 +++++++++++++--------- .../trackers/apptrackers/AppTrackersFragment.kt | 9 +++- .../trackers/apptrackers/AppTrackersViewModel.kt | 14 ++--- .../trackers/apptrackers/ToggleTrackersAdapter.kt | 2 +- app/src/main/res/values/strings.xml | 6 +++ 18 files changed, 140 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/foundation/e/privacycentralapp/domain/entities/TrackersPeriodicStatistics.kt create mode 100644 app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt (limited to 'app') diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt index 87159d2..ceb8202 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt @@ -85,7 +85,7 @@ class DependencyContainer constructor(val app: Application) { private val appListUseCase = AppListUseCase(permissionsModule, blockTrackersPrivacyModule, GlobalScope) private val trackersStatisticsUseCase by lazy { - TrackersStatisticsUseCase(trackTrackersPrivacyModule) + TrackersStatisticsUseCase(trackTrackersPrivacyModule, context.resources) } private val trackersStateUseCase by lazy { @@ -117,10 +117,10 @@ class DependencyContainer constructor(val app: Application) { } val trackersViewModelFactory by lazy { - TrackersViewModelFactory(getQuickPrivacyStateUseCase, trackersStatisticsUseCase, appListUseCase) + TrackersViewModelFactory(trackersStatisticsUseCase, appListUseCase) } val appTrackersViewModelFactory by lazy { - AppTrackersViewModelFactory(trackersStateUseCase, trackersStatisticsUseCase) + AppTrackersViewModelFactory(trackersStateUseCase, trackersStatisticsUseCase, getQuickPrivacyStateUseCase) } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/entities/TrackersPeriodicStatistics.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/TrackersPeriodicStatistics.kt new file mode 100644 index 0000000..8a27d6d --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/entities/TrackersPeriodicStatistics.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 . + */ + +package foundation.e.privacycentralapp.domain.entities + +data class TrackersPeriodicStatistics( + val calls: List, + val periods: List, + val trackersCount: Int +) 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 5850dc4..32affe0 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 @@ -132,7 +132,6 @@ class FakeLocationStateUseCase( val providerName = LocationManager.NETWORK_PROVIDER override fun onLocationChanged(location: Location) { - Log.e("DebugLoc", "onLocationChanged $location") currentLocation.value = location } @@ -140,12 +139,10 @@ class FakeLocationStateUseCase( override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} override fun onProviderEnabled(provider: String?) { - Log.e("DebugLoc", "ProvuderEnabled: $provider") reset(provider) } override fun onProviderDisabled(provider: String?) { - Log.e("DebugLoc", "ProvuderDisabled: $provider") reset(provider) } @@ -169,7 +166,6 @@ class FakeLocationStateUseCase( fun requestLocationUpdates(listener: LocationListener) { acquireLocationPermission() try { - Log.e("DebugLoc", "requestLocationUpdates") locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, // TODO: tight this with fakelocation module. 0L, 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 9e83eb1..237e5b2 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 @@ -17,7 +17,6 @@ package foundation.e.privacycentralapp.domain.usecases -import android.util.Log import foundation.e.privacycentralapp.data.repositories.LocalStateRepository import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacymodules.ipscramblermodule.IIpScramblerModule @@ -102,16 +101,11 @@ class IpScramblingStateUseCase( } ipScramblerModule.start(enableNotification = false) } - else -> { - Log.d("testQPFlow", "Not starting tor, already in started state") - } + else -> {} } else -> when (internetPrivacyMode.value) { InternetPrivacyMode.HIDE_IP, InternetPrivacyMode.HIDE_IP_LOADING -> ipScramblerModule.stop() - - else -> { - Log.d("testQPFlow", "Not stoping tor, already in stop or stoping state") - } + else -> {} } } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt index 1e1728c..ad5c86c 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt @@ -17,6 +17,9 @@ package foundation.e.privacycentralapp.domain.usecases +import android.content.res.Resources +import foundation.e.privacycentralapp.R +import foundation.e.privacycentralapp.domain.entities.TrackersPeriodicStatistics import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule import foundation.e.privacymodules.trackers.Tracker import kotlinx.coroutines.channels.awaitClose @@ -26,13 +29,9 @@ import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit -data class TrackersPeriodicStatistics( - val calls: List, - val periods: List, - val trackersCount: Int -) class TrackersStatisticsUseCase( - private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule + private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule, + private val resources: Resources ) { fun listenUpdates(): Flow = callbackFlow { @@ -53,7 +52,9 @@ class TrackersStatisticsUseCase( } private fun buildDayLabels(): List { - val formater = DateTimeFormatter.ofPattern("HH:mm") + val formater = DateTimeFormatter.ofPattern( + resources.getString(R.string.trackers_graph_hours_period_format) + ) val periods = mutableListOf() var end = ZonedDateTime.now() for (i in 1..24) { @@ -65,7 +66,9 @@ class TrackersStatisticsUseCase( } private fun buildMonthLabels(): List { - val formater = DateTimeFormatter.ofPattern("MMM d - EEE") + val formater = DateTimeFormatter.ofPattern( + resources.getString(R.string.trackers_graph_days_period_format) + ) val periods = mutableListOf() var day = ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS) for (i in 1..30) { @@ -76,7 +79,9 @@ class TrackersStatisticsUseCase( } private fun buildYearLabels(): List { - val formater = DateTimeFormatter.ofPattern("MMM yyyy") + val formater = DateTimeFormatter.ofPattern( + resources.getString(R.string.trackers_graph_months_period_format) + ) val periods = mutableListOf() var month = ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1) for (i in 1..12) { diff --git a/app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt b/app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt new file mode 100644 index 0000000..a870d33 --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt @@ -0,0 +1,26 @@ +/* + * 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.extensions + +import android.content.Context + +fun Any.toText(context: Context) = when (this) { + is Int -> context.getString(this) + is String -> this + else -> this.toString() +} 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 b434bb4..87f5e42 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 @@ -130,7 +130,6 @@ class DashboardFeature( } }, actor = { _: State, action: Action -> - Log.d("Feature", "action: $action") when (action) { Action.TogglePrivacyAction -> { getPrivacyStateUseCase.toggle() @@ -186,8 +185,7 @@ class DashboardFeature( ) } }, - singleEventProducer = { state, _, effect -> - Log.d("DashboardFeature", "$state, $effect") + singleEventProducer = { _, _, effect -> when (effect) { is Effect.OpenFakeMyLocationEffect -> SingleEvent.NavigateToLocationSingleEvent diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFeature.kt b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFeature.kt index 6ff3d27..8d50980 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFeature.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/internetprivacy/InternetPrivacyFeature.kt @@ -24,6 +24,7 @@ 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.R import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.usecases.AppListUseCase import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase @@ -71,7 +72,7 @@ class InternetPrivacyFeature( sealed class SingleEvent { data class StartAndroidVpnActivityEvent(val intent: Intent) : SingleEvent() - data class ErrorEvent(val error: String) : SingleEvent() + data class ErrorEvent(val error: Any) : SingleEvent() } sealed class Action { @@ -201,7 +202,7 @@ class InternetPrivacyFeature( singleEventProducer = { _, action, effect -> when { effect is Effect.ErrorEffect -> SingleEvent.ErrorEvent(effect.message) - effect == Effect.QuickPrivacyDisabledWarningEffect -> SingleEvent.ErrorEvent("Enabled Quick Privacy to use functionalities") + effect == Effect.QuickPrivacyDisabledWarningEffect -> SingleEvent.ErrorEvent(error = R.string.ipscrambling_error_quickprivacy_disabled) action is Action.UseHiddenIPAction && effect is Effect.ShowAndroidVpnDisclaimerEffect -> 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 f288320..07e0627 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 @@ -34,6 +34,7 @@ import foundation.e.privacycentralapp.common.NavToolbarFragment import foundation.e.privacycentralapp.common.ToggleAppsAdapter import foundation.e.privacycentralapp.databinding.FragmentInternetActivityPolicyBinding import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode +import foundation.e.privacycentralapp.extensions.toText import foundation.e.privacycentralapp.extensions.viewModelProviderFactoryOf import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collect @@ -62,7 +63,7 @@ class InternetPrivacyFragment : viewModel.internetPrivacyFeature.singleEvents.collect { event -> when (event) { is InternetPrivacyFeature.SingleEvent.ErrorEvent -> { - displayToast(event.error) + displayToast(event.error.toText(requireContext())) } is InternetPrivacyFeature.SingleEvent.StartAndroidVpnActivityEvent -> { launchAndroidVpnDisclaimer.launch(event.intent) 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 76c586c..6821a33 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 @@ -22,7 +22,6 @@ import android.content.Context import android.location.Location import android.os.Bundle import android.text.Editable -import android.util.Log import android.view.View import android.widget.Toast import androidx.annotation.NonNull @@ -171,7 +170,6 @@ class FakeLocationFragment : val lat = binding.edittextLatitude.text.toString().toFloat() val lon = binding.edittextLongitude.text.toString().toFloat() if (lat <= 90f && lat >= -90f && lon <= 180f && lon >= -180f) { - Log.e("UpdateText", "") mapboxMap?.moveCamera( CameraUpdateFactory.newLatLng( LatLng(lat.toDouble(), lon.toDouble()) diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt index f38e50f..00e3fb7 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/TrackersFeature.kt @@ -22,9 +22,8 @@ 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.TrackersPeriodicStatistics import foundation.e.privacycentralapp.domain.usecases.AppListUseCase -import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase -import foundation.e.privacycentralapp.domain.usecases.TrackersPeriodicStatistics import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase import foundation.e.privacymodules.permissions.data.ApplicationDescription import foundation.e.privacymodules.trackers.Tracker @@ -88,7 +87,6 @@ class TrackersFeature( fun create( initialState: State = State(), coroutineScope: CoroutineScope, - getPrivacyStateUseCase: GetQuickPrivacyStateUseCase, trackersStatisticsUseCase: TrackersStatisticsUseCase, appListUseCase: AppListUseCase ) = TrackersFeature( @@ -130,11 +128,9 @@ class TrackersFeature( ) is Action.ClickAppAction -> flowOf( - if (getPrivacyStateUseCase.isQuickPrivacyEnabled) { - state.apps?.find { it.packageName == action.packageName }?.let { - Effect.OpenAppDetailsEffect(it) - } ?: run { Effect.ErrorEffect("Can't find back app.") } - } else Effect.QuickPrivacyDisabledWarningEffect + state.apps?.find { it.packageName == action.packageName }?.let { + Effect.OpenAppDetailsEffect(it) + } ?: run { Effect.ErrorEffect("Can't find back app.") } ) is Action.FetchStatistics -> flow { trackersStatisticsUseCase.getDayMonthYearStatistics() 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 088787c..3b22f89 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 @@ -34,7 +34,7 @@ import foundation.e.privacycentralapp.common.GraphHolder import foundation.e.privacycentralapp.common.NavToolbarFragment import foundation.e.privacycentralapp.databinding.FragmentTrackersBinding import foundation.e.privacycentralapp.databinding.TrackersItemGraphBinding -import foundation.e.privacycentralapp.domain.usecases.TrackersPeriodicStatistics +import foundation.e.privacycentralapp.domain.entities.TrackersPeriodicStatistics import foundation.e.privacycentralapp.extensions.viewModelProviderFactoryOf import foundation.e.privacycentralapp.features.trackers.apptrackers.AppTrackersFragment import kotlinx.coroutines.flow.Flow 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 12b66d4..e3a97cc 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 @@ -17,19 +17,16 @@ package foundation.e.privacycentralapp.features.trackers -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import foundation.e.privacycentralapp.common.Factory import foundation.e.privacycentralapp.domain.usecases.AppListUseCase -import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.launch class TrackersViewModel( - private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase, private val trackersStatisticsUseCase: TrackersStatisticsUseCase, private val appListUseCase: AppListUseCase ) : ViewModel() { @@ -40,14 +37,13 @@ class TrackersViewModel( val trackersFeature: TrackersFeature by lazy { TrackersFeature.create( coroutineScope = viewModelScope, - getPrivacyStateUseCase = getQuickPrivacyStateUseCase, + trackersStatisticsUseCase = trackersStatisticsUseCase, appListUseCase = appListUseCase ) } fun submitAction(action: TrackersFeature.Action) { - Log.d("TrackersViewModel", "submitting action") viewModelScope.launch { _actions.emit(action) } @@ -55,12 +51,11 @@ class TrackersViewModel( } class TrackersViewModelFactory( - private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase, private val trackersStatisticsUseCase: TrackersStatisticsUseCase, private val appListUseCase: AppListUseCase ) : Factory { override fun create(): TrackersViewModel { - return TrackersViewModel(getQuickPrivacyStateUseCase, trackersStatisticsUseCase, appListUseCase) + return TrackersViewModel(trackersStatisticsUseCase, appListUseCase) } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt index 18cbb93..ff0c9db 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/AppTrackersFeature.kt @@ -22,6 +22,8 @@ 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.R +import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase import foundation.e.privacymodules.permissions.data.ApplicationDescription @@ -51,7 +53,8 @@ class AppTrackersFeature( val appDesc: ApplicationDescription? = null, val isBlockingActivated: Boolean = false, val trackers: List? = null, - val whitelist: List? = null + val whitelist: List? = null, + val isQuickPrivacyEnabled: Boolean = false ) { fun getTrackersStatus(): List>? { if (trackers != null && whitelist != null) { @@ -63,7 +66,7 @@ class AppTrackersFeature( } sealed class SingleEvent { - data class ErrorEvent(val error: String) : SingleEvent() + data class ErrorEvent(val error: Any) : SingleEvent() object NewStatisticsAvailableSingleEvent : SingleEvent() } @@ -75,18 +78,15 @@ class AppTrackersFeature( } sealed class Effect { + object NoEffect : Effect() + data class ErrorEffect(val message: String) : Effect() data class SetAppEffect(val appDesc: ApplicationDescription) : Effect() data class AppTrackersBlockingActivatedEffect(val isBlockingActivated: Boolean) : Effect() - data class AvailableTrackersListEffect( - // val isBlockingActivated: Boolean, - val trackers: List, - // val whitelist: List - ) : Effect() + data class AvailableTrackersListEffect(val trackers: List) : Effect() data class TrackersWhitelistUpdateEffect(val whitelist: List) : Effect() - - // object QuickPrivacyDisabledWarningEffect : Effect() - data class ErrorEffect(val message: String) : Effect() object NewStatisticsAvailablesEffect : Effect() + data class QuickPrivacyUpdatedEffect(val enabled: Boolean) : Effect() + object QuickPrivacyDisabledWarningEffect : Effect() } companion object { @@ -94,7 +94,8 @@ class AppTrackersFeature( initialState: State = State(), coroutineScope: CoroutineScope, trackersStateUseCase: TrackersStateUseCase, - trackersStatisticsUseCase: TrackersStatisticsUseCase + trackersStatisticsUseCase: TrackersStatisticsUseCase, + getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase ) = AppTrackersFeature( initialState, coroutineScope, reducer = { state, effect -> @@ -107,6 +108,8 @@ class AppTrackersFeature( is Effect.TrackersWhitelistUpdateEffect -> state.copy(whitelist = effect.whitelist) + is Effect.QuickPrivacyUpdatedEffect -> + state.copy(isQuickPrivacyEnabled = effect.enabled) is Effect.ErrorEffect -> state else -> state } @@ -138,6 +141,9 @@ class AppTrackersFeature( }, trackersStatisticsUseCase.listenUpdates().map { Effect.NewStatisticsAvailablesEffect + }, + getQuickPrivacyStateUseCase.quickPrivacyEnabledFlow.map { + Effect.QuickPrivacyUpdatedEffect(it) } ) } @@ -156,20 +162,24 @@ class AppTrackersFeature( } } ?: run { flowOf(Effect.ErrorEffect("No appDesc.")) } is Action.ToggleTrackerAction -> { - state.appDesc?.uid?.let { appUid -> - flow { - trackersStateUseCase.blockTracker( - appUid, - action.tracker, - action.isBlocked - ) - emit( - Effect.TrackersWhitelistUpdateEffect( - trackersStateUseCase.getTrackersWhitelistIds(appUid) + if (!state.isQuickPrivacyEnabled) { + flowOf(Effect.QuickPrivacyDisabledWarningEffect) + } else if (state.isBlockingActivated) { + state.appDesc?.uid?.let { appUid -> + flow { + trackersStateUseCase.blockTracker( + appUid, + action.tracker, + action.isBlocked ) - ) - } - } ?: run { flowOf(Effect.ErrorEffect("No appDesc.")) } + emit( + Effect.TrackersWhitelistUpdateEffect( + trackersStateUseCase.getTrackersWhitelistIds(appUid) + ) + ) + } + } ?: run { flowOf(Effect.ErrorEffect("No appDesc.")) } + } else flowOf(Effect.NoEffect) } is Action.FetchStatistics -> flowOf( state.appDesc?.uid?.let { @@ -184,6 +194,8 @@ class AppTrackersFeature( singleEventProducer = { _, _, effect -> when (effect) { is Effect.ErrorEffect -> SingleEvent.ErrorEvent(effect.message) + is Effect.QuickPrivacyDisabledWarningEffect -> + SingleEvent.ErrorEvent(R.string.apptrackers_error_quickprivacy_disabled) is Effect.NewStatisticsAvailablesEffect -> SingleEvent.NewStatisticsAvailableSingleEvent else -> null 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 5b09be5..1f339ee 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 @@ -31,6 +31,7 @@ import foundation.e.privacycentralapp.PrivacyCentralApplication import foundation.e.privacycentralapp.R import foundation.e.privacycentralapp.common.NavToolbarFragment import foundation.e.privacycentralapp.databinding.ApptrackersFragmentBinding +import foundation.e.privacycentralapp.extensions.toText import foundation.e.privacycentralapp.extensions.viewModelProviderFactoryOf import foundation.e.privacycentralapp.features.trackers.apptrackers.AppTrackersFeature.Action import foundation.e.privacycentralapp.features.trackers.apptrackers.AppTrackersFeature.SingleEvent @@ -70,7 +71,8 @@ class AppTrackersFragment : lifecycleScope.launchWhenStarted { viewModel.feature.singleEvents.collect { event -> when (event) { - is SingleEvent.ErrorEvent -> displayToast(event.error) + is SingleEvent.ErrorEvent -> + displayToast(event.error.toText(requireContext())) is SingleEvent.NewStatisticsAvailableSingleEvent -> { viewModel.submitAction(Action.FetchStatistics) } @@ -128,7 +130,10 @@ class AppTrackersFragment : if (!trackersStatus.isNullOrEmpty()) { binding.trackers.isVisible = true binding.trackers.post { - (binding.trackers.adapter as ToggleTrackersAdapter?)?.updateDataSet(trackersStatus, state.isBlockingActivated) + (binding.trackers.adapter as ToggleTrackersAdapter?)?.updateDataSet( + trackersStatus, + state.isBlockingActivated && state.isQuickPrivacyEnabled + ) } binding.noTrackersYet.isVisible = false } else { 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 37fdb85..995aa80 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 @@ -17,10 +17,10 @@ package foundation.e.privacycentralapp.features.trackers.apptrackers -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import foundation.e.privacycentralapp.common.Factory +import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStateUseCase import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase import kotlinx.coroutines.flow.MutableSharedFlow @@ -29,7 +29,8 @@ import kotlinx.coroutines.launch class AppTrackersViewModel( private val trackersStateUseCase: TrackersStateUseCase, - private val trackersStatisticsUseCase: TrackersStatisticsUseCase + private val trackersStatisticsUseCase: TrackersStatisticsUseCase, + private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase ) : ViewModel() { private val _actions = MutableSharedFlow() @@ -39,12 +40,12 @@ class AppTrackersViewModel( AppTrackersFeature.create( coroutineScope = viewModelScope, trackersStateUseCase = trackersStateUseCase, - trackersStatisticsUseCase = trackersStatisticsUseCase + trackersStatisticsUseCase = trackersStatisticsUseCase, + getQuickPrivacyStateUseCase = getQuickPrivacyStateUseCase, ) } fun submitAction(action: AppTrackersFeature.Action) { - Log.d("TrackersViewModel", "submitting action") viewModelScope.launch { _actions.emit(action) } @@ -53,10 +54,11 @@ class AppTrackersViewModel( class AppTrackersViewModelFactory( private val trackersStateUseCase: TrackersStateUseCase, - private val trackersStatisticsUseCase: TrackersStatisticsUseCase + private val trackersStatisticsUseCase: TrackersStatisticsUseCase, + private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase ) : Factory { override fun create(): AppTrackersViewModel { - return AppTrackersViewModel(trackersStateUseCase, trackersStatisticsUseCase) + return AppTrackersViewModel(trackersStateUseCase, trackersStatisticsUseCase, getQuickPrivacyStateUseCase) } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt index 95ea094..0ab3987 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/features/trackers/apptrackers/ToggleTrackersAdapter.kt @@ -58,7 +58,7 @@ class ToggleTrackersAdapter( val view = LayoutInflater.from(parent.context) .inflate(itemsLayout, parent, false) val holder = ViewHolder(view) - holder.toggle.setOnClickListener { + holder.itemView.setOnClickListener { listener(dataSet[holder.adapterPosition].first, holder.toggle.isChecked) } return holder diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 255f04a..8c2a0ba 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -43,6 +43,8 @@ Force a country of origin: Random country Apply this setting to all selected apps: + Enabled Quick Privacy to use functionalities + Fake my location @@ -62,12 +64,16 @@ past month past year Allow or deny trackers in apps + HH:mm + MMM d - EEE + MMM yyyy Block trackers Opt for the trackers you want to activate/desactivate. No trackers were detected yet. If new trackers are detected they will be updated here. No trackers were detected yet. All future trackers will be blocked. + Enable Quick Privacy to be able to activate/deactivate trackers. Quick protection enables these settings when turned on -- cgit v1.2.1