diff options
author | Guillaume Jacquart <guillaume.jacquart@hoodbrains.com> | 2022-03-21 17:13:10 +0000 |
---|---|---|
committer | Guillaume Jacquart <guillaume.jacquart@hoodbrains.com> | 2022-03-21 17:13:10 +0000 |
commit | 43e303886715d6115273cfba014a54805d3a1389 (patch) | |
tree | 799c478bff90fcada978801801b198873aad9338 /app | |
parent | d534cee490986771896f4fd2ca07742007ab6751 (diff) |
Add PVC Widget #5076
Diffstat (limited to 'app')
28 files changed, 992 insertions, 34 deletions
diff --git a/app/build.gradle b/app/build.gradle index fe3f903..b9b0613 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -100,6 +100,7 @@ android { buildFeatures { dataBinding true + viewBinding true } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bab78c2..c91f330 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,34 +1,55 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - package="foundation.e.privacycentralapp"> + package="foundation.e.privacycentralapp" + > - <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> - <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> - <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + <uses-permission + android:name="android.permission.WRITE_SECURE_SETTINGS" tools:ignore="ProtectedPermissions" /> - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" + <uses-permission + android:name="android.permission.INTERACT_ACROSS_USERS_FULL" tools:ignore="ProtectedPermissions" /> <uses-permission android:name="lineageos.permission.ACCESS_BLOCKER" /> - - <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" + <uses-permission + android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" /> <application - android:name=".PrivacyCentralApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" + android:name=".PrivacyCentralApplication" android:persistent="${persistent}" android:supportsRtl="true" android:theme="@style/Theme.PrivacyCentralApp" android:windowSoftInputMode="adjustResize" - tools:replace="android:icon,android:label,android:theme" > + <receiver + android:exported="true" + android:name=".Widget" + > + <intent-filter> + <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> + </intent-filter> + + <meta-data + android:name="android.appwidget.provider" + android:resource="@xml/widget_info" + /> + </receiver> + <receiver android:name=".widget.WidgetCommandReceiver"> + <intent-filter> + <action android:name="toggle_privacy" /> + </intent-filter> + </receiver> + <activity android:name=".main.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt index 639e7b4..fa4a3e3 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt @@ -43,6 +43,7 @@ import foundation.e.privacymodules.permissions.PermissionsPrivacyModule import foundation.e.privacymodules.permissions.data.ApplicationDescription import foundation.e.privacymodules.trackers.api.BlockTrackersPrivacyModule import foundation.e.privacymodules.trackers.api.TrackTrackersPrivacyModule +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.GlobalScope /** @@ -76,7 +77,7 @@ class DependencyContainer(val app: Application) { private val appListsRepository by lazy { AppListsRepository(permissionsModule, context, GlobalScope) } // Usecases - private val getQuickPrivacyStateUseCase by lazy { + val getQuickPrivacyStateUseCase by lazy { GetQuickPrivacyStateUseCase(localStateRepository) } private val ipScramblingStateUseCase by lazy { @@ -87,7 +88,7 @@ class DependencyContainer(val app: Application) { } private val appListUseCase = AppListUseCase(appListsRepository) - private val trackersStatisticsUseCase by lazy { + val trackersStatisticsUseCase by lazy { TrackersStatisticsUseCase(trackTrackersPrivacyModule, blockTrackersPrivacyModule, appListsRepository, context.resources) } @@ -126,11 +127,21 @@ class DependencyContainer(val app: Application) { } // Background + @FlowPreview fun initBackgroundSingletons() { trackersStateUseCase ipScramblingStateUseCase fakeLocationStateUseCase UpdateTrackersWorker.periodicUpdate(context) + + Widget.startListening( + context, + getQuickPrivacyStateUseCase, + ipScramblingStateUseCase, + trackersStatisticsUseCase, + trackersStateUseCase, + fakeLocationStateUseCase + ) } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/PrivacyCentralApplication.kt b/app/src/main/java/foundation/e/privacycentralapp/PrivacyCentralApplication.kt index 28e96e0..2d90c93 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/PrivacyCentralApplication.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/PrivacyCentralApplication.kt @@ -19,12 +19,14 @@ package foundation.e.privacycentralapp import android.app.Application import com.mapbox.mapboxsdk.Mapbox +import kotlinx.coroutines.FlowPreview class PrivacyCentralApplication : Application() { // Initialize the dependency container. val dependencyContainer: DependencyContainer by lazy { DependencyContainer(this) } + @FlowPreview override fun onCreate() { super.onCreate() Mapbox.getTelemetry()?.setUserTelemetryRequestState(false) diff --git a/app/src/main/java/foundation/e/privacycentralapp/common/GraphHolder.kt b/app/src/main/java/foundation/e/privacycentralapp/common/GraphHolder.kt index db6bc7e..929d838 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/common/GraphHolder.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/common/GraphHolder.kt @@ -34,6 +34,7 @@ import com.github.mikephil.charting.highlight.Highlight import com.github.mikephil.charting.listener.OnChartValueSelectedListener import com.github.mikephil.charting.utils.MPPointF import foundation.e.privacycentralapp.R +import foundation.e.privacycentralapp.extensions.dpToPxF class GraphHolder(val barChart: BarChart, val context: Context, val isMarkerAbove: Boolean = true) { var data = emptyList<Int>() @@ -113,8 +114,6 @@ class GraphHolder(val barChart: BarChart, val context: Context, val isMarkerAbov } } -private fun Int.dpToPxF(context: Context): Float = this.toFloat() * context.resources.displayMetrics.density - class PeriodMarkerView(context: Context, private val isMarkerAbove: Boolean = true) : MarkerView(context, R.layout.chart_tooltip) { enum class ArrowPosition { LEFT, CENTER, RIGHT } 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 ad8f565..69dd0d8 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 @@ -34,7 +34,8 @@ import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit class TrackersStatisticsUseCase( - private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule, + // TODO private + val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule, private val blockTrackersPrivacyModule: IBlockTrackersPrivacyModule, private val appListsRepository: AppListsRepository, private val resources: Resources @@ -46,6 +47,7 @@ class TrackersStatisticsUseCase( offer(Unit) } } + trackTrackersPrivacyModule.addListener(listener) awaitClose { trackTrackersPrivacyModule.removeListener(listener) } } @@ -57,6 +59,10 @@ class TrackersStatisticsUseCase( ) to trackTrackersPrivacyModule.getTrackersCount() } + fun getDayTrackersCalls() = trackTrackersPrivacyModule.getPastDayTrackersCalls() + + fun getDayTrackersCount() = trackTrackersPrivacyModule.getPastDayTrackersCount() + private fun buildDayLabels(): List<String> { val formater = DateTimeFormatter.ofPattern( resources.getString(R.string.trackers_graph_hours_period_format) diff --git a/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/UpdateWidgetUseCase.kt b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/UpdateWidgetUseCase.kt new file mode 100644 index 0000000..dab0b18 --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/UpdateWidgetUseCase.kt @@ -0,0 +1,33 @@ +/* + * 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.usecases + +import foundation.e.privacycentralapp.data.repositories.LocalStateRepository +import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule + +class UpdateWidgetUseCase( + private val localStateRepository: LocalStateRepository, + private val trackTrackersPrivacyModule: ITrackTrackersPrivacyModule, +) { + init { + trackTrackersPrivacyModule.addListener(object : ITrackTrackersPrivacyModule.Listener { + override fun onNewData() { + } + }) + } +} diff --git a/app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt b/app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt index a870d33..2074b69 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/extensions/AnyExtension.kt @@ -24,3 +24,5 @@ fun Any.toText(context: Context) = when (this) { is String -> this else -> this.toString() } + +fun Int.dpToPxF(context: Context): Float = this.toFloat() * context.resources.displayMetrics.density 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 41f6509..4d191bd 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 @@ -150,6 +150,8 @@ class DashboardFragment : else R.drawable.ic_shield_off ) + binding.togglePrivacyCentral.isChecked = state.isQuickPrivacyEnabled + val trackersEnabled = state.isQuickPrivacyEnabled && state.isAllTrackersBlocked binding.stateTrackers.text = getString( if (trackersEnabled) R.string.dashboard_state_trackers_on diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt new file mode 100644 index 0000000..1969fe5 --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/widget/Widget.kt @@ -0,0 +1,137 @@ +/* + * 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 + +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 +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.sample +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch + +/** + * Implementation of App Widget functionality. + */ +class Widget : AppWidgetProvider() { + @FlowPreview + override fun onUpdate( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray + ) { + render(context, state.value, appWidgetManager) + } + + override fun onEnabled(context: Context) { + // Enter relevant functionality for when the first widget is created + } + + override fun onDisabled(context: Context) { + // Enter relevant functionality for when the last widget is disabled + } + + @FlowPreview + companion object { + private var updateWidgetJob: Job? = null + + private var state: StateFlow<State> = MutableStateFlow(State()) + + 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 -> + + State( + isQuickPrivacyEnabled = isQuickPrivacyEnabled, + isAllTrackersBlocked = isAllTrackersBlocked, + locationMode = locationMode, + internetPrivacyMode = internetPrivacyMode + ) + }.sample(50) + .combine( + trackersStatisticsUseCase.listenUpdates() + .onStart { emit(Unit) } + .debounce(5000) + ) { state, _ -> + state.copy( + dayStatistics = trackersStatisticsUseCase.getDayTrackersCalls(), + activeTrackersCount = trackersStatisticsUseCase.getDayTrackersCount() + ) + }.stateIn( + scope = coroutineScope, + started = SharingStarted.Eagerly, + initialValue = State() + ) + } + + fun startListening( + appContext: Context, + getPrivacyStateUseCase: GetQuickPrivacyStateUseCase, + ipScramblingStateUseCase: IpScramblingStateUseCase, + trackersStatisticsUseCase: TrackersStatisticsUseCase, + trackersStateUseCase: TrackersStateUseCase, + fakeLocationStateUseCase: FakeLocationStateUseCase + ) { + state = initState( + getPrivacyStateUseCase, + ipScramblingStateUseCase, + trackersStatisticsUseCase, + trackersStateUseCase, + fakeLocationStateUseCase, + GlobalScope + ) + + updateWidgetJob?.cancel() + updateWidgetJob = GlobalScope.launch(Dispatchers.Main) { + state.collect { + render(appContext, it, AppWidgetManager.getInstance(appContext)) + } + } + } + } +} diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt new file mode 100644 index 0000000..87e88df --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetCommandReceiver.kt @@ -0,0 +1,39 @@ +/* + * 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.widget + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import foundation.e.privacycentralapp.PrivacyCentralApplication + +class WidgetCommandReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + when (intent?.action) { + ACTION_TOGGLE_PRIVACY -> { + (context?.applicationContext as? PrivacyCentralApplication) + ?.dependencyContainer?.getQuickPrivacyStateUseCase?.toggle() + } + else -> {} + } + } + + companion object { + const val ACTION_TOGGLE_PRIVACY = "toggle_privacy" + } +} diff --git a/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt new file mode 100644 index 0000000..ae2238f --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/widget/WidgetUI.kt @@ -0,0 +1,167 @@ +/* + * 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.widget + +import android.app.PendingIntent +import android.app.PendingIntent.FLAG_UPDATE_CURRENT +import android.appwidget.AppWidgetManager +import android.content.ComponentName +import android.content.Context +import android.content.Intent +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.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 dayStatistics: List<Int> = emptyList(), + val activeTrackersCount: Int = 0, +) { + val isTrackersDenied get() = isQuickPrivacyEnabled && isAllTrackersBlocked + val isLocationHidden get() = isQuickPrivacyEnabled && locationMode != LocationMode.REAL_LOCATION +} + +@FlowPreview +fun render( + context: Context, + state: State, + appWidgetManager: AppWidgetManager, +) { + val views = RemoteViews(context.packageName, R.layout.widget) + views.apply { + setOnClickPendingIntent( + R.id.settings_btn, + PendingIntent.getActivity( + context, 0, Intent(context, MainActivity::class.java), FLAG_UPDATE_CURRENT + ) + ) + + setImageViewResource( + R.id.state_icon, + if (state.isQuickPrivacyEnabled) R.drawable.ic_shield_on else R.drawable.ic_shield_off + ) + setTextViewText( + R.id.state_label, + context.getString( + if (state.isQuickPrivacyEnabled) R.string.widget_state_title_on + else R.string.widget_state_title_off + ) + ) + setImageViewResource( + R.id.toggle_privacy_central, + if (state.isQuickPrivacyEnabled) R.drawable.ic_switch_enabled + else R.drawable.ic_switch_disabled + ) + + setOnClickPendingIntent( + R.id.toggle_privacy_central, + PendingIntent.getBroadcast( + context, + 0, + Intent(context, WidgetCommandReceiver::class.java).apply { + action = ACTION_TOGGLE_PRIVACY + }, + FLAG_UPDATE_CURRENT + ) + ) + + setTextViewText( + R.id.state_trackers, + context.getString( + if (state.isTrackersDenied) R.string.widget_state_trackers_on + else R.string.widget_state_trackers_off + ) + ) + + setTextViewText( + R.id.state_geolocation, + context.getString( + if (state.isLocationHidden) R.string.widget_state_geolocation_on + else R.string.widget_state_geolocation_off + ) + ) + + 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_title_on + ) + ) + + val loading = state.internetPrivacyMode in listOf( + InternetPrivacyMode.HIDE_IP_LOADING, + InternetPrivacyMode.REAL_IP_LOADING + ) + + setViewVisibility(R.id.state_ip_address, if (loading) View.GONE else View.VISIBLE) + + setViewVisibility(R.id.state_ip_address_loader, if (loading) View.VISIBLE else View.GONE) + + val graphHeightPx = 26.dpToPxF(context) + val maxValue = state.dayStatistics.maxOrNull().let { if (it == null || it == 0) 1 else it } + val ratio = graphHeightPx / maxValue + + state.dayStatistics.zip(barIds).forEach { (value, viewId) -> + val topPadding = graphHeightPx - value * ratio + setViewPadding(viewId, 0, topPadding.toInt(), 0, 0) + } + + setTextViewText(R.id.graph_legend, context.getString(R.string.widget_graph_trackers_legend, state.activeTrackersCount.toString())) + } + + appWidgetManager.updateAppWidget(ComponentName(context, Widget::class.java), views) +} + +private val barIds = listOf( + R.id.widget_graph_bar_0, + R.id.widget_graph_bar_1, + R.id.widget_graph_bar_2, + R.id.widget_graph_bar_3, + R.id.widget_graph_bar_4, + R.id.widget_graph_bar_5, + R.id.widget_graph_bar_6, + R.id.widget_graph_bar_7, + R.id.widget_graph_bar_8, + R.id.widget_graph_bar_9, + R.id.widget_graph_bar_10, + R.id.widget_graph_bar_11, + R.id.widget_graph_bar_12, + R.id.widget_graph_bar_13, + R.id.widget_graph_bar_14, + R.id.widget_graph_bar_15, + R.id.widget_graph_bar_16, + R.id.widget_graph_bar_17, + R.id.widget_graph_bar_18, + R.id.widget_graph_bar_19, + R.id.widget_graph_bar_20, + R.id.widget_graph_bar_21, + R.id.widget_graph_bar_22, + R.id.widget_graph_bar_23 +) diff --git a/app/src/main/res/drawable/bg_graph_bar.xml b/app/src/main/res/drawable/bg_graph_bar.xml new file mode 100644 index 0000000..cdeae6e --- /dev/null +++ b/app/src/main/res/drawable/bg_graph_bar.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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/>. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/purple_200" /> +</shape>
\ No newline at end of file diff --git a/app/src/main/res/drawable/bg_widget.xml b/app/src/main/res/drawable/bg_widget.xml new file mode 100644 index 0000000..b0d91de --- /dev/null +++ b/app/src/main/res/drawable/bg_widget.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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/>. + --> + +<!-- +Background for widgets to make the rounded corners based on the +appWidgetRadius attribute value +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + > + + <corners android:radius="12dp" /> + <solid android:color="@color/widget_background" /> +</shape>
\ No newline at end of file diff --git a/app/src/main/res/drawable/dummy_img_map_picker.png b/app/src/main/res/drawable/dummy_img_map_picker.png Binary files differdeleted file mode 100644 index c1cf32b..0000000 --- a/app/src/main/res/drawable/dummy_img_map_picker.png +++ /dev/null diff --git a/app/src/main/res/drawable/dummy_leakage_analytics.png b/app/src/main/res/drawable/dummy_leakage_analytics.png Binary files differdeleted file mode 100644 index 5379cd4..0000000 --- a/app/src/main/res/drawable/dummy_leakage_analytics.png +++ /dev/null diff --git a/app/src/main/res/drawable/dummy_trackers_usage.png b/app/src/main/res/drawable/dummy_trackers_usage.png Binary files differdeleted file mode 100644 index 9b7e090..0000000 --- a/app/src/main/res/drawable/dummy_trackers_usage.png +++ /dev/null diff --git a/app/src/main/res/drawable/ic_quick_privacy_off.png b/app/src/main/res/drawable/ic_quick_privacy_off.png Binary files differdeleted file mode 100644 index 90f1b04..0000000 --- a/app/src/main/res/drawable/ic_quick_privacy_off.png +++ /dev/null diff --git a/app/src/main/res/drawable/ic_quick_privacy_on.png b/app/src/main/res/drawable/ic_quick_privacy_on.png Binary files differdeleted file mode 100644 index 99f6719..0000000 --- a/app/src/main/res/drawable/ic_quick_privacy_on.png +++ /dev/null diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 0000000..e68deb7 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19.14,12.94C19.18,12.64 19.2,12.33 19.2,12C19.2,11.68 19.18,11.36 19.13,11.06L21.16,9.48C21.34,9.34 21.39,9.07 21.28,8.87L19.36,5.55C19.24,5.33 18.99,5.26 18.77,5.33L16.38,6.29C15.88,5.91 15.35,5.59 14.76,5.35L14.4,2.81C14.36,2.57 14.16,2.4 13.92,2.4H10.08C9.84,2.4 9.65,2.57 9.61,2.81L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33C5.02,5.25 4.77,5.33 4.65,5.55L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48L4.89,11.06C4.84,11.36 4.8,11.69 4.8,12C4.8,12.31 4.82,12.64 4.87,12.94L2.84,14.52C2.66,14.66 2.61,14.93 2.72,15.13L4.64,18.45C4.76,18.67 5.01,18.74 5.23,18.67L7.62,17.71C8.12,18.09 8.65,18.41 9.24,18.65L9.6,21.19C9.65,21.43 9.84,21.6 10.08,21.6H13.92C14.16,21.6 14.36,21.43 14.39,21.19L14.75,18.65C15.34,18.41 15.88,18.09 16.37,17.71L18.76,18.67C18.98,18.75 19.23,18.67 19.35,18.45L21.27,15.13C21.39,14.91 21.34,14.66 21.15,14.52L19.14,12.94ZM12,15.6C10.02,15.6 8.4,13.98 8.4,12C8.4,10.02 10.02,8.4 12,8.4C13.98,8.4 15.6,10.02 15.6,12C15.6,13.98 13.98,15.6 12,15.6Z" + 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 f3565d5..7c2fc8e 100644 --- a/app/src/main/res/drawable/ic_shield_off.xml +++ b/app/src/main/res/drawable/ic_shield_off.xml @@ -3,13 +3,13 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - <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="#F8432E"/> - <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:fillColor="#F8432E" - android:fillType="evenOdd"/> + <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="#F8432E"/> + <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:fillColor="#F8432E" + 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 39416ed..b70dc6e 100644 --- a/app/src/main/res/drawable/ic_shield_on.xml +++ b/app/src/main/res/drawable/ic_shield_on.xml @@ -3,15 +3,15 @@ android:height="25dp" android:viewportWidth="24" android:viewportHeight="25"> - <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"/> + <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"/> </vector> diff --git a/app/src/main/res/drawable/ic_switch_disabled.xml b/app/src/main/res/drawable/ic_switch_disabled.xml new file mode 100644 index 0000000..4158483 --- /dev/null +++ b/app/src/main/res/drawable/ic_switch_disabled.xml @@ -0,0 +1,8 @@ +<vector android:height="30dp" android:viewportHeight="29" + android:viewportWidth="53" android:width="54.827587dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillAlpha="0.38" android:fillColor="#ffffff" android:pathData="M14.5,0L38.5,0A14.5,14.5 0,0 1,53 14.5L53,14.5A14.5,14.5 0,0 1,38.5 29L14.5,29A14.5,14.5 0,0 1,0 14.5L0,14.5A14.5,14.5 0,0 1,14.5 0z"/> + <path android:fillColor="#121212" android:fillType="evenOdd" android:pathData="M14.9869,26.9286C21.9321,26.9286 27.5623,21.3641 27.5623,14.5C27.5623,7.6359 21.9321,2.0714 14.9869,2.0714C8.0417,2.0714 2.4115,7.6359 2.4115,14.5C2.4115,21.3641 8.0417,26.9286 14.9869,26.9286Z"/> + <path android:fillAlpha="0.05" android:fillColor="#ffffff" + android:fillType="evenOdd" android:pathData="M14.9869,26.9286C21.9321,26.9286 27.5623,21.3641 27.5623,14.5C27.5623,7.6359 21.9321,2.0714 14.9869,2.0714C8.0417,2.0714 2.4115,7.6359 2.4115,14.5C2.4115,21.3641 8.0417,26.9286 14.9869,26.9286Z"/> + <path android:fillColor="#ffffff" android:fillType="evenOdd" android:pathData="M14.9869,26.9286C21.9321,26.9286 27.5623,21.3641 27.5623,14.5C27.5623,7.6359 21.9321,2.0714 14.9869,2.0714C8.0417,2.0714 2.4115,7.6359 2.4115,14.5C2.4115,21.3641 8.0417,26.9286 14.9869,26.9286Z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_switch_enabled.xml b/app/src/main/res/drawable/ic_switch_enabled.xml new file mode 100644 index 0000000..10e83f7 --- /dev/null +++ b/app/src/main/res/drawable/ic_switch_enabled.xml @@ -0,0 +1,22 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="55dp" + android:height="30dp" + android:viewportWidth="55" + android:viewportHeight="30"> + <path + android:pathData="M15.3417,0L40.3417,0A14.5,14.5 0,0 1,54.8417 14.5L54.8417,14.5A14.5,14.5 0,0 1,40.3417 29L15.3417,29A14.5,14.5 0,0 1,0.8417 14.5L0.8417,14.5A14.5,14.5 0,0 1,15.3417 0z" + android:fillColor="#2CC766"/> + <path + android:pathData="M39.5854,26.9286C46.6616,26.9286 52.398,21.3642 52.398,14.5C52.398,7.6359 46.6616,2.0715 39.5854,2.0715C32.5091,2.0715 26.7727,7.6359 26.7727,14.5C26.7727,21.3642 32.5091,26.9286 39.5854,26.9286Z" + android:fillColor="#121212" + android:fillType="evenOdd"/> + <path + android:pathData="M39.5854,26.9286C46.6616,26.9286 52.398,21.3642 52.398,14.5C52.398,7.6359 46.6616,2.0715 39.5854,2.0715C32.5091,2.0715 26.7727,7.6359 26.7727,14.5C26.7727,21.3642 32.5091,26.9286 39.5854,26.9286Z" + android:fillColor="#ffffff" + android:fillAlpha="0.05" + android:fillType="evenOdd"/> + <path + android:pathData="M39.5854,26.9286C46.6616,26.9286 52.398,21.3642 52.398,14.5C52.398,7.6359 46.6616,2.0715 39.5854,2.0715C32.5091,2.0715 26.7727,7.6359 26.7727,14.5C26.7727,21.3642 32.5091,26.9286 39.5854,26.9286Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> +</vector> diff --git a/app/src/main/res/layout/widget.xml b/app/src/main/res/layout/widget.xml new file mode 100644 index 0000000..612221a --- /dev/null +++ b/app/src/main/res/layout/widget.xml @@ -0,0 +1,391 @@ +<!-- + ~ 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/>. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:orientation="vertical" + android:background="@drawable/bg_widget" + > + <LinearLayout + android:layout_width="match_parent" + android:layout_height="40dp" + android:orientation="horizontal" + android:gravity="center_vertical"> + <TextView + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginLeft="12dp" + android:textSize="16sp" + android:textColor="@color/on_surface_high_emphasis" + android:textAllCaps="true" + android:text="@string/widget_title" + /> + <ImageView + android:id="@+id/settings_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="8dp" + android:src="@drawable/ic_settings" + /> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="16dp" + > + <ImageView + android:id="@+id/state_icon" + android:layout_height="25dp" + android:layout_width="24dp" + android:src="@drawable/ic_shield_off" + android:scaleType="fitCenter" + /> + <TextView + android:id="@+id/state_label" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginLeft="8dp" + android:text="@string/widget_state_title_off" + android:textSize="12sp" + android:textColor="@color/on_primary_medium_emphasis" + /> + <ImageView + android:id="@+id/toggle_privacy_central" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_switch_disabled" + /> + + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginHorizontal="24dp" + android:layout_marginTop="16dp" + android:layout_marginBottom="16dp"> + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + > + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dashboard_state_trackers_label" + android:textSize="10sp" + android:textColor="@color/on_primary_disabled" + android:layout_marginBottom="4dp" + android:textAllCaps="true" + /> + <TextView + android:id="@+id/state_trackers" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dashboard_state_trackers_off" + android:textSize="14sp" + android:textColor="@color/on_primary_high_emphasis" + android:textAllCaps="true" + /> + </LinearLayout> + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + > + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dashboard_state_geolocation_label" + android:textSize="10sp" + android:textColor="@color/on_primary_disabled" + android:layout_marginBottom="4dp" + android:textAllCaps="true" + /> + <TextView + android:id="@+id/state_geolocation" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dashboard_state_geolocation_off" + android:textSize="14sp" + android:textColor="@color/on_primary_high_emphasis" + android:textAllCaps="true" + /> + </LinearLayout> + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:orientation="vertical" + > + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dashboard_state_ipaddress_label" + android:textSize="10sp" + android:textColor="@color/on_primary_disabled" + android:layout_marginBottom="4dp" + android:textAllCaps="true" + /> + <TextView + android:id="@+id/state_ip_address" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/dashboard_state_ipaddress_off" + android:textSize="14sp" + android:textColor="@color/on_primary_high_emphasis" + android:textAllCaps="true" + android:visibility="gone" + /> + <ProgressBar + android:id="@+id/state_ip_address_loader" + android:layout_width="16dp" + android:layout_height="16dp" + android:indeterminate="true" + android:visibility="visible"/> + </LinearLayout> + </LinearLayout> + + + <LinearLayout + android:layout_width="match_parent" + android:layout_marginTop="16dp" + android:layout_marginHorizontal="24dp" + android:layout_height="26dp" + > + <ImageView + android:id="@+id/widget_graph_bar_0" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_1" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_2" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_3" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_4" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_5" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_6" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_7" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_8" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_9" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_10" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_11" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_12" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_13" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_14" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_15" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_16" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_17" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_18" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_19" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_20" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_21" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_22" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + android:layout_marginRight="1.5dp" + /> + <ImageView + android:id="@+id/widget_graph_bar_23" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="match_parent" + android:src="@color/accent" + /> + </LinearLayout> + +<!-- <com.github.mikephil.charting.charts.BarChart--> +<!-- android:id="@+id/graph"--> +<!-- android:layout_height="144dp"--> +<!-- android:layout_width="match_parent"--> +<!-- android:layout_marginHorizontal="24dp"--> +<!-- />--> + + <TextView + android:id="@+id/graph_legend" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="0 Trackers" + android:textSize="12sp" + android:textColor="@color/on_primary_high_emphasis" + android:layout_marginTop="16dp" + android:layout_marginHorizontal="24dp" + android:layout_marginBottom="24dp" + /> + +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index d867b74..2bf09cc 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -26,4 +26,18 @@ <color name="e_blue2">@lineageos.platform:color/color_default_blue1</color> <color name="dark_color">#263238</color> <color name="blue_unselected">#AADCFE</color> + <color name="light_blue_50">#FFE1F5FE</color> + <color name="light_blue_200">#FF81D4FA</color> + <color name="light_blue_600">#FF039BE5</color> + <color name="light_blue_900">#FF01579B</color> + + + <!-- Widget --> + <color name="on_surface_high_emphasis">#DEFFFFFF</color> + <color name="on_primary_medium_emphasis">#BDFFFFFF</color> + <color name="on_primary_high_emphasis">#FFFFFF</color> + <color name="on_primary_disabled">#61FFFFFF</color> + + <color name="widget_background">#33000000</color> + </resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 30f017c..a0df574 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -113,4 +113,22 @@ <string name="following_trackers_in_use">Following trackers are in use</string> <string name="enable_disable_tracker_info">Enable or disable this tracker for the following apps</string> <string name="tracker">Tracker</string> + <string name="appwidget_text">EXAMPLE</string> + <string name="add_widget">Add widget</string> + <string name="app_widget_description">This is an app widget description</string> + + <!-- Widget --> + <string name="widget_title">Extended privacy</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_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> + <string name="widget_state_geolocation_label">@string/dashboard_state_geolocation_label</string> + <string name="widget_state_geolocation_off">@string/dashboard_state_geolocation_off</string> + <string name="widget_state_geolocation_on">@string/dashboard_state_geolocation_on</string> + <string name="widget_state_ipaddress_label">@string/dashboard_state_ipaddress_label</string> + <string name="widget_state_ipaddress_off">@string/dashboard_state_ipaddress_off</string> + <string name="widget_state_ipaddress_on">@string/dashboard_state_ipaddress_on</string> + <string name="widget_graph_trackers_legend">@string/dashboard_graph_trackers_legend</string> </resources>
\ No newline at end of file diff --git a/app/src/main/res/xml/widget_info.xml b/app/src/main/res/xml/widget_info.xml new file mode 100644 index 0000000..b20fd31 --- /dev/null +++ b/app/src/main/res/xml/widget_info.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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/>. + --> + +<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" + android:initialKeyguardLayout="@layout/widget" + android:initialLayout="@layout/widget" + android:minHeight="180dp" + android:minWidth="250dp" + + android:updatePeriodMillis="0" + android:widgetCategory="home_screen" + />
\ No newline at end of file |