Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit a750777

Browse files
authored
Lazy load background tabs at app startup (#553)
Task/Issue URL: https://app.asana.com/0/1177771139624306/1201065943414949/f Description: I added a mechanism that records selected tabs in chronological order and reloads them in that order at app startup. The logic is as follows: * app launches * if there are no URL tabs or only 1 URL tab and it's currently selected, do nothing, don't even initialize * if current tab is a URL tab, wait until it finishes loading (or fails to load), otherwise proceed immediately * pick up to 3 most recently visited URL tab and reload them in background * as background tabs finish (or fail) loading, repeat previous step (keeping at most 3 concurrent loads) until 20 background tabs are loaded or there are no more URL tabs to load * as the user switches through tabs during lazy loading, record visited tabs and remove them from the lazy loading queue (they were visited manually which triggered a reload) * if 20 tabs were reloaded in background or there are no more not activated URL tabs, report finished work Additional details: * TabLazyLoader is owned by TabCollectionViewModel which serves as its data source * When lazy loader reports completion, it gets deallocated * Lazy loader does not differentiate between successful and failed loads, it only records website load attempts and completion (regardless of the outcome) - it's therefore not affected by "no internet" scenario * the implementation is based on generic types to allow for more thorough unit testing * the mechanism is inspired by how Chromium-based browsers work, but magic numbers 3 and 20 mentioned above were picked by Gabriel - you'll find more information in the Asana task. * OSLog.tabLazyLoading was added to help debugging lazy loading (disabled by default) * If there are more than 20 tabs at app startup, lazy loading starts with 10 tabs adjacent to the current one, before proceeding to 10 most recently selected. * Lazy loading is paused every time the user interacts with the current tab (triggers a navigation).
1 parent db86137 commit a750777

File tree

13 files changed

+1053
-4
lines changed

13 files changed

+1053
-4
lines changed

DuckDuckGo.xcodeproj/project.pbxproj

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
339A6B5826A044BA00E3DAE8 /* duckduckgo-privacy-dashboard in Resources */ = {isa = PBXBuildFile; fileRef = 339A6B5726A044BA00E3DAE8 /* duckduckgo-privacy-dashboard */; };
2121
371C0A2927E33EDC0070591F /* FeedbackPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371C0A2827E33EDC0070591F /* FeedbackPresenter.swift */; };
2222
371E141927E92E42009E3B5B /* MultilineScrollableTextFix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371E141827E92E42009E3B5B /* MultilineScrollableTextFix.swift */; };
23+
37534C9E28104D9B002621E7 /* TabLazyLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534C9D28104D9B002621E7 /* TabLazyLoaderTests.swift */; };
24+
37534CA028113101002621E7 /* LazyLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534C9F28113101002621E7 /* LazyLoadable.swift */; };
25+
37534CA3281132CB002621E7 /* TabLazyLoaderDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534CA2281132CB002621E7 /* TabLazyLoaderDataSource.swift */; };
26+
37534CA52811987D002621E7 /* AdjacentItemEnumeratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534CA42811987D002621E7 /* AdjacentItemEnumeratorTests.swift */; };
27+
37534CA8281198CD002621E7 /* AdjacentItemEnumerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534CA62811988E002621E7 /* AdjacentItemEnumerator.swift */; };
2328
376705AF27EB488600DD8D76 /* RoundedSelectionRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0511B3262CAA5A00F6079C /* RoundedSelectionRowView.swift */; };
2429
376705B327EC7D4F00DD8D76 /* TextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376705B227EC7D4F00DD8D76 /* TextButton.swift */; };
2530
3776582D27F71652009A6B35 /* WebsiteBreakageReportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3776582C27F71652009A6B35 /* WebsiteBreakageReportTests.swift */; };
@@ -33,6 +38,7 @@
3338
37AFCE8927DA33BA00471A10 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8827DA33BA00471A10 /* Preferences.swift */; };
3439
37AFCE8B27DB69BC00471A10 /* PreferencesDefaultBrowserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8A27DB69BC00471A10 /* PreferencesDefaultBrowserView.swift */; };
3540
37AFCE9227DB8CAD00471A10 /* PreferencesAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE9127DB8CAD00471A10 /* PreferencesAboutView.swift */; };
41+
37B11B3928095E6600CBB621 /* TabLazyLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B11B3828095E6600CBB621 /* TabLazyLoader.swift */; };
3642
37CC53EC27E8A4D10028713D /* PreferencesPrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CC53EB27E8A4D10028713D /* PreferencesPrivacyView.swift */; };
3743
37CC53F027E8D1440028713D /* PreferencesDownloadsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CC53EF27E8D1440028713D /* PreferencesDownloadsView.swift */; };
3844
37CC53F427E8D4620028713D /* NSPathControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CC53F327E8D4620028713D /* NSPathControlView.swift */; };
@@ -762,6 +768,11 @@
762768
339A6B5726A044BA00E3DAE8 /* duckduckgo-privacy-dashboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "duckduckgo-privacy-dashboard"; path = "Submodules/duckduckgo-privacy-dashboard"; sourceTree = SOURCE_ROOT; };
763769
371C0A2827E33EDC0070591F /* FeedbackPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackPresenter.swift; sourceTree = "<group>"; };
764770
371E141827E92E42009E3B5B /* MultilineScrollableTextFix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultilineScrollableTextFix.swift; sourceTree = "<group>"; };
771+
37534C9D28104D9B002621E7 /* TabLazyLoaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabLazyLoaderTests.swift; sourceTree = "<group>"; };
772+
37534C9F28113101002621E7 /* LazyLoadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyLoadable.swift; sourceTree = "<group>"; };
773+
37534CA2281132CB002621E7 /* TabLazyLoaderDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabLazyLoaderDataSource.swift; sourceTree = "<group>"; };
774+
37534CA42811987D002621E7 /* AdjacentItemEnumeratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjacentItemEnumeratorTests.swift; sourceTree = "<group>"; };
775+
37534CA62811988E002621E7 /* AdjacentItemEnumerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjacentItemEnumerator.swift; sourceTree = "<group>"; };
765776
376705B227EC7D4F00DD8D76 /* TextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextButton.swift; sourceTree = "<group>"; };
766777
3776582C27F71652009A6B35 /* WebsiteBreakageReportTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebsiteBreakageReportTests.swift; sourceTree = "<group>"; };
767778
3776582E27F82E62009A6B35 /* AutofillPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillPreferences.swift; sourceTree = "<group>"; };
@@ -774,6 +785,7 @@
774785
37AFCE8827DA33BA00471A10 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
775786
37AFCE8A27DB69BC00471A10 /* PreferencesDefaultBrowserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesDefaultBrowserView.swift; sourceTree = "<group>"; };
776787
37AFCE9127DB8CAD00471A10 /* PreferencesAboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesAboutView.swift; sourceTree = "<group>"; };
788+
37B11B3828095E6600CBB621 /* TabLazyLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabLazyLoader.swift; sourceTree = "<group>"; };
777789
37CC53EB27E8A4D10028713D /* PreferencesPrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesPrivacyView.swift; sourceTree = "<group>"; };
778790
37CC53EF27E8D1440028713D /* PreferencesDownloadsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesDownloadsView.swift; sourceTree = "<group>"; };
779791
37CC53F327E8D4620028713D /* NSPathControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSPathControlView.swift; sourceTree = "<group>"; };
@@ -1550,6 +1562,16 @@
15501562
path = dist;
15511563
sourceTree = "<group>";
15521564
};
1565+
37534CA128113277002621E7 /* TabLazyLoader */ = {
1566+
isa = PBXGroup;
1567+
children = (
1568+
37534C9F28113101002621E7 /* LazyLoadable.swift */,
1569+
37534CA2281132CB002621E7 /* TabLazyLoaderDataSource.swift */,
1570+
37B11B3828095E6600CBB621 /* TabLazyLoader.swift */,
1571+
);
1572+
path = TabLazyLoader;
1573+
sourceTree = "<group>";
1574+
};
15531575
3776582B27F7163B009A6B35 /* Website Breakage Report */ = {
15541576
isa = PBXGroup;
15551577
children = (
@@ -1971,6 +1993,7 @@
19711993
85C6A29525CC1FFD00EEB5F1 /* UserDefaultsWrapper.swift */,
19721994
B6AAAC2C260330580029438D /* PublishedAfter.swift */,
19731995
4BB6CE5E26B77ED000EC5860 /* Cryptography.swift */,
1996+
37534CA62811988E002621E7 /* AdjacentItemEnumerator.swift */,
19741997
);
19751998
path = Utilities;
19761999
sourceTree = "<group>";
@@ -2901,6 +2924,7 @@
29012924
isa = PBXGroup;
29022925
children = (
29032926
AA9FF95E24A1FB680039E328 /* TabCollectionViewModel.swift */,
2927+
37534CA128113277002621E7 /* TabLazyLoader */,
29042928
);
29052929
path = ViewModel;
29062930
sourceTree = "<group>";
@@ -3164,6 +3188,8 @@
31643188
children = (
31653189
AAC9C01D24CB6BEB00AD1325 /* TabCollectionViewModelTests.swift */,
31663190
AAE39D1A24F44885008EF28B /* TabCollectionViewModelDelegateMock.swift */,
3191+
37534C9D28104D9B002621E7 /* TabLazyLoaderTests.swift */,
3192+
37534CA42811987D002621E7 /* AdjacentItemEnumeratorTests.swift */,
31673193
);
31683194
path = ViewModel;
31693195
sourceTree = "<group>";
@@ -4057,8 +4083,10 @@
40574083
AAA0CC572539EBC90079BC96 /* FaviconUserScript.swift in Sources */,
40584084
B6A9E45A261460350067D1B9 /* ApiRequestError.swift in Sources */,
40594085
AADCBF3A26F7C2CE00EF67A8 /* LottieAnimationCache.swift in Sources */,
4086+
37534CA3281132CB002621E7 /* TabLazyLoaderDataSource.swift in Sources */,
40604087
4B723E0E26B0006300E14D75 /* LoginImport.swift in Sources */,
40614088
85589E9627BFE25D0038AD11 /* FailedAssertionView.swift in Sources */,
4089+
37534CA028113101002621E7 /* LazyLoadable.swift in Sources */,
40624090
EAE42800275D47FA00DAC26B /* ClickToLoadModel.swift in Sources */,
40634091
0230C0A3272080090018F728 /* KeyedCodingExtension.swift in Sources */,
40644092
B6C0B23026E61D630031CB7F /* DownloadListStore.swift in Sources */,
@@ -4116,6 +4144,7 @@
41164144
0230C0A52721F3750018F728 /* GPCRequestFactory.swift in Sources */,
41174145
9833912F27AAA3CE00DAF119 /* AppTrackerDataSetProvider.swift in Sources */,
41184146
4BA1A6B3258B080A00F6F690 /* EncryptionKeyGeneration.swift in Sources */,
4147+
37B11B3928095E6600CBB621 /* TabLazyLoader.swift in Sources */,
41194148
4B723E0B26B0005B00E14D75 /* CSVImportViewController.swift in Sources */,
41204149
8589063C267BCDC000D23B0D /* SaveCredentialsViewController.swift in Sources */,
41214150
4BBE0AA727B9B027003B37A8 /* PopUpButton.swift in Sources */,
@@ -4527,6 +4556,7 @@
45274556
37D2771527E870D4003365FD /* PreferencesAppearanceView.swift in Sources */,
45284557
AA72D5FE25FFF94E00C77619 /* NSMenuItemExtension.swift in Sources */,
45294558
4BA1A6C2258B0A1300F6F690 /* ContiguousBytesExtension.swift in Sources */,
4559+
37534CA8281198CD002621E7 /* AdjacentItemEnumerator.swift in Sources */,
45304560
AA9B7C7E26A06E040008D425 /* TrackerInfo.swift in Sources */,
45314561
B6553692268440D700085A79 /* WKProcessPool+GeolocationProvider.swift in Sources */,
45324562
);
@@ -4543,9 +4573,11 @@
45434573
142879DA24CE1179005419BB /* SuggestionViewModelTests.swift in Sources */,
45444574
4B9292C12667103100AD2C21 /* BookmarkMigrationTests.swift in Sources */,
45454575
4B9292BC2667103100AD2C21 /* BookmarkSidebarTreeControllerTests.swift in Sources */,
4576+
37534CA52811987D002621E7 /* AdjacentItemEnumeratorTests.swift in Sources */,
45464577
B662D3DC2755DF670035D4D6 /* OldPixelDataModel.xcdatamodeld in Sources */,
45474578
B6DA44232616CABC00DD1EC2 /* PixelArgumentsTests.swift in Sources */,
45484579
AAEC74BC2642F0F800C2EFBC /* History.xcdatamodeld in Sources */,
4580+
37534C9E28104D9B002621E7 /* TabLazyLoaderTests.swift in Sources */,
45494581
85F1B0C925EF9759004792B6 /* URLEventHandlerTests.swift in Sources */,
45504582
4B9292BD2667103100AD2C21 /* BookmarkOutlineViewDataSourceTests.swift in Sources */,
45514583
B6A5A27925B93FFF00AA7ADA /* StateRestorationManagerTests.swift in Sources */,

