Skip to content

Commit 2638cec

Browse files
committed
Improve NTP menus
1 parent 02e69f2 commit 2638cec

File tree

2 files changed

+107
-89
lines changed

2 files changed

+107
-89
lines changed

iOS/DuckDuckGo/BrowsingMenu/SheetPresentationMenu/BrowsingMenuVariantBBuilder.swift

Lines changed: 71 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,26 @@ import Core
2424
/// Variant B Builder: Custom structure with specific sections
2525
final class BrowsingMenuVariantBBuilder: BrowsingMenuVariantBuilder {
2626
private weak var entryBuilder: BrowsingMenuEntryBuilding?
27-
27+
2828
init(entryBuilder: BrowsingMenuEntryBuilding) {
2929
self.entryBuilder = entryBuilder
3030
}
31-
31+
3232
func buildMenu(
3333
context: BrowsingMenuContext,
3434
bookmarksInterface: MenuBookmarksInteracting,
3535
mobileCustomization: MobileCustomization,
3636
clearTabsAndData: @escaping () -> Void
3737
) -> BrowsingMenuModel? {
38-
38+
3939
switch context {
4040
case .newTabPage:
41-
return buildNewTabPageMenu()
42-
41+
return buildNewTabPageMenu(mobileCustomization: mobileCustomization,
42+
clearTabsAndData: clearTabsAndData)
43+
4344
case .aiChatTab:
4445
return buildAIChatMenu()
45-
46+
4647
case .website:
4748
return buildWebsiteMenu(
4849
bookmarksInterface: bookmarksInterface,
@@ -51,41 +52,51 @@ final class BrowsingMenuVariantBBuilder: BrowsingMenuVariantBuilder {
5152
)
5253
}
5354
}
54-
55-
private func buildNewTabPageMenu() -> BrowsingMenuModel? {
55+
56+
private func buildNewTabPageMenu(mobileCustomization: MobileCustomization,
57+
clearTabsAndData: @escaping () -> Void) -> BrowsingMenuModel? {
5658
guard let entryBuilder = entryBuilder else { return nil }
57-
59+
5860
var headerItems = [BrowsingMenuModel.Entry]()
59-
61+
6062
let newTabEntry = entryBuilder.buildNewTabEntry()
6163
headerItems.append(.init(newTabEntry))
62-
63-
var sectionItems = [BrowsingMenuEntry]()
64-
64+
6565
if entryBuilder.shouldShowAIChatInMenu {
66-
let chatEntry = entryBuilder.buildChatEntry(withSmallIcon: true)
67-
sectionItems.append(chatEntry)
66+
let chatEntry = entryBuilder.buildChatEntry(withSmallIcon: false)
67+
headerItems.append(.init(chatEntry))
6868
}
69-
69+
70+
var shortcutsItems = [BrowsingMenuModel.Entry]()
71+
7072
let bookmarksEntry = entryBuilder.buildOpenBookmarksEntry()
71-
sectionItems.append(bookmarksEntry)
72-
73+
shortcutsItems.append(.init(bookmarksEntry))
74+
7375
if entryBuilder.featureFlagger.isFeatureOn(.autofillAccessCredentialManagement) {
7476
let autofillEntry = entryBuilder.buildAutoFillEntry()
75-
sectionItems.append(autofillEntry)
77+
shortcutsItems.append(.init(autofillEntry))
7678
}
77-
79+
7880
let downloadsEntry = entryBuilder.buildDownloadsEntry()
79-
sectionItems.append(downloadsEntry)
80-
81+
shortcutsItems.append(.init(downloadsEntry))
82+
83+
// Privacy section
84+
var privacyItems = [BrowsingMenuModel.Entry]()
85+
8186
if entryBuilder.featureFlagger.isFeatureOn(.vpnMenuItem), AppDependencyProvider.shared.subscriptionAuthV1toV2Bridge.canPurchase {
8287
let vpnEntry = entryBuilder.buildVPNEntry()
83-
sectionItems.append(vpnEntry)
88+
privacyItems.append(.init(vpnEntry))
89+
}
90+
91+
if mobileCustomization.isEnabled && !mobileCustomization.hasFireButton {
92+
let clearDataEntry = entryBuilder.buildClearDataEntry(clearTabsAndData: clearTabsAndData)
93+
privacyItems.append(.init(clearDataEntry))
8494
}
85-
86-
let sections = [BrowsingMenuModel.Section(
87-
items: sectionItems.map { .init($0) }
88-
)]
95+
96+
let sections = [
97+
BrowsingMenuModel.Section(items: shortcutsItems),
98+
BrowsingMenuModel.Section(items: privacyItems)
99+
]
89100

90101
var footerItems = [BrowsingMenuModel.Entry]()
91102
let settingsEntry = entryBuilder.buildSettingsEntry(useSmallIcon: false)
@@ -97,140 +108,140 @@ final class BrowsingMenuVariantBBuilder: BrowsingMenuVariantBuilder {
97108
footerItems: footerItems
98109
)
99110
}
100-
111+
101112
private func buildAIChatMenu() -> BrowsingMenuModel? {
102113
guard let entryBuilder = entryBuilder else { return nil }
103-
114+
104115
let header = entryBuilder.buildAITabMenuHeaderContent()
105116
let menu = entryBuilder.buildAITabMenu()
106-
117+
107118
let headerItems: [BrowsingMenuModel.Entry] = header.map { .init($0) }
108119
let sections: [BrowsingMenuModel.Section] = menu.split(whereSeparator: \.isSeparator).map {
109120
BrowsingMenuModel.Section(items: $0.compactMap { .init($0) })
110121
}
111-
122+
112123
return BrowsingMenuModel(
113124
headerItems: headerItems,
114125
sections: sections,
115126
footerItems: []
116127
)
117128
}
118-
129+
119130
private func buildWebsiteMenu(
120131
bookmarksInterface: MenuBookmarksInteracting,
121132
mobileCustomization: MobileCustomization,
122133
clearTabsAndData: @escaping () -> Void
123134
) -> BrowsingMenuModel? {
124135
guard let entryBuilder = entryBuilder else { return nil }
125-
136+
126137
// Header: new tab, duck.ai (conditional), settings
127138
var headerItems = [BrowsingMenuModel.Entry]()
128139
let newTabEntry = entryBuilder.buildNewTabEntry()
129140
headerItems.append(.init(newTabEntry))
130-
141+
131142
if entryBuilder.shouldShowAIChatInMenu {
132143
let aiChat = entryBuilder.buildChatEntry(withSmallIcon: false)
133144
headerItems.append(.init(aiChat))
134145
}
135-
146+
136147
// Sections
137148
var sections = [BrowsingMenuModel.Section]()
138-
149+
139150
// Link section
140151
if let link = entryBuilder.link, !entryBuilder.isError {
141152
var linkItems = [BrowsingMenuModel.Entry]()
142-
153+
143154
let bookmarkEntries = entryBuilder.buildBookmarkEntries(for: link, with: bookmarksInterface)
144155
linkItems.append(.init(bookmarkEntries.bookmark))
145156
linkItems.append(.init(bookmarkEntries.favorite, tag: .favorite))
146-
157+
147158
let shareEntry = entryBuilder.buildShareEntry(useSmallIcon: true)
148159
linkItems.append(.init(shareEntry))
149-
160+
150161
if !linkItems.isEmpty {
151162
sections.append(BrowsingMenuModel.Section(items: linkItems))
152163
}
153164
}
154-
165+
155166
// Tab actions section
156167
if let link = entryBuilder.link, !entryBuilder.isError {
157168
var tabActionItems = [BrowsingMenuModel.Entry]()
158-
169+
159170
let findInPageEntry = entryBuilder.buildFindInPageEntry(forLink: link)
160171
tabActionItems.append(.init(findInPageEntry))
161-
172+
162173
if let zoomEntry = entryBuilder.buildZoomEntry(forLink: link) {
163174
tabActionItems.append(.init(zoomEntry))
164175
}
165-
176+
166177
let desktopSiteEntry = entryBuilder.buildDesktopSiteEntry(forLink: link)
167178
tabActionItems.append(.init(desktopSiteEntry))
168-
179+
169180
if !tabActionItems.isEmpty {
170181
sections.append(BrowsingMenuModel.Section(items: tabActionItems))
171182
}
172183
}
173-
184+
174185
// Shortcuts section
175186
var shortcutItems = [BrowsingMenuModel.Entry]()
176-
187+
177188
let bookmarksEntry = entryBuilder.buildOpenBookmarksEntry()
178189
shortcutItems.append(.init(bookmarksEntry))
179-
190+
180191
if entryBuilder.featureFlagger.isFeatureOn(.autofillAccessCredentialManagement) {
181192
let passwordsEntry = entryBuilder.buildAutoFillEntry()
182193
shortcutItems.append(.init(passwordsEntry))
183194
}
184-
195+
185196
let downloadsEntry = entryBuilder.buildDownloadsEntry()
186197
shortcutItems.append(.init(downloadsEntry))
187-
198+
188199
if !shortcutItems.isEmpty {
189200
sections.append(BrowsingMenuModel.Section(items: shortcutItems))
190201
}
191-
202+
192203
// Privacy section
193204
var privacyItems = [BrowsingMenuModel.Entry]()
194-
205+
195206
if entryBuilder.featureFlagger.isFeatureOn(.vpnMenuItem), AppDependencyProvider.shared.subscriptionAuthV1toV2Bridge.canPurchase {
196207
let vpnEntry = entryBuilder.buildVPNEntry()
197208
privacyItems.append(.init(vpnEntry))
198209
}
199-
210+
200211
if let link = entryBuilder.link, !entryBuilder.isError {
201212
if let duckAddressEntry = entryBuilder.buildUseNewDuckAddressEntry(forLink: link) {
202213
privacyItems.append(.init(duckAddressEntry))
203214
}
204-
215+
205216
if let fireproofEntry = entryBuilder.buildKeepSignInEntry(forLink: link) {
206217
privacyItems.append(.init(fireproofEntry))
207218
}
208219
}
209-
220+
210221
if mobileCustomization.isEnabled && !mobileCustomization.hasFireButton {
211222
let clearDataEntry = entryBuilder.buildClearDataEntry(clearTabsAndData: clearTabsAndData)
212223
privacyItems.append(.init(clearDataEntry))
213224
}
214-
225+
215226
if !privacyItems.isEmpty {
216227
sections.append(BrowsingMenuModel.Section(items: privacyItems))
217228
}
218-
229+
219230
// Other section
220231
if entryBuilder.link != nil, !entryBuilder.isError {
221232
var otherItems = [BrowsingMenuModel.Entry]()
222-
233+
223234
let reportBrokenSiteEntry = entryBuilder.buildReportBrokenSiteEntry()
224235
otherItems.append(.init(reportBrokenSiteEntry))
225-
236+
226237
let printEntry = entryBuilder.buildPrintEntry(withSmallIcon: true)
227238
otherItems.append(.init(printEntry))
228-
239+
229240
if !otherItems.isEmpty {
230241
sections.append(BrowsingMenuModel.Section(items: otherItems))
231242
}
232243
}
233-
244+
234245
// Footer
235246
var footerItems = [BrowsingMenuModel.Entry]()
236247
let settingsEntry = entryBuilder.buildSettingsEntry(useSmallIcon: false)
@@ -252,4 +263,3 @@ private extension BrowsingMenuEntry {
252263
}
253264
}
254265
}
255-

iOS/DuckDuckGo/BrowsingMenu/SheetPresentationMenu/BrowsingMenuVariantCBuilder.swift

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ final class BrowsingMenuVariantCBuilder: BrowsingMenuVariantBuilder {
3838

3939
switch context {
4040
case .newTabPage:
41-
return buildNewTabPageMenu()
42-
41+
return buildNewTabPageMenu(mobileCustomization: mobileCustomization,
42+
clearTabsAndData: clearTabsAndData)
43+
4344
case .aiChatTab:
4445
return buildAIChatMenu()
4546

@@ -52,55 +53,62 @@ final class BrowsingMenuVariantCBuilder: BrowsingMenuVariantBuilder {
5253
}
5354
}
5455

55-
private func buildNewTabPageMenu() -> BrowsingMenuModel? {
56+
private func buildNewTabPageMenu(mobileCustomization: MobileCustomization,
57+
clearTabsAndData: @escaping () -> Void) -> BrowsingMenuModel? {
5658
guard let entryBuilder = entryBuilder else { return nil }
57-
59+
5860
var headerItems = [BrowsingMenuModel.Entry]()
59-
61+
6062
let newTabEntry = entryBuilder.buildNewTabEntry()
6163
headerItems.append(.init(newTabEntry))
62-
63-
let shareEntry = entryBuilder.buildShareEntry(useSmallIcon: false)
64-
headerItems.append(.init(shareEntry))
65-
66-
var sectionItems = [BrowsingMenuEntry]()
67-
64+
6865
if entryBuilder.shouldShowAIChatInMenu {
69-
let chatEntry = entryBuilder.buildChatEntry(withSmallIcon: true)
70-
sectionItems.append(chatEntry)
66+
let chatEntry = entryBuilder.buildChatEntry(withSmallIcon: false)
67+
headerItems.append(.init(chatEntry))
7168
}
72-
69+
70+
var shortcutsItems = [BrowsingMenuModel.Entry]()
71+
7372
let bookmarksEntry = entryBuilder.buildOpenBookmarksEntry()
74-
sectionItems.append(bookmarksEntry)
75-
73+
shortcutsItems.append(.init(bookmarksEntry))
74+
7675
if entryBuilder.featureFlagger.isFeatureOn(.autofillAccessCredentialManagement) {
7776
let autofillEntry = entryBuilder.buildAutoFillEntry()
78-
sectionItems.append(autofillEntry)
77+
shortcutsItems.append(.init(autofillEntry))
7978
}
80-
79+
8180
let downloadsEntry = entryBuilder.buildDownloadsEntry()
82-
sectionItems.append(downloadsEntry)
83-
81+
shortcutsItems.append(.init(downloadsEntry))
82+
83+
// Privacy section
84+
var privacyItems = [BrowsingMenuModel.Entry]()
85+
8486
if entryBuilder.featureFlagger.isFeatureOn(.vpnMenuItem), AppDependencyProvider.shared.subscriptionAuthV1toV2Bridge.canPurchase {
8587
let vpnEntry = entryBuilder.buildVPNEntry()
86-
sectionItems.append(vpnEntry)
88+
privacyItems.append(.init(vpnEntry))
8789
}
88-
89-
let sections = [BrowsingMenuModel.Section(
90-
items: sectionItems.map { .init($0) }
91-
)]
92-
90+
91+
if mobileCustomization.isEnabled && !mobileCustomization.hasFireButton {
92+
let clearDataEntry = entryBuilder.buildClearDataEntry(clearTabsAndData: clearTabsAndData)
93+
privacyItems.append(.init(clearDataEntry))
94+
}
95+
96+
let sections = [
97+
BrowsingMenuModel.Section(items: shortcutsItems),
98+
BrowsingMenuModel.Section(items: privacyItems)
99+
]
100+
93101
var footerItems = [BrowsingMenuModel.Entry]()
94102
let settingsEntry = entryBuilder.buildSettingsEntry(useSmallIcon: false)
95103
footerItems.append(.init(settingsEntry))
96-
104+
97105
return BrowsingMenuModel(
98106
headerItems: headerItems,
99107
sections: sections,
100108
footerItems: footerItems
101109
)
102110
}
103-
111+
104112
private func buildAIChatMenu() -> BrowsingMenuModel? {
105113
guard let entryBuilder = entryBuilder else { return nil }
106114

0 commit comments

Comments
 (0)