Loading app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt +17 −6 Original line number Diff line number Diff line Loading @@ -27,10 +27,15 @@ import foundation.e.advancedprivacy.domain.usecases.ShowFeaturesWarningUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStatisticsUseCase import foundation.e.advancedprivacy.domain.usecases.VpnSupervisorUseCase import foundation.e.advancedprivacy.domain.usecases.WeeklyReportUseCase import foundation.e.advancedprivacy.externalinterfaces.workers.WeeklyReportWorker import foundation.e.advancedprivacy.trackers.data.TrackersRepository import foundation.e.advancedprivacy.trackers.services.UpdateTrackersWorker import foundation.e.lib.telemetry.Telemetry import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin import org.koin.java.KoinJavaComponent.get Loading @@ -44,21 +49,26 @@ class AdvancedPrivacyApplication : Application() { androidContext(this@AdvancedPrivacyApplication) modules(appModule) } get<CoroutineScope>(CoroutineScope::class.java).launch { initBackgroundSingletons() } } private suspend fun initBackgroundSingletons() = withContext(Dispatchers.IO) { get<TrackersRepository>(TrackersRepository::class.java).initTrackersFile() private fun initBackgroundSingletons() { UpdateTrackersWorker.periodicUpdate(this) WeeklyReportWorker.scheduleNext(this) UpdateTrackersWorker.periodicUpdate(this@AdvancedPrivacyApplication) WeeklyReportWorker.scheduleNext(this@AdvancedPrivacyApplication) WarningDialog.startListening( get(ShowFeaturesWarningUseCase::class.java), get(CoroutineScope::class.java), this this@AdvancedPrivacyApplication ) Widget.startListening( this, this@AdvancedPrivacyApplication, get(GetQuickPrivacyStateUseCase::class.java), get(TrackersStatisticsUseCase::class.java) ) Loading @@ -69,5 +79,6 @@ class AdvancedPrivacyApplication : Application() { get<TrackersStateUseCase>(TrackersStateUseCase::class.java) get<FakeLocationStateUseCase>(FakeLocationStateUseCase::class.java) get<VpnSupervisorUseCase>(VpnSupervisorUseCase::class.java).listenSettings() get<WeeklyReportUseCase>(WeeklyReportUseCase::class.java).listen() } } app/src/main/java/foundation/e/advancedprivacy/domain/usecases/WeeklyReportUseCase.kt +41 −18 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ class WeeklyReportUseCase( private var stopDisplayJob: Job? = null init { fun listen() { scope.launch { updateCurrent() } Loading @@ -66,7 +66,6 @@ class WeeklyReportUseCase( stopDisplayJob = scope.launch { delay(endOfDisplay.toEpochMilli() - now.toEpochMilli()) _currentReport.value = null stopDisplayJob = null } } else { Loading Loading @@ -104,7 +103,6 @@ class WeeklyReportUseCase( addCallPerAppCandidates(candidates, endOfWeek) addNewTrackerCandidates(candidates, endOfWeek) addCallAndLeaksCandidates(candidates, endOfWeek) addTrackerWithMostAppsCandidates(candidates, endOfWeek) return candidates.map { computeScore(it, history) }.sortedBy { it.score } } Loading Loading @@ -145,8 +143,8 @@ class WeeklyReportUseCase( ) } private suspend fun addNewTrackerCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) { val startOfWeek = endOfWeek.minus(7, ChronoUnit.DAYS) private suspend fun addNewTrackerCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) = withContext(Dispatchers.IO) { val startOfWeek = getStartOfWeek(endOfWeek) val startOfYear = endOfWeek.minus(365, ChronoUnit.DAYS) val trackerAppsHistoric = statsDatabase.getDistinctTrackerAndApp(startOfYear, startOfWeek) Loading @@ -156,7 +154,6 @@ class WeeklyReportUseCase( val newTrackersDetected = trackerAppsOfWeek.filter { it.first !in historicTrackers } val appsIntroducingNewTracker = newTrackersDetected.mapNotNull { appListRepository.getAppById(it.second) }.toSet() // TODO dummy apps ?&& displayableApp != appListRepository appsIntroducingNewTracker.forEach { app -> candidates.add( WeeklyReport( Loading Loading @@ -193,6 +190,44 @@ class WeeklyReportUseCase( ) ) } addTrackerWithMostAppsCandidates( candidates, endOfWeek, trackerAppsHistoric.toSet() + trackerAppsOfWeek.toSet() ) } private fun addTrackerWithMostAppsCandidates( candidates: MutableList<WeeklyReport>, endOfWeek: Instant, trackerApps: Set<Pair<String, String>> ) { val (tracker, appCount) = trackerApps.groupBy( keySelector = { (trackerId, _) -> trackersRepository.getTracker(trackerId) }, valueTransform = { (_, apId) -> appListRepository.getInternetAppByApId(apId) } ).filterKeys { it != null } .mapValues { appsByTracker -> appsByTracker.value.filterNotNull().distinct().size } .maxBy { appCountByTracker -> appCountByTracker.value } .let { appCountByTracker -> appCountByTracker.key to appCountByTracker.value } if (tracker != null && appCount > 1) { candidates.add( WeeklyReport( endOfWeek, WeeklyReport.StatType.TRACKER_WITH_MOST_APPS, WeeklyReport.LabelId.TRACKER_WITH_MOST_APPS_1, tracker.id, listOf(appCount.toString()) ) ) } } private fun addCallAndLeaksCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) { Loading @@ -219,18 +254,6 @@ class WeeklyReportUseCase( ) } private fun addTrackerWithMostAppsCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) { candidates.add( WeeklyReport( endOfWeek, WeeklyReport.StatType.TRACKER_WITH_MOST_APPS, WeeklyReport.LabelId.TRACKER_WITH_MOST_APPS_1, "wtm_yahoo", listOf(Random.nextInt(20).toString()) ) ) } private fun computeScore(weeklyReport: WeeklyReport, history: List<WeeklyReport>): WeeklyReportScore { // Smaller score is the best to display. // Score is the rank in history, categorized by most visible parameters: Loading app/src/main/java/foundation/e/advancedprivacy/features/trackers/TrackersViewModel.kt +8 −3 Original line number Diff line number Diff line Loading @@ -105,16 +105,21 @@ class TrackersViewModel( fun onClickWeeklyReportAction() = viewModelScope.launch { val report = state.value val labelId = report?.report?.labelId when { report?.report?.labelId == WeeklyReport.LabelId.NEW_TRACKER_1 && labelId == WeeklyReport.LabelId.NEW_TRACKER_1 && report is DisplayableReport.ReportWithApp -> { _navigate.emit(TrackersFragmentDirections.gotoAppTrackersFragment(appId = report.app.id)) } report?.report?.labelId == WeeklyReport.LabelId.NEW_TRACKER_2 || report?.report?.labelId == WeeklyReport.LabelId.NEW_TRACKER_3 -> { labelId == WeeklyReport.LabelId.NEW_TRACKER_2 || labelId == WeeklyReport.LabelId.NEW_TRACKER_3 -> { trackersScreenUseCase.selectTab(Period.MONTH, TrackerTab.TRACKERS) } labelId == WeeklyReport.LabelId.TRACKER_WITH_MOST_APPS_1 && report is DisplayableReport.ReportWithTracker -> _navigate.emit(TrackersFragmentDirections.gotoTrackerDetailsFragment(trackerId = report.tracker.id)) } } Loading app/src/main/java/foundation/e/advancedprivacy/features/weeklyreport/TrackerWithMostAppsViewFactory.kt 0 → 100644 +121 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.advancedprivacy.features.weeklyreport import android.content.Context import android.content.res.Configuration import android.graphics.drawable.Drawable import android.text.method.LinkMovementMethod import android.text.style.ClickableSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.core.text.bold import androidx.core.text.buildSpannedString import androidx.core.text.inSpans import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.databinding.WeeklyreportItemNewTrackersBinding import foundation.e.advancedprivacy.databinding.WeeklyreportItemNewTrackersForSharingBinding import foundation.e.advancedprivacy.domain.entities.weeklyreport.DisplayableReport class TrackerWithMostAppsViewFactory(private val context: Context) { fun getShareTitle(): CharSequence { return context.getString(R.string.weeklyreport_share_title_base) } fun createView(report: DisplayableReport, inflater: LayoutInflater, viewGroup: ViewGroup, onClick: () -> Unit): View? { val binding = WeeklyreportItemNewTrackersBinding.inflate(inflater, viewGroup, false) if (context.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) { binding.icon.setImageResource(R.drawable.ic_big_brother_yellow_bg) } else { binding.icon.setImageResource(R.drawable.ic_big_brother) } binding.icon.imageTintList = null binding.title.text = getTitle() binding.description.text = buildNewTrackersDescription(report, onClick) binding.description.movementMethod = LinkMovementMethod.getInstance() with(binding.viewDetails) { setText(R.string.weeklyreport_label_tracker_with_most_apps_1_cta) setOnClickListener { onClick() } } return binding.root } fun createViewForSharing(report: DisplayableReport, inflater: LayoutInflater, viewGroup: ViewGroup): View? { val binding = WeeklyreportItemNewTrackersForSharingBinding.inflate(inflater, viewGroup, false) binding.icon.setImageDrawable(getIconForNotification()) binding.title.text = getTitle() binding.description.text = buildNewTrackersDescription(report, null, true) return binding.root } fun getTitle(): CharSequence { return context.getString(R.string.weeklyreport_label_tracker_with_most_apps_1_title) } fun getDescriptionForNotification(report: DisplayableReport): String { return buildNewTrackersDescription(report, null, forSharing = false).toString() } fun getIconForNotification(): Drawable? { return ContextCompat.getDrawable(context, R.drawable.ic_big_brother_yellow_bg) } private fun buildNewTrackersDescription( report: DisplayableReport, clickCallBack: (() -> Unit)?, forSharing: Boolean = false ): CharSequence { val value = (report as? DisplayableReport.ReportWithTracker)?.tracker?.label ?: "" return buildSpannedString { if (forSharing) { bold { append(value) } } else { inSpans( object : ClickableSpan() { override fun onClick(p0: View) { clickCallBack?.invoke() } } ) { append(value) } } append(" ") append( context.getString( if (forSharing) { R.string.weeklyreport_label_tracker_with_most_apps_1_description_sharing } else { R.string.weeklyreport_label_tracker_with_most_apps_1_description }, report.report.secondaryValues.firstOrNull() ?: "" ) ) } } } app/src/main/java/foundation/e/advancedprivacy/features/weeklyreport/WeeklyReportViewFactory.kt +13 −5 Original line number Diff line number Diff line Loading @@ -37,12 +37,14 @@ import foundation.e.advancedprivacy.domain.entities.weeklyreport.WeeklyReport class WeeklyReportViewFactory(private val context: Context) { val newTrackersViewFactory: NewTrackersViewFactory by lazy { NewTrackersViewFactory(context) } val trackerWithMostAppsViewFactory: TrackerWithMostAppsViewFactory by lazy { TrackerWithMostAppsViewFactory(context) } fun getShareTitle(report: DisplayableReport): CharSequence { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getShareTitle(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getShareTitle() else -> context.getString(R.string.weeklyreport_share_title_base) } } Loading @@ -51,7 +53,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.createView(report, inflater, viewGroup, onClick) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.createView(report, inflater, viewGroup, onClick) else -> null } ?: createDefaultView(report, inflater, viewGroup) } Loading Loading @@ -104,7 +107,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.createViewForSharing(report, inflater, viewGroup) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.createViewForSharing(report, inflater, viewGroup) else -> null } ?: createDefaultView(report, inflater, viewGroup) } Loading @@ -122,7 +126,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getTitle(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getTitle() else -> report.report.labelId.name } } Loading @@ -131,7 +136,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getDescriptionForNotification(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getDescriptionForNotification(report) else -> getDefaultDescription(report).toString() } } Loading @@ -150,6 +156,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getIconForNotification(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getIconForNotification() else -> null } } Loading Loading
app/src/main/java/foundation/e/advancedprivacy/AdvancedPrivacyApplication.kt +17 −6 Original line number Diff line number Diff line Loading @@ -27,10 +27,15 @@ import foundation.e.advancedprivacy.domain.usecases.ShowFeaturesWarningUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStateUseCase import foundation.e.advancedprivacy.domain.usecases.TrackersStatisticsUseCase import foundation.e.advancedprivacy.domain.usecases.VpnSupervisorUseCase import foundation.e.advancedprivacy.domain.usecases.WeeklyReportUseCase import foundation.e.advancedprivacy.externalinterfaces.workers.WeeklyReportWorker import foundation.e.advancedprivacy.trackers.data.TrackersRepository import foundation.e.advancedprivacy.trackers.services.UpdateTrackersWorker import foundation.e.lib.telemetry.Telemetry import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin import org.koin.java.KoinJavaComponent.get Loading @@ -44,21 +49,26 @@ class AdvancedPrivacyApplication : Application() { androidContext(this@AdvancedPrivacyApplication) modules(appModule) } get<CoroutineScope>(CoroutineScope::class.java).launch { initBackgroundSingletons() } } private suspend fun initBackgroundSingletons() = withContext(Dispatchers.IO) { get<TrackersRepository>(TrackersRepository::class.java).initTrackersFile() private fun initBackgroundSingletons() { UpdateTrackersWorker.periodicUpdate(this) WeeklyReportWorker.scheduleNext(this) UpdateTrackersWorker.periodicUpdate(this@AdvancedPrivacyApplication) WeeklyReportWorker.scheduleNext(this@AdvancedPrivacyApplication) WarningDialog.startListening( get(ShowFeaturesWarningUseCase::class.java), get(CoroutineScope::class.java), this this@AdvancedPrivacyApplication ) Widget.startListening( this, this@AdvancedPrivacyApplication, get(GetQuickPrivacyStateUseCase::class.java), get(TrackersStatisticsUseCase::class.java) ) Loading @@ -69,5 +79,6 @@ class AdvancedPrivacyApplication : Application() { get<TrackersStateUseCase>(TrackersStateUseCase::class.java) get<FakeLocationStateUseCase>(FakeLocationStateUseCase::class.java) get<VpnSupervisorUseCase>(VpnSupervisorUseCase::class.java).listenSettings() get<WeeklyReportUseCase>(WeeklyReportUseCase::class.java).listen() } }
app/src/main/java/foundation/e/advancedprivacy/domain/usecases/WeeklyReportUseCase.kt +41 −18 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ class WeeklyReportUseCase( private var stopDisplayJob: Job? = null init { fun listen() { scope.launch { updateCurrent() } Loading @@ -66,7 +66,6 @@ class WeeklyReportUseCase( stopDisplayJob = scope.launch { delay(endOfDisplay.toEpochMilli() - now.toEpochMilli()) _currentReport.value = null stopDisplayJob = null } } else { Loading Loading @@ -104,7 +103,6 @@ class WeeklyReportUseCase( addCallPerAppCandidates(candidates, endOfWeek) addNewTrackerCandidates(candidates, endOfWeek) addCallAndLeaksCandidates(candidates, endOfWeek) addTrackerWithMostAppsCandidates(candidates, endOfWeek) return candidates.map { computeScore(it, history) }.sortedBy { it.score } } Loading Loading @@ -145,8 +143,8 @@ class WeeklyReportUseCase( ) } private suspend fun addNewTrackerCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) { val startOfWeek = endOfWeek.minus(7, ChronoUnit.DAYS) private suspend fun addNewTrackerCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) = withContext(Dispatchers.IO) { val startOfWeek = getStartOfWeek(endOfWeek) val startOfYear = endOfWeek.minus(365, ChronoUnit.DAYS) val trackerAppsHistoric = statsDatabase.getDistinctTrackerAndApp(startOfYear, startOfWeek) Loading @@ -156,7 +154,6 @@ class WeeklyReportUseCase( val newTrackersDetected = trackerAppsOfWeek.filter { it.first !in historicTrackers } val appsIntroducingNewTracker = newTrackersDetected.mapNotNull { appListRepository.getAppById(it.second) }.toSet() // TODO dummy apps ?&& displayableApp != appListRepository appsIntroducingNewTracker.forEach { app -> candidates.add( WeeklyReport( Loading Loading @@ -193,6 +190,44 @@ class WeeklyReportUseCase( ) ) } addTrackerWithMostAppsCandidates( candidates, endOfWeek, trackerAppsHistoric.toSet() + trackerAppsOfWeek.toSet() ) } private fun addTrackerWithMostAppsCandidates( candidates: MutableList<WeeklyReport>, endOfWeek: Instant, trackerApps: Set<Pair<String, String>> ) { val (tracker, appCount) = trackerApps.groupBy( keySelector = { (trackerId, _) -> trackersRepository.getTracker(trackerId) }, valueTransform = { (_, apId) -> appListRepository.getInternetAppByApId(apId) } ).filterKeys { it != null } .mapValues { appsByTracker -> appsByTracker.value.filterNotNull().distinct().size } .maxBy { appCountByTracker -> appCountByTracker.value } .let { appCountByTracker -> appCountByTracker.key to appCountByTracker.value } if (tracker != null && appCount > 1) { candidates.add( WeeklyReport( endOfWeek, WeeklyReport.StatType.TRACKER_WITH_MOST_APPS, WeeklyReport.LabelId.TRACKER_WITH_MOST_APPS_1, tracker.id, listOf(appCount.toString()) ) ) } } private fun addCallAndLeaksCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) { Loading @@ -219,18 +254,6 @@ class WeeklyReportUseCase( ) } private fun addTrackerWithMostAppsCandidates(candidates: MutableList<WeeklyReport>, endOfWeek: Instant) { candidates.add( WeeklyReport( endOfWeek, WeeklyReport.StatType.TRACKER_WITH_MOST_APPS, WeeklyReport.LabelId.TRACKER_WITH_MOST_APPS_1, "wtm_yahoo", listOf(Random.nextInt(20).toString()) ) ) } private fun computeScore(weeklyReport: WeeklyReport, history: List<WeeklyReport>): WeeklyReportScore { // Smaller score is the best to display. // Score is the rank in history, categorized by most visible parameters: Loading
app/src/main/java/foundation/e/advancedprivacy/features/trackers/TrackersViewModel.kt +8 −3 Original line number Diff line number Diff line Loading @@ -105,16 +105,21 @@ class TrackersViewModel( fun onClickWeeklyReportAction() = viewModelScope.launch { val report = state.value val labelId = report?.report?.labelId when { report?.report?.labelId == WeeklyReport.LabelId.NEW_TRACKER_1 && labelId == WeeklyReport.LabelId.NEW_TRACKER_1 && report is DisplayableReport.ReportWithApp -> { _navigate.emit(TrackersFragmentDirections.gotoAppTrackersFragment(appId = report.app.id)) } report?.report?.labelId == WeeklyReport.LabelId.NEW_TRACKER_2 || report?.report?.labelId == WeeklyReport.LabelId.NEW_TRACKER_3 -> { labelId == WeeklyReport.LabelId.NEW_TRACKER_2 || labelId == WeeklyReport.LabelId.NEW_TRACKER_3 -> { trackersScreenUseCase.selectTab(Period.MONTH, TrackerTab.TRACKERS) } labelId == WeeklyReport.LabelId.TRACKER_WITH_MOST_APPS_1 && report is DisplayableReport.ReportWithTracker -> _navigate.emit(TrackersFragmentDirections.gotoTrackerDetailsFragment(trackerId = report.tracker.id)) } } Loading
app/src/main/java/foundation/e/advancedprivacy/features/weeklyreport/TrackerWithMostAppsViewFactory.kt 0 → 100644 +121 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.advancedprivacy.features.weeklyreport import android.content.Context import android.content.res.Configuration import android.graphics.drawable.Drawable import android.text.method.LinkMovementMethod import android.text.style.ClickableSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.core.text.bold import androidx.core.text.buildSpannedString import androidx.core.text.inSpans import foundation.e.advancedprivacy.R import foundation.e.advancedprivacy.databinding.WeeklyreportItemNewTrackersBinding import foundation.e.advancedprivacy.databinding.WeeklyreportItemNewTrackersForSharingBinding import foundation.e.advancedprivacy.domain.entities.weeklyreport.DisplayableReport class TrackerWithMostAppsViewFactory(private val context: Context) { fun getShareTitle(): CharSequence { return context.getString(R.string.weeklyreport_share_title_base) } fun createView(report: DisplayableReport, inflater: LayoutInflater, viewGroup: ViewGroup, onClick: () -> Unit): View? { val binding = WeeklyreportItemNewTrackersBinding.inflate(inflater, viewGroup, false) if (context.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) { binding.icon.setImageResource(R.drawable.ic_big_brother_yellow_bg) } else { binding.icon.setImageResource(R.drawable.ic_big_brother) } binding.icon.imageTintList = null binding.title.text = getTitle() binding.description.text = buildNewTrackersDescription(report, onClick) binding.description.movementMethod = LinkMovementMethod.getInstance() with(binding.viewDetails) { setText(R.string.weeklyreport_label_tracker_with_most_apps_1_cta) setOnClickListener { onClick() } } return binding.root } fun createViewForSharing(report: DisplayableReport, inflater: LayoutInflater, viewGroup: ViewGroup): View? { val binding = WeeklyreportItemNewTrackersForSharingBinding.inflate(inflater, viewGroup, false) binding.icon.setImageDrawable(getIconForNotification()) binding.title.text = getTitle() binding.description.text = buildNewTrackersDescription(report, null, true) return binding.root } fun getTitle(): CharSequence { return context.getString(R.string.weeklyreport_label_tracker_with_most_apps_1_title) } fun getDescriptionForNotification(report: DisplayableReport): String { return buildNewTrackersDescription(report, null, forSharing = false).toString() } fun getIconForNotification(): Drawable? { return ContextCompat.getDrawable(context, R.drawable.ic_big_brother_yellow_bg) } private fun buildNewTrackersDescription( report: DisplayableReport, clickCallBack: (() -> Unit)?, forSharing: Boolean = false ): CharSequence { val value = (report as? DisplayableReport.ReportWithTracker)?.tracker?.label ?: "" return buildSpannedString { if (forSharing) { bold { append(value) } } else { inSpans( object : ClickableSpan() { override fun onClick(p0: View) { clickCallBack?.invoke() } } ) { append(value) } } append(" ") append( context.getString( if (forSharing) { R.string.weeklyreport_label_tracker_with_most_apps_1_description_sharing } else { R.string.weeklyreport_label_tracker_with_most_apps_1_description }, report.report.secondaryValues.firstOrNull() ?: "" ) ) } } }
app/src/main/java/foundation/e/advancedprivacy/features/weeklyreport/WeeklyReportViewFactory.kt +13 −5 Original line number Diff line number Diff line Loading @@ -37,12 +37,14 @@ import foundation.e.advancedprivacy.domain.entities.weeklyreport.WeeklyReport class WeeklyReportViewFactory(private val context: Context) { val newTrackersViewFactory: NewTrackersViewFactory by lazy { NewTrackersViewFactory(context) } val trackerWithMostAppsViewFactory: TrackerWithMostAppsViewFactory by lazy { TrackerWithMostAppsViewFactory(context) } fun getShareTitle(report: DisplayableReport): CharSequence { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getShareTitle(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getShareTitle() else -> context.getString(R.string.weeklyreport_share_title_base) } } Loading @@ -51,7 +53,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.createView(report, inflater, viewGroup, onClick) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.createView(report, inflater, viewGroup, onClick) else -> null } ?: createDefaultView(report, inflater, viewGroup) } Loading Loading @@ -104,7 +107,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.createViewForSharing(report, inflater, viewGroup) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.createViewForSharing(report, inflater, viewGroup) else -> null } ?: createDefaultView(report, inflater, viewGroup) } Loading @@ -122,7 +126,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getTitle(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getTitle() else -> report.report.labelId.name } } Loading @@ -131,7 +136,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getDescriptionForNotification(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getDescriptionForNotification(report) else -> getDefaultDescription(report).toString() } } Loading @@ -150,6 +156,8 @@ class WeeklyReportViewFactory(private val context: Context) { return when (report.report.statType) { WeeklyReport.StatType.NEW_TRACKER -> newTrackersViewFactory.getIconForNotification(report) WeeklyReport.StatType.TRACKER_WITH_MOST_APPS -> trackerWithMostAppsViewFactory.getIconForNotification() else -> null } } Loading