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

Subscriptions Base Implementation #2259

Merged
merged 106 commits into from
Jan 10, 2024
Merged
Changes from 1 commit
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
7422774
General View, Sync, Logins, Appeareance first implementation
afterxleep Dec 6, 2023
f85324f
Extract Model and State to separate classes
afterxleep Dec 7, 2023
2060dc1
Improve separation of concerns/responsibilities
afterxleep Dec 7, 2023
317ca72
Use LazyViews
afterxleep Dec 7, 2023
4a8946a
Removed unnecesary viewcontrollers
afterxleep Dec 7, 2023
a63bb5a
Application Lock
afterxleep Dec 7, 2023
1779ecc
Present legacy views from the Root Navigation Controller
afterxleep Dec 7, 2023
67436be
State Management Updates
afterxleep Dec 8, 2023
2cc396e
Email Protection and other links
afterxleep Dec 8, 2023
2102043
State initialization
afterxleep Dec 8, 2023
81d0502
Added Required Cells
afterxleep Dec 8, 2023
8a64f7b
Dismiss legacy ViewControllers and update settings
afterxleep Dec 8, 2023
38f07c0
Network Protection Status
afterxleep Dec 8, 2023
50f5731
Remaining views and cleanup
afterxleep Dec 8, 2023
dd5ae07
Fix Debug Menu
afterxleep Dec 8, 2023
3fa4ee9
Move Font settings out of viewModel
afterxleep Dec 8, 2023
18f4d2a
Fix presentation for login
afterxleep Dec 9, 2023
7f61c51
Cell design
afterxleep Dec 9, 2023
b79586e
Renamed Type
afterxleep Dec 9, 2023
99d8be2
Dismiss the view
afterxleep Dec 9, 2023
a85d5e8
UI Cleanup
afterxleep Dec 9, 2023
c84b756
Add Required Strings to UserText
afterxleep Dec 11, 2023
067d0d9
Move all strings to UserText
afterxleep Dec 11, 2023
eab0239
Merge branch 'main' into daniel/settings-swiftui
afterxleep Dec 11, 2023
897d021
Updated Strings
afterxleep Dec 11, 2023
eab5c1d
Fixed Remaining Strings
afterxleep Dec 11, 2023
a6cc6df
Localization Files
afterxleep Dec 11, 2023
7f43367
Remove SettingsViewController
afterxleep Dec 11, 2023
92e0afd
Update layout priority for Text accesory
afterxleep Dec 11, 2023
2f7c31b
Merge branch 'main' into daniel/settings-swiftui
afterxleep Dec 11, 2023
2607889
Cleanup
afterxleep Dec 11, 2023
3355e92
Revert Appicon changes
afterxleep Dec 11, 2023
f2bcb58
Revert AppIcon Changes
afterxleep Dec 11, 2023
1e7d33a
Fix linter issues (pass 1)
afterxleep Dec 11, 2023
f88de4d
Remove cyclomatic warning
afterxleep Dec 11, 2023
394e3f2
Added debug to previews
afterxleep Dec 11, 2023
d987709
Add all params to preview
afterxleep Dec 11, 2023
4cc3c7a
Comment out preview
afterxleep Dec 11, 2023
f484f89
Passes content from a variable
afterxleep Dec 11, 2023
5521fd0
Make disclosure indicator conditional
afterxleep Dec 11, 2023
ad637f4
Comment out cell
afterxleep Dec 11, 2023
970c283
Add additional debug options to the VPN debug menu (#2251)
samsymons Dec 11, 2023
9c0b336
Quality metrics for Sync (#2254)
bwaresiak Dec 11, 2023
af736fc
Release 7.101.0 (#2257)
jaceklyp Dec 11, 2023
72fe6c6
Fix VPN IPv6 connectivity (#2258)
samsymons Dec 11, 2023
b2b07cb
Run sync e2e on multiple OS versions (#2256)
loremattei Dec 12, 2023
8cbb935
Updated packages
afterxleep Dec 12, 2023
c5a5f65
Added base subscription Packages
afterxleep Nov 24, 2023
a3c991e
Added subscription local packages
afterxleep Nov 27, 2023
d09dc98
Updated constraints
afterxleep Nov 27, 2023
6253101
Moved Dependencies into a single package
afterxleep Nov 27, 2023
db15d93
Display Base Webview
afterxleep Nov 28, 2023
1a33d17
Properly configure userscripts
afterxleep Nov 28, 2023
61830e8
Confirm mesages are being properly received
afterxleep Nov 29, 2023
1762cf8
Display Webview
afterxleep Nov 29, 2023
cfa4241
Implement Settings cell in storyboard
afterxleep Nov 29, 2023
8572ce8
Fix constraints
afterxleep Nov 29, 2023
0184e8e
Only load the WebApp when we have products Available
afterxleep Nov 29, 2023
bd64542
User PurchaseManager publishers
afterxleep Nov 30, 2023
f7621dc
Base Purchase Flow
afterxleep Nov 30, 2023
c816b2b
Remove unwanted reference
afterxleep Nov 30, 2023
66755fc
Add transaction progress view
afterxleep Dec 1, 2023
5762d05
Adjust progress view colors
afterxleep Dec 1, 2023
4595d46
Debug Settings
afterxleep Dec 1, 2023
ca4b133
Update Debug Options
afterxleep Dec 4, 2023
d6be013
Update Settings view to dynamicall show PrivacyPro settings
afterxleep Dec 4, 2023
2547e9c
Inject Fake Authentication
afterxleep Dec 4, 2023
a0f60b4
Updated agent
afterxleep Dec 12, 2023
855774c
Fix conflicts
afterxleep Dec 12, 2023
f8e92ee
Merge branch 'main' into daniel/subscriptions/1.headless-webview
afterxleep Dec 12, 2023
90c0849
Added compiler conditional
afterxleep Dec 12, 2023
a981a07
Remove SettingsVC
afterxleep Dec 12, 2023
73a8afc
Updated Profiles
afterxleep Dec 12, 2023
8599afd
Add IAP Capability
afterxleep Dec 12, 2023
3e78942
Create debug build configuration
afterxleep Dec 12, 2023
53e0974
Hide netP subtitle if “”
afterxleep Dec 12, 2023
ccc4924
Updated missing string
afterxleep Dec 12, 2023
ccb0e3d
Revert Localizable change
afterxleep Dec 12, 2023
9634cff
Updated translations from Smartling
afterxleep Dec 12, 2023
45bb821
Updated missing string
afterxleep Dec 12, 2023
620920e
Revert Localizable change
afterxleep Dec 12, 2023
673d94a
Updated translations from Smartling
afterxleep Dec 12, 2023
379b6c9
Base Privacy Pro Cell in Settings
afterxleep Dec 12, 2023
ea0abd6
Display Privacy Pro Cell when available
afterxleep Dec 12, 2023
e4f9232
Update caption style
afterxleep Dec 12, 2023
b724c35
Added Debug flag
afterxleep Dec 12, 2023
224c683
Use a custom view to render Privacy Pro Cells
afterxleep Dec 12, 2023
70d0355
Section title is now Privacy Pro
afterxleep Dec 12, 2023
8ccd30f
Remove subscription flag from Debug version
afterxleep Dec 12, 2023
044c525
Merge branch 'main' into daniel/settings-swiftui
afterxleep Dec 12, 2023
140bdb6
Merge branch 'daniel/subscriptions-integration' into daniel/subscript…
afterxleep Dec 12, 2023
1735eb6
Update Subscription Code from macOS
afterxleep Dec 13, 2023
61d4bea
Use a custom agent temporarily
afterxleep Dec 13, 2023
66cc3b7
Initialize subscription environment in AppDelegate
afterxleep Dec 13, 2023
01c0fbe
Move subscription init to a method
afterxleep Dec 13, 2023
264766d
Removed non-required scripts
afterxleep Dec 13, 2023
d0e199d
Noop change
afterxleep Jan 5, 2024
c103960
NOOP
afterxleep Jan 5, 2024
5b41f0d
Merge branch 'daniel/settings-swiftui' into daniel/subscriptions/1.he…
afterxleep Jan 5, 2024
10fa11d
We are now using “Passwords” for login items
afterxleep Jan 5, 2024
06ffe72
Merged Feedback from Settings Swift UI PR
afterxleep Jan 8, 2024
6a34923
Apply Grouped UI Style for settings
afterxleep Jan 8, 2024
874e2ca
Update locig to display netP
afterxleep Jan 9, 2024
b6f4cfd
Merge branch 'main' into daniel/subscriptions/1.headless-webview
afterxleep Jan 9, 2024
d4b11a4
Move properties to Settings State
afterxleep Jan 9, 2024
b31a1fd
Fix lint issues
afterxleep Jan 10, 2024
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
Prev Previous commit
Next Next commit
State Management Updates
afterxleep committed Dec 8, 2023
commit 67436beeccff23dd55fb4c1f2f480540cb7202af
12 changes: 4 additions & 8 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -775,11 +775,10 @@
D6E83C412B1FC285006C8AFB /* SettingsAppeareanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C402B1FC285006C8AFB /* SettingsAppeareanceView.swift */; };
D6E83C482B20C812006C8AFB /* SettingsHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C472B20C812006C8AFB /* SettingsHostingController.swift */; };
D6E83C4B2B20C88E006C8AFB /* SettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C4A2B20C88E006C8AFB /* SettingsModel.swift */; };
D6E83C4D2B20DD51006C8AFB /* NavigationLink+Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C4C2B20DD51006C8AFB /* NavigationLink+Empty.swift */; };
D6E83C502B2147B0006C8AFB /* SettingsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C4F2B2147B0006C8AFB /* SettingsState.swift */; };
D6E83C562B21ECC1006C8AFB /* SettingsLegacyViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C552B21ECC1006C8AFB /* SettingsLegacyViewProvider.swift */; };
D6E83C5A2B2213ED006C8AFB /* SettingsPrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C592B2213ED006C8AFB /* SettingsPrivacyView.swift */; };
D6E83C5E2B224676006C8AFB /* SettingsCustomizeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C5D2B224676006C8AFB /* SettingsCustomizeView.swift */; };
D6E83C602B22B3C9006C8AFB /* SettingsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C5F2B22B3C9006C8AFB /* SettingsState.swift */; };
EA39B7E2268A1A35000C62CD /* privacy-reference-tests in Resources */ = {isa = PBXBuildFile; fileRef = EA39B7E1268A1A35000C62CD /* privacy-reference-tests */; };
EAB19EDA268963510015D3EA /* DomainMatchingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB19ED9268963510015D3EA /* DomainMatchingTests.swift */; };
EE0153E12A6EABE0002A8B26 /* NetworkProtectionConvenienceInitialisers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0153E02A6EABE0002A8B26 /* NetworkProtectionConvenienceInitialisers.swift */; };
@@ -2410,11 +2409,10 @@
D6E83C402B1FC285006C8AFB /* SettingsAppeareanceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAppeareanceView.swift; sourceTree = "<group>"; };
D6E83C472B20C812006C8AFB /* SettingsHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHostingController.swift; sourceTree = "<group>"; };
D6E83C4A2B20C88E006C8AFB /* SettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModel.swift; sourceTree = "<group>"; };
D6E83C4C2B20DD51006C8AFB /* NavigationLink+Empty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NavigationLink+Empty.swift"; sourceTree = "<group>"; };
D6E83C4F2B2147B0006C8AFB /* SettingsState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsState.swift; sourceTree = "<group>"; };
D6E83C552B21ECC1006C8AFB /* SettingsLegacyViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsLegacyViewProvider.swift; sourceTree = "<group>"; };
D6E83C592B2213ED006C8AFB /* SettingsPrivacyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsPrivacyView.swift; sourceTree = "<group>"; };
D6E83C5D2B224676006C8AFB /* SettingsCustomizeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsCustomizeView.swift; sourceTree = "<group>"; };
D6E83C5F2B22B3C9006C8AFB /* SettingsState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsState.swift; sourceTree = "<group>"; };
EA39B7E1268A1A35000C62CD /* privacy-reference-tests */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "privacy-reference-tests"; path = "submodules/privacy-reference-tests"; sourceTree = SOURCE_ROOT; };
EAB19ED9268963510015D3EA /* DomainMatchingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainMatchingTests.swift; sourceTree = "<group>"; };
EE0153E02A6EABE0002A8B26 /* NetworkProtectionConvenienceInitialisers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionConvenienceInitialisers.swift; sourceTree = "<group>"; };
@@ -4508,15 +4506,14 @@
D6E83C112B1E6AB3006C8AFB /* SettingsView.swift */,
D6E83C302B1EA309006C8AFB /* SettingsCell.swift */,
D6E83C322B1F1279006C8AFB /* Sections */,
D6E83C4C2B20DD51006C8AFB /* NavigationLink+Empty.swift */,
);
name = Views;
sourceTree = "<group>";
};
D6E83C492B20C883006C8AFB /* Model */ = {
isa = PBXGroup;
children = (
D6E83C4F2B2147B0006C8AFB /* SettingsState.swift */,
D6E83C5F2B22B3C9006C8AFB /* SettingsState.swift */,
D6E83C4A2B20C88E006C8AFB /* SettingsModel.swift */,
D6E83C2D2B1EA06E006C8AFB /* SettingsViewModel.swift */,
D6E83C552B21ECC1006C8AFB /* SettingsLegacyViewProvider.swift */,
@@ -6345,10 +6342,8 @@
3151F0F02735802800226F58 /* VoiceSearchViewController.swift in Sources */,
85BDC310243359040053DB07 /* FindInPageUserScript.swift in Sources */,
F1DE78581E5CAE350058895A /* TabViewGridCell.swift in Sources */,
D6E83C502B2147B0006C8AFB /* SettingsState.swift in Sources */,
984D035824ACCC6F0066CFB8 /* TabViewListCell.swift in Sources */,
B6BA95C328891E33004ABA20 /* BrowsingMenuAnimator.swift in Sources */,
D6E83C4D2B20DD51006C8AFB /* NavigationLink+Empty.swift in Sources */,
EE9D68DC2AE16AE100B55EF4 /* NotificationsAuthorizationController.swift in Sources */,
AA3D854923DA1DFB00788410 /* AppIcon.swift in Sources */,
D6E83C2E2B1EA06E006C8AFB /* SettingsViewModel.swift in Sources */,
@@ -6497,6 +6492,7 @@
85374D3C21AC41E700FF5A1E /* FavoritesHomeViewSectionRenderer.swift in Sources */,
85DFEDF124C7EEA400973FE7 /* LargeOmniBarState.swift in Sources */,
9880722A25FA497B0039EF4B /* MenuButton.swift in Sources */,
D6E83C602B22B3C9006C8AFB /* SettingsState.swift in Sources */,
D6E83C482B20C812006C8AFB /* SettingsHostingController.swift in Sources */,
F46FEC5727987A5F0061D9DF /* KeychainItemsDebugViewController.swift in Sources */,
02341FA62A4379CC008A1531 /* OnboardingStepViewModel.swift in Sources */,
29 changes: 0 additions & 29 deletions DuckDuckGo/NavigationLink+Empty.swift

This file was deleted.

34 changes: 29 additions & 5 deletions DuckDuckGo/SettingsCustomizeView.swift
Original file line number Diff line number Diff line change
@@ -22,7 +22,11 @@ import UIKit
struct SettingsCustomizeView: View {

@EnvironmentObject var viewModel: SettingsViewModel
@EnvironmentObject var viewProvider: SettingsLegacyViewProvider
@State var shouldShowNoMicrophonePermissionAlert = false {
didSet {
print("Set alert!!! \(shouldShowNoMicrophonePermissionAlert)")
}
}

var body: some View {
Section(header: Text("Customize"),
@@ -33,13 +37,33 @@ struct SettingsCustomizeView: View {
asLink: true,
disclosureIndicator: true)

SettingsCellView(label: "Autocomplete Suggestions", accesory: .toggle(isOn: viewModel.autocompleteBinding))
SettingsCellView(label: "Autocomplete Suggestions",
accesory: .toggle(isOn: viewModel.autocompleteBinding))

if viewModel.shouldShowSpeechRecognitionCell {
SettingsCellView(label: "Private Voice Search", accesory: .toggle(isOn: viewModel.applicationLockBinding))
SettingsCellView(label: "Private Voice Search",
accesory: .toggle(isOn: viewModel.voiceSearchEnabledBinding))
}
SettingsCellView(label: "Long-Press Previews", accesory: .toggle(isOn: viewModel.applicationLockBinding))
SettingsCellView(label: "Open Links in Associated Apps", accesory: .toggle(isOn: viewModel.applicationLockBinding))

SettingsCellView(label: "Open Links in Associated Apps", accesory: .toggle(isOn: viewModel.applicationLockBinding))
}
}

.alert(isPresented: $shouldShowNoMicrophonePermissionAlert) {
Alert(title: Text(UserText.noVoicePermissionAlertTitle),
message: Text(UserText.noVoicePermissionAlertMessage),
dismissButton: .default(Text("OK"),
action: {
viewModel.shouldShowNoMicrophonePermissionAlert = false
})
)
}
.onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in
shouldShowNoMicrophonePermissionAlert = value
}


}


}
41 changes: 31 additions & 10 deletions DuckDuckGo/SettingsModel.swift
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ import NetworkProtection
import Core
#endif

