Skip to content

Commit 77a4244

Browse files
committed
Add variant D
1 parent e7f2334 commit 77a4244

File tree

4 files changed

+241
-0
lines changed

4 files changed

+241
-0
lines changed

iOS/DuckDuckGo-iOS.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@
458458
6F55BCF92ECE29B3009E50C1 /* BrowsingMenuSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F55BCF82ECE29B3009E50C1 /* BrowsingMenuSheetView.swift */; };
459459
6F5938982DB1028200C8C068 /* BrowserChromeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5938972DB1028200C8C068 /* BrowserChromeButton.swift */; };
460460
6F5AA3EF2CC1588400685CB4 /* FavoritesListInteractingAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5AA3EE2CC1588400685CB4 /* FavoritesListInteractingAdapterTests.swift */; };
461+
6F5B2FD92EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5B2FD82EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift */; };
461462
6F5DCFCE2E854C2000758C8A /* UniversalOmniBarEditingStateTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5DCFCD2E854C2000758C8A /* UniversalOmniBarEditingStateTransition.swift */; };
462463
6F64AA532C47E92600CF4489 /* FavoritesFaviconLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F64AA522C47E92600CF4489 /* FavoritesFaviconLoader.swift */; };
463464
6F655BE22BAB289E00AC3597 /* DefaultTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F655BE12BAB289E00AC3597 /* DefaultTheme.swift */; };
@@ -2584,6 +2585,7 @@
25842585
6F55BCF82ECE29B3009E50C1 /* BrowsingMenuSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingMenuSheetView.swift; sourceTree = "<group>"; };
25852586
6F5938972DB1028200C8C068 /* BrowserChromeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserChromeButton.swift; sourceTree = "<group>"; };
25862587
6F5AA3EE2CC1588400685CB4 /* FavoritesListInteractingAdapterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesListInteractingAdapterTests.swift; sourceTree = "<group>"; };
2588+
6F5B2FD82EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingMenuVariantDBuilder.swift; sourceTree = "<group>"; };
25872589
6F5DCFCD2E854C2000758C8A /* UniversalOmniBarEditingStateTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalOmniBarEditingStateTransition.swift; sourceTree = "<group>"; };
25882590
6F64AA522C47E92600CF4489 /* FavoritesFaviconLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesFaviconLoader.swift; sourceTree = "<group>"; };
25892591
6F655BE12BAB289E00AC3597 /* DefaultTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTheme.swift; sourceTree = "<group>"; };
@@ -5887,6 +5889,7 @@
58875889
6F55AE5F2ED8E7BB005D1F5B /* BrowsingMenuVariantABuilder.swift */,
58885890
6F55AE602ED8E7BB005D1F5B /* BrowsingMenuVariantBBuilder.swift */,
58895891
6F55AE632ED8EBE6005D1F5B /* BrowsingMenuVariantCBuilder.swift */,
5892+
6F5B2FD82EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift */,
58905893
);
58915894
path = SheetPresentationMenu;
58925895
sourceTree = "<group>";
@@ -11497,6 +11500,7 @@
1149711500
CB7E0A232D5E1E55002A7C0C /* LaunchActionHandler.swift in Sources */,
1149811501
97770B702EC1ED2600CACA68 /* OnboardingSearchExperiencePicker.swift in Sources */,
1149911502
97770B712EC1ED2600CACA68 /* OnboardingSearchExperiencePickerViewModel.swift in Sources */,
11503+
6F5B2FD92EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift in Sources */,
1150011504
97770B722EC1ED2600CACA68 /* OnboardingSearchExperienceProvider.swift in Sources */,
1150111505
97770B732EC1ED2600CACA68 /* OnboardingSearchExperienceSelectionHandler.swift in Sources */,
1150211506
C189966E2E4F45A200246F22 /* Logger+DaxEasterEgg.swift in Sources */,

iOS/DuckDuckGo/BrowsingMenu/SheetPresentationMenu/BrowsingMenuSheetCapability.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,15 @@ enum BrowsingMenuClusteringVariant: String, CaseIterable, CustomStringConvertibl
4040
"Easy Shortcuts"
4141
case .c:
4242
"Easy Privacy Tools"
43+
case .d:
44+
"Easy Privacy - No floating button"
4345
}
4446
}
4547

4648
case a
4749
case b
4850
case c
51+
case d
4952
}
5053

