From a484bf584f4163c8a0a1260e81d598fdec87ff3b Mon Sep 17 00:00:00 2001
From: jacquarg <guillaume.jacquart@hoodbrains.com>
Date: Mon, 1 Nov 2021 21:24:09 +0100
Subject: Add trackers UI

---
 .../e/privacycentralapp/DependencyContainer.kt     |   6 ++
 .../e/privacycentralapp/common/AppsAdapter.kt      |  67 ++++++++++++
 .../privacycentralapp/common/ToggleAppsAdapter.kt  |   2 -
 .../domain/usecases/TrackersStatisticsUseCase.kt   |  16 +++
 .../dummy/TrackTrackersPrivacyMock.kt              |  12 +++
 .../features/dashboard/DashboardFragment.kt        |  16 ---
 .../features/trackers/TrackersFeature.kt           |  77 +++++++++++++-
 .../features/trackers/TrackersFragment.kt          | 118 +++++++++++++++++----
 .../features/trackers/TrackersViewModel.kt         |  28 ++++-
 9 files changed, 302 insertions(+), 40 deletions(-)
 create mode 100644 app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt

(limited to 'app/src/main/java')

diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
index ccb0a75..1ba235b 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
@@ -30,6 +30,7 @@ import foundation.e.privacycentralapp.features.dashboard.DashBoardViewModelFacto
 import foundation.e.privacycentralapp.features.internetprivacy.InternetPrivacyViewModelFactory
 import foundation.e.privacycentralapp.features.location.FakeLocationViewModelFactory
 import foundation.e.privacycentralapp.features.location.LocationApiDelegate
+import foundation.e.privacycentralapp.features.trackers.TrackersViewModelFactory
 import foundation.e.privacymodules.ipscrambler.IpScramblerModule
 import foundation.e.privacymodules.ipscramblermodule.IIpScramblerModule
 import foundation.e.privacymodules.location.FakeLocation
@@ -83,6 +84,7 @@ class DependencyContainer constructor(val app: Application) {
         TrackersStatisticsUseCase(trackTrackersPrivacyModule)
     }
 
+    // ViewModelFactories
     val dashBoardViewModelFactory by lazy {
         DashBoardViewModelFactory(getQuickPrivacyStateUseCase, ipScramblingStateUseCase, trackersStatisticsUseCase)
     }
@@ -96,4 +98,8 @@ class DependencyContainer constructor(val app: Application) {
     val internetPrivacyViewModelFactory by lazy {
         InternetPrivacyViewModelFactory(ipScramblerModule, getQuickPrivacyStateUseCase, ipScramblingStateUseCase, appListUseCase)
     }
+
+    val trackersViewModelFactory by lazy {
+        TrackersViewModelFactory(getQuickPrivacyStateUseCase, trackersStatisticsUseCase, appListUseCase)
+    }
 }
diff --git a/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt b/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt
new file mode 100644
index 0000000..d66ce76
--- /dev/null
+++ b/app/src/main/java/foundation/e/privacycentralapp/common/AppsAdapter.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.common
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import foundation.e.privacycentralapp.R
+import foundation.e.privacymodules.permissions.data.ApplicationDescription
+
+class AppsAdapter(
+    private val itemsLayout: Int,
+    private val listener: (String) -> Unit
+) :
+    RecyclerView.Adapter<AppsAdapter.ViewHolder>() {
+
+    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+        val appName: TextView = view.findViewById(R.id.title)
+
+        fun bind(item: ApplicationDescription) {
+            appName.text = item.label
+
+            itemView.findViewById<ImageView>(R.id.icon).setImageDrawable(item.icon)
+        }
+    }
+
+    var dataSet: List<ApplicationDescription> = emptyList()
+        set(value) {
+            field = value
+            notifyDataSetChanged()
+        }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val view = LayoutInflater.from(parent.context)
+            .inflate(itemsLayout, parent, false)
+        val holder = ViewHolder(view)
+        holder.itemView.setOnClickListener { _ ->
+            listener(dataSet[holder.adapterPosition].packageName)
+        }
+        return holder
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        val app = dataSet[position]
+        holder.bind(app)
+    }
+
+    override fun getItemCount(): Int = dataSet.size
+}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/common/ToggleAppsAdapter.kt b/app/src/main/java/foundation/e/privacycentralapp/common/ToggleAppsAdapter.kt
index 71b5e97..1817a0d 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/common/ToggleAppsAdapter.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/common/ToggleAppsAdapter.kt
@@ -22,7 +22,6 @@ import android.view.View
 import android.view.ViewGroup
 import android.widget.CheckBox
 import android.widget.ImageView
