Skip to content

Commit 0f478e5

Browse files
authored
Back navigation to previous tab (#897)
* only store sourceTabId when tab is opened after clicking on a link * Store sourceTabId only when tab opened from current tab * store sourceTabId when tab opened in background from currentTab * When back pressed, if sourceTab of current tab is different to null, navigate to that tab * use room to nullify sourceTabId when tab deleted * Rename method to be explicit about what sourceTab will be added. Cleanup a isDefaultTab as it was never used in some parts of the code. * Passing around sourceTabId from tab fragment. Adds flexibility and it's more explicit about what's happening. * Removing isDefaultTab param from multiple methods where it was always false * Add necessary migration to create foreign key in table tabs
1 parent 408259c commit 0f478e5

File tree

14 files changed

+214
-135
lines changed

14 files changed

+214
-135
lines changed

app/schemas/com.duckduckgo.app.global.db.AppDatabase/24.json

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"formatVersion": 1,
33
"database": {
44
"version": 24,
5-
"identityHash": "03673f6d5937091013955e2520b94c0e",
5+
"identityHash": "d6df0e21b463f404e4ea0a430f7d905c",
66
"entities": [
77
{
88
"tableName": "tds_tracker",
@@ -258,7 +258,7 @@
258258
},
259259
{
260260
"tableName": "tabs",
261-
"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, `tabPreviewFile` TEXT, `sourceTabId` TEXT, PRIMARY KEY(`tabId`))",
261+
"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, `tabPreviewFile` TEXT, `sourceTabId` TEXT, PRIMARY KEY(`tabId`), FOREIGN KEY(`sourceTabId`) REFERENCES `tabs`(`tabId`) ON UPDATE SET NULL ON DELETE SET NULL )",
262262
"fields": [
263263
{
264264
"fieldPath": "tabId",
@@ -325,7 +325,19 @@
325325
"createSql": "CREATE INDEX IF NOT EXISTS `index_tabs_tabId` ON `${TABLE_NAME}` (`tabId`)"
326326
}
327327
],
328-
"foreignKeys": []
328+
"foreignKeys": [
329+
{
330+
"table": "tabs",
331+
"onDelete": "SET NULL",
332+
"onUpdate": "SET NULL",
333+
"columns": [
334+
"sourceTabId"
335+
],
336+
"referencedColumns": [
337+
"tabId"
338+
]
339+
}
340+
]
329341
},
330342
{
331343
"tableName": "tab_selection",
@@ -746,7 +758,7 @@
746758
"views": [],
747759
"setupQueries": [
748760
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
749-
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '03673f6d5937091013955e2520b94c0e')"
761+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd6df0e21b463f404e4ea0a430f7d905c')"
750762
]
751763
}
752764
}

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,9 @@ class BrowserTabViewModelTest {
476476
givenOneActiveTabSelected()
477477
givenInvalidatedGlobalLayout()
478478
testee.onUserSubmittedQuery("foo")
479-
assertCommandIssued<Command.OpenInNewTab>()
479+
assertCommandIssued<Command.OpenInNewTab> {
480+
assertNull(sourceTabId)
481+
}
480482
}
481483

482484
@Test
@@ -1093,7 +1095,9 @@ class BrowserTabViewModelTest {
10931095

10941096
testee.onRefreshRequested()
10951097

1096-
assertCommandIssued<Command.OpenInNewTab>()
1098+
assertCommandIssued<Command.OpenInNewTab>() {
1099+
assertNull(sourceTabId)
1100+
}
10971101
}
10981102

10991103
@Test
@@ -1188,6 +1192,10 @@ class BrowserTabViewModelTest {
11881192
testee.userSelectedItemFromLongPressMenu(longPressTarget, mockMenItem)
11891193
val command = captureCommands().value as Command.OpenInNewTab
11901194
assertEquals("http://example.com", command.query)
1195+
1196+
assertCommandIssued<Command.OpenInNewTab> {
1197+
assertNotNull(sourceTabId)
1198+
}
11911199
}
11921200

11931201
@Test
@@ -1319,18 +1327,6 @@ class BrowserTabViewModelTest {
13191327
assertEquals(true, testee.browserViewState.value?.browserShowing)
13201328
}
13211329

1322-
@Test
1323-
fun whenOpenInNewTabThenOpenInNewTabCommandWithCorrectUrlSent() {
1324-
val url = "https://example.com"
1325-
testee.openInNewTab(url)
1326-
verify(mockCommandObserver).onChanged(commandCaptor.capture())
1327-
1328-
val command = commandCaptor.lastValue
1329-
assertTrue(command is Command.OpenInNewTab)
1330-
command as Command.OpenInNewTab
1331-
assertEquals(url, command.query)
1332-
}
1333-
13341330
@Test
13351331
fun whenRecoveringFromProcessGoneThenShowErrorWithAction() {
13361332
testee.recoverFromRenderProcessGone()
@@ -1348,6 +1344,7 @@ class BrowserTabViewModelTest {
13481344

13491345
assertCommandIssued<Command.OpenInNewTab> {
13501346
assertEquals("https://example.com", query)
1347+
assertNull(sourceTabId)
13511348
}
13521349
}
13531350

@@ -1558,6 +1555,16 @@ class BrowserTabViewModelTest {
15581555
assertTrue(commandCaptor.allValues.contains(Command.ShowKeyboard))
15591556
}
15601557

1558+
@Test
1559+
fun whenUserPressesBackOnATabWithASourceTabThenDeleteCurrentAndSelectSource() = coroutineRule.runBlocking {
1560+
selectedTabLiveData.value = TabEntity("TAB_ID", "https://example.com", position = 0, sourceTabId = "TAB_ID_SOURCE")
1561+
setupNavigation(isBrowsing = true)
1562+
1563+
testee.onUserPressedBack()
1564+
1565+
verify(mockTabsRepository).deleteCurrentTabAndSelectSource()
1566+
}
1567+
15611568
@Test
15621569
fun whenScheduledSurveyChangesAndInstalledDaysMatchThenCtaIsSurvey() {
15631570
testee.onSurveyChanged(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,14 @@ class BrowserViewModelTest {
123123
fun whenNewTabRequestedThenTabAddedToRepository() = runBlocking<Unit> {
124124
whenever(mockTabRepository.liveSelectedTab).doReturn(MutableLiveData())
125125
testee.onNewTabRequested()
126-
verify(mockTabRepository).addWithSource()
126+
verify(mockTabRepository).add()
127+
}
128+
129+
@Test
130+
fun whenNewTabRequestedFromSourceTabThenTabAddedToRepositoryWithSourceTabId() = runBlocking<Unit> {
131+
whenever(mockTabRepository.liveSelectedTab).doReturn(MutableLiveData())
132+
testee.onNewTabRequested("sourceTabId")
133+
verify(mockTabRepository).addFromSourceTab(sourceTabId = "sourceTabId")
127134
}
128135

129136
@Test
@@ -132,13 +139,22 @@ class BrowserViewModelTest {
132139
whenever(mockOmnibarEntryConverter.convertQueryToUrl(url)).thenReturn(url)
133140
whenever(mockTabRepository.liveSelectedTab).doReturn(MutableLiveData())
134141
testee.onOpenInNewTabRequested(url)
135-
verify(mockTabRepository).addWithSource(url)
142+
verify(mockTabRepository).add(url = url, skipHome = false)
143+
}
144+
145+
@Test
146+
fun whenOpenInNewTabRequestedWithSourceTabIdThenTabAddedToRepositoryWithSourceTabId() = runBlocking<Unit> {
147+
val url = "http://example.com"
148+
whenever(mockOmnibarEntryConverter.convertQueryToUrl(url)).thenReturn(url)
149+
whenever(mockTabRepository.liveSelectedTab).doReturn(MutableLiveData())
150+
testee.onOpenInNewTabRequested(url, sourceTabId = "tabId")
151+
verify(mockTabRepository).addFromSourceTab(url = url, skipHome = false, sourceTabId = "tabId")
136152
}
137153

138154
@Test
139-
fun whenTabsUpdatedAndNoTabsThenNewTabAddedToRepository() = runBlocking<Unit> {
155+
fun whenTabsUpdatedAndNoTabsThenDefaultTabAddedToRepository() = runBlocking<Unit> {
140156
testee.onTabsUpdated(ArrayList())
141-
verify(mockTabRepository).add(null, false, true)
157+
verify(mockTabRepository).addDefaultTab()
142158
}
143159

144160
@Test

app/src/androidTest/java/com/duckduckgo/app/tabs/db/TabsDaoTest.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ class TabsDaoTest {
206206

207207
@Test
208208
fun whenTabInsertedAtPositionThenOtherTabsReordered() {
209-
210209
testee.insertTab(TabEntity("TAB_ID1", position = 0))
211210
testee.insertTab(TabEntity("TAB_ID2", position = 1))
212211
testee.insertTab(TabEntity("TAB_ID3", position = 2))
@@ -226,7 +225,18 @@ class TabsDaoTest {
226225

227226
assertEquals(3, tabs[3].position)
228227
assertEquals("TAB_ID3", tabs[3].tabId)
229-
230228
}
231229

230+
@Test
231+
fun whenSourceTabDeletedThenRelatedTabsUpdated() {
232+
val firstTab = TabEntity("TAB_ID", "http//updatedexample.com", position = 0)
233+
val secondTab = TabEntity("TAB_ID_1", "http//updatedexample.com", position = 1, sourceTabId = "TAB_ID")
234+
testee.insertTab(firstTab)
235+
testee.insertTab(secondTab)
236+
237+
testee.deleteTab(firstTab)
238+
239+
assertNotNull(testee.tab("TAB_ID_1"))
240+
assertNull(testee.tab("TAB_ID_1")?.sourceTabId)
241+
}
232242
}

0 commit comments

Comments
 (0)