5154
enum BrowsingMenuSheetCapability {
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
//
2+
// BrowsingMenuVariantDBuilder.swift
3+
// DuckDuckGo
4+
//
5+
// Copyright © 2025 DuckDuckGo. All rights reserved.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
import Foundation
21+
import Bookmarks
22+
import Core
23+
24+
/// Variant D Builder: Settings in header, share below favorites, no footer
25+
final class BrowsingMenuVariantDBuilder: BrowsingMenuVariantBuilder {
26+
weak var entryBuilder: BrowsingMenuEntryBuilding?
27+
28+
init(entryBuilder: BrowsingMenuEntryBuilding) {
29+
self.entryBuilder = entryBuilder
30+
}
31+
32+
func buildMenu(
33+
context: BrowsingMenuContext,
34+
bookmarksInterface: MenuBookmarksInteracting,
35+
mobileCustomization: MobileCustomization,
36+
clearTabsAndData: @escaping () -> Void
37+
) -> BrowsingMenuModel? {
38+
39+
switch context {
40+
case .newTabPage:
41+
return buildNewTabPageMenu(mobileCustomization: mobileCustomization,
42+
clearTabsAndData: clearTabsAndData)
43+
44+
case .aiChatTab:
45+
return buildAIChatMenu()
46+
47+
case .website:
48+
return buildWebsiteMenu(
49+
bookmarksInterface: bookmarksInterface,
50+
mobileCustomization: mobileCustomization,
51+
clearTabsAndData: clearTabsAndData
52+
)
53+
}
54+
}
55+
56+
private func buildNewTabPageMenu(mobileCustomization: MobileCustomization,
57+
clearTabsAndData: @escaping () -> Void) -> BrowsingMenuModel? {
58+
guard let entryBuilder = entryBuilder else { return nil }
59+
60+
var headerItems = [BrowsingMenuModel.Entry]()
61+
62+
let newTabEntry = entryBuilder.makeNewTabEntry()
63+
headerItems.append(.init(newTabEntry))
64+
65+
if let chatEntry = entryBuilder.makeChatEntry(withSmallIcon: false) {
66+
headerItems.append(.init(chatEntry))
67+
}
68+
69+
let settingsEntry = entryBuilder.makeSettingsEntry(useSmallIcon: false)
70+
headerItems.append(.init(settingsEntry))
71+
72+
var shortcutsItems = [BrowsingMenuModel.Entry]()
73+
74+
let bookmarksEntry = entryBuilder.makeOpenBookmarksEntry()
75+
shortcutsItems.append(.init(bookmarksEntry))
76+
77+
if let autofillEntry = entryBuilder.makeAutoFillEntry() {
78+
shortcutsItems.append(.init(autofillEntry))
79+
}
80+
81+
let downloadsEntry = entryBuilder.makeDownloadsEntry()
82+
shortcutsItems.append(.init(downloadsEntry))
83+
84+
// Privacy section
85+
var privacyItems = [BrowsingMenuModel.Entry]()
86+
87+
if let vpnEntry = entryBuilder.makeVPNEntry() {
88+
privacyItems.append(.init(vpnEntry))
89+
}
90+
91+
if let clearDataEntry = entryBuilder.makeClearDataEntry(mobileCustomization: mobileCustomization, clearTabsAndData: clearTabsAndData) {
92+
privacyItems.append(.init(clearDataEntry))
93+
}
94+
95+
let sections = [
96+
BrowsingMenuModel.Section(items: shortcutsItems),
97+
BrowsingMenuModel.Section(items: privacyItems)
98+
]
99+
100+
return BrowsingMenuModel(
101+
headerItems: headerItems,
102+
sections: sections,
103+
footerItems: []
104+
)
105+
}
106+
107+
private func buildWebsiteMenu(
108+
bookmarksInterface: MenuBookmarksInteracting,
109+
mobileCustomization: MobileCustomization,
110+
clearTabsAndData: @escaping () -> Void
111+
) -> BrowsingMenuModel? {
112+
guard let entryBuilder = entryBuilder else { return nil }
113+
114+
// Header: new tab, duck.ai (conditional), settings
115+
var headerItems = [BrowsingMenuModel.Entry]()
116+
let newTabEntry = entryBuilder.makeNewTabEntry()
117+
headerItems.append(.init(newTabEntry))
118+
119+
if let aiChat = entryBuilder.makeChatEntry(withSmallIcon: false) {
120+
headerItems.append(.init(aiChat))
121+
}
122+
123+
let settingsEntry = entryBuilder.makeSettingsEntry(useSmallIcon: false)
124+
headerItems.append(.init(settingsEntry))
125+
126+
// Sections
127+
var sections = [BrowsingMenuModel.Section]()
128+
129+
// Link section
130+
if let bookmarkEntries = entryBuilder.makeBookmarkEntries(with: bookmarksInterface) {
131+
var linkItems = [BrowsingMenuModel.Entry]()
132+
133+
linkItems.append(.init(bookmarkEntries.bookmark))
134+
linkItems.append(.init(bookmarkEntries.favorite, tag: .favorite))
135+
136+
let shareEntry = entryBuilder.makeShareEntry(useSmallIcon: true)
137+
linkItems.append(.init(shareEntry))
138+
139+
if !linkItems.isEmpty {
140+
sections.append(BrowsingMenuModel.Section(items: linkItems))
141+
}
142+
}
143+
144+
// Tab actions section
145+
var tabActionItems = [BrowsingMenuModel.Entry]()
146+
147+
if let findInPageEntry = entryBuilder.makeFindInPageEntry() {
148+
tabActionItems.append(.init(findInPageEntry))
149+
}
150+
151+
if let zoomEntry = entryBuilder.makeZoomEntry() {
152+
tabActionItems.append(.init(zoomEntry))
153+
}
154+
155+
if let desktopSiteEntry = entryBuilder.makeDesktopSiteEntry() {
156+
tabActionItems.append(.init(desktopSiteEntry))
157+
}
158+
159+
if !tabActionItems.isEmpty {
160+
sections.append(BrowsingMenuModel.Section(items: tabActionItems))
161+
}
162+
163+
// Privacy section
164+
var privacyItems = [BrowsingMenuModel.Entry]()
165+
166+
if let vpnEntry = entryBuilder.makeVPNEntry() {
167+
privacyItems.append(.init(vpnEntry))
168+
}
169+
170+
if let duckAddressEntry = entryBuilder.makeUseNewDuckAddressEntry() {
171+
privacyItems.append(.init(duckAddressEntry))
172+
}
173+
174+
if let toggleProtectionEntry = entryBuilder.makeToggleProtectionEntry() {
175+
privacyItems.append(.init(toggleProtectionEntry))
176+
}
177+
178+
if let fireproofEntry = entryBuilder.makeKeepSignInEntry() {
179+
privacyItems.append(.init(fireproofEntry))
180+
}
181+
182+
if let clearDataEntry = entryBuilder.makeClearDataEntry(mobileCustomization: mobileCustomization, clearTabsAndData: clearTabsAndData) {
183+
privacyItems.append(.init(clearDataEntry))
184+
}
185+
186+
if !privacyItems.isEmpty {
187+
sections.append(BrowsingMenuModel.Section(items: privacyItems))
188+
}
189+
190+
// Shortcuts section
191+
var shortcutItems = [BrowsingMenuModel.Entry]()
192+
193+
let bookmarksEntry = entryBuilder.makeOpenBookmarksEntry()
194+
shortcutItems.append(.init(bookmarksEntry))
195+
196+
if let passwordsEntry = entryBuilder.makeAutoFillEntry() {
197+
shortcutItems.append(.init(passwordsEntry))
198+
}
199+
200+
let downloadsEntry = entryBuilder.makeDownloadsEntry()
201+
shortcutItems.append(.init(downloadsEntry))
202+
203+
if !shortcutItems.isEmpty {
204+
sections.append(BrowsingMenuModel.Section(items: shortcutItems))
205+
}
206+
207+
// Other section
208+
var otherItems = [BrowsingMenuModel.Entry]()
209+
210+
if let reloadEntry = entryBuilder.makeReloadEntry() {
211+
otherItems.append(.init(reloadEntry))
212+
}
213+
214+
if let reportBrokenSiteEntry = entryBuilder.makeReportBrokenSiteEntry() {
215+
otherItems.append(.init(reportBrokenSiteEntry))
216+
}
217+
218+
let printEntry = entryBuilder.makePrintEntry(withSmallIcon: true)
219+
otherItems.append(.init(printEntry))
220+
221+
if !otherItems.isEmpty {
222+
sections.append(BrowsingMenuModel.Section(items: otherItems))
223+
}
224+
225+
return BrowsingMenuModel(
226+
headerItems: headerItems,
227+
sections: sections,
228+
footerItems: []
229+
)
230+
}
231+
}
232+

iOS/DuckDuckGo/TabViewControllerMenuBuilderExtension.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ extension TabViewController {
9797
return BrowsingMenuVariantBBuilder(entryBuilder: self)
9898
case .c:
9999
return BrowsingMenuVariantCBuilder(entryBuilder: self)
100+
case .d:
101+
return BrowsingMenuVariantDBuilder(entryBuilder: self)
100102
}
101103
}
102104

0 commit comments

Comments
 (0)