-import android.widget.Switch
 import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
 import foundation.e.privacycentralapp.R
@@ -60,7 +59,6 @@ class ToggleAppsAdapter(
         holder.togglePermission.setOnCheckedChangeListener { _, isChecked ->
             listener(dataSet[holder.adapterPosition].first.packageName, isChecked)
         }
-        view.findViewById<Switch>(R.id.toggle)
         return holder
     }
 
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 93fbc08..33c3f64 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
@@ -26,4 +26,20 @@ class TrackersStatisticsUseCase(
     fun getPast24HoursTrackersCalls(): List<Int> {
         return trackTrackersPrivacyModule.getPast24HoursTrackersCalls()
     }
+
+    fun getDayMonthYearStatistics(): Triple<List<Int>, List<Int>, List<Int>> {
+        return Triple(
+            trackTrackersPrivacyModule.getPast24HoursTrackersCalls(),
+            trackTrackersPrivacyModule.getPastMonthTrackersCalls(),
+            trackTrackersPrivacyModule.getPastYearTrackersCalls()
+        )
+    }
+
+    fun getDayMonthYearCounts(): Triple<Int, Int, Int> {
+        return Triple(
+            trackTrackersPrivacyModule.getPast24HoursTrackersCount(),
+            trackTrackersPrivacyModule.getPastMonthTrackersCount(),
+            trackTrackersPrivacyModule.getPastYearTrackersCount()
+        )
+    }
 }
diff --git a/app/src/main/java/foundation/e/privacycentralapp/dummy/TrackTrackersPrivacyMock.kt b/app/src/main/java/foundation/e/privacycentralapp/dummy/TrackTrackersPrivacyMock.kt
index 76da6a2..55ca6ec 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/dummy/TrackTrackersPrivacyMock.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/dummy/TrackTrackersPrivacyMock.kt
@@ -30,6 +30,10 @@ class TrackTrackersPrivacyMock : ITrackTrackersPrivacyModule {
         )
     }
 
