Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address tab feedback #2705

Merged
merged 18 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
objects = {

/* Begin PBXBuildFile section */
021EA0802BD2A9D500772C9A /* TabsPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */; };
021EA0812BD2A9D500772C9A /* TabsPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */; };
021EA0842BD6E01A00772C9A /* TabsPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */; };
021EA0852BD6E0EB00772C9A /* TabsPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */; };
0230C0A3272080090018F728 /* KeyedCodingExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230C0A2272080090018F728 /* KeyedCodingExtension.swift */; };
026ADE1426C3010C002518EE /* macos-config.json in Resources */ = {isa = PBXBuildFile; fileRef = 026ADE1326C3010C002518EE /* macos-config.json */; };
028904202A7B25380028369C /* AppConfigurationURLProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0289041E2A7B23CE0028369C /* AppConfigurationURLProviderTests.swift */; };
Expand Down Expand Up @@ -2741,6 +2745,8 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsPreferences.swift; sourceTree = "<group>"; };
021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsPreferencesTests.swift; sourceTree = "<group>"; };
0230C0A2272080090018F728 /* KeyedCodingExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyedCodingExtension.swift; sourceTree = "<group>"; };
026ADE1326C3010C002518EE /* macos-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "macos-config.json"; sourceTree = "<group>"; };
0289041E2A7B23CE0028369C /* AppConfigurationURLProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfigurationURLProviderTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4768,6 +4774,7 @@
37F19A6628E1B43200740DC6 /* DuckPlayerPreferences.swift */,
37CD54C527F2FDD100F1F7B9 /* AboutModel.swift */,
1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */,
021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */,
);
path = Model;
sourceTree = "<group>";
Expand Down Expand Up @@ -4879,6 +4886,7 @@
1D9FDEC22B9B63C90040B78C /* DataClearingPreferencesTests.swift */,
3714B1E628EDB7FA0056C57A /* DuckPlayerPreferencesTests.swift */,
1D9FDEC52B9B64DB0040B78C /* PrivacyProtectionStatusTests.swift */,
021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */,
);
path = Preferences;
sourceTree = "<group>";
Expand Down Expand Up @@ -9916,6 +9924,7 @@
3706FC06293F65D500E42796 /* OnboardingViewModel.swift in Sources */,
3706FC07293F65D500E42796 /* ScriptSourceProviding.swift in Sources */,
31EF1E832B63FFCA00E6DB17 /* LoginItem+DataBrokerProtection.swift in Sources */,
021EA0812BD2A9D500772C9A /* TabsPreferences.swift in Sources */,
B6619EFC2B111CC600CD9186 /* InstructionsFormatParser.swift in Sources */,
3706FC08293F65D500E42796 /* CoreDataBookmarkImporter.swift in Sources */,
3706FC09293F65D500E42796 /* SuggestionViewModel.swift in Sources */,
Expand Down Expand Up @@ -10385,6 +10394,7 @@
C1E961F32B87B273001760E1 /* MockAutofillActionExecutor.swift in Sources */,
376E2D2729428353001CD31B /* BrokenSiteReportingReferenceTests.swift in Sources */,
3707C72F294B5D4F00682A9F /* WebViewTests.swift in Sources */,
021EA0852BD6E0EB00772C9A /* TabsPreferencesTests.swift in Sources */,
5682C69429B79B57004DE3C8 /* TabBarViewItemTests.swift in Sources */,
3706FE77293F661700E42796 /* PreferencesSidebarModelTests.swift in Sources */,
3706FE78293F661700E42796 /* HistoryCoordinatingMock.swift in Sources */,
Expand Down Expand Up @@ -11280,6 +11290,7 @@
B684592725C93C0500DC17B6 /* Publishers.NestedObjectChanges.swift in Sources */,
B6DA06E62913F39400225DE2 /* MenuItemSelectors.swift in Sources */,
85589E9A27BFE3C30038AD11 /* FaviconView.swift in Sources */,
021EA0802BD2A9D500772C9A /* TabsPreferences.swift in Sources */,
85707F2C276A364E00DC0649 /* OnboardingFlow.swift in Sources */,
4BE65480271FCD4D008D1D63 /* PasswordManagementLoginModel.swift in Sources */,
AA9FF95B24A1EFC20039E328 /* TabViewModel.swift in Sources */,
Expand Down Expand Up @@ -11719,6 +11730,7 @@
56D145EE29E6DAD900E3488A /* DataImportProviderTests.swift in Sources */,
4BB99D0F26FE1A84001E4761 /* ChromiumBookmarksReaderTests.swift in Sources */,
1D9FDEB72B9B5D150040B78C /* SearchPreferencesTests.swift in Sources */,
021EA0842BD6E01A00772C9A /* TabsPreferencesTests.swift in Sources */,
1D12F2E2298BC660009A65FD /* InternalUserDeciderStoreMock.swift in Sources */,
4BB99D1026FE1A84001E4761 /* FirefoxBookmarksReaderTests.swift in Sources */,
9FBD84702BB3DD8400220859 /* MockAttributionsPixelHandler.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.8">
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
Expand Down
16 changes: 16 additions & 0 deletions DuckDuckGo/Common/Localizables/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ struct UserText {
static let muteTab = NSLocalizedString("mute.tab", value: "Mute Tab", comment: "Menu item. Mute tab")
static let unmuteTab = NSLocalizedString("unmute.tab", value: "Unmute Tab", comment: "Menu item. Unmute tab")
static let closeOtherTabs = NSLocalizedString("close.other.tabs", value: "Close Other Tabs", comment: "Menu item")
static let closeAllOtherTabs = NSLocalizedString("close.all.other.tabs", value: "Close All Other Tabs", comment: "Menu item")
static let closeTabsToTheLeft = NSLocalizedString("close.tabs.to.the.left", value: "Close Tabs to the Left", comment: "Menu item")
static let closeTabsToTheRight = NSLocalizedString("close.tabs.to.the.right", value: "Close Tabs to the Right", comment: "Menu item")
static let openInNewTab = NSLocalizedString("open.in.new.tab", value: "Open in New Tab", comment: "Menu item that opens the link in a new tab")
static let openInNewWindow = NSLocalizedString("open.in.new.window", value: "Open in New Window", comment: "Menu item that opens the link in a new window")
Expand Down Expand Up @@ -606,6 +608,20 @@ struct UserText {
static let setHomePage = NSLocalizedString("preferences-homepage-set-homePage", value: "Set Homepage", comment: "Set Homepage dialog title")
static let addressLabel = NSLocalizedString("preferences-homepage-address", value: "Address:", comment: "Homepage address field label")

static let tabs = NSLocalizedString("preferences-tabs.title", value: "Tabs", comment: "Title for tabs section in settings")
static let preferNewTabsToWindows = NSLocalizedString("preferences-tabs.prefer.new.tabs.to.windows", value: "Open links in new tabs instead of new windows whenever possible", comment: "Option to prefer opening new tabs instead of windows when opening links")
static let switchToNewTabWhenOpened = NSLocalizedString("preferences-tabs.switch.tab.when.opened", value: "When opening links, switch to the new tab or window immediately", comment: "Option to switch to a new tab/window when it is opened")
static let newTabPositionTitle = NSLocalizedString("preferences-tabs.new.tab.position.title", value: "When creating a new tab", comment: "Title for new tab positioning")

static func newTabPositionMode(for position: NewTabPosition) -> String {
switch position {
case .atEnd:
return NSLocalizedString("context.menu.new.tab.mode.at.end", value: "Add to the right of other tabs", comment: "Preferences > Tabs > At end of list")
case .nextToCurrent:
return NSLocalizedString("context.menu.new.tab.mode.next.to.current", value: "Add to the right of the current tab", comment: "Preferences > Tabs > Next to current tab")
}
}

static func homeButtonMode(for position: HomeButtonPosition) -> String {
switch position {
case .hidden:
Expand Down
3 changes: 3 additions & 0 deletions DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public struct UserDefaultsWrapper<T> {
case currentThemeName = "com.duckduckgo.macos.currentThemeNameKey"
case showFullURL = "preferences.appearance.show-full-url"
case showAutocompleteSuggestions = "preferences.appearance.show-autocomplete-suggestions"
case preferNewTabsToWindows = "preferences.tabs.prefer-new-tabs-to-windows"
case switchToNewTabWhenOpened = "preferences.tabs.switch-to-new-tab-when-opened"
case newTabPosition = "preferences.tabs.new-tab-position"
case defaultPageZoom = "preferences.appearance.default-page-zoom"
case bookmarksBarAppearance = "preferences.appearance.bookmarks-bar"

Expand Down
98 changes: 97 additions & 1 deletion DuckDuckGo/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -11469,6 +11469,18 @@
}
}
},
"close.all.other.tabs" : {
"comment" : "Menu item",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Close All Other Tabs"
}
}
}
},
"close.other.tabs" : {
"comment" : "Menu item",
"extractionState" : "extracted_with_value",
Expand Down Expand Up @@ -11709,6 +11721,18 @@
}
}
},
"close.tabs.to.the.left" : {
"comment" : "Menu item",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Close Tabs to the Left"
}
}
}
},
"close.tabs.to.the.right" : {
"comment" : "Menu item",
"extractionState" : "extracted_with_value",
Expand Down Expand Up @@ -12002,6 +12026,30 @@
}
}
},
"context.menu.new.tab.mode.at.end" : {
"comment" : "Preferences > Tabs > At end of list",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Add to the right of other tabs"
}
}
}
},
"context.menu.new.tab.mode.next.to.current" : {
"comment" : "Preferences > Tabs > Next to current tab",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Add to the right of the current tab"
}
}
}
},
"copy" : {
"comment" : "Copy button",
"extractionState" : "extracted_with_value",
Expand Down Expand Up @@ -43652,6 +43700,54 @@
}
}
},
"preferences-tabs.new.tab.position.title" : {
"comment" : "Title for new tab positioning",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "When creating a new tab"
}
}
}
},
"preferences-tabs.prefer.new.tabs.to.windows" : {
"comment" : "Option to prefer opening new tabs instead of windows when opening links",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Open links in new tabs instead of new windows whenever possible"
}
}
}
},
"preferences-tabs.switch.tab.when.opened" : {
"comment" : "Option to switch to a new tab/window when it is opened",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "When opening links, switch to the new tab or window immediately"
}
}
}
},
"preferences-tabs.title" : {
"comment" : "Title for tabs section in settings",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Tabs"
}
}
}
},
"preferences.about" : {
"comment" : "Title of the option to show the About screen",
"extractionState" : "extracted_with_value",
Expand Down Expand Up @@ -54335,4 +54431,4 @@
}
},
"version" : "1.0"
}
}
73 changes: 73 additions & 0 deletions DuckDuckGo/Preferences/Model/TabsPreferences.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// TabsPreferences.swift
//
// Copyright © 2024 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

protocol TabsPreferencesPersistor {
var switchToNewTabWhenOpened: Bool { get set }
var preferNewTabsToWindows: Bool { get set }
var newTabPosition: NewTabPosition { get set }
}

struct TabsPreferencesUserDefaultsPersistor: TabsPreferencesPersistor {
@UserDefaultsWrapper(key: .preferNewTabsToWindows, defaultValue: true)
var preferNewTabsToWindows: Bool

@UserDefaultsWrapper(key: .switchToNewTabWhenOpened, defaultValue: false)
var switchToNewTabWhenOpened: Bool

@UserDefaultsWrapper(key: .newTabPosition, defaultValue: .atEnd)
var newTabPosition: NewTabPosition
}

final class TabsPreferences: ObservableObject, PreferencesTabOpening {

static let shared = TabsPreferences()

@Published var preferNewTabsToWindows: Bool {
didSet {
persistor.preferNewTabsToWindows = preferNewTabsToWindows
}
}

@Published var switchToNewTabWhenOpened: Bool {
didSet {
persistor.switchToNewTabWhenOpened = switchToNewTabWhenOpened
}
}

@Published var newTabPosition: NewTabPosition {
didSet {
persistor.newTabPosition = newTabPosition
}
}

init(persistor: TabsPreferencesPersistor = TabsPreferencesUserDefaultsPersistor()) {
self.persistor = persistor
preferNewTabsToWindows = persistor.preferNewTabsToWindows
switchToNewTabWhenOpened = persistor.switchToNewTabWhenOpened
newTabPosition = persistor.newTabPosition
}

private var persistor: TabsPreferencesPersistor
}

enum NewTabPosition: String, CaseIterable {
case atEnd
case nextToCurrent
}
26 changes: 23 additions & 3 deletions DuckDuckGo/Preferences/View/PreferencesGeneralView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extension Preferences {
@ObservedObject var startupModel: StartupPreferences
@ObservedObject var downloadsModel: DownloadsPreferences
@ObservedObject var searchModel: SearchPreferences
@ObservedObject var tabsModel: TabsPreferences
@ObservedObject var dataClearingModel: DataClearingPreferences
@State private var showingCustomHomePageSheet = false

Expand Down Expand Up @@ -60,7 +61,26 @@ extension Preferences {
}
}

// SECTION 2: Home Page
// SECTION 2: Tabs
PreferencePaneSection(UserText.tabs) {
PreferencePaneSubSection {
ToggleMenuItem(UserText.preferNewTabsToWindows, isOn: $tabsModel.preferNewTabsToWindows)
ToggleMenuItem(UserText.switchToNewTabWhenOpened, isOn: $tabsModel.switchToNewTabWhenOpened)
}

PreferencePaneSubSection {
HStack {
Picker(UserText.newTabPositionTitle, selection: $tabsModel.newTabPosition) {
ForEach(NewTabPosition.allCases, id: \.self) { position in
Text(UserText.newTabPositionMode(for: position)).tag(position)
}
}
.fixedSize()
}
}
}

// SECTION 3: Home Page
PreferencePaneSection(UserText.homePage) {

PreferencePaneSubSection {
Expand Down Expand Up @@ -104,12 +124,12 @@ extension Preferences {
CustomHomePageSheet(startupModel: startupModel, isSheetPresented: $showingCustomHomePageSheet)
}

// SECTION 3: Search Settings
// SECTION 4: Search Settings
PreferencePaneSection(UserText.privateSearch) {
ToggleMenuItem(UserText.showAutocompleteSuggestions, isOn: $searchModel.showAutocompleteSuggestions).accessibilityIdentifier("PreferencesGeneralView.showAutocompleteSuggestions")
}

// SECTION 4: Downloads
// SECTION 5: Downloads
PreferencePaneSection(UserText.downloads) {
PreferencePaneSubSection {
ToggleMenuItem(UserText.downloadsOpenPopupOnCompletion,
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/Preferences/View/PreferencesRootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ enum Preferences {
GeneralView(startupModel: StartupPreferences.shared,
downloadsModel: DownloadsPreferences.shared,
searchModel: SearchPreferences.shared,
tabsModel: TabsPreferences.shared,
dataClearingModel: DataClearingPreferences.shared)
case .sync:
SyncView()
Expand Down
Loading
Loading