class SettingsModel {
class SettingsModel: ObservableObject {

private let appIconManager = AppIconManager.shared
private let bookmarksDatabase: CoreDataDatabase
@@ -43,8 +43,15 @@ class SettingsModel {
private(set) lazy var appSettings = AppDependencyProvider.shared.appSettings
private lazy var isPad = UIDevice.current.userInterfaceIdiom == .pad
private var privacyStore = PrivacyUserDefaults()
private var cancellables = Set<AnyCancellable>()

var appIcon: AppIcon = AppIcon.defaultAppIcon
var textSize: Int { appSettings.textSize }
var sendDoNotSell: Bool { appSettings.sendDoNotSell }
var autoconsentEnabled: Bool { appSettings.autoconsentEnabled }
var longPressPreviews: Bool { appSettings.longPressPreviews }
var allowUniversalLinks: Bool { appSettings.allowUniversalLinks }

var fireButtonAnimation: FireButtonAnimationType {
get { appSettings.currentFireButtonAnimation }
set {
@@ -60,6 +67,7 @@ class SettingsModel {
}
}
}

var appTheme: ThemeName {
get { appSettings.currentThemeName }
set {
@@ -68,13 +76,12 @@ class SettingsModel {
ThemeManager.shared.updateUserInterfaceStyle()
}
}
var textSize: Int { appSettings.textSize }

var addressBarPosition: AddressBarPosition {
get { appSettings.currentAddressBarPosition }
set { appSettings.currentAddressBarPosition = newValue }
}
var sendDoNotSell: Bool { appSettings.sendDoNotSell }
var autoconsentEnabled: Bool { appSettings.autoconsentEnabled }

var autoclearDataEnabled: Bool {
if AutoClearSettingsModel(settings: appSettings) != nil {
return true
@@ -86,22 +93,23 @@ class SettingsModel {
get { privacyStore.authenticationEnabled }
set { privacyStore.authenticationEnabled = newValue }
}

var autocomplete: Bool {
get { appSettings.autocomplete }
set { appSettings.autocomplete = newValue }
}

var voiceSearchEnabled: Bool {
get { appSettings.voiceSearchEnabled }
set { appSettings.autocomplete = newValue }
get {
appSettings.voiceSearchEnabled && AppDependencyProvider.shared.voiceSearchHelper.isSpeechRecognizerAvailable }
set {
appSettings.voiceSearchEnabled = newValue
}
}
var longPressPreviews: Bool { appSettings.longPressPreviews }
var allowUniversalLinks: Bool { appSettings.allowUniversalLinks }


#if NETWORK_PROTECTION
private let connectionObserver = ConnectionStatusObserverThroughSession()
#endif
private var cancellables: Set<AnyCancellable> = []

init(bookmarksDatabase: CoreDataDatabase,
internalUserDecider: InternalUserDecider) {
@@ -159,4 +167,17 @@ class SettingsModel {
}
}

func enableVoiceSearch(completion: @escaping (Bool) -> Void) {
let isFirstTimeAskingForPermission = SpeechRecognizer.recordPermission == .undetermined

SpeechRecognizer.requestMicAccess { permission in
if !permission {
completion(false)
return
}
AppDependencyProvider.shared.voiceSearchHelper.enableVoiceSearch(true)
completion(true)
}
}

}
2 changes: 1 addition & 1 deletion DuckDuckGo/SettingsView.swift
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ struct SettingsView: View {
.environmentObject(viewModel)

.onAppear {
viewModel.initializeState()
// viewModel.initalizeState()
}
}

2 changes: 1 addition & 1 deletion DuckDuckGo/SettingsViewController.swift
Original file line number Diff line number Diff line change
@@ -154,7 +154,7 @@ class SettingsViewController: UITableViewController {
configureDebugCell()
configureVoiceSearchCell()
configureNetPCell()
applyTheme(ThemeManager.shared.currentTheme)
(ThemeManager.shared.currentTheme)

internalUserDecider.isInternalUserPublisher.dropFirst().sink(receiveValue: { [weak self] _ in
self?.configureAutofillCell()
21 changes: 18 additions & 3 deletions DuckDuckGo/SettingsViewModel.swift
Original file line number Diff line number Diff line change
@@ -55,6 +55,7 @@ final class SettingsViewModel: ObservableObject {
var shouldShowAddressBarPositionCell: Bool { model.isFeatureAvailable(.addressbarPosition) }
var shouldShowNetworkProtectionCell: Bool { model.isFeatureAvailable(.networkProtection) }
var shouldShowSpeechRecognitionCell: Bool { model.isFeatureAvailable(.speechRecognition) }
var shouldShowNoMicrophonePermissionAlert: Bool = false

// Bindings
var themeBinding: Binding<ThemeName> {
@@ -107,9 +108,22 @@ final class SettingsViewModel: ObservableObject {
var voiceSearchEnabledBinding: Binding<Bool> {
Binding<Bool>(
get: { self.state.general.voiceSearchEnabled },
set: {
self.model.voiceSearchEnabled = $0
self.state.general.voiceSearchEnabled = $0
set: { value in
if value {
self.model.enableVoiceSearch { [weak self] result in
DispatchQueue.main.async {
self?.state.general.voiceSearchEnabled = result
self?.model.voiceSearchEnabled = result
if !result {
// Permission is denied
self?.shouldShowNoMicrophonePermissionAlert = true
}
}
}
} else {
self.state.general.voiceSearchEnabled = false
self.model.voiceSearchEnabled = false
}
}
)
}
@@ -138,6 +152,7 @@ final class SettingsViewModel: ObservableObject {
state.general.longPressPreviews = model.longPressPreviews
state.general.allowUniversalLinks = model.allowUniversalLinks
}

}

extension SettingsViewModel {