+    override fun getPast24HoursTrackersCount(): Int {
+        return 30
+    }
+
     override fun getPastMonthTrackersCalls(): List<Int> {
         return listOf(
             20000, 23000, 24130, 12500, 31000, 22000,
@@ -40,6 +44,10 @@ class TrackTrackersPrivacyMock : ITrackTrackersPrivacyModule {
         )
     }
 
+    override fun getPastMonthTrackersCount(): Int {
+        return 43
+    }
+
     override fun getPastYearTrackersCalls(): List<Int> {
         return listOf(
             620000, 823000, 424130, 712500, 831000, 922000,
@@ -47,6 +55,10 @@ class TrackTrackersPrivacyMock : ITrackTrackersPrivacyModule {
         )
     }
 
+    override fun getPastYearTrackersCount(): Int {
+        return 46
+    }
+
     override fun getTrackersCount(): Int {
         return 72
     }
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 abdf764..1b4ad39 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
@@ -18,13 +18,8 @@
 package foundation.e.privacycentralapp.features.dashboard
 
 import android.content.Intent
-import android.graphics.Color
 import android.os.Bundle
-import android.text.Spannable
-import android.text.SpannableString
-import android.text.style.ForegroundColorSpan
 import android.view.View
-import android.widget.TextView
 import androidx.core.content.ContextCompat.getColor
 import androidx.fragment.app.activityViewModels
 import androidx.fragment.app.add
@@ -143,17 +138,6 @@ class DashboardFragment :
         return getString(R.string.dashboard_title)
     }
 
-    private fun addClickToMore(textView: TextView) {
-        val clickToMore = SpannableString(getString(R.string.click_to_learn_more))
-        clickToMore.setSpan(
-            ForegroundColorSpan(Color.parseColor("#007fff")),
-            0,
-            clickToMore.length,
-            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
-        )
-        textView.append(clickToMore)
-    }
-
     override fun render(state: State) {
 
         binding.stateLabel.text = getString(
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 9400181..0394abb 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,11 +22,17 @@ 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.usecases.AppListUseCase
+import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase
+import foundation.e.privacycentralapp.domain.usecases.TrackersStatisticsUseCase
 import foundation.e.privacycentralapp.dummy.Tracker
 import foundation.e.privacycentralapp.dummy.TrackersDataSource
+import foundation.e.privacymodules.permissions.data.ApplicationDescription
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
 
 // Define a state machine for Tracker feature.
 class TrackersFeature(
@@ -44,16 +50,28 @@ class TrackersFeature(
     singleEventProducer
 ) {
     data class State(
+        val dayStatistics: List<Int>? = null,
+        val dayTrackersCount: Int? = null,
+        val monthStatistics: List<Int>? = null,
+        val monthTrackersCount: Int? = null,
+        val yearStatistics: List<Int>? = null,
+        val yearTrackersCount: Int? = null,
+        val apps: List<ApplicationDescription>? = null,
+
         val trackers: List<Tracker> = emptyList(),
         val currentSelectedTracker: Tracker? = null
     )
 
     sealed class SingleEvent {
         data class ErrorEvent(val error: String) : SingleEvent()
+        data class OpenAppDetailsEvent(val packageName: String) : SingleEvent()
         object BlockerErrorEvent : SingleEvent()
     }
 
     sealed class Action {
+        object InitAction : Action()
+        data class ClickAppAction(val packageName: String) : Action()
+
         object ObserveTrackers : Action()
         data class SetSelectedTracker(val tracker: Tracker) : Action()
         data class ToggleTrackerAction(
@@ -64,6 +82,19 @@ class TrackersFeature(
     }
 
     sealed class Effect {
+        data class TrackersStatisticsLoadedEffect(
+            val dayStatistics: List<Int>? = null,
+            val dayTrackersCount: Int? = null,
+            val monthStatistics: List<Int>? = null,
+            val monthTrackersCount: Int? = null,
+            val yearStatistics: List<Int>? = null,
+            val yearTrackersCount: Int? = null
+        ) : Effect()
+        data class AvailableAppsListEffect(
+            val apps: List<ApplicationDescription>
+        ) : Effect()
+        data class OpenAppDetailsEffect(val packageName: String) : Effect()
+        object QuickPrivacyDisabledWarningEffect : Effect()
         data class TrackersLoadedEffect(val trackers: List<Tracker>) : Effect()
         data class TrackerSelectedEffect(val tracker: Tracker) : Effect()
         data class TrackerToggleEffect(val result: Boolean) : Effect()
@@ -74,12 +105,25 @@ class TrackersFeature(
     companion object {
         fun create(
             initialState: State = State(),
-            coroutineScope: CoroutineScope
+            coroutineScope: CoroutineScope,
+            getPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
+            trackersStatisticsUseCase: TrackersStatisticsUseCase,
+            appListUseCase: AppListUseCase
         ) = TrackersFeature(
             initialState, coroutineScope,
             reducer = { state, effect ->
                 when (effect) {
-                    is Effect.TrackersLoadedEffect -> State(effect.trackers)
+                    is Effect.TrackersStatisticsLoadedEffect -> state.copy(
+                        dayStatistics = effect.dayStatistics,
+                        dayTrackersCount = effect.dayTrackersCount,
+                        monthStatistics = effect.monthStatistics,
+                        monthTrackersCount = effect.monthTrackersCount,
+                        yearStatistics = effect.yearStatistics,
+                        yearTrackersCount = effect.yearTrackersCount
+                    )
+                    is Effect.AvailableAppsListEffect -> state.copy(apps = effect.apps)
+
+                    is Effect.TrackersLoadedEffect -> State()
                     is Effect.TrackerSelectedEffect -> state.copy(currentSelectedTracker = effect.tracker)
                     is Effect.ErrorEffect -> state
                     is Effect.TrackerToggleEffect -> {
@@ -88,10 +132,37 @@ class TrackersFeature(
                     is Effect.TrackerLoadedEffect -> {
                         state.copy(currentSelectedTracker = effect.tracker)
                     }
+                    else -> state
                 }
             },
             actor = { state, action ->
                 when (action) {
+                    Action.InitAction -> merge(
+                        flow {
+                            val statistics = trackersStatisticsUseCase.getDayMonthYearStatistics()
+                            val counts = trackersStatisticsUseCase.getDayMonthYearCounts()
+                            emit(
+                                Effect.TrackersStatisticsLoadedEffect(
+                                    dayStatistics = statistics.first,
+                                    dayTrackersCount = counts.first,
+                                    monthStatistics = statistics.second,
+                                    monthTrackersCount = counts.second,
+                                    yearStatistics = statistics.third,
+                                    yearTrackersCount = counts.third
+                                )
+                            )
+                        },
+                        flow {
+                            val apps = appListUseCase.getAppsUsingInternet()
+                            emit(Effect.AvailableAppsListEffect(apps))
+                        }
+                    )
+
+                    is Action.ClickAppAction -> flowOf(
+                        if (getPrivacyStateUseCase.isQuickPrivacyEnabled)
+                            Effect.OpenAppDetailsEffect(action.packageName)
+                        else Effect.QuickPrivacyDisabledWarningEffect
+                    )
                     Action.ObserveTrackers -> TrackersDataSource.trackers.map {
                         Effect.TrackersLoadedEffect(
                             it
@@ -131,9 +202,11 @@ class TrackersFeature(
             singleEventProducer = { _, _, effect ->
                 when (effect) {
                     is Effect.ErrorEffect -> SingleEvent.ErrorEvent(effect.message)
+                    is Effect.OpenAppDetailsEffect -> SingleEvent.OpenAppDetailsEvent(effect.packageName)
                     is Effect.TrackerToggleEffect -> {
                         if (!effect.result) SingleEvent.BlockerErrorEvent else null
                     }
+                    Effect.QuickPrivacyDisabledWarningEffect -> SingleEvent.ErrorEvent("Enabled Quick Privacy to use functionalities")
                     else -> null
                 }
             }
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 e3dc941..441f39a 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
@@ -19,24 +19,39 @@ package foundation.e.privacycentralapp.features.trackers
 
 import android.os.Bundle
 import android.view.View
-import androidx.core.os.bundleOf
-import androidx.fragment.app.add
-import androidx.fragment.app.commit
+import android.widget.Toast
+import androidx.core.content.ContextCompat
 import androidx.fragment.app.viewModels
 import androidx.lifecycle.lifecycleScope
 import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
+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
 import foundation.e.privacycentralapp.R
+import foundation.e.privacycentralapp.common.AppsAdapter
 import foundation.e.privacycentralapp.common.NavToolbarFragment
+import foundation.e.privacycentralapp.databinding.FragmentTrackersBinding
+import foundation.e.privacycentralapp.databinding.TrackersItemGraphBinding
+import foundation.e.privacycentralapp.extensions.viewModelProviderFactoryOf
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
 
 class TrackersFragment :
     NavToolbarFragment(R.layout.fragment_trackers),
     MVIView<TrackersFeature.State, TrackersFeature.Action> {
 
-    private val viewModel: TrackersViewModel by viewModels()
-    private lateinit var trackersAdapter: TrackersAdapter
+    private val dependencyContainer: DependencyContainer by lazy {
+        (this.requireActivity().application as PrivacyCentralApplication).dependencyContainer
+    }
+
+    private val viewModel: TrackersViewModel by viewModels {
+        viewModelProviderFactoryOf { dependencyContainer.trackersViewModelFactory.create() }
+    }
+
+    private lateinit var binding: FragmentTrackersBinding
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -44,32 +59,99 @@ class TrackersFragment :
             viewModel.trackersFeature.takeView(this, this@TrackersFragment)
         }
         lifecycleScope.launchWhenStarted {
-            viewModel.submitAction(TrackersFeature.Action.ObserveTrackers)
+            viewModel.trackersFeature.singleEvents.collect { event ->
+                when (event) {
+                    is TrackersFeature.SingleEvent.ErrorEvent -> {
+                        displayToast(event.error)
+                    }
+                    is TrackersFeature.SingleEvent.OpenAppDetailsEvent -> {
+                        displayToast(event.packageName)
+                    }
+                }
+            }
+        }
+
+        lifecycleScope.launchWhenStarted {
+            viewModel.submitAction(TrackersFeature.Action.InitAction)
         }
     }
 
+    private fun displayToast(message: String) {
+        Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT)
+            .show()
+    }
+
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
-        trackersAdapter = TrackersAdapter {
-            requireActivity().supportFragmentManager.commit {
-                val bundle = bundleOf("TRACKER" to it.name)
-                add<TrackerAppsFragment>(R.id.container, args = bundle)
-                setReorderingAllowed(true)
-                addToBackStack("trackers")
+
+        binding = FragmentTrackersBinding.bind(view)
+
+        listOf(binding.graphDay, binding.graphMonth, binding.graphYear).forEach {
+            it.graph.apply {
+                description = null
+                setTouchEnabled(false)
+                setDrawGridBackground(false)
+                setDrawBorders(false)
+                axisLeft.isEnabled = false
+                axisRight.isEnabled = false
+                xAxis.isEnabled = false
+                legend.isEnabled = false
             }
-            // viewModel.submitAction(TrackersFeature.Action.SetSelectedTracker(it))
         }
-        view.findViewById<RecyclerView>(R.id.recylcer_view_trackers)?.apply {
+
+        binding.apps.apply {
             layoutManager = LinearLayoutManager(requireContext())
             setHasFixedSize(true)
-            adapter = trackersAdapter
+            adapter = AppsAdapter(R.layout.trackers_item_app) { packageName ->
+                viewModel.submitAction(
+                    TrackersFeature.Action.ClickAppAction(packageName)
+                )
+            }
         }
+
+        //
+        // requireActivity().supportFragmentManager.commit {
+        //     val bundle = bundleOf("TRACKER" to it.name)
+        //     add<TrackerAppsFragment>(R.id.container, args = bundle)
+        //     setReorderingAllowed(true)
+        //     addToBackStack("trackers")
+        // }
     }
 
-    override fun getTitle() = getString(R.string.trackers)
+    override fun getTitle() = getString(R.string.trackers_title)
 
     override fun render(state: TrackersFeature.State) {
-        trackersAdapter.setData(state.trackers)
+        if (state.dayStatistics != null && state.dayTrackersCount != null) {
+            renderGraph(state.dayTrackersCount, state.dayStatistics, binding.graphDay)
+        }
+
+        if (state.monthStatistics != null && state.monthTrackersCount != null) {
+            renderGraph(state.monthTrackersCount, state.monthStatistics, binding.graphMonth)
+        }
+
+        if (state.yearStatistics != null && state.yearTrackersCount != null) {
+            renderGraph(state.yearTrackersCount, state.yearStatistics, binding.graphYear)
+        }
+
+        state.apps?.let {
+            binding.apps.post {
+                (binding.apps.adapter as AppsAdapter?)?.dataSet = it
+            }
+        }
+    }
+
+    private fun renderGraph(trackersCount: Int, data: List<Int>, graphBinding: TrackersItemGraphBinding) {
+        val trackersDataSet = BarDataSet(
+            data.mapIndexed { index, value -> BarEntry(index.toFloat(), value.toFloat()) },
+            getString(R.string.trackers_count_label)
+        ).apply {
+            color = ContextCompat.getColor(requireContext(), R.color.purple_chart)
+            setDrawValues(false)
+        }
+
+        graphBinding.graph.data = BarData(trackersDataSet)
+        graphBinding.graph.invalidate()
+        graphBinding.trackersCountLabel.text = getString(R.string.trackers_count_label, trackersCount)
     }
 
     override fun actions(): Flow<TrackersFeature.Action> = viewModel.actions
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 ee89887..12b66d4 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
@@ -20,17 +20,30 @@ 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 : ViewModel() {
+class TrackersViewModel(
+    private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
+    private val trackersStatisticsUseCase: TrackersStatisticsUseCase,
+    private val appListUseCase: AppListUseCase
+) : ViewModel() {
 
     private val _actions = MutableSharedFlow<TrackersFeature.Action>()
     val actions = _actions.asSharedFlow()
 
     val trackersFeature: TrackersFeature by lazy {
-        TrackersFeature.create(coroutineScope = viewModelScope)
+        TrackersFeature.create(
+            coroutineScope = viewModelScope,
+            getPrivacyStateUseCase = getQuickPrivacyStateUseCase,
+            trackersStatisticsUseCase = trackersStatisticsUseCase,
+            appListUseCase = appListUseCase
+        )
     }
 
     fun submitAction(action: TrackersFeature.Action) {
@@ -40,3 +53,14 @@ class TrackersViewModel : ViewModel() {
         }
     }
 }
+
+class TrackersViewModelFactory(
+    private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
+    private val trackersStatisticsUseCase: TrackersStatisticsUseCase,
+    private val appListUseCase: AppListUseCase
+) :
+    Factory<TrackersViewModel> {
+    override fun create(): TrackersViewModel {
+        return TrackersViewModel(getQuickPrivacyStateUseCase, trackersStatisticsUseCase, appListUseCase)
+    }
+}
-- 
cgit v1.2.1