Skip to content

Commit 075984d

Browse files
committed
Add variant D
1 parent a830dca commit 075984d

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

iOS/DuckDuckGo-iOS.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@
457457
6F55BCF92ECE29B3009E50C1 /* BrowsingMenuSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F55BCF82ECE29B3009E50C1 /* BrowsingMenuSheetView.swift */; };
458458
6F5938982DB1028200C8C068 /* BrowserChromeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5938972DB1028200C8C068 /* BrowserChromeButton.swift */; };
459459
6F5AA3EF2CC1588400685CB4 /* FavoritesListInteractingAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5AA3EE2CC1588400685CB4 /* FavoritesListInteractingAdapterTests.swift */; };
460+
6F5B2FD92EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5B2FD82EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift */; };
460461
6F5DCFCE2E854C2000758C8A /* UniversalOmniBarEditingStateTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5DCFCD2E854C2000758C8A /* UniversalOmniBarEditingStateTransition.swift */; };
461462
6F64AA532C47E92600CF4489 /* FavoritesFaviconLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F64AA522C47E92600CF4489 /* FavoritesFaviconLoader.swift */; };
462463
6F655BE22BAB289E00AC3597 /* DefaultTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F655BE12BAB289E00AC3597 /* DefaultTheme.swift */; };
@@ -2582,6 +2583,7 @@
25822583
6F55BCF82ECE29B3009E50C1 /* BrowsingMenuSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingMenuSheetView.swift; sourceTree = "<group>"; };
25832584
6F5938972DB1028200C8C068 /* BrowserChromeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserChromeButton.swift; sourceTree = "<group>"; };
25842585
6F5AA3EE2CC1588400685CB4 /* FavoritesListInteractingAdapterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesListInteractingAdapterTests.swift; sourceTree = "<group>"; };
2586+
6F5B2FD82EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingMenuVariantDBuilder.swift; sourceTree = "<group>"; };
25852587
6F5DCFCD2E854C2000758C8A /* UniversalOmniBarEditingStateTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalOmniBarEditingStateTransition.swift; sourceTree = "<group>"; };
25862588
6F64AA522C47E92600CF4489 /* FavoritesFaviconLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesFaviconLoader.swift; sourceTree = "<group>"; };
25872589
6F655BE12BAB289E00AC3597 /* DefaultTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTheme.swift; sourceTree = "<group>"; };
@@ -5877,6 +5879,7 @@
58775879
6F55AE5F2ED8E7BB005D1F5B /* BrowsingMenuVariantABuilder.swift */,
58785880
6F55AE602ED8E7BB005D1F5B /* BrowsingMenuVariantBBuilder.swift */,
58795881
6F55AE632ED8EBE6005D1F5B /* BrowsingMenuVariantCBuilder.swift */,
5882+
6F5B2FD82EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift */,
58805883
);
58815884
path = SheetPresentationMenu;
58825885
sourceTree = "<group>";
@@ -11486,6 +11489,7 @@
1148611489
CB7E0A232D5E1E55002A7C0C /* LaunchActionHandler.swift in Sources */,
1148711490
97770B702EC1ED2600CACA68 /* OnboardingSearchExperiencePicker.swift in Sources */,
1148811491
97770B712EC1ED2600CACA68 /* OnboardingSearchExperiencePickerViewModel.swift in Sources */,
11492+
6F5B2FD92EDA4CB100E85FAC /* BrowsingMenuVariantDBuilder.swift in Sources */,
1148911493
97770B722EC1ED2600CACA68 /* OnboardingSearchExperienceProvider.swift in Sources */,
1149011494
97770B732EC1ED2600CACA68 /* OnboardingSearchExperienceSelectionHandler.swift in Sources */,
1149111495
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: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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+
let headerItems: [BrowsingMenuModel.Entry] = [
61+
.init(entryBuilder.makeNewTabEntry()),
62+
.init(entryBuilder.makeChatEntry(withSmallIcon: false)),
63+
.init(entryBuilder.makeSettingsEntry(useSmallIcon: false))
64+
].compactMap { $0 }
65+
66+
let shortcutsItems: [BrowsingMenuModel.Entry] = [
67+
.init(entryBuilder.makeOpenBookmarksEntry()),
68+
.init(entryBuilder.makeAutoFillEntry()),
69+
.init(entryBuilder.makeDownloadsEntry())
70+
].compactMap { $0 }
71+
72+
let privacyItems: [BrowsingMenuModel.Entry] = [
73+
.init(entryBuilder.makeVPNEntry()),
74+
.init(entryBuilder.makeClearDataEntry(mobileCustomization: mobileCustomization, clearTabsAndData: clearTabsAndData))
75+
].compactMap { $0 }
76+
77+
let sections = [
78+
BrowsingMenuModel.Section(items: shortcutsItems),
79+
BrowsingMenuModel.Section(items: privacyItems)
80+
]
81+
82+
return BrowsingMenuModel(
83+
headerItems: headerItems,
84+
sections: sections,
85+
footerItems: []
86+
)
87+
}
88+
89+
private func buildWebsiteMenu(
90+
bookmarksInterface: MenuBookmarksInteracting,
91+
mobileCustomization: MobileCustomization,
92+
clearTabsAndData: @escaping () -> Void
93+
) -> BrowsingMenuModel? {
94+
guard let entryBuilder = entryBuilder else { return nil }
95+
96+
// Header: new tab, duck.ai (conditional), settings
97+
let headerItems: [BrowsingMenuModel.Entry] = [
98+
.init(entryBuilder.makeNewTabEntry()),
99+
.init(entryBuilder.makeChatEntry(withSmallIcon: false)),
100+
.init(entryBuilder.makeSettingsEntry(useSmallIcon: false))
101+
].compactMap { $0 }
102+
103+
// Sections
104+
var sections = [BrowsingMenuModel.Section]()
105+
106+
// Link section
107+
if let bookmarkEntries = entryBuilder.makeBookmarkEntries(with: bookmarksInterface) {
108+
let linkItems: [BrowsingMenuModel.Entry] = [
109+
.init(bookmarkEntries.bookmark),
110+
.init(bookmarkEntries.favorite, tag: .favorite),
111+
.init(entryBuilder.makeShareEntry(useSmallIcon: true))
112+
].compactMap { $0 }
113+
sections.append(BrowsingMenuModel.Section(items: linkItems))
114+
}
115+
116+
// Tab actions section
117+
let tabActionItems: [BrowsingMenuModel.Entry] = [
118+
.init(entryBuilder.makeFindInPageEntry()),
119+
.init(entryBuilder.makeZoomEntry()),
120+
.init(entryBuilder.makeDesktopSiteEntry())
121+
].compactMap { $0 }
122+
123+
if !tabActionItems.isEmpty {
124+
sections.append(BrowsingMenuModel.Section(items: tabActionItems))
125+
}
126+
127+
// Privacy section
128+
let privacyItems: [BrowsingMenuModel.Entry] = [
129+
.init(entryBuilder.makeVPNEntry()),
130+
.init(entryBuilder.makeUseNewDuckAddressEntry()),
131+
.init(entryBuilder.makeToggleProtectionEntry()),
132+
.init(entryBuilder.makeKeepSignInEntry()),
133+
.init(entryBuilder.makeClearDataEntry(mobileCustomization: mobileCustomization, clearTabsAndData: clearTabsAndData))
134+
].compactMap { $0 }
135+
136+
if !privacyItems.isEmpty {
137+
sections.append(BrowsingMenuModel.Section(items: privacyItems))
138+
}
139+
140+
// Shortcuts section
141+
let shortcutItems: [BrowsingMenuModel.Entry] = [
142+
.init(entryBuilder.makeOpenBookmarksEntry()),
143+
.init(entryBuilder.makeAutoFillEntry()),
144+
.init(entryBuilder.makeDownloadsEntry())
145+
].compactMap { $0 }
146+
147+
if !shortcutItems.isEmpty {
148+
sections.append(BrowsingMenuModel.Section(items: shortcutItems))
149+
}
150+
151+
// Other section
152+
let otherItems: [BrowsingMenuModel.Entry] = [
153+
.init(entryBuilder.makeReloadEntry()),
154+
.init(entryBuilder.makeReportBrokenSiteEntry()),
155+
.init(entryBuilder.makePrintEntry(withSmallIcon: true))
156+
].compactMap { $0 }
157+
158+
if !otherItems.isEmpty {
159+
sections.append(BrowsingMenuModel.Section(items: otherItems))
160+
}
161+
162+
return BrowsingMenuModel(
163+
headerItems: headerItems,
164+
sections: sections,
165+
footerItems: []
166+
)
167+
}
168+
}

0 commit comments

Comments
 (0)