DuckDuckGo/Browser Tab/Model/Tab.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protocol TabDelegate: FileDownloadManagerDelegate, ContentOverlayUserScriptDeleg
4242

4343
// swiftlint:disable type_body_length
4444
// swiftlint:disable file_length
45-
final class Tab: NSObject {
45+
final class Tab: NSObject, Identifiable {
4646

4747
enum TabContent: Equatable {
4848
case homePage
@@ -147,7 +147,9 @@ final class Tab: NSObject {
147147
parentTab: Tab? = nil,
148148
shouldLoadInBackground: Bool = false,
149149
canBeClosedWithBack: Bool = false,
150-
currentDownload: URL? = nil) {
150+
lastSelectedAt: Date? = nil,
151+
currentDownload: URL? = nil
152+
) {
151153

152154
self.content = content
153155
self.faviconManagement = faviconManagement
@@ -160,6 +162,7 @@ final class Tab: NSObject {
160162
self.parentTab = parentTab
161163
self._canBeClosedWithBack = canBeClosedWithBack
162164
self.sessionStateData = sessionStateData
165+
self.lastSelectedAt = lastSelectedAt
163166
self.currentDownload = currentDownload
164167

165168
let configuration = webViewConfiguration ?? WKWebViewConfiguration()
@@ -189,6 +192,7 @@ final class Tab: NSObject {
189192
// MARK: - Event Publishers
190193

191194
let webViewDidFinishNavigationPublisher = PassthroughSubject<Void, Never>()
195+
let webViewDidFailNavigationPublisher = PassthroughSubject<Void, Never>()
192196

193197
@MainActor
194198
@Published var isAMPProtectionExtracting: Bool = false
@@ -205,6 +209,8 @@ final class Tab: NSObject {
205209

206210
var fbBlockingEnabled = true
207211

212+
var isLazyLoadingInProgress = false
213+
208214
@Published private(set) var content: TabContent {
209215
didSet {
210216
handleFavicon(oldContent: oldValue)
@@ -234,6 +240,8 @@ final class Tab: NSObject {
234240
self.content = content
235241
}
236242
}
243+
244+
var lastSelectedAt: Date?
237245

238246
@Published var title: String?
239247
@Published var error: Error?
@@ -1100,6 +1108,7 @@ extension Tab: WKNavigationDelegate {
11001108
// https://app.asana.com/0/1199230911884351/1200381133504356/f
11011109
// hasError = true
11021110

1111+
webViewDidFailNavigationPublisher.send()
11031112
invalidateSessionStateData()
11041113
}
11051114

@@ -1113,6 +1122,7 @@ extension Tab: WKNavigationDelegate {
11131122
}
11141123

11151124
self.error = error
1125+
webViewDidFailNavigationPublisher.send()
11161126
}
11171127

11181128
@available(macOS 11.3, *)

DuckDuckGo/Browser Tab/ViewModel/TabViewModel.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,27 @@ final class TabViewModel {
105105
}
106106

107107
private func subscribeToTitle() {
108-
tab.$title.receive(on: DispatchQueue.main).sink { [weak self] _ in self?.updateTitle() } .store(in: &cancellables)
108+
tab.$title
109+
.filter { [weak self] _ in
110+
self?.tab.isLazyLoadingInProgress == false
111+
}
112+
.receive(on: DispatchQueue.main)
113+
.sink { [weak self] _ in
114+
self?.updateTitle()
115+
}
116+
.store(in: &cancellables)
109117
}
110118

111119
private func subscribeToFavicon() {
112-
tab.$favicon.receive(on: DispatchQueue.main).sink { [weak self] _ in self?.updateFavicon() } .store(in: &cancellables)
120+
tab.$favicon
121+
.filter { [weak self] _ in
122+
self?.tab.isLazyLoadingInProgress == false
123+
}
124+
.receive(on: DispatchQueue.main)
125+
.sink { [weak self] _ in
126+
self?.updateFavicon()
127+
}
128+
.store(in: &cancellables)
113129
}
114130

115131
private func subscribeToTabError() {
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//
2+
// AdjacentItemEnumerator.swift
3+
//
4+
// Copyright © 2022 DuckDuckGo. All rights reserved.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
19+
import Foundation
20+
21+
/**
22+
* This struct generates array indices adjacent to a given index.
23+
*
24+
* The _adjacent_ indices are generated as diffs against given index
25+
* with the following pattern:
26+
*
27+
* 1, -1, 2, -2, 3, -3, 4, -4, ...
28+
*
29+
*/
30+
struct AdjacentItemEnumerator {
31+
32+
/**
33+
* The index of an item for which adjacent items indices are computed.
34+
*/
35+
var itemIndex: Int
36+
37+
/**
38+
* Last valid adjacent item index returned by `nextIndex(arraySize:)`.
39+
*/
40+
var currentAdjacentIndex: Int {
41+
itemIndex + currentDiff
42+
}
43+
44+
/**
45+
* Computes next adjacent index, constrained by `arraySize`.
46+
*
47+
* Returns the next available and valid index, between by `0` and `arraySize-1`,
48+
* or `nil` if the index falls outside array bounds.
49+
*/
50+
mutating func nextIndex(arraySize: Int) -> Int? {
51+
if currentDiff != 0 {
52+
operation = operation.next
53+
}
54+
55+
previousDiff = currentDiff
56+
currentDiff = operation.perform(with: currentDiff)
57+
58+
let newIndex = itemIndex + currentDiff
59+
60+
if newIndex < 0 || newIndex >= arraySize {
61+
let previousIndex = itemIndex + previousDiff
62+
if previousIndex <= 0 || previousIndex >= arraySize - 1 {
63+
return nil
64+
}
65+
return nextIndex(arraySize: arraySize)
66+
}
67+
return newIndex
68+
}
69+
70+
/**
71+
* Resets the enumerator internal state
72+
*
73+
* Calling this function is equivalent to reinstantiating the enumerator.
74+
*/
75+
mutating func reset() {
76+
currentDiff = 0
77+
previousDiff = 0
78+
operation = .toggleSignAndAdvance
79+
}
80+
81+
init(itemIndex: Int = 0) {
82+
self.itemIndex = itemIndex
83+
}
84+
85+
// MARK: - Private
86+
87+
private var currentDiff = 0
88+
private var previousDiff = 0
89+
private var operation: Operation = .toggleSignAndAdvance
90+
91+
private enum Operation {
92+
case toggleSign, toggleSignAndAdvance
93+
94+
func perform(with value: Int) -> Int {
95+
switch self {
96+
case .toggleSign:
97+
return value * -1
98+
case .toggleSignAndAdvance:
99+
return (value * -1) + 1
100+
}
101+
}
102+
103+
var next: Operation {
104+
switch self {
105+
case .toggleSign:
106+
return .toggleSignAndAdvance
107+
case .toggleSignAndAdvance:
108+
return .toggleSign
109+
}
110+
}
111+
}
112+
}

DuckDuckGo/Common/Utilities/Logging.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ extension OSLog {
6161
Logging.autoLockLoggingEnabled ? Logging.autoLockLog : .disabled
6262
}
6363

64+
static var tabLazyLoading: OSLog {
65+
Logging.tabLazyLoaderLoggingEnabled ? Logging.tabLazyLoaderLog : .disabled
66+
}
6467
}
6568

6669
struct Logging {
@@ -92,6 +95,9 @@ struct Logging {
9295
fileprivate static let autoLockLoggingEnabled = false
9396
fileprivate static let autoLockLog: OSLog = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "DuckDuckGo", category: "Auto-Lock")
9497

98+
fileprivate static let tabLazyLoaderLoggingEnabled = false
99+
fileprivate static let tabLazyLoaderLog: OSLog = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "DuckDuckGo", category: "Lazy Loading")
100+
95101
fileprivate static let autoconsentLoggingEnabled = false
96102
fileprivate static let autoconsentLog: OSLog = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "DuckDuckGo", category: "Autoconsent")
97103

DuckDuckGo/State Restoration/Tab+NSSecureCoding.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extension Tab: NSSecureCoding {
2929
static let tabType = "tabType"
3030
static let preferencePane = "preferencePane"
3131
static let visitedDomains = "visitedDomains"
32+
static let lastSelectedAt = "lastSelectedAt"
3233
static let currentDownload = "currentDownload"
3334
}
3435

@@ -52,6 +53,7 @@ extension Tab: NSSecureCoding {
5253
title: decoder.decodeIfPresent(at: NSSecureCodingKeys.title),
5354
favicon: decoder.decodeIfPresent(at: NSSecureCodingKeys.favicon),
5455
sessionStateData: decoder.decodeIfPresent(at: NSSecureCodingKeys.sessionStateData),
56+
lastSelectedAt: decoder.decodeIfPresent(at: NSSecureCodingKeys.lastSelectedAt),
5557
currentDownload: currentDownload)
5658
}
5759

@@ -64,6 +66,7 @@ extension Tab: NSSecureCoding {
6466
favicon.map(coder.encode(forKey: NSSecureCodingKeys.favicon))
6567
getActualSessionStateData().map(coder.encode(forKey: NSSecureCodingKeys.sessionStateData))
6668
coder.encode(content.type.rawValue, forKey: NSSecureCodingKeys.tabType)
69+
lastSelectedAt.map(coder.encode(forKey: NSSecureCodingKeys.lastSelectedAt))
6770
coder.encode(currentDownload, forKey: NSSecureCodingKeys.currentDownload)
6871

6972
if let pane = content.preferencePane {

DuckDuckGo/State Restoration/WindowManager+StateRestoration.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,20 @@ extension WindowsManager {
3434
let isOriginalKeyWindowPresent = Self.windows.contains(where: {$0.isKeyWindow})
3535

3636
var newKeyWindow: NSWindow?
37+
var newKeyWindowModel: TabCollectionViewModel?
3738
for (idx, item) in state.windows.enumerated() {
3839
guard let window = self.openNewWindow(with: item.model, showWindow: false) else { continue }
3940
window.setContentSize(item.frame.size)
4041
window.setFrameOrigin(item.frame.origin)
4142

4243
if idx == state.keyWindowIndex {
4344
newKeyWindow = window
45+
newKeyWindowModel = item.model
4446
}
4547
}
4648
if !isOriginalKeyWindowPresent {
4749
newKeyWindow?.makeKeyAndOrderFront(self)
50+
newKeyWindowModel?.setUpLazyLoadingIfNeeded()
4851
}
4952

5053
if !state.windows.isEmpty {

0 commit comments

Comments
 (0)