diff --git a/app/schemas/com.duckduckgo.app.global.db.AppDatabase/13.json b/app/schemas/com.duckduckgo.app.global.db.AppDatabase/13.json new file mode 100644 index 000000000000..f29d68dba084 --- /dev/null +++ b/app/schemas/com.duckduckgo.app.global.db.AppDatabase/13.json @@ -0,0 +1,546 @@ +{ + "formatVersion": 1, + "database": { + "version": 13, + "identityHash": "04130d73cf4edde498a7b6833f40049d", + "entities": [ + { + "tableName": "disconnect_tracker", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `category` TEXT NOT NULL, `networkName` TEXT NOT NULL, `networkUrl` TEXT NOT NULL, PRIMARY KEY(`url`))", + "fields": [ + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "networkName", + "columnName": "networkName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "networkUrl", + "columnName": "networkUrl", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "url" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "https_bloom_filter_spec", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `errorRate` REAL NOT NULL, `totalEntries` INTEGER NOT NULL, `sha256` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "errorRate", + "columnName": "errorRate", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "totalEntries", + "columnName": "totalEntries", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sha256", + "columnName": "sha256", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "https_whitelisted_domain", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`domain` TEXT NOT NULL, PRIMARY KEY(`domain`))", + "fields": [ + { + "fieldPath": "domain", + "columnName": "domain", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "domain" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "network_leaderboard", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`networkName` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`networkName`))", + "fields": [ + { + "fieldPath": "networkName", + "columnName": "networkName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "networkName" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sites_visited", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "app_configuration", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `appConfigurationDownloaded` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "appConfigurationDownloaded", + "columnName": "appConfigurationDownloaded", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tabs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tabId` TEXT NOT NULL, `url` TEXT, `title` TEXT, `skipHome` INTEGER NOT NULL, `viewed` INTEGER NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`tabId`))", + "fields": [ + { + "fieldPath": "tabId", + "columnName": "tabId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "skipHome", + "columnName": "skipHome", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewed", + "columnName": "viewed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "tabId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_tabs_tabId", + "unique": false, + "columnNames": [ + "tabId" + ], + "createSql": "CREATE INDEX `index_tabs_tabId` ON `${TABLE_NAME}` (`tabId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "tab_selection", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `tabId` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`tabId`) REFERENCES `tabs`(`tabId`) ON UPDATE NO ACTION ON DELETE SET NULL )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "tabId", + "columnName": "tabId", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_tab_selection_tabId", + "unique": false, + "columnNames": [ + "tabId" + ], + "createSql": "CREATE INDEX `index_tab_selection_tabId` ON `${TABLE_NAME}` (`tabId`)" + } + ], + "foreignKeys": [ + { + "table": "tabs", + "onDelete": "SET NULL", + "onUpdate": "NO ACTION", + "columns": [ + "tabId" + ], + "referencedColumns": [ + "tabId" + ] + } + ] + }, + { + "tableName": "bookmarks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `url` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "entity_list", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`domainName` TEXT NOT NULL, `entityName` TEXT NOT NULL, PRIMARY KEY(`domainName`))", + "fields": [ + { + "fieldPath": "domainName", + "columnName": "domainName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entityName", + "columnName": "entityName", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "domainName" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "survey", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`surveyId` TEXT NOT NULL, `url` TEXT, `daysInstalled` INTEGER, `status` TEXT NOT NULL, PRIMARY KEY(`surveyId`))", + "fields": [ + { + "fieldPath": "surveyId", + "columnName": "surveyId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "daysInstalled", + "columnName": "daysInstalled", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "surveyId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "dismissed_cta", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`ctaId` TEXT NOT NULL, PRIMARY KEY(`ctaId`))", + "fields": [ + { + "fieldPath": "ctaId", + "columnName": "ctaId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "ctaId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "search_count", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "count", + "columnName": "count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "app_days_used", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`date` TEXT NOT NULL, PRIMARY KEY(`date`))", + "fields": [ + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "date" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "app_enjoyment", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`eventType` INTEGER NOT NULL, `promptCount` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `primaryKey` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "eventType", + "columnName": "eventType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "promptCount", + "columnName": "promptCount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "primaryKey", + "columnName": "primaryKey", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "primaryKey" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "notification", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`notificationId` TEXT NOT NULL, PRIMARY KEY(`notificationId`))", + "fields": [ + { + "fieldPath": "notificationId", + "columnName": "notificationId", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "notificationId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "privacy_protection_count", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `blocked_tracker_count` INTEGER NOT NULL, `upgrade_count` INTEGER NOT NULL, PRIMARY KEY(`key`))", + "fields": [ + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "blockedTrackerCount", + "columnName": "blocked_tracker_count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "upgradeCount", + "columnName": "upgrade_count", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"04130d73cf4edde498a7b6833f40049d\")" + ] + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt index 24524df21452..7572209399fc 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt @@ -52,7 +52,6 @@ import com.duckduckgo.app.global.install.AppInstallStore import com.duckduckgo.app.global.model.SiteFactory import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry -import com.duckduckgo.app.privacy.db.SiteVisitedEntity import com.duckduckgo.app.privacy.model.PrivacyPractices import com.duckduckgo.app.privacy.store.PrevalenceStore import com.duckduckgo.app.settings.db.SettingsDataStore @@ -298,7 +297,7 @@ class BrowserTabViewModelTest { fun whenTrackerDetectedThenNetworkLeaderboardUpdated() { val event = TrackingEvent("http://www.example.com", "http://www.tracker.com/tracker.js", TrackerNetwork("Network1", "www.tracker.com"), false) testee.trackerDetected(event) - verify(mockNetworkLeaderboardDao).insert(NetworkLeaderboardEntry("Network1", "www.example.com")) + verify(mockNetworkLeaderboardDao).incrementNetworkCount("Network1") } @Test @@ -389,7 +388,7 @@ class BrowserTabViewModelTest { isBrowsing(true) testee.loadingStarted("http://example.com/abc") testee.loadingFinished("http://example.com/abc") - verify(mockNetworkLeaderboardDao).insert(SiteVisitedEntity("example.com")) + verify(mockNetworkLeaderboardDao).incrementSitesVisited() } @Test @@ -397,7 +396,7 @@ class BrowserTabViewModelTest { isBrowsing(false) testee.loadingStarted("http://example.com/abc") testee.loadingFinished("http://example.com/abc") - verify(mockNetworkLeaderboardDao, never()).insert(SiteVisitedEntity("example.com")) + verify(mockNetworkLeaderboardDao, never()).incrementSitesVisited() } @Test @@ -443,13 +442,13 @@ class BrowserTabViewModelTest { @Test fun whenLoadingFinishedWithNoUrlThenSiteVisitedEntryNotAddedToLeaderboardDao() { testee.loadingFinished(null) - verify(mockNetworkLeaderboardDao, never()).insert(SiteVisitedEntity("example.com")) + verify(mockNetworkLeaderboardDao, never()).incrementSitesVisited() } @Test fun whenTrackerDetectedThenSiteVisitedEntryAddedToLeaderboardDao() { testee.trackerDetected(TrackingEvent("http://example.com/abc", "http://tracker.com", TrackerNetwork("Network", "http:// netwotk.com"), true)) - verify(mockNetworkLeaderboardDao).insert(SiteVisitedEntity("example.com")) + verify(mockNetworkLeaderboardDao).incrementSitesVisited() } @Test diff --git a/app/src/androidTest/java/com/duckduckgo/app/global/db/AppDatabaseTest.kt b/app/src/androidTest/java/com/duckduckgo/app/global/db/AppDatabaseTest.kt index 41984f5a6a8e..afdec041dc57 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/global/db/AppDatabaseTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/global/db/AppDatabaseTest.kt @@ -52,7 +52,7 @@ class AppDatabaseTest { testHelper.createDatabase(TEST_DB_NAME, 2).use { it.execSQL("INSERT INTO `network_leaderboard` VALUES ('Network2', 'example.com')") } - assertTrue(database().networkLeaderboardDao().trackerNetworkTally().blockingObserve()!!.isEmpty()) + assertTrue(database().networkLeaderboardDao().trackerNetworkLeaderboard().blockingObserve()!!.isEmpty()) } @Test @@ -120,6 +120,11 @@ class AppDatabaseTest { createDatabaseAndMigrate(11, 12, AppDatabase.MIGRATION_11_TO_12) } + @Test + fun whenMigratingFromVersion12To13ThenValidationSucceeds() { + createDatabaseAndMigrate(12, 13, AppDatabase.MIGRATION_12_TO_13) + } + @Test fun whenMigratingFromVersion11To12ThenTabsDoNotSkipHome() { testHelper.createDatabase(TEST_DB_NAME, 11).use { diff --git a/app/src/androidTest/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDaoTest.kt b/app/src/androidTest/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDaoTest.kt index 8cf69bb54a0a..58d347ed1288 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDaoTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDaoTest.kt @@ -21,7 +21,6 @@ import androidx.room.Room import androidx.test.platform.app.InstrumentationRegistry import com.duckduckgo.app.blockingObserve import com.duckduckgo.app.global.db.AppDatabase -import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue @@ -54,31 +53,34 @@ class NetworkLeaderboardDaoTest { } @Test - fun whenNetworksInsertedThenAddedToTallyWithCount() { - dao.insert(NetworkLeaderboardEntry("Network1", domainVisited = "www.example1.com")) - dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example2.com")) - dao.insert(NetworkLeaderboardEntry("Network3", domainVisited = "www.example3.com")) - - val data: List? = dao.trackerNetworkTally().blockingObserve() - assertEquals(3, data!!.size) - assertTrue(data.contains(NetworkTally("Network1", 1))) - assertTrue(data.contains(NetworkTally("Network2", 1))) - assertTrue(data.contains(NetworkTally("Network3", 1))) + fun whenNetworkThatDoesNotExistIncrementedThenAddedToDatabase() { + dao.incrementNetworkCount("Network1") + val data: List? = dao.trackerNetworkLeaderboard().blockingObserve() + assertEquals(1, data!!.size) + assertTrue(data.contains(NetworkLeaderboardEntry("Network1", 1))) } + @Test - fun whenNetworksHaveMultipleDomainsThenAddedToTallyWithCountInDescendingOrder() { - dao.insert(NetworkLeaderboardEntry("Network1", domainVisited = "www.example1.com")) - dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example1.com")) - dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example2.com")) - dao.insert(NetworkLeaderboardEntry("Network2", domainVisited = "www.example3.com")) - dao.insert(NetworkLeaderboardEntry("Network3", domainVisited = "www.example3.com")) - dao.insert(NetworkLeaderboardEntry("Network3", domainVisited = "www.example4.com")) + fun whenNetworksIncrementedMultipleTimesThenReturnedWithCountInDescendingOrder() { + dao.incrementNetworkCount("Network1") + dao.incrementNetworkCount("Network2") + dao.incrementNetworkCount("Network2") + dao.incrementNetworkCount("Network2") + dao.incrementNetworkCount("Network3") + dao.incrementNetworkCount("Network3") + val data: List = dao.trackerNetworkLeaderboard().blockingObserve()!! + assertEquals(NetworkLeaderboardEntry("Network2", 3), data[0]) + assertEquals(NetworkLeaderboardEntry("Network3", 2), data[1]) + assertEquals(NetworkLeaderboardEntry("Network1", 1), data[2]) + } - val data: List = dao.trackerNetworkTally().blockingObserve()!! - assertEquals(NetworkTally("Network2", 3), data[0]) - assertEquals(NetworkTally("Network3", 2), data[1]) - assertEquals(NetworkTally("Network1", 1), data[2]) + @Test + fun whenSiteVisitedIncremenetedThenSiteVisitedCountIncreaesByOne() { + dao.incrementSitesVisited() + assertEquals(1, dao.sitesVisited().blockingObserve()) + dao.incrementSitesVisited() + assertEquals(2, dao.sitesVisited().blockingObserve()) } } diff --git a/app/src/androidTest/java/com/duckduckgo/app/privacy/renderer/TrackersRendererTest.kt b/app/src/androidTest/java/com/duckduckgo/app/privacy/renderer/TrackersRendererTest.kt index b1b0802cb526..70e3f0450ab7 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/privacy/renderer/TrackersRendererTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/privacy/renderer/TrackersRendererTest.kt @@ -18,7 +18,7 @@ package com.duckduckgo.app.privacy.renderer import androidx.test.platform.app.InstrumentationRegistry import com.duckduckgo.app.browser.R -import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally +import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Test @@ -65,26 +65,26 @@ class TrackersRendererTest { } @Test - fun whenTotalDomainsIsZeroThenPercentageIsBlank() { - val text = testee.networkPercentage(NetworkTally("", 10), 0) + fun whenSitestVisitedIsZeroThenPercentageIsBlank() { + val text = testee.networkPercentage(NetworkLeaderboardEntry("", 10), 0) assertEquals("", text) } @Test - fun whenDomainCountIsZeroThenPercentageIsBlank() { - val text = testee.networkPercentage(NetworkTally("", 0), 10) + fun whenNetworkCountIsZeroThenPercentageIsBlank() { + val text = testee.networkPercentage(NetworkLeaderboardEntry("", 0), 10) assertEquals("", text) } @Test fun whenPortionIsRecurringFractionThenPercentageIsRoundNumber() { - val text = testee.networkPercentage(NetworkTally("", 10), 30) + val text = testee.networkPercentage(NetworkLeaderboardEntry("", 10), 30) assertEquals("33%", text) } @Test fun whenPortionIsHalfThenPercentageIs50Percent() { - val text = testee.networkPercentage(NetworkTally("", 10), 20) + val text = testee.networkPercentage(NetworkLeaderboardEntry("", 10), 20) assertEquals("50%", text) } diff --git a/app/src/androidTest/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModelTest.kt index ebf5cf1f3f10..6f34a2d58b0b 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModelTest.kt @@ -21,7 +21,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import com.duckduckgo.app.global.model.Site import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao -import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally +import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry import com.duckduckgo.app.privacy.model.HttpsStatus import com.duckduckgo.app.privacy.model.PrivacyGrade import com.duckduckgo.app.privacy.model.PrivacyPractices @@ -47,23 +47,23 @@ class PrivacyDashboardViewModelTest { private var viewStateObserver: Observer = mock() private var settingStore: PrivacySettingsStore = mock() - private var networkLeaderboard: NetworkLeaderboardDao = mock() - private var networkTallyLiveData: LiveData> = mock() - private var domainsVisitedLiveData: LiveData = mock() + private var networkLeaderboardDao: NetworkLeaderboardDao = mock() + private var networkLeaserboardLiveData: LiveData> = mock() + private var sitesVisitedLiveData: LiveData = mock() private var mockPixel: Pixel = mock() private val testee: PrivacyDashboardViewModel by lazy { - val model = PrivacyDashboardViewModel(settingStore, networkLeaderboard, mockPixel) + val model = PrivacyDashboardViewModel(settingStore, networkLeaderboardDao, mockPixel) model.viewState.observeForever(viewStateObserver) model } @Before fun before() { - whenever(domainsVisitedLiveData.value).thenReturn(0) - whenever(networkTallyLiveData.value).thenReturn(emptyList()) - whenever(networkLeaderboard.domainsVisitedCount()).thenReturn(domainsVisitedLiveData) - whenever(networkLeaderboard.trackerNetworkTally()).thenReturn(networkTallyLiveData) + whenever(sitesVisitedLiveData.value).thenReturn(0) + whenever(networkLeaserboardLiveData.value).thenReturn(emptyList()) + whenever(networkLeaderboardDao.sitesVisited()).thenReturn(sitesVisitedLiveData) + whenever(networkLeaderboardDao.trackerNetworkLeaderboard()).thenReturn(networkLeaserboardLiveData) } @After @@ -151,50 +151,50 @@ class PrivacyDashboardViewModelTest { } @Test - fun whenNetworkCountIsAtLeastThreeAndTotalDomainsIsOverThirtyThenShowSummaryIsTrue() { - val first = NetworkTally("Network1", 5) - val second = NetworkTally("Network2", 3) - val third = NetworkTally("Network3", 3) - testee.onTrackerNetworkTallyChanged(listOf(first, second, third)) - testee.onDomainsVisitedChanged(31) + fun whenNetworkCountIsAtLeastThreeAndTotalSitesIsOverThirtyThenShowSummaryIsTrue() { + val first = NetworkLeaderboardEntry("Network1", 5) + val second = NetworkLeaderboardEntry("Network2", 3) + val third = NetworkLeaderboardEntry("Network3", 3) + testee.onTrackerNetworkEntriesChanged(listOf(first, second, third)) + testee.onSitesVisitedChanged(31) assertTrue(testee.viewState.value!!.showTrackerNetworkLeaderboard) } @Test fun whenNetworkCountIsLessThanThreeThenShowSummaryIsFalse() { - val first = NetworkTally("Network1", 5) - val second = NetworkTally("Network2", 3) - testee.onTrackerNetworkTallyChanged(listOf(first, second)) - testee.onDomainsVisitedChanged(31) + val first = NetworkLeaderboardEntry("Network1", 5) + val second = NetworkLeaderboardEntry("Network2", 3) + testee.onTrackerNetworkEntriesChanged(listOf(first, second)) + testee.onSitesVisitedChanged(31) assertFalse(testee.viewState.value!!.showTrackerNetworkLeaderboard) } @Test - fun whenDomainsIsNotOverThirtyThenShowSummaryIsFalse() { - val first = NetworkTally("Network1", 5) - val second = NetworkTally("Network2", 3) - val third = NetworkTally("Network3", 3) - testee.onTrackerNetworkTallyChanged(listOf(first, second, third)) - testee.onDomainsVisitedChanged(30) + fun whenSitesIsNotOverThirtyThenShowSummaryIsFalse() { + val first = NetworkLeaderboardEntry("Network1", 5) + val second = NetworkLeaderboardEntry("Network2", 3) + val third = NetworkLeaderboardEntry("Network3", 3) + testee.onTrackerNetworkEntriesChanged(listOf(first, second, third)) + testee.onSitesVisitedChanged(30) assertFalse(testee.viewState.value!!.showTrackerNetworkLeaderboard) } @Test fun whenNetworkLeaderboardDataAvailableThenViewStateUpdated() { - val first = NetworkTally("Network1", 5) - val second = NetworkTally("Network2", 3) - testee.onTrackerNetworkTallyChanged(listOf(first, second)) + val first = NetworkLeaderboardEntry("Network1", 5) + val second = NetworkLeaderboardEntry("Network2", 3) + testee.onTrackerNetworkEntriesChanged(listOf(first, second)) val viewState = testee.viewState.value!! - assertEquals(first, viewState.trackerNetworkTally[0]) - assertEquals(second, viewState.trackerNetworkTally[1]) + assertEquals(first, viewState.trackerNetworkEntries[0]) + assertEquals(second, viewState.trackerNetworkEntries[1]) } @Test fun whenNoNetworkLeaderboardDataThenDefaultValuesAreUsed() { - testee.onTrackerNetworkTallyChanged(emptyList()) + testee.onTrackerNetworkEntriesChanged(emptyList()) val viewState = testee.viewState.value!! - assertEquals(emptyList(), viewState.trackerNetworkTally) + assertEquals(emptyList(), viewState.trackerNetworkEntries) assertFalse(viewState.showTrackerNetworkLeaderboard) } diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt index c6660131b5c0..f98197e5e562 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt @@ -55,8 +55,6 @@ import com.duckduckgo.app.global.db.AppConfigurationEntity import com.duckduckgo.app.global.model.Site import com.duckduckgo.app.global.model.SiteFactory import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao -import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry -import com.duckduckgo.app.privacy.db.SiteVisitedEntity import com.duckduckgo.app.privacy.model.PrivacyGrade import com.duckduckgo.app.settings.db.SettingsDataStore import com.duckduckgo.app.statistics.api.StatisticsUpdater @@ -431,9 +429,8 @@ class BrowserTabViewModel( } private fun registerSiteVisit() { - val domainVisited = url?.toUri()?.host ?: return Schedulers.io().scheduleDirect { - networkLeaderboardDao.insert(SiteVisitedEntity(domainVisited)) + networkLeaderboardDao.incrementSitesVisited() } } @@ -515,9 +512,8 @@ class BrowserTabViewModel( private fun updateNetworkLeaderboard(event: TrackingEvent) { val networkName = event.trackerNetwork?.name ?: return - val domainVisited = Uri.parse(event.documentUrl).host ?: return - networkLeaderboardDao.insert(NetworkLeaderboardEntry(networkName, domainVisited)) - networkLeaderboardDao.insert(SiteVisitedEntity(domainVisited)) + networkLeaderboardDao.incrementNetworkCount(networkName) + networkLeaderboardDao.incrementSitesVisited() } override fun pageHasHttpResources(page: String?) { diff --git a/app/src/main/java/com/duckduckgo/app/global/db/AppDatabase.kt b/app/src/main/java/com/duckduckgo/app/global/db/AppDatabase.kt index dfabacdf1598..c811ef5524c4 100644 --- a/app/src/main/java/com/duckduckgo/app/global/db/AppDatabase.kt +++ b/app/src/main/java/com/duckduckgo/app/global/db/AppDatabase.kt @@ -40,7 +40,7 @@ import com.duckduckgo.app.notification.model.Notification import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry import com.duckduckgo.app.privacy.db.PrivacyProtectionCountDao -import com.duckduckgo.app.privacy.db.SiteVisitedEntity +import com.duckduckgo.app.privacy.db.SitesVisitedEntity import com.duckduckgo.app.privacy.model.PrivacyProtectionCountsEntity import com.duckduckgo.app.survey.db.SurveyDao import com.duckduckgo.app.survey.model.Survey @@ -55,12 +55,12 @@ import com.duckduckgo.app.usage.search.SearchCountDao import com.duckduckgo.app.usage.search.SearchCountEntity @Database( - exportSchema = true, version = 12, entities = [ + exportSchema = true, version = 13, entities = [ DisconnectTracker::class, HttpsBloomFilterSpec::class, HttpsWhitelistedDomain::class, NetworkLeaderboardEntry::class, - SiteVisitedEntity::class, + SitesVisitedEntity::class, AppConfigurationEntity::class, TabEntity::class, TabSelectionEntity::class, @@ -188,6 +188,15 @@ abstract class AppDatabase : RoomDatabase() { } } + val MIGRATION_12_TO_13: Migration = object : Migration(12, 13) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE `site_visited`") + database.execSQL("DROP TABLE `network_leaderboard`") + database.execSQL("CREATE TABLE IF NOT EXISTS `sites_visited` (`key` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`key`))") + database.execSQL("CREATE TABLE IF NOT EXISTS `network_leaderboard` (`networkName` TEXT NOT NULL, `count` INTEGER NOT NULL, PRIMARY KEY(`networkName`))") + } + } + val ALL_MIGRATIONS: List get() = listOf( MIGRATION_1_TO_2, @@ -200,7 +209,8 @@ abstract class AppDatabase : RoomDatabase() { MIGRATION_8_TO_9, MIGRATION_9_TO_10, MIGRATION_10_TO_11, - MIGRATION_11_TO_12 + MIGRATION_11_TO_12, + MIGRATION_12_TO_13 ) } } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDao.kt b/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDao.kt index 11c942ad162a..176eaf162287 100644 --- a/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDao.kt +++ b/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardDao.kt @@ -17,30 +17,43 @@ package com.duckduckgo.app.privacy.db import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query +import androidx.room.* @Dao -interface NetworkLeaderboardDao { +abstract class NetworkLeaderboardDao { - @Insert(onConflict = OnConflictStrategy.IGNORE) - fun insert(siteVisited: SiteVisitedEntity) + @Query("select count from sites_visited") + abstract fun sitesVisited(): LiveData + + @Transaction + open fun incrementSitesVisited() { + val changedRows = incrementSitesVisitedIfExists() + if (changedRows == 0) { + initializeSitesVisited(SitesVisitedEntity(count = 1)) + } + } + + @Insert + protected abstract fun initializeSitesVisited(entity: SitesVisitedEntity) - @Query("select count(distinct domain) from site_visited") - fun domainsVisitedCount(): LiveData + @Query("UPDATE sites_visited SET count = count + 1") + protected abstract fun incrementSitesVisitedIfExists(): Int + + @Transaction + open fun incrementNetworkCount(network: String) { + val changedRows = incrementNetworkCountIfExists(network) + if (changedRows == 0) { + initializeNetwork(NetworkLeaderboardEntry(network, 1)) + } + } @Insert(onConflict = OnConflictStrategy.IGNORE) - fun insert(leaderboardEntry: NetworkLeaderboardEntry) + protected abstract fun initializeNetwork(leaderboardEntry: NetworkLeaderboardEntry) + + @Query("UPDATE network_leaderboard SET count = count + 1 WHERE networkName = :networkName") + protected abstract fun incrementNetworkCountIfExists(networkName: String): Int - @Query( - "select networkName, count(domainVisited) as domainCount " + - "from network_leaderboard " + - "group by networkName " + - "order by domainCount desc" - ) - fun trackerNetworkTally(): LiveData> - data class NetworkTally(val networkName: String, val domainCount: Int) + @Query("select * from network_leaderboard order by count desc") + abstract fun trackerNetworkLeaderboard(): LiveData> } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardEntry.kt b/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardEntry.kt index bde37408c0cb..a55e17bb31f2 100644 --- a/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardEntry.kt +++ b/app/src/main/java/com/duckduckgo/app/privacy/db/NetworkLeaderboardEntry.kt @@ -17,12 +17,12 @@ package com.duckduckgo.app.privacy.db import androidx.room.Entity +import androidx.room.PrimaryKey @Entity( - tableName = "network_leaderboard", - primaryKeys = ["networkName", "domainVisited"] + tableName = "network_leaderboard" ) data class NetworkLeaderboardEntry( - val networkName: String, - val domainVisited: String + @PrimaryKey val networkName: String, + val count: Int ) diff --git a/app/src/main/java/com/duckduckgo/app/privacy/db/SiteVisitedEntity.kt b/app/src/main/java/com/duckduckgo/app/privacy/db/SitesVisitedEntity.kt similarity index 76% rename from app/src/main/java/com/duckduckgo/app/privacy/db/SiteVisitedEntity.kt rename to app/src/main/java/com/duckduckgo/app/privacy/db/SitesVisitedEntity.kt index 4626b5b5cd87..359c0b30a972 100644 --- a/app/src/main/java/com/duckduckgo/app/privacy/db/SiteVisitedEntity.kt +++ b/app/src/main/java/com/duckduckgo/app/privacy/db/SitesVisitedEntity.kt @@ -19,7 +19,12 @@ package com.duckduckgo.app.privacy.db import androidx.room.Entity import androidx.room.PrimaryKey -@Entity(tableName = "site_visited") -data class SiteVisitedEntity( - @PrimaryKey val domain: String -) +@Entity(tableName = "sites_visited") +data class SitesVisitedEntity( + @PrimaryKey val key: String = SINGLETON_KEY, + val count: Int +) { + companion object { + const val SINGLETON_KEY = "SINGLETON_KEY" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/privacy/renderer/TrackersRenderer.kt b/app/src/main/java/com/duckduckgo/app/privacy/renderer/TrackersRenderer.kt index ef0a61c76409..a4b8c8def65b 100644 --- a/app/src/main/java/com/duckduckgo/app/privacy/renderer/TrackersRenderer.kt +++ b/app/src/main/java/com/duckduckgo/app/privacy/renderer/TrackersRenderer.kt @@ -19,7 +19,7 @@ package com.duckduckgo.app.privacy.renderer import android.content.Context import androidx.annotation.DrawableRes import com.duckduckgo.app.browser.R -import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally +import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry class TrackersRenderer { @@ -63,9 +63,9 @@ class TrackersRenderer { return if (resource != 0) resource else null } - fun networkPercentage(tally: NetworkTally, totalDomainsVisited: Int): String? { - if (totalDomainsVisited == 0 || tally.domainCount == 0) return "" - val to100 = ((tally.domainCount / totalDomainsVisited.toFloat()) * 100).toInt() + fun networkPercentage(network: NetworkLeaderboardEntry, totalDomainsVisited: Int): String? { + if (totalDomainsVisited == 0 || network.count == 0) return "" + val to100 = ((network.count / totalDomainsVisited.toFloat()) * 100).toInt() return "$to100%" } diff --git a/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardActivity.kt b/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardActivity.kt index 0cc719193bda..a887ca8e4d89 100644 --- a/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardActivity.kt @@ -104,9 +104,9 @@ class PrivacyDashboardActivity : DuckDuckGoActivity() { return } - trackerNetworkPill1.render(viewState.trackerNetworkTally.elementAtOrNull(0), viewState.domainsVisited) - trackerNetworkPill2.render(viewState.trackerNetworkTally.elementAtOrNull(1), viewState.domainsVisited) - trackerNetworkPill3.render(viewState.trackerNetworkTally.elementAtOrNull(2), viewState.domainsVisited) + trackerNetworkPill1.render(viewState.trackerNetworkEntries.elementAtOrNull(0), viewState.sitesVisited) + trackerNetworkPill2.render(viewState.trackerNetworkEntries.elementAtOrNull(1), viewState.sitesVisited) + trackerNetworkPill3.render(viewState.trackerNetworkEntries.elementAtOrNull(2), viewState.sitesVisited) showTrackerNetworkLeaderboard() } diff --git a/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModel.kt b/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModel.kt index 5461532924da..572d1f20714d 100644 --- a/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/privacy/ui/PrivacyDashboardViewModel.kt @@ -23,7 +23,7 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModel import com.duckduckgo.app.global.model.Site import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao -import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally +import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry import com.duckduckgo.app.privacy.model.HttpsStatus import com.duckduckgo.app.privacy.model.PrivacyGrade import com.duckduckgo.app.privacy.model.PrivacyPractices @@ -48,18 +48,18 @@ class PrivacyDashboardViewModel( val practices: PrivacyPractices.Summary, val toggleEnabled: Boolean, val showTrackerNetworkLeaderboard: Boolean, - val domainsVisited: Int, - val trackerNetworkTally: List, + val sitesVisited: Int, + val trackerNetworkEntries: List, val shouldReloadPage: Boolean ) val viewState: MutableLiveData = MutableLiveData() private var site: Site? = null - private val domainsVisited: LiveData = networkLeaderboardDao.domainsVisitedCount() - private val domainsVisitedObserver = Observer { onDomainsVisitedChanged(it) } - private val trackerNetworkTally: LiveData> = networkLeaderboardDao.trackerNetworkTally() - private val trackerNetworkActivityObserver = Observer> { onTrackerNetworkTallyChanged(it) } + private val sitesVisited: LiveData = networkLeaderboardDao.sitesVisited() + private val sitesVisitedObserver = Observer { onSitesVisitedChanged(it) } + private val trackerNetworkLeaderboard: LiveData> = networkLeaderboardDao.trackerNetworkLeaderboard() + private val trackerNetworkActivityObserver = Observer> { onTrackerNetworkEntriesChanged(it) } private val privacyInitiallyOn = settingsStore.privacyOn @@ -69,37 +69,37 @@ class PrivacyDashboardViewModel( init { pixel.fire(PRIVACY_DASHBOARD_OPENED) resetViewState() - domainsVisited.observeForever(domainsVisitedObserver) - trackerNetworkTally.observeForever(trackerNetworkActivityObserver) + sitesVisited.observeForever(sitesVisitedObserver) + trackerNetworkLeaderboard.observeForever(trackerNetworkActivityObserver) } @VisibleForTesting public override fun onCleared() { super.onCleared() - domainsVisited.removeObserver(domainsVisitedObserver) - trackerNetworkTally.removeObserver(trackerNetworkActivityObserver) + sitesVisited.removeObserver(sitesVisitedObserver) + trackerNetworkLeaderboard.removeObserver(trackerNetworkActivityObserver) } - fun onDomainsVisitedChanged(count: Int?) { - val domainCount = count ?: 0 - val networkCount = viewState.value?.trackerNetworkTally?.count() ?: 0 + fun onSitesVisitedChanged(count: Int?) { + val siteCount = count ?: 0 + val networkCount = viewState.value?.trackerNetworkEntries?.count() ?: 0 viewState.value = viewState.value?.copy( - showTrackerNetworkLeaderboard = showTrackerNetworkLeaderboard(domainCount, networkCount), - domainsVisited = domainCount + showTrackerNetworkLeaderboard = showTrackerNetworkLeaderboard(siteCount, networkCount), + sitesVisited = siteCount ) } - fun onTrackerNetworkTallyChanged(tally: List?) { - val domainCount = viewState.value?.domainsVisited ?: 0 - val networkTally = tally ?: emptyList() + fun onTrackerNetworkEntriesChanged(networkLeaderboardEntries: List?) { + val domainCount = viewState.value?.sitesVisited ?: 0 + val networkEntries = networkLeaderboardEntries ?: emptyList() viewState.value = viewState.value?.copy( - showTrackerNetworkLeaderboard = showTrackerNetworkLeaderboard(domainCount, networkTally.count()), - trackerNetworkTally = networkTally + showTrackerNetworkLeaderboard = showTrackerNetworkLeaderboard(domainCount, networkEntries.count()), + trackerNetworkEntries = networkEntries ) } - private fun showTrackerNetworkLeaderboard(domainCount: Int, networkCount: Int): Boolean { - return domainCount > LEADERNOARD_MIN_DOMAINS_EXCLUSIVE && networkCount >= LEADERBOARD_MIN_NETWORKS + private fun showTrackerNetworkLeaderboard(siteVisitedCount: Int, networkCount: Int): Boolean { + return siteVisitedCount > LEADERBOARD_MIN_DOMAINS_EXCLUSIVE && networkCount >= LEADERBOARD_MIN_NETWORKS } fun onSiteChanged(site: Site?) { @@ -122,8 +122,8 @@ class PrivacyDashboardViewModel( toggleEnabled = settingsStore.privacyOn, practices = UNKNOWN, showTrackerNetworkLeaderboard = false, - domainsVisited = 0, - trackerNetworkTally = emptyList(), + sitesVisited = 0, + trackerNetworkEntries = emptyList(), shouldReloadPage = shouldReloadPage ) } @@ -158,7 +158,7 @@ class PrivacyDashboardViewModel( private companion object { private const val LEADERBOARD_MIN_NETWORKS = 3 - private const val LEADERNOARD_MIN_DOMAINS_EXCLUSIVE = 30 + private const val LEADERBOARD_MIN_DOMAINS_EXCLUSIVE = 30 } } diff --git a/app/src/main/java/com/duckduckgo/app/privacy/ui/TrackerNetworkLeaderboardPillView.kt b/app/src/main/java/com/duckduckgo/app/privacy/ui/TrackerNetworkLeaderboardPillView.kt index 392002776e96..8ba56719c1fa 100644 --- a/app/src/main/java/com/duckduckgo/app/privacy/ui/TrackerNetworkLeaderboardPillView.kt +++ b/app/src/main/java/com/duckduckgo/app/privacy/ui/TrackerNetworkLeaderboardPillView.kt @@ -21,7 +21,7 @@ import android.util.AttributeSet import android.view.View import android.widget.FrameLayout import com.duckduckgo.app.browser.R -import com.duckduckgo.app.privacy.db.NetworkLeaderboardDao.NetworkTally +import com.duckduckgo.app.privacy.db.NetworkLeaderboardEntry import com.duckduckgo.app.privacy.renderer.TrackersRenderer import kotlinx.android.synthetic.main.view_network_tracker_pill.view.* @@ -45,11 +45,11 @@ class TrackerNetworkLeaderboardPillView : FrameLayout { View.inflate(context, R.layout.view_network_tracker_pill, this) } - fun render(tally: NetworkTally?, totalDomains: Int) { - tally ?: return - icon.setImageResource(renderer.networkPillIcon(context, tally.networkName) ?: R.drawable.network_pill_generic) - val percentText = renderer.networkPercentage(tally, totalDomains) - icon.contentDescription = "${tally.networkName} $percentText" + fun render(netowrkEntity: NetworkLeaderboardEntry?, totalSitesVisited: Int) { + netowrkEntity ?: return + icon.setImageResource(renderer.networkPillIcon(context, netowrkEntity.networkName) ?: R.drawable.network_pill_generic) + val percentText = renderer.networkPercentage(netowrkEntity, totalSitesVisited) + icon.contentDescription = "${netowrkEntity.networkName} $percentText" percentage.text = percentText }