diff options
author | jacquarg <guillaume.jacquart@hoodbrains.com> | 2021-10-31 19:11:27 +0100 |
---|---|---|
committer | jacquarg <guillaume.jacquart@hoodbrains.com> | 2021-10-31 19:11:27 +0100 |
commit | b0d9079811b08b95dd623d94c1d4338f28597d4c (patch) | |
tree | 52f409643ee6733c232e1218eb2ecbd1e4999240 /app/src | |
parent | 880a48c87686dfc976a11ade9429bc9c50d4c7f2 (diff) |
Add graph view on home dashboard.
Diffstat (limited to 'app/src')
13 files changed, 236 insertions, 142 deletions
diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt index 1f7cd3d..ccb0a75 100644 --- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt +++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt @@ -24,6 +24,8 @@ import foundation.e.privacycentralapp.data.repositories.LocalStateRepository import foundation.e.privacycentralapp.domain.usecases.AppListUseCase import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase +import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase +import foundation.e.privacycentralapp.dummy.TrackTrackersPrivacyMock import foundation.e.privacycentralapp.features.dashboard.DashBoardViewModelFactory import foundation.e.privacycentralapp.features.internetprivacy.InternetPrivacyViewModelFactory import foundation.e.privacycentralapp.features.location.FakeLocationViewModelFactory @@ -66,7 +68,7 @@ class DependencyContainer constructor(val app: Application) { // Repositories private val localStateRepository by lazy { LocalStateRepository(context) } - + private val trackTrackersPrivacyModule by lazy { TrackTrackersPrivacyMock() } // Usecases private val getQuickPrivacyStateUseCase by lazy { GetQuickPrivacyStateUseCase(localStateRepository) @@ -77,9 +79,12 @@ class DependencyContainer constructor(val app: Application) { private val appListUseCase by lazy { AppListUseCase(permissionsModule) } + private val trackersStatisticsUseCase by lazy { + TrackersStatisticsUseCase(trackTrackersPrivacyModule) + } val dashBoardViewModelFactory by lazy { - DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase) + DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase) } val fakeLocationViewModelFactory by lazy { 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 new file mode 100644 index 0000000..93fbc08 --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/domain/usecases/TrackersStatisticsUseCase.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 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.dummy.TrackTrackersPrivacyMock + +class TrackersStatisticsUseCase( + private val trackTrackersPrivacyModule: TrackTrackersPrivacyMock +) { + + fun getPast24HoursTrackersCalls(): List<Int> { + return trackTrackersPrivacyModule.getPast24HoursTrackersCalls() + } +} diff --git a/app/src/main/java/foundation/e/privacycentralapp/dummy/TrackTrackersPrivacyMock.kt b/app/src/main/java/foundation/e/privacycentralapp/dummy/TrackTrackersPrivacyMock.kt new file mode 100644 index 0000000..76da6a2 --- /dev/null +++ b/app/src/main/java/foundation/e/privacycentralapp/dummy/TrackTrackersPrivacyMock.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 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.dummy + +import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule +import foundation.e.privacymodules.trackers.Tracker + +class TrackTrackersPrivacyMock : ITrackTrackersPrivacyModule { + override fun getPast24HoursTrackersCalls(): List<Int> { + return listOf( + 2000, 2300, 130, 2500, 1000, 2000, + 2000, 2300, 130, 2500, 1000, 2000, + 2000, 2300, 130, 2500, 1000, 2000, + 2000, 2300, 130, 2500, 1000, 2000 + ) + } + + override fun getPastMonthTrackersCalls(): List<Int> { + return listOf( + 20000, 23000, 24130, 12500, 31000, 22000, + 20000, 23000, 24130, 12500, 31000, 22000, + 20000, 23000, 24130, 12500, 31000, 22000, + 20000, 23000, 24130, 12500, 31000, 22000, + 20000, 23000, 24130, 12500, 31000, 22000 + ) + } + + override fun getPastYearTrackersCalls(): List<Int> { + return listOf( + 620000, 823000, 424130, 712500, 831000, 922000, + 620000, 823000, 424130, 712500, 831000, 922000 + ) + } + + override fun getTrackersCount(): Int { + return 72 + } + + override fun getTrackersForApp(appUid: Int): List<Tracker> { + return listOf( + Tracker("Crashlytics", null), + Tracker(label = "Facebook", null) + ) + } +} 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 9d439ec..d38d4f6 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 @@ -26,7 +26,9 @@ import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase +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 @@ -45,24 +47,17 @@ class DashboardFeature( initialState, actor, reducer, coroutineScope, { message -> Log.d("DashboardFeature", message) }, singleEventProducer ) { - sealed class State() { - object LoadingState : State() - data class DisabledState( - val totalGraph: Int = 230, - // val graphData - val trackersCount: Int = 77, - val activeTrackersCount: Int = 22 - ) : State() - data class EnabledState( - val isAllTrackersBlocked: Boolean = false, - val locationMode: LocationMode = LocationMode.CUSTOM_LOCATION, - val internetPrivacyMode: InternetPrivacyMode, - val totalGraph: Int = 150, - // val graphData - val trackersCount: Int = 80, - val activeTrackersCount: Int = 10 - ) : State() - } + data class State( + val isQuickPrivacyEnabled: Boolean = false, + val isAllTrackersBlocked: Boolean = false, + val locationMode: LocationMode = LocationMode.REAL_LOCATION, + val internetPrivacyMode: InternetPrivacyMode = InternetPrivacyMode.REAL_IP, + val totalGraph: Int? = null, + // val graphData + val trackersCount: Int? = null, + val activeTrackersCount: Int? = null, + val dayStatistics: List<Int>? = null + ) sealed class SingleEvent { object NavigateToQuickProtectionSingleEvent : SingleEvent() @@ -89,6 +84,7 @@ class DashboardFeature( object NoEffect : Effect() data class UpdateStateEffect(val isEnabled: Boolean) : Effect() data class IpScramblingModeUpdatedEffect(val mode: InternetPrivacyMode) : Effect() + data class TrackersStatisticsUpdatedEffect(val dayStatistics: List<Int>) : Effect() object OpenQuickPrivacyProtectionEffect : Effect() data class OpenDashboardEffect( @@ -118,36 +114,17 @@ class DashboardFeature( fun create( coroutineScope: CoroutineScope, getPrivacyStateUseCase: GetQuickPrivacyStateUseCase, - ipScramblingStateUseCase: IpScramblingStateUseCase + ipScramblingStateUseCase: IpScramblingStateUseCase, + trackersStatisticsUseCase: TrackersStatisticsUseCase ): DashboardFeature = DashboardFeature( - initialState = State.DisabledState(), + initialState = State(), coroutineScope, reducer = { state, effect -> - if (state is State.LoadingState) state - else when (effect) { - is Effect.UpdateStateEffect -> when { - effect.isEnabled && state is State.EnabledState - || !effect.isEnabled && state is State.DisabledState -> state - effect.isEnabled && state is State.DisabledState -> State.EnabledState( - isAllTrackersBlocked = false, - locationMode = LocationMode.REAL_LOCATION, - internetPrivacyMode = InternetPrivacyMode.REAL_IP, - totalGraph = state.totalGraph, - // val graphData - trackersCount = state.trackersCount, - activeTrackersCount = state.activeTrackersCount - ) - !effect.isEnabled && state is State.EnabledState -> State.DisabledState( - totalGraph = state.totalGraph, - // val graphData - trackersCount = state.trackersCount, - activeTrackersCount = state.activeTrackersCount - ) - else -> state - } - is Effect.IpScramblingModeUpdatedEffect -> if (state is State.EnabledState) state.copy(internetPrivacyMode = effect.mode) - else state + when (effect) { + is Effect.UpdateStateEffect -> state.copy(isQuickPrivacyEnabled = effect.isEnabled) + is Effect.IpScramblingModeUpdatedEffect -> state.copy(internetPrivacyMode = effect.mode) + is Effect.TrackersStatisticsUpdatedEffect -> state.copy(dayStatistics = effect.dayStatistics) /*is Effect.OpenDashboardEffect -> State.DashboardState( effect.trackersCount, @@ -196,13 +173,11 @@ class DashboardFeature( else -> state } }, - actor = { state: State, action: Action -> + actor = { _: State, action: Action -> Log.d("Feature", "action: $action") when (action) { Action.TogglePrivacyAction -> { - if (state != State.LoadingState) { - getPrivacyStateUseCase.toggle() - } + getPrivacyStateUseCase.toggle() flowOf(Effect.NoEffect) } @@ -213,6 +188,9 @@ class DashboardFeature( }, ipScramblingStateUseCase.internetPrivacyMode.map { Effect.IpScramblingModeUpdatedEffect(it) + }, + flow { + emit(Effect.TrackersStatisticsUpdatedEffect(trackersStatisticsUseCase.getPast24HoursTrackersCalls())) } ) /* 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 fade14b..abdf764 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 @@ -30,6 +30,9 @@ import androidx.fragment.app.activityViewModels import androidx.fragment.app.add import androidx.fragment.app.commit import androidx.lifecycle.lifecycleScope +import com.github.mikephil.charting.data.BarData +import com.github.mikephil.charting.data.BarDataSet +import com.github.mikephil.charting.data.BarEntry import foundation.e.flowmvi.MVIView import foundation.e.privacycentralapp.DependencyContainer import foundation.e.privacycentralapp.PrivacyCentralApplication @@ -39,9 +42,7 @@ import foundation.e.privacycentralapp.databinding.FragmentDashboardBinding import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode import foundation.e.privacycentralapp.domain.entities.LocationMode import foundation.e.privacycentralapp.extensions.viewModelProviderFactoryOf -import foundation.e.privacycentralapp.features.dashboard.DashboardFeature.State.DisabledState -import foundation.e.privacycentralapp.features.dashboard.DashboardFeature.State.EnabledState -import foundation.e.privacycentralapp.features.dashboard.DashboardFeature.State.LoadingState +import foundation.e.privacycentralapp.features.dashboard.DashboardFeature.State import foundation.e.privacycentralapp.features.internetprivacy.InternetPrivacyFragment import foundation.e.privacycentralapp.features.location.FakeLocationFragment import foundation.e.privacycentralapp.features.trackers.TrackersFragment @@ -77,13 +78,6 @@ class DashboardFragment : addToBackStack("dashboard") } } - is DashboardFeature.SingleEvent.NavigateToQuickProtectionSingleEvent -> { - requireActivity().supportFragmentManager.commit { - add<QuickProtectionFragment>(R.id.container) - setReorderingAllowed(true) - addToBackStack("dashboard") - } - } is DashboardFeature.SingleEvent.NavigateToInternetActivityPrivacySingleEvent -> { requireActivity().supportFragmentManager.commit { add<InternetPrivacyFragment>(R.id.container) @@ -116,6 +110,17 @@ class DashboardFragment : super.onViewCreated(view, savedInstanceState) binding = FragmentDashboardBinding.bind(view) + binding.graph.apply { + description = null + setTouchEnabled(false) + setDrawGridBackground(false) + setDrawBorders(false) + axisLeft.isEnabled = false + axisRight.isEnabled = false + xAxis.isEnabled = false + legend.isEnabled = false + } + binding.togglePrivacyCentral.setOnClickListener { viewModel.submitAction(DashboardFeature.Action.TogglePrivacyAction) } @@ -149,27 +154,26 @@ class DashboardFragment : textView.append(clickToMore) } - override fun render(state: DashboardFeature.State) { - val enabled = state is EnabledState + override fun render(state: State) { + binding.stateLabel.text = getString( - if (enabled) R.string.dashboard_state_label_on + if (state.isQuickPrivacyEnabled) R.string.dashboard_state_label_on else R.string.dashboard_state_label_off ) binding.togglePrivacyCentral.setImageResource( - if (enabled) R.drawable.ic_quick_privacy_on + if (state.isQuickPrivacyEnabled) R.drawable.ic_quick_privacy_on else R.drawable.ic_quick_privacy_off ) binding.stateLabel.setTextColor( getColor( requireContext(), - if (enabled) R.color.green_on + if (state.isQuickPrivacyEnabled) R.color.green_on else R.color.orange_off ) ) - val trackersEnabled = state is EnabledState && - state.isAllTrackersBlocked + val trackersEnabled = state.isQuickPrivacyEnabled && state.isAllTrackersBlocked binding.stateTrackers.text = getString( if (trackersEnabled) R.string.dashboard_state_trackers_on else R.string.dashboard_state_trackers_off @@ -182,7 +186,7 @@ class DashboardFragment : ) ) - val geolocEnabled = state is EnabledState && state.locationMode != LocationMode.REAL_LOCATION + val geolocEnabled = state.isQuickPrivacyEnabled && state.locationMode != LocationMode.REAL_LOCATION binding.stateGeolocation.text = getString( if (geolocEnabled) R.string.dashboard_state_geolocation_on else R.string.dashboard_state_geolocation_off @@ -195,8 +199,8 @@ class DashboardFragment : ) ) - val ipAddressEnabled = state is EnabledState && state.internetPrivacyMode != InternetPrivacyMode.REAL_IP - val isLoading = state is EnabledState && state.internetPrivacyMode in listOf( + 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 ) @@ -216,6 +220,23 @@ class DashboardFragment : ) ) + state.dayStatistics?.let { + val trackersDataSet = BarDataSet( + it.mapIndexed { index, value -> BarEntry(index.toFloat(), value.toFloat()) }, + getString(R.string.dashboard_graph_trackers_legend) + ).apply { + color = getColor(requireContext(), R.color.purple_chart) + setDrawValues(false) + } + + binding.graph.data = BarData(trackersDataSet) + binding.graph.invalidate() + } + + state.trackersCount?.let { + binding.graphLegend.text = getString(R.string.dashboard_graph_trackers_legend, it) + } + // binding.graphTotal.text = if (state == DashboardFeature.State.LoadingState) { // "" // } else { @@ -225,16 +246,12 @@ class DashboardFragment : // getString(R.string.dashboard_graph_total, value) // } - binding.amITracked.subtitle.text = if (state == LoadingState) "" - else { - val value = if (state is EnabledState) state.activeTrackersCount - else if (state is DisabledState) state.activeTrackersCount - else 0 // dummy - getString(R.string.dashboard_am_i_tracked_subtitle, 77, value) + state.activeTrackersCount?.let { + binding.amITracked.subtitle.text = getString(R.string.dashboard_am_i_tracked_subtitle, 77, it) } binding.myLocation.subtitle.text = getString( - if (state is EnabledState && + if (state.isQuickPrivacyEnabled && state.locationMode != LocationMode.REAL_LOCATION ) R.string.dashboard_location_subtitle_on @@ -242,7 +259,7 @@ class DashboardFragment : ) binding.internetActivityPrivacy.subtitle.text = getString( - if (state is EnabledState && + if (state.isQuickPrivacyEnabled && state.internetPrivacyMode != InternetPrivacyMode.REAL_IP ) R.string.dashboard_internet_activity_privacy_subtitle_on 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 67801eb..fa24b1d 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 @@ -22,13 +22,15 @@ import androidx.lifecycle.viewModelScope import foundation.e.privacycentralapp.common.Factory import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase import foundation.e.privacycentralapp.domain.usecases.IpScramblingStateUseCase +import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.launch class DashboardViewModel( private val getPrivacyStateUseCase: GetQuickPrivacyStateUseCase, - private val ipScramblingStateUseCase: IpScramblingStateUseCase + private val ipScramblingStateUseCase: IpScramblingStateUseCase, + private val trackersStatisticsUseCase: TrackersStatisticsUseCase ) : ViewModel() { private val _actions = MutableSharedFlow<DashboardFeature.Action>() @@ -38,7 +40,8 @@ class DashboardViewModel( DashboardFeature.create( coroutineScope = viewModelScope, getPrivacyStateUseCase = getPrivacyStateUseCase, - ipScramblingStateUseCase = ipScramblingStateUseCase + ipScramblingStateUseCase = ipScramblingStateUseCase, + trackersStatisticsUseCase = trackersStatisticsUseCase ) } @@ -51,9 +54,10 @@ class DashboardViewModel( class DashBoardViewModelFactory( private val getPrivacyStateUseCase: GetQuickPrivacyStateUseCase, - private val ipScramblingStateUseCase: IpScramblingStateUseCase + private val ipScramblingStateUseCase: IpScramblingStateUseCase, + private val trackersStatisticsUseCase: TrackersStatisticsUseCase ) : Factory<DashboardViewModel> { override fun create(): DashboardViewModel { - return DashboardViewModel(getPrivacyStateUseCase, ipScramblingStateUseCase) + return DashboardViewModel(getPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase) } } diff --git a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/QuickProtectionFragment.kt b/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/QuickProtectionFragment.kt deleted file mode 100644 index 981c8da..0000000 --- a/app/src/main/java/foundation/e/privacycentralapp/features/dashboard/QuickProtectionFragment.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2021 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.features.dashboard - -import android.content.Context -import androidx.activity.addCallback -import androidx.fragment.app.activityViewModels -import foundation.e.privacycentralapp.R -import foundation.e.privacycentralapp.common.NavToolbarFragment - -class QuickProtectionFragment : NavToolbarFragment(R.layout.fragment_quick_protection) { - - private val viewModel: DashboardViewModel by activityViewModels() - - override fun getTitle(): String = getString(R.string.quick_protection) - - override fun onAttach(context: Context) { - super.onAttach(context) - requireActivity().onBackPressedDispatcher.addCallback(this, true) { - // viewModel.submitAction(DashboardFeature.Action.ShowDashboardAction) - this.isEnabled = false - requireActivity().onBackPressed() - } - } -} diff --git a/app/src/main/res/drawable/outlined_background.xml b/app/src/main/res/drawable/bg_outlined.xml index 2040f18..2040f18 100644 --- a/app/src/main/res/drawable/outlined_background.xml +++ b/app/src/main/res/drawable/bg_outlined.xml diff --git a/app/src/main/res/drawable/ic_disk.xml b/app/src/main/res/drawable/ic_disk.xml new file mode 100644 index 0000000..92200b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_disk.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2021 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" + android:shape="oval"> + <solid android:color="@color/purple_chart" /> +</shape>
\ No newline at end of file diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml index c97d1a5..6976948 100644 --- a/app/src/main/res/layout/fragment_dashboard.xml +++ b/app/src/main/res/layout/fragment_dashboard.xml @@ -142,11 +142,14 @@ android:text="@string/dashboard_state_ipaddress_off" <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:padding="16dp"> + android:paddingTop="16dp" + android:paddingBottom="16dp" + > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/dashboard_graph_label" + android:layout_marginLeft="16dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -160,6 +163,7 @@ android:text="@string/dashboard_state_ipaddress_off" android:textColor="@color/grey_text_2" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" + android:layout_marginRight="16dp" /> <!-- <TextView--> @@ -170,12 +174,35 @@ android:text="@string/dashboard_state_ipaddress_off" <!-- app:layout_constraintRight_toRightOf="parent"--> <!-- app:layout_constraintTop_toBottomOf="@+id/graph_period"--> <!-- />--> - <ImageView + + <com.github.mikephil.charting.charts.BarChart android:id="@+id/graph" - android:layout_height="160dp" + android:layout_height="100dp" android:layout_width="match_parent" - android:src="@drawable/dummy_leakage_analytics" app:layout_constraintTop_toBottomOf="@+id/graph_period" + android:layout_marginTop="16dp" + /> + + <View + android:id="@+id/graph_legend_form" + android:layout_width="16dp" + android:layout_height="16dp" + android:padding="1dp" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toBottomOf="@+id/graph" + android:layout_marginTop="8dp" + android:layout_marginStart="16dp" + android:background="@drawable/ic_disk" + /> + <TextView + android:id="@+id/graph_legend" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="0 Trackers" + android:layout_marginStart="8dp" + android:textSize="12sp" + app:layout_constraintLeft_toRightOf="@+id/graph_legend_form" + app:layout_constraintBottom_toBottomOf="@+id/graph_legend_form" /> </androidx.constraintlayout.widget.ConstraintLayout> @@ -183,7 +210,7 @@ android:text="@string/dashboard_state_ipaddress_off" layout="@layout/dashboard_item_submenu_button" android:id="@+id/am_i_tracked" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="88dp" app:icon="@{@drawable/ic_tracked}" app:title="@{@string/dashboard_am_i_tracked_title}" app:subTitle='@{""}' @@ -199,7 +226,7 @@ android:text="@string/dashboard_state_ipaddress_off" layout="@layout/dashboard_item_submenu_button" android:id="@+id/apps_permissions" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="88dp" app:icon="@{@drawable/ic_apps_permissions}" app:title="@{@string/dashboard_apps_permissions_title}" app:subTitle='@{@string/dashboard_apps_permissions_subtitle}' @@ -207,7 +234,7 @@ android:text="@string/dashboard_state_ipaddress_off" <View android:layout_width="match_parent" android:layout_height="1dp" - android:layout_marginStart="72dp" + android:layout_marginStart="48dp" android:background="@color/grey_divider" /> @@ -215,7 +242,7 @@ android:text="@string/dashboard_state_ipaddress_off" layout="@layout/dashboard_item_submenu_button" android:id="@+id/my_location" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="88dp" app:icon="@{@drawable/ic_my_location}" app:title="@{@string/dashboard_location_title}" app:subTitle='@{@string/dashboard_location_subtitle_off}' @@ -223,7 +250,7 @@ android:text="@string/dashboard_state_ipaddress_off" <View android:layout_width="match_parent" android:layout_height="1dp" - android:layout_marginStart="72dp" + android:layout_marginStart="48dp" android:background="@color/grey_divider" /> @@ -231,17 +258,11 @@ android:text="@string/dashboard_state_ipaddress_off" layout="@layout/dashboard_item_submenu_button" android:id="@+id/internet_activity_privacy" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="88dp" app:icon="@{@drawable/ic_internet_activity}" app:title="@{@string/dashboard_internet_activity_privacy_title}" app:subTitle='@{@string/dashboard_internet_activity_privacy_subtitle_off}' /> - <View - android:layout_width="match_parent" - android:layout_height="1dp" - android:layout_marginStart="72dp" - android:background="@color/grey_divider" - /> </LinearLayout> </androidx.core.widget.NestedScrollView> </androidx.coordinatorlayout.widget.CoordinatorLayout> diff --git a/app/src/main/res/layout/fragment_internet_activity_policy.xml b/app/src/main/res/layout/fragment_internet_activity_policy.xml index 4f29776..a59d807 100644 --- a/app/src/main/res/layout/fragment_internet_activity_policy.xml +++ b/app/src/main/res/layout/fragment_internet_activity_policy.xml @@ -91,7 +91,7 @@ android:id="@+id/select_location_container" android:layout_width="match_parent" android:layout_height="54dp" - android:background="@drawable/outlined_background" + android:background="@drawable/bg_outlined" android:layout_marginTop="16dp" android:padding="1dp" > diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index a3ebbeb..935d0a7 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -21,6 +21,5 @@ <color name="green_on">#169659</color> <color name="green_valid">#2CC766</color> - - + <color name="purple_chart">#855CF8</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 d675a79..7433080 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,7 +17,7 @@ <string name="dashboard_state_ipaddress_on">Hidden</string> <string name="dashboard_graph_label">Personal data leakage</string> <string name="dashboard_graph_period">Last 24 hours</string> - <string name="dashboard_graph_total">%d hits</string> + <string name="dashboard_graph_trackers_legend">%d Trackers</string> <string name="dashboard_am_i_tracked_title">Am I tracked?</string> <string name="dashboard_am_i_tracked_subtitle">%1$d app trackers, %2$d active trackers</string> |