diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index fd2141d790..baa64aaa4f 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -297,6 +297,7 @@ 6CB9144B29BEC7F100BC47F2 /* (null) in Sources */ = {isa = PBXBuildFile; }; 6CBD1BC62978DE53006639D5 /* Font+Caption3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBD1BC52978DE53006639D5 /* Font+Caption3.swift */; }; 6CC9E4B229B5669900C97388 /* Environment+ActiveTabGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC9E4B129B5669900C97388 /* Environment+ActiveTabGroup.swift */; }; + 6CD03B6A29FC773F001BD1D0 /* SettingsInjector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD03B6929FC773F001BD1D0 /* SettingsInjector.swift */; }; 6CDA84AD284C1BA000C1CC3A /* TabBarContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CDA84AC284C1BA000C1CC3A /* TabBarContextMenu.swift */; }; 6CDEFC9629E22C2700B7C684 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 6CDEFC9529E22C2700B7C684 /* Introspect */; }; 6CFF967429BEBCC300182D6F /* FindCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFF967329BEBCC300182D6F /* FindCommands.swift */; }; @@ -697,6 +698,7 @@ 6CABB1A029C5593800340467 /* OverlayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverlayView.swift; sourceTree = ""; }; 6CBD1BC52978DE53006639D5 /* Font+Caption3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Font+Caption3.swift"; sourceTree = ""; }; 6CC9E4B129B5669900C97388 /* Environment+ActiveTabGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Environment+ActiveTabGroup.swift"; sourceTree = ""; }; + 6CD03B6929FC773F001BD1D0 /* SettingsInjector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsInjector.swift; sourceTree = ""; }; 6CDA84AC284C1BA000C1CC3A /* TabBarContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarContextMenu.swift; sourceTree = ""; }; 6CFF967329BEBCC300182D6F /* FindCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindCommands.swift; sourceTree = ""; }; 6CFF967529BEBCD900182D6F /* FileCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileCommands.swift; sourceTree = ""; }; @@ -2041,6 +2043,7 @@ 58F2EADB292FB2B0004A9BDE /* SettingsData.swift */, 58F2EAD2292FB2B0004A9BDE /* Settings.swift */, 6C5FDF7929E6160000BC08C0 /* AppSettings.swift */, + 6CD03B6929FC773F001BD1D0 /* SettingsInjector.swift */, 6C0D0C6729E861B000AE4D3F /* SettingsSidebarFix.swift */, 850C631129D6B03400E1444C /* SettingsPage.swift */, ); @@ -2814,6 +2817,7 @@ 5878DAB2291D627C00DD95A3 /* PathBarView.swift in Sources */, 043C321627E3201F006AE443 /* WorkspaceDocument.swift in Sources */, 58F2EAEC292FB2B0004A9BDE /* IgnoredFiles.swift in Sources */, + 6CD03B6A29FC773F001BD1D0 /* SettingsInjector.swift in Sources */, 58798236292E30B90085B254 /* FeedbackType.swift in Sources */, 587B9E6D29301D8F00AC7927 /* GitLabEventNote.swift in Sources */, 587B9E9129301D8F00AC7927 /* BitBucketOAuthRouter.swift in Sources */, diff --git a/CodeEdit/Features/CodeFile/CodeFile.swift b/CodeEdit/Features/CodeFile/CodeFile.swift index 72ca1fbe96..7a8d18c58e 100644 --- a/CodeEdit/Features/CodeFile/CodeFile.swift +++ b/CodeEdit/Features/CodeFile/CodeFile.swift @@ -80,7 +80,9 @@ final class CodeFileDocument: NSDocument, ObservableObject, QLPreviewItem { let windowController = NSWindowController(window: window) addWindowController(windowController) - window.contentView = NSHostingView(rootView: WindowCodeFileView(codeFile: self)) + window.contentView = NSHostingView(rootView: SettingsInjector { + WindowCodeFileView(codeFile: self) + }) window.makeKeyAndOrderFront(nil) window.center() diff --git a/CodeEdit/Features/CodeFile/CodeFileView.swift b/CodeEdit/Features/CodeFile/CodeFileView.swift index 8de951edd7..3be2be5290 100644 --- a/CodeEdit/Features/CodeFile/CodeFileView.swift +++ b/CodeEdit/Features/CodeFile/CodeFileView.swift @@ -16,7 +16,12 @@ struct CodeFileView: View { @ObservedObject private var codeFile: CodeFileDocument - @AppSettings var settings + @AppSettings(\.textEditing.defaultTabWidth) var defaultTabWidth + @AppSettings(\.textEditing.lineHeightMultiple) var lineHeightMultiple + @AppSettings(\.textEditing.wrapLinesToEditorWidth) var wrapLinesToEditorWidth + @AppSettings(\.textEditing.font) var settingsFont + @AppSettings(\.theme.useThemeBackground) var useThemeBackground + @AppSettings(\.theme.matchAppearance) var matchAppearance @Environment(\.colorScheme) private var colorScheme @@ -56,7 +61,7 @@ struct CodeFileView: View { @State private var font: NSFont = { - return Settings.shared.preferences.textEditing.font.current() + return Settings[\.textEditing].font.current() }() @Environment(\.edgeInsets) @@ -71,11 +76,11 @@ struct CodeFileView: View { language: getLanguage(), theme: $selectedTheme.editor.editorTheme, font: $font, - tabWidth: $settings.textEditing.defaultTabWidth, - lineHeight: $settings.textEditing.lineHeightMultiple, - wrapLines: $settings.textEditing.wrapLinesToEditorWidth, + tabWidth: $defaultTabWidth, + lineHeight: $lineHeightMultiple, + wrapLines: $wrapLinesToEditorWidth, cursorPosition: $codeFile.cursorPosition, - useThemeBackground: settings.theme.useThemeBackground, + useThemeBackground: useThemeBackground, contentInsets: edgeInsets.nsEdgeInsets, isEditable: isEditable ) @@ -99,13 +104,13 @@ struct CodeFileView: View { self.selectedTheme = theme } .onChange(of: colorScheme) { newValue in - if settings.theme.matchAppearance { + if matchAppearance { ThemeModel.shared.selectedTheme = newValue == .dark ? ThemeModel.shared.selectedDarkTheme! : ThemeModel.shared.selectedLightTheme! } } - .onChange(of: settings.textEditing.font) { _ in + .onChange(of: settingsFont) { _ in font = Settings.shared.preferences.textEditing.font.current() } } diff --git a/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift b/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift index 21183acfaa..de97857b04 100644 --- a/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift +++ b/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift @@ -86,9 +86,11 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs let feedbackPerformer = NSHapticFeedbackManager.defaultPerformer let splitVC = CodeEditSplitViewController(workspace: workspace, feedbackPerformer: feedbackPerformer) - let navigatorView = NavigatorSidebarView(workspace: workspace) - .environmentObject(workspace) - .environmentObject(workspace.tabManager) + let navigatorView = SettingsInjector { + NavigatorSidebarView(workspace: workspace) + .environmentObject(workspace) + .environmentObject(workspace.tabManager) + } let navigator = NSSplitViewItem( sidebarWithViewController: NSHostingController(rootView: navigatorView) @@ -98,10 +100,12 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs navigator.collapseBehavior = .useConstraints splitVC.addSplitViewItem(navigator) - let workspaceView = WindowObserver(window: window!) { - WorkspaceView() - .environmentObject(workspace) - .environmentObject(workspace.tabManager) + let workspaceView = SettingsInjector { + WindowObserver(window: window!) { + WorkspaceView() + .environmentObject(workspace) + .environmentObject(workspace.tabManager) + } } let mainContent = NSSplitViewItem( @@ -110,9 +114,11 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs mainContent.titlebarSeparatorStyle = .line splitVC.addSplitViewItem(mainContent) - let inspectorView = InspectorSidebarView(workspace: workspace) - .environmentObject(workspace) - .environmentObject(workspace.tabManager) + let inspectorView = SettingsInjector { + InspectorSidebarView(workspace: workspace) + .environmentObject(workspace) + .environmentObject(workspace.tabManager) + } let inspector = NSSplitViewItem( viewController: NSHostingController(rootView: inspectorView) @@ -220,9 +226,9 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs let toolbarItem = NSToolbarItem(itemIdentifier: .branchPicker) let view = NSHostingView( rootView: ToolbarBranchPicker( - shellClient: currentWorld.shellClient, - workspace: workspace?.workspaceClient - ) + shellClient: currentWorld.shellClient, + workspace: workspace?.workspaceClient + ) ) toolbarItem.view = view @@ -261,7 +267,7 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs let panel = OverlayPanel() self.commandPalettePanel = panel let contentView = CommandPaletteView(state: state, closePalette: panel.close) - panel.contentView = NSHostingView(rootView: contentView) + panel.contentView = NSHostingView(rootView: SettingsInjector { contentView }) window?.addChildWindow(panel, ordered: .above) panel.makeKeyAndOrderFront(self) } @@ -288,7 +294,7 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs workspace.tabManager.openTab(item: file) } - panel.contentView = NSHostingView(rootView: contentView) + panel.contentView = NSHostingView(rootView: SettingsInjector { contentView }) window?.addChildWindow(panel, ordered: .above) panel.makeKeyAndOrderFront(self) } diff --git a/CodeEdit/Features/Documents/Views/WorkspaceCodeFileView.swift b/CodeEdit/Features/Documents/Views/WorkspaceCodeFileView.swift index 17db685cab..47aa4698e3 100644 --- a/CodeEdit/Features/Documents/Views/WorkspaceCodeFileView.swift +++ b/CodeEdit/Features/Documents/Views/WorkspaceCodeFileView.swift @@ -11,9 +11,6 @@ import UniformTypeIdentifiers struct WorkspaceCodeFileView: View { var file: WorkspaceClient.FileItem - @StateObject - private var prefs: Settings = .shared - @ViewBuilder var codeView: some View { if let document = file.fileDocument { diff --git a/CodeEdit/Features/Feedback/Controllers/FeedbackWindowController.swift b/CodeEdit/Features/Feedback/Controllers/FeedbackWindowController.swift index 86c70e868a..824125d3bd 100644 --- a/CodeEdit/Features/Feedback/Controllers/FeedbackWindowController.swift +++ b/CodeEdit/Features/Feedback/Controllers/FeedbackWindowController.swift @@ -9,7 +9,7 @@ import SwiftUI final class FeedbackWindowController: NSWindowController, NSToolbarDelegate { convenience init(view: T, size: NSSize) { - let hostingController = NSHostingController(rootView: view) + let hostingController = NSHostingController(rootView: SettingsInjector { view }) let window = NSWindow(contentViewController: hostingController) self.init(window: window) window.title = "Feedback for CodeEdit" diff --git a/CodeEdit/Features/Feedback/FeedbackView.swift b/CodeEdit/Features/Feedback/FeedbackView.swift index c49f2cda93..6a9f0d1213 100644 --- a/CodeEdit/Features/Feedback/FeedbackView.swift +++ b/CodeEdit/Features/Feedback/FeedbackView.swift @@ -11,9 +11,6 @@ struct FeedbackView: View { @ObservedObject private var feedbackModel: FeedbackModel = .shared - @StateObject - var prefs: Settings = .shared - @State var showsAlert: Bool = false diff --git a/CodeEdit/Features/Keybindings/KeybindingManager.swift b/CodeEdit/Features/Keybindings/KeybindingManager.swift index 83989f8266..8c3b1bfebc 100644 --- a/CodeEdit/Features/Keybindings/KeybindingManager.swift +++ b/CodeEdit/Features/Keybindings/KeybindingManager.swift @@ -60,7 +60,7 @@ final class KeybindingManager { } /// Wrapper for KeyboardShortcut. It contains name, keybindings. -struct KeyboardShortcutWrapper: Codable { +struct KeyboardShortcutWrapper: Codable, Hashable { var keyboardShortcut: KeyboardShortcut { return KeyboardShortcut.init(.init(Character(keybinding)), modifiers: parsedModifier) } diff --git a/CodeEdit/Features/NavigatorSidebar/FindNavigator/FindNavigatorResultList/FindNavigatorResultList.swift b/CodeEdit/Features/NavigatorSidebar/FindNavigator/FindNavigatorResultList/FindNavigatorResultList.swift index 5108146667..4260e4d13c 100644 --- a/CodeEdit/Features/NavigatorSidebar/FindNavigator/FindNavigatorResultList/FindNavigatorResultList.swift +++ b/CodeEdit/Features/NavigatorSidebar/FindNavigator/FindNavigatorResultList/FindNavigatorResultList.swift @@ -13,14 +13,14 @@ struct FindNavigatorResultList: NSViewControllerRepresentable { @EnvironmentObject var workspace: WorkspaceDocument - @AppSettings var settings + @AppSettings(\.general.projectNavigatorSize) var projectNavigatorSize typealias NSViewControllerType = FindNavigatorListViewController func makeNSViewController(context: Context) -> FindNavigatorListViewController { let controller = FindNavigatorListViewController(workspace: workspace) controller.setSearchResults(workspace.searchState?.searchResult ?? []) - controller.rowHeight = settings.general.projectNavigatorSize.rowHeight + controller.rowHeight = projectNavigatorSize.rowHeight context.coordinator.controller = controller return controller } @@ -30,8 +30,8 @@ struct FindNavigatorResultList: NSViewControllerRepresentable { workspace.searchState?.searchResult ?? [], searchId: workspace.searchState?.searchId ) - if nsViewController.rowHeight != settings.general.projectNavigatorSize.rowHeight { - nsViewController.rowHeight = settings.general.projectNavigatorSize.rowHeight + if nsViewController.rowHeight != projectNavigatorSize.rowHeight { + nsViewController.rowHeight = projectNavigatorSize.rowHeight } return } diff --git a/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineTableViewCell.swift b/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineTableViewCell.swift index 95762ca9c0..7f985ce903 100644 --- a/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineTableViewCell.swift +++ b/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineTableViewCell.swift @@ -15,8 +15,6 @@ protocol OutlineTableViewCellDelegate: AnyObject { /// A `NSTableCellView` showing an ``icon`` and a ``label`` final class OutlineTableViewCell: NSTableCellView { - @AppSettings var settings - var label: NSTextField! var icon: NSImageView! private var fileItem: WorkspaceClient.FileItem! diff --git a/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineView.swift b/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineView.swift index 3a7d890a6f..0d478285eb 100644 --- a/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineView.swift +++ b/CodeEdit/Features/NavigatorSidebar/ProjectNavigator/OutlineView/OutlineView.swift @@ -14,8 +14,6 @@ struct OutlineView: NSViewControllerRepresentable { @EnvironmentObject var workspace: WorkspaceDocument - @AppSettings var settings - // This is mainly just used to trigger a view update. @Binding var selection: WorkspaceClient.FileItem? @@ -25,7 +23,7 @@ struct OutlineView: NSViewControllerRepresentable { func makeNSViewController(context: Context) -> OutlineViewController { let controller = OutlineViewController() controller.workspace = workspace - controller.iconColor = settings.general.fileIconStyle + controller.iconColor = Settings[\.general].fileIconStyle context.coordinator.controller = controller @@ -33,11 +31,11 @@ struct OutlineView: NSViewControllerRepresentable { } func updateNSViewController(_ nsViewController: OutlineViewController, context: Context) { - nsViewController.iconColor = settings.general.fileIconStyle - nsViewController.rowHeight = settings.general.projectNavigatorSize.rowHeight - nsViewController.fileExtensionsVisibility = settings.general.fileExtensionsVisibility - nsViewController.shownFileExtensions = settings.general.shownFileExtensions - nsViewController.hiddenFileExtensions = settings.general.hiddenFileExtensions + nsViewController.iconColor = Settings[\.general].fileIconStyle + nsViewController.rowHeight = Settings[\.general].projectNavigatorSize.rowHeight + nsViewController.fileExtensionsVisibility = Settings[\.general].fileExtensionsVisibility + nsViewController.shownFileExtensions = Settings[\.general].shownFileExtensions + nsViewController.hiddenFileExtensions = Settings[\.general].hiddenFileExtensions nsViewController.updateSelection() return } diff --git a/CodeEdit/Features/PathBar/Views/PathBarComponent.swift b/CodeEdit/Features/PathBar/Views/PathBarComponent.swift index f0f77b2687..1122e595fd 100644 --- a/CodeEdit/Features/PathBar/Views/PathBarComponent.swift +++ b/CodeEdit/Features/PathBar/Views/PathBarComponent.swift @@ -19,9 +19,6 @@ struct PathBarComponent: View { @Environment(\.controlActiveState) private var activeState - @StateObject - private var prefs: Settings = .shared - @State var position: NSPoint? diff --git a/CodeEdit/Features/Settings/Models/AppSettings.swift b/CodeEdit/Features/Settings/Models/AppSettings.swift index fff7dd850f..b3d4757e2e 100644 --- a/CodeEdit/Features/Settings/Models/AppSettings.swift +++ b/CodeEdit/Features/Settings/Models/AppSettings.swift @@ -9,24 +9,54 @@ import Foundation import SwiftUI @propertyWrapper -struct AppSettings: DynamicProperty { - @ObservedObject - private var prefs: Settings +struct AppSettings: DynamicProperty where T: Equatable { - init(_ prefs: Settings = .shared) { - self.prefs = prefs + var settings: Environment + + let keyPath: WritableKeyPath + + @available(*, + deprecated, + message: """ +Use init(_ keyPath:) instead, otherwise the view will be reevaluated on every settings change. +""" + ) + init() where T == SettingsData { + self.keyPath = \.self + self.settings = .init(\.settings) } - var wrappedValue: SettingsData { + init(_ keyPath: WritableKeyPath) { + self.keyPath = keyPath + let newKeyPath = (\EnvironmentValues.settings).appending(path: keyPath) + self.settings = .init(newKeyPath) + } + + var wrappedValue: T { get { - prefs.preferences + settings.wrappedValue } nonmutating set { - prefs.preferences = newValue + Settings.shared.preferences[keyPath: keyPath] = newValue + } + } + + var projectedValue: Binding { + .init { + settings.wrappedValue + } set: { + Settings.shared.preferences[keyPath: keyPath] = $0 } } +} + +struct SettingsDataEnvironmentKey: EnvironmentKey { + static var defaultValue: SettingsData = .init() +} - var projectedValue: Binding { - $prefs.preferences +extension EnvironmentValues { + var settings: SettingsDataEnvironmentKey.Value { + get { self[SettingsDataEnvironmentKey.self] } + set { self[SettingsDataEnvironmentKey.self] = newValue } } } diff --git a/CodeEdit/Features/Settings/Models/Settings.swift b/CodeEdit/Features/Settings/Models/Settings.swift index 35039c5071..21bcda4b40 100644 --- a/CodeEdit/Features/Settings/Models/Settings.swift +++ b/CodeEdit/Features/Settings/Models/Settings.swift @@ -7,6 +7,7 @@ import Foundation import SwiftUI +import Combine /// The Preferences View Model. Accessible via the singleton "``SettingsModel/shared``". /// @@ -20,9 +21,15 @@ final class Settings: ObservableObject { /// The publicly available singleton instance of ``SettingsModel`` static let shared: Settings = .init() + private var storeTask: AnyCancellable! + private init() { self.preferences = .init() self.preferences = loadSettings() + + self.storeTask = self.$preferences.throttle(for: 2, scheduler: RunLoop.main, latest: true).sink { + try? self.savePreferences($0) + } } static subscript(_ path: WritableKeyPath, suite: Settings = .shared) -> T { @@ -38,11 +45,7 @@ final class Settings: ObservableObject { /// /// Changes are saved automatically. @Published - var preferences: SettingsData { - didSet { - try? savePreferences() - } - } + var preferences: SettingsData /// Load and construct ``Settings`` model from /// `~/Library/Application Support/CodeEdit/settings.json` @@ -62,8 +65,9 @@ final class Settings: ObservableObject { /// Save``Settings`` model to /// `~/Library/Application Support/CodeEdit/settings.json` - private func savePreferences() throws { - let data = try JSONEncoder().encode(preferences) + private func savePreferences(_ data: SettingsData) throws { + print("Saving...") + let data = try JSONEncoder().encode(data) let json = try JSONSerialization.jsonObject(with: data) let prettyJSON = try JSONSerialization.data(withJSONObject: json, options: [.prettyPrinted]) try prettyJSON.write(to: settingsURL, options: .atomic) diff --git a/CodeEdit/Features/Settings/Models/SettingsData.swift b/CodeEdit/Features/Settings/Models/SettingsData.swift index 44f38f86f1..b7e2844e31 100644 --- a/CodeEdit/Features/Settings/Models/SettingsData.swift +++ b/CodeEdit/Features/Settings/Models/SettingsData.swift @@ -20,7 +20,7 @@ import SwiftUI /// all properties with /// [`decodeIfPresent`](https://developer.apple.com/documentation/swift/keyeddecodingcontainer/2921389-decodeifpresent) /// and providing a default value. Otherwise all settings get overridden. -struct SettingsData: Codable { +struct SettingsData: Codable, Hashable { /// The general global setting var general: GeneralSettings = .init() diff --git a/CodeEdit/Features/Settings/Models/SettingsInjector.swift b/CodeEdit/Features/Settings/Models/SettingsInjector.swift new file mode 100644 index 0000000000..301991273d --- /dev/null +++ b/CodeEdit/Features/Settings/Models/SettingsInjector.swift @@ -0,0 +1,20 @@ +// +// SettingsInjector.swift +// CodeEdit +// +// Created by Wouter Hennen on 28/04/2023. +// + +import SwiftUI + +struct SettingsInjector: View { + + @ObservedObject var settings = Settings.shared + + @ViewBuilder var content: Content + + var body: some View { + content + .environment(\.settings, settings.preferences) + } +} diff --git a/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsDetailsView.swift b/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsDetailsView.swift index 78d6e35c86..554c8a875b 100644 --- a/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsDetailsView.swift +++ b/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsDetailsView.swift @@ -8,7 +8,7 @@ import SwiftUI struct AccountsSettingsDetailsView: View { - @AppSettings var settings + @AppSettings(\.accounts.sourceControlAccounts.sshKey) var sshKey @Binding var account: SourceControlAccount @@ -45,7 +45,7 @@ struct AccountsSettingsDetailsView: View { } .pickerStyle(.radioGroup) - Picker("SSH Key", selection: $settings.accounts.sourceControlAccounts.sshKey) { + Picker("SSH Key", selection: $sshKey) { Text("None") Text("Create New...") Text("Choose...") diff --git a/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsSigninView.swift b/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsSigninView.swift index fe64a765ef..bb44326904 100644 --- a/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsSigninView.swift +++ b/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsSigninView.swift @@ -23,7 +23,7 @@ struct AccountsSettingsSigninView: View { @State var username = "" @State var personalAccessToken = "" - @AppSettings var settings + @AppSettings(\.accounts.sourceControlAccounts.gitAccounts) var gitAccounts private let keychain = CodeEditKeychain() @@ -184,7 +184,7 @@ struct AccountsSettingsSigninView: View { } private func handleGitRequestSuccess() { - let gitAccounts = settings.accounts.sourceControlAccounts.gitAccounts + let gitAccounts = self.gitAccounts let providerLink = provider.baseURL?.absoluteString ?? server if gitAccounts.contains( @@ -195,7 +195,7 @@ struct AccountsSettingsSigninView: View { ) { print("Account with the same username and provider already exists!") } else { - settings.accounts.sourceControlAccounts.gitAccounts.append( + self.gitAccounts.append( SourceControlAccount( id: "\(providerLink)_\(username.lowercased())", name: username, diff --git a/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsView.swift b/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsView.swift index 8bbdfc9583..9baefee8b3 100644 --- a/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/AccountsSettings/AccountsSettingsView.swift @@ -8,7 +8,7 @@ import SwiftUI struct AccountsSettingsView: View { - @AppSettings var settings + @AppSettings(\.accounts.sourceControlAccounts.gitAccounts) var gitAccounts @State private var addAccountSheetPresented: Bool = false @State private var selectedProvider: SourceControlAccount.Provider? @@ -16,12 +16,12 @@ struct AccountsSettingsView: View { var body: some View { SettingsForm { Section { - if $settings.accounts.sourceControlAccounts.gitAccounts.isEmpty { + if $gitAccounts.isEmpty { Text("No accounts") .foregroundColor(.secondary) .frame(maxWidth: .infinity, alignment: .center) } else { - ForEach($settings.accounts.sourceControlAccounts.gitAccounts) { $account in + ForEach($gitAccounts) { $account in AccountsSettingsAccountLink($account) } } diff --git a/CodeEdit/Features/Settings/Pages/AccountsSettings/Models/AccountsSettings.swift b/CodeEdit/Features/Settings/Pages/AccountsSettings/Models/AccountsSettings.swift index cd3ec7710d..10e5b5f685 100644 --- a/CodeEdit/Features/Settings/Pages/AccountsSettings/Models/AccountsSettings.swift +++ b/CodeEdit/Features/Settings/Pages/AccountsSettings/Models/AccountsSettings.swift @@ -10,7 +10,7 @@ import Foundation extension SettingsData { /// The global settings for text editing - struct AccountsSettings: Codable { + struct AccountsSettings: Codable, Hashable { /// An integer indicating how many spaces a `tab` will generate var sourceControlAccounts: GitAccounts = .init() @@ -27,7 +27,7 @@ extension SettingsData { } } - struct GitAccounts: Codable { + struct GitAccounts: Codable, Hashable { /// This id will store the account name as the identifiable var gitAccounts: [SourceControlAccount] = [] diff --git a/CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift b/CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift index 4c0fd112c2..b0d8b8a9c9 100644 --- a/CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift @@ -16,7 +16,7 @@ struct GeneralSettingsView: View { @EnvironmentObject var updater: SoftwareUpdater @FocusState private var focusedField: UUID? - @AppSettings var settings + @AppSettings(\.general) var settings @State private var openInCodeEdit: Bool = true @@ -72,7 +72,7 @@ struct GeneralSettingsView: View { /// The extension of the view with all the preferences private extension GeneralSettingsView { var appearance: some View { - Picker("Appearance", selection: $settings.general.appAppearance) { + Picker("Appearance", selection: $settings.appAppearance) { Text("System") .tag(SettingsData.Appearances.system) Divider() @@ -81,14 +81,14 @@ private extension GeneralSettingsView { Text("Dark") .tag(SettingsData.Appearances.dark) } - .onChange(of: settings.general.appAppearance) { tag in + .onChange(of: settings.appAppearance) { tag in tag.applyAppearance() } } // TODO: Implement reflecting Show Issues preference and remove disabled modifier var showIssues: some View { - Picker("Show Issues", selection: $settings.general.showIssues) { + Picker("Show Issues", selection: $settings.showIssues) { Text("Show Inline") .tag(SettingsData.Issues.inline) Text("Show Minimized") @@ -97,12 +97,12 @@ private extension GeneralSettingsView { } var showLiveIssues: some View { - Toggle("Show Live Issues", isOn: $settings.general.showLiveIssues) + Toggle("Show Live Issues", isOn: $settings.showLiveIssues) } var fileExtensions: some View { Group { - Picker("File Extensions", selection: $settings.general.fileExtensionsVisibility) { + Picker("File Extensions", selection: $settings.fileExtensionsVisibility) { Text("Hide all") .tag(SettingsData.FileExtensionsVisibility.hideAll) Text("Show all") @@ -113,13 +113,13 @@ private extension GeneralSettingsView { Text("Hide only") .tag(SettingsData.FileExtensionsVisibility.hideOnly) } - if case .showOnly = settings.general.fileExtensionsVisibility { - TextField("", text: $settings.general.shownFileExtensions.string, axis: .vertical) + if case .showOnly = settings.fileExtensionsVisibility { + TextField("", text: $settings.shownFileExtensions.string, axis: .vertical) .labelsHidden() .lineLimit(1...3) } - if case .hideOnly = settings.general.fileExtensionsVisibility { - TextField("", text: $settings.general.hiddenFileExtensions.string, axis: .vertical) + if case .hideOnly = settings.fileExtensionsVisibility { + TextField("", text: $settings.hiddenFileExtensions.string, axis: .vertical) .labelsHidden() .lineLimit(1...3) } @@ -127,7 +127,7 @@ private extension GeneralSettingsView { } var fileIconStyle: some View { - Picker("File Icon Style", selection: $settings.general.fileIconStyle) { + Picker("File Icon Style", selection: $settings.fileIconStyle) { Text("Color") .tag(SettingsData.FileIconStyle.color) Text("Monochrome") @@ -137,7 +137,7 @@ private extension GeneralSettingsView { } var tabBarStyle: some View { - Picker("Tab Bar Style", selection: $settings.general.tabBarStyle) { + Picker("Tab Bar Style", selection: $settings.tabBarStyle) { Text("Xcode") .tag(SettingsData.TabBarStyle.xcode) Text("Native") @@ -147,7 +147,7 @@ private extension GeneralSettingsView { } var reopenBehavior: some View { - Picker("Reopen Behavior", selection: $settings.general.reopenBehavior) { + Picker("Reopen Behavior", selection: $settings.reopenBehavior) { Text("Welcome Screen") .tag(SettingsData.ReopenBehavior.welcome) Divider() @@ -161,7 +161,7 @@ private extension GeneralSettingsView { var afterWindowsCloseBehaviour: some View { Picker( "After the last window is closed", - selection: $settings.general.reopenWindowAfterClose + selection: $settings.reopenWindowAfterClose ) { Text("Do nothing") .tag(SettingsData.ReopenWindowBehavior.doNothing) @@ -174,7 +174,7 @@ private extension GeneralSettingsView { } var projectNavigatorSize: some View { - Picker("Project Navigator Size", selection: $settings.general.projectNavigatorSize) { + Picker("Project Navigator Size", selection: $settings.projectNavigatorSize) { Text("Small") .tag(SettingsData.ProjectNavigatorSize.small) Text("Medium") @@ -185,7 +185,7 @@ private extension GeneralSettingsView { } var findNavigatorDetail: some View { - Picker("Find Navigator Detail", selection: $settings.general.findNavigatorDetail) { + Picker("Find Navigator Detail", selection: $settings.findNavigatorDetail) { ForEach(SettingsData.NavigatorDetail.allCases, id: \.self) { tag in Text(tag.label).tag(tag) } @@ -194,7 +194,7 @@ private extension GeneralSettingsView { // TODO: Implement reflecting Issue Navigator Detail preference and remove disabled modifier var issueNavigatorDetail: some View { - Picker("Issue Navigator Detail", selection: $settings.general.issueNavigatorDetail) { + Picker("Issue Navigator Detail", selection: $settings.issueNavigatorDetail) { ForEach(SettingsData.NavigatorDetail.allCases, id: \.self) { tag in Text(tag.label).tag(tag) } @@ -282,7 +282,7 @@ private extension GeneralSettingsView { var autoSave: some View { Toggle( "Automatically save changes to disk", - isOn: $settings.general.isAutoSaveOn + isOn: $settings.isAutoSaveOn ) } @@ -343,7 +343,7 @@ private extension GeneralSettingsView { } var revealFileOnFocusChangeToggle: some View { - Toggle("Automatically reveal in project navigator", isOn: $settings.general.revealFileOnFocusChange) + Toggle("Automatically reveal in project navigator", isOn: $settings.revealFileOnFocusChange) } private static let formatter = configure(DateFormatter()) { diff --git a/CodeEdit/Features/Settings/Pages/GeneralSettings/Models/GeneralSettings.swift b/CodeEdit/Features/Settings/Pages/GeneralSettings/Models/GeneralSettings.swift index 3087154def..36c2c6734a 100644 --- a/CodeEdit/Features/Settings/Pages/GeneralSettings/Models/GeneralSettings.swift +++ b/CodeEdit/Features/Settings/Pages/GeneralSettings/Models/GeneralSettings.swift @@ -10,7 +10,7 @@ import SwiftUI extension SettingsData { /// The general global setting - struct GeneralSettings: Codable { + struct GeneralSettings: Codable, Hashable { /// The appearance of the app var appAppearance: Appearances = .system diff --git a/CodeEdit/Features/Settings/Pages/Keybindings/Models/KeybindingsSettings.swift b/CodeEdit/Features/Settings/Pages/Keybindings/Models/KeybindingsSettings.swift index 9fed884a41..6fd65cfe57 100644 --- a/CodeEdit/Features/Settings/Pages/Keybindings/Models/KeybindingsSettings.swift +++ b/CodeEdit/Features/Settings/Pages/Keybindings/Models/KeybindingsSettings.swift @@ -10,7 +10,7 @@ import Foundation extension SettingsData { /// The global settings for text editing - struct KeybindingsSettings: Codable { + struct KeybindingsSettings: Codable, Hashable { /// An integer indicating how many spaces a `tab` will generate var keybindings: [String: KeyboardShortcutWrapper] = .init() diff --git a/CodeEdit/Features/Settings/Pages/SourceControlSettings/Models/SourceControlSettings.swift b/CodeEdit/Features/Settings/Pages/SourceControlSettings/Models/SourceControlSettings.swift index 6616b5528d..2e67c61494 100644 --- a/CodeEdit/Features/Settings/Pages/SourceControlSettings/Models/SourceControlSettings.swift +++ b/CodeEdit/Features/Settings/Pages/SourceControlSettings/Models/SourceControlSettings.swift @@ -9,7 +9,7 @@ import Foundation extension SettingsData { /// The global settings for source control - struct SourceControlSettings: Codable { + struct SourceControlSettings: Codable, Hashable { /// The general source control settings var general: SourceControlGeneral = .init() /// The source control git settings @@ -24,7 +24,7 @@ extension SettingsData { } } - struct SourceControlGeneral: Codable { + struct SourceControlGeneral: Codable, Hashable { /// Indicates whether or not the source control is active var enableSourceControl: Bool = true /// Indicates whether or not we should include the upstream changes @@ -103,7 +103,7 @@ extension SettingsData { case sortByDate } - struct SourceControlGit: Codable { + struct SourceControlGit: Codable, Hashable { /// The author name var authorName: String = "" /// The author email diff --git a/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift index 3f453e6a02..ef66927dbd 100644 --- a/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift +++ b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift @@ -8,7 +8,7 @@ import SwiftUI struct SourceControlGeneralView: View { - @AppSettings var settings + @AppSettings(\.sourceControl.general) var settings @State private var text: String = "main" @@ -39,56 +39,56 @@ private extension SourceControlGeneralView { private var enableSourceControl: some View { Toggle( "Enable source control", - isOn: $settings.sourceControl.general.enableSourceControl + isOn: $settings.enableSourceControl ) } private var refreshLocalStatusAuto: some View { Toggle( "Refresh local status automatically", - isOn: $settings.sourceControl.general.refreshStatusLocally + isOn: $settings.refreshStatusLocally ) } private var fetchRefreshStatusAuto: some View { Toggle( "Fetch and refresh server status automatically", - isOn: $settings.sourceControl.general.fetchRefreshServerStatus + isOn: $settings.fetchRefreshServerStatus ) } private var addRemoveFilesAuto: some View { Toggle( "Add and remove files automatically", - isOn: $settings.sourceControl.general.addRemoveAutomatically + isOn: $settings.addRemoveAutomatically ) } private var selectFilesToCommitAuto: some View { Toggle( "Select files to commit automatically", - isOn: $settings.sourceControl.general.selectFilesToCommit + isOn: $settings.selectFilesToCommit ) } private var showSourceControlChanges: some View { Toggle( "Show source control changes", - isOn: $settings.sourceControl.general.showSourceControlChanges + isOn: $settings.showSourceControlChanges ) } private var includeUpstreamChanges: some View { Toggle( "Include upstream changes", - isOn: $settings.sourceControl.general.includeUpstreamChanges + isOn: $settings.includeUpstreamChanges ) } private var comparisonView: some View { Picker( "Comparison view", - selection: $settings.sourceControl.general.revisionComparisonLayout + selection: $settings.revisionComparisonLayout ) { Text("Local Revision on Left Side") .tag(SettingsData.RevisionComparisonLayout.localLeft) @@ -100,7 +100,7 @@ private extension SourceControlGeneralView { private var sourceControlNavigator: some View { Picker( "Source control navigator", - selection: $settings.sourceControl.general.controlNavigatorOrder + selection: $settings.controlNavigatorOrder ) { Text("Sort by Name") .tag(SettingsData.ControlNavigatorOrder.sortByName) diff --git a/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift index 84d795da03..011030a3db 100644 --- a/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift +++ b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift @@ -8,7 +8,7 @@ import SwiftUI struct SourceControlGitView: View { - @AppSettings var settings + @AppSettings(\.sourceControl.git) var git @State var ignoredFileSelection: IgnoredFiles.ID? @@ -29,24 +29,24 @@ struct SourceControlGitView: View { private extension SourceControlGitView { private var gitAuthorName: some View { - TextField("Author Name", text: $settings.sourceControl.git.authorName) + TextField("Author Name", text: $git.authorName) } private var gitEmail: some View { - TextField("Author Email", text: $settings.sourceControl.git.authorEmail) + TextField("Author Email", text: $git.authorEmail) } private var preferToRebaseWhenPulling: some View { Toggle( "Prefer to rebase when pulling", - isOn: $settings.sourceControl.git.preferRebaseWhenPulling + isOn: $git.preferRebaseWhenPulling ) } private var showMergeCommitsInPerFileLog: some View { Toggle( "Show merge commits in per-file log", - isOn: $settings.sourceControl.git.showMergeCommitsPerFileLog + isOn: $git.showMergeCommitsPerFileLog ) } diff --git a/CodeEdit/Features/Settings/Pages/TerminalSettings/Models/TerminalSettings.swift b/CodeEdit/Features/Settings/Pages/TerminalSettings/Models/TerminalSettings.swift index ac1bcf84ee..fa7e4dc070 100644 --- a/CodeEdit/Features/Settings/Pages/TerminalSettings/Models/TerminalSettings.swift +++ b/CodeEdit/Features/Settings/Pages/TerminalSettings/Models/TerminalSettings.swift @@ -10,7 +10,7 @@ import Foundation extension SettingsData { /// The global settings for the terminal emulator - struct TerminalSettings: Codable { + struct TerminalSettings: Codable, Hashable { /// If true terminal will use editor theme. var useEditorTheme: Bool = true @@ -62,19 +62,19 @@ extension SettingsData { /// - **bash**: uses the default bash shell /// - **zsh**: uses the ZSH shell /// - **system**: uses the system default shell (most likely ZSH) - enum TerminalShell: String, Codable { + enum TerminalShell: String, Codable, Hashable { case bash case zsh case system } - enum TerminalCursorStyle: String, Codable { + enum TerminalCursorStyle: String, Codable, Hashable { case block case underline case bar } - struct TerminalFont: Codable { + struct TerminalFont: Codable, Hashable { /// Indicates whether or not to use a custom font var customFont: Bool = false diff --git a/CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift b/CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift index 93771d3508..12b6f7b382 100644 --- a/CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift @@ -8,7 +8,7 @@ import SwiftUI struct TerminalSettingsView: View { - @AppSettings var settings + @AppSettings(\.terminal) var settings var body: some View { SettingsForm { @@ -18,7 +18,7 @@ struct TerminalSettingsView: View { } Section { useTextEditorFontToggle - if !settings.terminal.useTextEditorFont { + if !settings.useTextEditorFont { fontSelector fontSizeSelector } @@ -34,7 +34,7 @@ struct TerminalSettingsView: View { private extension TerminalSettingsView { @ViewBuilder private var shellSelector: some View { - Picker("Shell", selection: $settings.terminal.shell) { + Picker("Shell", selection: $settings.shell) { Text("System Default") .tag(SettingsData.TerminalShell.system) Divider() @@ -46,7 +46,7 @@ private extension TerminalSettingsView { } private var cursorStyle: some View { - Picker("Terminal Cursor Style", selection: $settings.terminal.cursorStyle) { + Picker("Terminal Cursor Style", selection: $settings.cursorStyle) { Text("Block") .tag(SettingsData.TerminalCursorStyle.block) Text("Underline") @@ -57,29 +57,29 @@ private extension TerminalSettingsView { } private var cursorBlink: some View { - Toggle("Blink Cursor", isOn: $settings.terminal.cursorBlink) + Toggle("Blink Cursor", isOn: $settings.cursorBlink) } private var optionAsMetaToggle: some View { - Toggle("Use \"Option\" key as \"Meta\"", isOn: $settings.terminal.optionAsMeta) + Toggle("Use \"Option\" key as \"Meta\"", isOn: $settings.optionAsMeta) } private var useTextEditorFontToggle: some View { - Toggle("Use text editor font", isOn: $settings.terminal.useTextEditorFont) + Toggle("Use text editor font", isOn: $settings.useTextEditorFont) } @ViewBuilder private var fontSelector: some View { - MonospacedFontPicker(title: "Font", selectedFontName: $settings.terminal.font.name) - .onChange(of: settings.terminal.font.name) { fontName in - settings.terminal.font.customFont = fontName != "SF Mono" + MonospacedFontPicker(title: "Font", selectedFontName: $settings.font.name) + .onChange(of: settings.font.name) { fontName in + settings.font.customFont = fontName != "SF Mono" } } private var fontSizeSelector: some View { Stepper( "Font Size", - value: $settings.terminal.font.size, + value: $settings.font.size, in: 1...288, step: 1, format: .number diff --git a/CodeEdit/Features/Settings/Pages/TextEditingSettings/Models/TextEditingSettings.swift b/CodeEdit/Features/Settings/Pages/TextEditingSettings/Models/TextEditingSettings.swift index 3a27717285..e9bbe63e0b 100644 --- a/CodeEdit/Features/Settings/Pages/TextEditingSettings/Models/TextEditingSettings.swift +++ b/CodeEdit/Features/Settings/Pages/TextEditingSettings/Models/TextEditingSettings.swift @@ -11,7 +11,7 @@ import Foundation extension SettingsData { /// The global settings for text editing - struct TextEditingSettings: Codable { + struct TextEditingSettings: Codable, Hashable { /// An integer indicating how many spaces a `tab` will generate var defaultTabWidth: Int = 4 @@ -93,7 +93,7 @@ extension SettingsData { } } - struct EditorFont: Codable, Equatable { + struct EditorFont: Codable, Hashable { /// Indicates whether or not to use a custom font var customFont: Bool = false diff --git a/CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift b/CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift index e26ede5a86..4ed39e592d 100644 --- a/CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift @@ -9,7 +9,7 @@ import SwiftUI /// A view that implements the `Text Editing` settings page struct TextEditingSettingsView: View { - @AppSettings var settings + @AppSettings(\.textEditing) var textEditing var body: some View { SettingsForm { @@ -33,16 +33,16 @@ struct TextEditingSettingsView: View { private extension TextEditingSettingsView { @ViewBuilder private var fontSelector: some View { - MonospacedFontPicker(title: "Font", selectedFontName: $settings.textEditing.font.name) - .onChange(of: settings.textEditing.font.name) { fontName in - settings.textEditing.font.customFont = fontName != "SF Mono" + MonospacedFontPicker(title: "Font", selectedFontName: $textEditing.font.name) + .onChange(of: textEditing.font.name) { fontName in + textEditing.font.customFont = fontName != "SF Mono" } } private var fontSizeSelector: some View { Stepper( "Font Size", - value: $settings.textEditing.font.size, + value: $textEditing.font.size, in: 1...288, step: 1, format: .number @@ -50,24 +50,24 @@ private extension TextEditingSettingsView { } private var autocompleteBraces: some View { - Toggle(isOn: $settings.textEditing.autocompleteBraces) { + Toggle(isOn: $textEditing.autocompleteBraces) { Text("Autocomplete braces") Text("Automatically insert closing braces (\"}\")") } } private var enableTypeOverCompletion: some View { - Toggle("Enable type-over completion", isOn: $settings.textEditing.enableTypeOverCompletion) + Toggle("Enable type-over completion", isOn: $textEditing.enableTypeOverCompletion) } private var wrapLinesToEditorWidth: some View { - Toggle("Wrap lines to editor width", isOn: $settings.textEditing.wrapLinesToEditorWidth) + Toggle("Wrap lines to editor width", isOn: $textEditing.wrapLinesToEditorWidth) } private var lineHeight: some View { Stepper( "Line Height", - value: $settings.textEditing.lineHeightMultiple, + value: $textEditing.lineHeightMultiple, in: 0.75...2.0, step: 0.05, format: .number @@ -79,8 +79,8 @@ private extension TextEditingSettingsView { Stepper( "Default Tab Width", value: Binding( - get: { Double(settings.textEditing.defaultTabWidth) }, - set: { settings.textEditing.defaultTabWidth = Int($0) } + get: { Double(textEditing.defaultTabWidth) }, + set: { textEditing.defaultTabWidth = Int($0) } ), in: 1...8, step: 1, diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/Models/ThemeSettings.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/Models/ThemeSettings.swift index 3327cecb8d..4ca3a18cb4 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/Models/ThemeSettings.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/Models/ThemeSettings.swift @@ -30,7 +30,7 @@ extension SettingsData { typealias ThemeOverrides = [String: [String: Theme.Attributes]] /// The global settings for themes - struct ThemeSettings: Codable { + struct ThemeSettings: Codable, Hashable { /// The name of the currently selected dark theme var selectedDarkTheme: String = "codeedit-xcode-dark" diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift index f1738417aa..8f7bdea321 100644 --- a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -12,7 +12,8 @@ import Preferences struct ThemeSettingsView: View { @Environment(\.colorScheme) var colorScheme @ObservedObject private var themeModel: ThemeModel = .shared - @AppSettings var settings + @AppSettings(\.theme) var settings + @AppSettings(\.terminal.darkAppearance) var useDarkTerminalAppearance @State private var listView: Bool = false @State private var selectedAppearance: ThemeSettingsAppearances = .dark @@ -23,7 +24,7 @@ struct ThemeSettingsView: View { } func getThemeActive (_ theme: Theme) -> Bool { - if settings.theme.matchAppearance { + if settings.matchAppearance { return selectedAppearance == .dark ? themeModel.selectedDarkTheme == theme : selectedAppearance == .light @@ -34,7 +35,7 @@ struct ThemeSettingsView: View { } func activateTheme (_ theme: Theme) { - if settings.theme.matchAppearance { + if settings.matchAppearance { if selectedAppearance == .dark { themeModel.selectedDarkTheme = theme } else if selectedAppearance == .light { @@ -59,14 +60,14 @@ struct ThemeSettingsView: View { SettingsForm { Section { changeThemeOnSystemAppearance - if settings.theme.matchAppearance { + if settings.matchAppearance { alwaysUseDarkTerminalAppearance } useThemeBackground } Section { VStack(spacing: 0) { - if settings.theme.matchAppearance { + if settings.matchAppearance { Picker("", selection: $selectedAppearance) { ForEach(ThemeSettingsAppearances.allCases, id: \.self) { tab in Text(tab.rawValue) @@ -104,19 +105,19 @@ struct ThemeSettingsView: View { private extension ThemeSettingsView { private var useThemeBackground: some View { - Toggle("Use theme background ", isOn: $settings.theme.useThemeBackground) + Toggle("Use theme background ", isOn: $settings.useThemeBackground) } private var alwaysUseDarkTerminalAppearance: some View { - Toggle("Always use dark terminal appearance", isOn: $settings.terminal.darkAppearance) + Toggle("Always use dark terminal appearance", isOn: $useDarkTerminalAppearance) } private var changeThemeOnSystemAppearance: some View { Toggle( "Automatically change theme based on system appearance", - isOn: $settings.theme.matchAppearance + isOn: $settings.matchAppearance ) - .onChange(of: settings.theme.matchAppearance) { value in + .onChange(of: settings.matchAppearance) { value in if value { if colorScheme == .dark { themeModel.selectedTheme = themeModel.selectedDarkTheme @@ -125,7 +126,7 @@ private extension ThemeSettingsView { } } else { themeModel.selectedTheme = themeModel.themes.first { - $0.name == settings.theme.selectedTheme + $0.name == settings.selectedTheme } } } diff --git a/CodeEdit/Features/Settings/SettingsView.swift b/CodeEdit/Features/Settings/SettingsView.swift index d6c5f6b4d6..2b4235a15c 100644 --- a/CodeEdit/Features/Settings/SettingsView.swift +++ b/CodeEdit/Features/Settings/SettingsView.swift @@ -35,6 +35,8 @@ struct SettingsView: View { @State private var selectedPage = pages.first! @State private var searchText: String = "" + @ObservedObject private var settings: Settings = .shared + @Environment(\.presentationMode) var presentationMode let updater: SoftwareUpdater @@ -114,6 +116,7 @@ struct SettingsView: View { } } .environmentObject(model) + .environment(\.settings, settings.preferences) } } diff --git a/CodeEdit/Features/StatusBar/Views/StatusBarDrawer/StatusBarDrawer.swift b/CodeEdit/Features/StatusBar/Views/StatusBarDrawer/StatusBarDrawer.swift index 9476206207..40596fdf0e 100644 --- a/CodeEdit/Features/StatusBar/Views/StatusBarDrawer/StatusBarDrawer.swift +++ b/CodeEdit/Features/StatusBar/Views/StatusBarDrawer/StatusBarDrawer.swift @@ -17,8 +17,9 @@ struct StatusBarDrawer: View { @EnvironmentObject private var model: StatusBarViewModel - @AppSettings - private var settings + @AppSettings(\.theme.matchAppearance) private var matchAppearance + @AppSettings(\.terminal.darkAppearance) private var darkAppearance + @AppSettings(\.theme.useThemeBackground) private var useThemeBackground @StateObject private var themeModel: ThemeModel = .shared @@ -28,7 +29,7 @@ struct StatusBarDrawer: View { /// Returns the `background` color of the selected theme private var backgroundColor: NSColor { - if let selectedTheme = settings.theme.matchAppearance && settings.terminal.darkAppearance + if let selectedTheme = matchAppearance && darkAppearance ? themeModel.selectedDarkTheme : themeModel.selectedTheme, let index = themeModel.themes.firstIndex(of: selectedTheme) { @@ -76,7 +77,7 @@ struct StatusBarDrawer: View { .frame(maxHeight: 28) } .background { - if settings.theme.useThemeBackground { + if useThemeBackground { Color(nsColor: backgroundColor) } else { if colorScheme == .dark { @@ -87,7 +88,7 @@ struct StatusBarDrawer: View { } } .colorScheme( - settings.theme.matchAppearance && settings.terminal.darkAppearance + matchAppearance && darkAppearance ? themeModel.selectedDarkTheme?.appearance == .dark ? .dark : .light : themeModel.selectedTheme?.appearance == .dark ? .dark : .light ) diff --git a/CodeEdit/Features/StatusBar/Views/StatusBarItems/StatusBarIndentSelector.swift b/CodeEdit/Features/StatusBar/Views/StatusBarItems/StatusBarIndentSelector.swift index 0d786968f0..5ceb75a1d0 100644 --- a/CodeEdit/Features/StatusBar/Views/StatusBarItems/StatusBarIndentSelector.swift +++ b/CodeEdit/Features/StatusBar/Views/StatusBarItems/StatusBarIndentSelector.swift @@ -8,7 +8,7 @@ import SwiftUI struct StatusBarIndentSelector: View { - @AppSettings var settings + @AppSettings(\.textEditing.defaultTabWidth) var defaultTabWidth var body: some View { Menu { @@ -22,14 +22,14 @@ struct StatusBarIndentSelector: View { Divider() - Picker("Tab Width", selection: $settings.textEditing.defaultTabWidth) { + Picker("Tab Width", selection: $defaultTabWidth) { ForEach(2..<9) { index in Text("\(index) Spaces") .tag(index) } } } label: { - Text("\(settings.textEditing.defaultTabWidth) Spaces") + Text("\(defaultTabWidth) Spaces") } .menuStyle(StatusBarMenuStyle()) .onHover { isHovering($0) } diff --git a/CodeEdit/Features/StatusBar/Views/StatusBarView.swift b/CodeEdit/Features/StatusBar/Views/StatusBarView.swift index 435692c12a..a2c5e8b432 100644 --- a/CodeEdit/Features/StatusBar/Views/StatusBarView.swift +++ b/CodeEdit/Features/StatusBar/Views/StatusBarView.swift @@ -23,9 +23,6 @@ struct StatusBarView: View { @EnvironmentObject private var model: StatusBarViewModel - @ObservedObject - private var prefs: Settings = .shared - static let height = 28.0 @Environment(\.colorScheme) diff --git a/CodeEdit/Features/Tabs/Views/TabBarDivider.swift b/CodeEdit/Features/Tabs/Views/TabBarDivider.swift index ff1bfd8ec8..dec8635376 100644 --- a/CodeEdit/Features/Tabs/Views/TabBarDivider.swift +++ b/CodeEdit/Features/Tabs/Views/TabBarDivider.swift @@ -12,16 +12,16 @@ struct TabDivider: View { @Environment(\.colorScheme) var colorScheme - @AppSettings var settings + @AppSettings(\.general.tabBarStyle) var tabBarStyle let width: CGFloat = 1 var body: some View { Rectangle() .frame(width: width) - .padding(.vertical, settings.general.tabBarStyle == .xcode ? 8 : 0) + .padding(.vertical, tabBarStyle == .xcode ? 8 : 0) .foregroundColor( - settings.general.tabBarStyle == .xcode + tabBarStyle == .xcode ? Color(nsColor: colorScheme == .dark ? .white : .black) .opacity(0.12) : Color(nsColor: colorScheme == .dark ? .controlColor : .black) @@ -35,15 +35,15 @@ struct TabBarTopDivider: View { @Environment(\.colorScheme) var colorScheme - @AppSettings var settings + @AppSettings(\.general.tabBarStyle) var tabBarStyle var body: some View { ZStack(alignment: .top) { - if settings.general.tabBarStyle == .native { + if tabBarStyle == .native { // Color background overlay in native style. Color(nsColor: .black) .opacity(colorScheme == .dark ? 0.80 : 0.02) - .frame(height: settings.general.tabBarStyle == .xcode ? 1.0 : 0.8) + .frame(height: tabBarStyle == .xcode ? 1.0 : 0.8) // Shadow of top divider in native style. TabBarNativeShadow() } @@ -56,19 +56,19 @@ struct TabBarBottomDivider: View { @Environment(\.colorScheme) var colorScheme - @AppSettings var settings + @AppSettings(\.general.tabBarStyle) var tabBarStyle var body: some View { Rectangle() .foregroundColor( - settings.general.tabBarStyle == .xcode + tabBarStyle == .xcode ? Color(nsColor: .separatorColor) .opacity(colorScheme == .dark ? 0.80 : 1) : Color(nsColor: .black) .opacity(colorScheme == .dark ? 0.65 : 0.13) ) - .frame(height: settings.general.tabBarStyle == .xcode ? 1.0 : 0.8) + .frame(height: tabBarStyle == .xcode ? 1.0 : 0.8) } } diff --git a/CodeEdit/Features/Tabs/Views/TabBarItemButtonStyle.swift b/CodeEdit/Features/Tabs/Views/TabBarItemButtonStyle.swift index 7fc9d162d5..997f28d95e 100644 --- a/CodeEdit/Features/Tabs/Views/TabBarItemButtonStyle.swift +++ b/CodeEdit/Features/Tabs/Views/TabBarItemButtonStyle.swift @@ -11,9 +11,6 @@ struct TabBarItemButtonStyle: ButtonStyle { @Environment(\.colorScheme) var colorScheme - @StateObject - private var prefs: Settings = .shared - @Binding private var isPressing: Bool diff --git a/CodeEdit/Features/Tabs/Views/TabBarItemCloseButton.swift b/CodeEdit/Features/Tabs/Views/TabBarItemCloseButton.swift index c80e545ce6..1744294faf 100644 --- a/CodeEdit/Features/Tabs/Views/TabBarItemCloseButton.swift +++ b/CodeEdit/Features/Tabs/Views/TabBarItemCloseButton.swift @@ -19,7 +19,7 @@ struct TabBarItemCloseButton: View { @Environment(\.colorScheme) var colorScheme - @AppSettings var settings + @AppSettings(\.general.tabBarStyle) var tabBarStyle @State private var isPressingClose: Bool = false @@ -31,7 +31,7 @@ struct TabBarItemCloseButton: View { var body: some View { HStack { - if settings.general.tabBarStyle == .xcode { + if tabBarStyle == .xcode { Image(systemName: "xmark") .font(.system(size: 11.5, weight: .regular, design: .rounded)) .foregroundColor( @@ -51,7 +51,7 @@ struct TabBarItemCloseButton: View { ? Color(nsColor: .white) .opacity(isPressingClose ? 0.10 : isHoveringClose ? 0.05 : 0) : ( - settings.general.tabBarStyle == .xcode + tabBarStyle == .xcode ? Color(nsColor: isActive ? .controlAccentColor : .black) .opacity( isPressingClose diff --git a/CodeEdit/Features/Tabs/Views/TabBarItemView.swift b/CodeEdit/Features/Tabs/Views/TabBarItemView.swift index da89956708..4bcbbcbe25 100644 --- a/CodeEdit/Features/Tabs/Views/TabBarItemView.swift +++ b/CodeEdit/Features/Tabs/Views/TabBarItemView.swift @@ -26,7 +26,9 @@ struct TabBarItemView: View { @EnvironmentObject private var tabManager: TabManager - @AppSettings var settings + @AppSettings(\.general.tabBarStyle) var tabBarStyle + + @AppSettings(\.general.fileIconStyle) var fileIconStyle /// Is cursor hovering over the entire tab. @State @@ -110,7 +112,7 @@ struct TabBarItemView: View { func closeAction() { isAppeared = false withAnimation( - .easeOut(duration: settings.general.tabBarStyle == .native ? 0.15 : 0.20) + .easeOut(duration: tabBarStyle == .native ? 0.15 : 0.20) ) { tabgroup.closeTab(item: item) } @@ -138,16 +140,16 @@ struct TabBarItemView: View { TabDivider() .opacity( (isActive || inHoldingState) - && settings.general.tabBarStyle == .xcode ? 0.0 : 1.0 + && tabBarStyle == .xcode ? 0.0 : 1.0 ) - .padding(.top, isActive && settings.general.tabBarStyle == .native ? 1.22 : 0) + .padding(.top, isActive && tabBarStyle == .native ? 1.22 : 0) // Tab content (icon and text). HStack(alignment: .center, spacing: 5) { Image(systemName: item.systemImage) .resizable() .aspectRatio(contentMode: .fit) .foregroundColor( - settings.general.fileIconStyle == .color + fileIconStyle == .color && activeState != .inactive && isActiveTabGroup ? item.iconColor : .secondary @@ -163,11 +165,11 @@ struct TabBarItemView: View { } .frame( // To horizontally max-out the given width area ONLY in native tab bar style. - maxWidth: settings.general.tabBarStyle == .native ? .infinity : nil, + maxWidth: tabBarStyle == .native ? .infinity : nil, // To max-out the parent (tab bar) area. maxHeight: .infinity ) - .padding(.horizontal, settings.general.tabBarStyle == .native ? 28 : 23) + .padding(.horizontal, tabBarStyle == .native ? 28 : 23) .overlay { ZStack { if isActive { @@ -216,31 +218,31 @@ struct TabBarItemView: View { ? 1.0 : ( isActive - ? (settings.general.tabBarStyle == .xcode ? 0.6 : 0.35) - : (settings.general.tabBarStyle == .xcode ? 0.4 : 0.55) + ? (tabBarStyle == .xcode ? 0.6 : 0.35) + : (tabBarStyle == .xcode ? 0.4 : 0.55) ) ) TabDivider() .opacity( (isActive || inHoldingState) - && settings.general.tabBarStyle == .xcode ? 0.0 : 1.0 + && tabBarStyle == .xcode ? 0.0 : 1.0 ) - .padding(.top, isActive && settings.general.tabBarStyle == .native ? 1.22 : 0) + .padding(.top, isActive && tabBarStyle == .native ? 1.22 : 0) } .overlay(alignment: .top) { // Only show NativeTabShadow when `tabBarStyle` is native and this tab is not active. TabBarTopDivider() - .opacity(settings.general.tabBarStyle == .native && !isActive ? 1 : 0) + .opacity(tabBarStyle == .native && !isActive ? 1 : 0) } .foregroundColor( isActive && isActiveTabGroup ? ( - settings.general.tabBarStyle == .xcode && colorScheme != .dark + tabBarStyle == .xcode && colorScheme != .dark ? Color(nsColor: .controlAccentColor) : .primary ) : ( - settings.general.tabBarStyle == .xcode + tabBarStyle == .xcode ? .primary : .secondary ) @@ -265,7 +267,7 @@ struct TabBarItemView: View { content } .background { - if settings.general.tabBarStyle == .xcode { + if tabBarStyle == .xcode { TabBarItemBackground(isActive: isActive, isPressing: isPressing, isDragging: isDragging) .animation(.easeInOut(duration: 0.08), value: isHovering) } else { @@ -304,29 +306,29 @@ struct TabBarItemView: View { ) .padding( // This padding is to avoid background color overlapping with top divider. - .top, settings.general.tabBarStyle == .xcode ? 1 : 0 + .top, tabBarStyle == .xcode ? 1 : 0 ) // .offset( -// x: isAppeared || settings.general.tabBarStyle == .native ? 0 : -14, +// x: isAppeared || tabBarStyle == .native ? 0 : -14, // y: 0 // ) // .opacity(isAppeared && onDragTabId != item.id ? 1.0 : 0.0) .zIndex( isActive - ? (settings.general.tabBarStyle == .native ? -1 : 2) + ? (tabBarStyle == .native ? -1 : 2) : (isDragging ? 3 : (isPressing ? 1 : 0)) ) .frame( width: ( // Constrain the width of tab bar item for native tab style only. - settings.general.tabBarStyle == .native + tabBarStyle == .native ? max(expectedWidth.isFinite ? expectedWidth : 0, 0) : nil ) ) .onAppear { withAnimation( - .easeOut(duration: settings.general.tabBarStyle == .native ? 0.15 : 0.20) + .easeOut(duration: tabBarStyle == .native ? 0.15 : 0.20) ) { // isAppeared = true } diff --git a/CodeEdit/Features/Tabs/Views/TabBarView.swift b/CodeEdit/Features/Tabs/Views/TabBarView.swift index bdb79dca5d..3d5a668e2c 100644 --- a/CodeEdit/Features/Tabs/Views/TabBarView.swift +++ b/CodeEdit/Features/Tabs/Views/TabBarView.swift @@ -40,7 +40,7 @@ struct TabBarView: View { @Environment(\.splitEditor) var splitEditor - @AppSettings var settings + @AppSettings(\.general.tabBarStyle) var tabBarStyle /// The tab id of current dragging tab. /// @@ -350,7 +350,7 @@ struct TabBarView: View { } } // This padding is to hide dividers at two ends under the accessory view divider. - .padding(.horizontal, settings.general.tabBarStyle == .native ? -1 : 0) + .padding(.horizontal, tabBarStyle == .native ? -1 : 0) .onAppear { openedTabs = tabgroup.tabs.map(\.id) // On view appeared, compute the initial expected width for tabs. @@ -363,7 +363,7 @@ struct TabBarView: View { updateForTabCountChange(geometryProxy: geometryProxy) } else { withAnimation( - .easeOut(duration: settings.general.tabBarStyle == .native ? 0.15 : 0.20) + .easeOut(duration: tabBarStyle == .native ? 0.15 : 0.20) ) { updateForTabCountChange(geometryProxy: geometryProxy) } @@ -404,13 +404,13 @@ struct TabBarView: View { // To fill up the parent space of tab bar. .frame(maxWidth: .infinity) .background { - if settings.general.tabBarStyle == .native { + if tabBarStyle == .native { TabBarNativeInactiveBackground() } } } .background { - if settings.general.tabBarStyle == .native { + if tabBarStyle == .native { TabBarAccessoryNativeBackground(dividerAt: .none) } } @@ -421,12 +421,12 @@ struct TabBarView: View { .frame(height: TabBarView.height) .overlay(alignment: .top) { // When tab bar style is `xcode`, we put the top divider as an overlay. - if settings.general.tabBarStyle == .xcode { + if tabBarStyle == .xcode { TabBarTopDivider() } } .background { - if settings.general.tabBarStyle == .native { + if tabBarStyle == .native { TabBarNativeMaterial() .edgesIgnoringSafeArea(.top) } else { @@ -527,7 +527,7 @@ struct TabBarView: View { .opacity(activeState != .inactive ? 1.0 : 0.5) .frame(maxHeight: .infinity) // Fill out vertical spaces. .background { - if settings.general.tabBarStyle == .native { + if tabBarStyle == .native { TabBarAccessoryNativeBackground(dividerAt: .trailing) } } @@ -555,7 +555,7 @@ struct TabBarView: View { .opacity(activeState != .inactive ? 1.0 : 0.5) .frame(maxHeight: .infinity) // Fill out vertical spaces. .background { - if settings.general.tabBarStyle == .native { + if tabBarStyle == .native { TabBarAccessoryNativeBackground(dividerAt: .leading) } } diff --git a/CodeEdit/Features/TerminalEmulator/TerminalEmulatorView.swift b/CodeEdit/Features/TerminalEmulator/TerminalEmulatorView.swift index b1a637478a..5acc11d1f0 100644 --- a/CodeEdit/Features/TerminalEmulator/TerminalEmulatorView.swift +++ b/CodeEdit/Features/TerminalEmulator/TerminalEmulatorView.swift @@ -16,7 +16,8 @@ import SwiftTerm /// for use in SwiftUI. /// struct TerminalEmulatorView: NSViewRepresentable { - @AppSettings var settings + @AppSettings(\.terminal) var terminalSettings + @AppSettings(\.textEditing.font) var fontSettings @StateObject private var themeModel: ThemeModel = .shared @@ -29,22 +30,22 @@ struct TerminalEmulatorView: NSViewRepresentable { private let systemFont: NSFont = .monospacedSystemFont(ofSize: 11, weight: .medium) private var font: NSFont { - if settings.terminal.useTextEditorFont { - if !settings.textEditing.font.customFont { - return systemFont.withSize(CGFloat(settings.textEditing.font.size)) + if terminalSettings.useTextEditorFont { + if !fontSettings.customFont { + return systemFont.withSize(CGFloat(fontSettings.size)) } return NSFont( - name: settings.textEditing.font.name, - size: CGFloat(settings.textEditing.font.size) + name: fontSettings.name, + size: CGFloat(fontSettings.size) ) ?? systemFont } - if !settings.terminal.font.customFont { - return systemFont.withSize(CGFloat(settings.terminal.font.size)) + if !terminalSettings.font.customFont { + return systemFont.withSize(CGFloat(terminalSettings.font.size)) } return NSFont( - name: settings.terminal.font.name, - size: CGFloat(settings.terminal.font.size) + name: terminalSettings.font.name, + size: CGFloat(terminalSettings.font.size) ) ?? systemFont } @@ -72,7 +73,7 @@ struct TerminalEmulatorView: NSViewRepresentable { /// return String(cString: pwd.pw_shell) /// ``` private func getShell() -> String { - switch settings.terminal.shell { + switch terminalSettings.shell { case .system: return autoDetectDefaultShell() case .bash: @@ -83,8 +84,8 @@ struct TerminalEmulatorView: NSViewRepresentable { } private func getTerminalCursor() -> CursorStyle { - let blink = settings.terminal.cursorBlink - switch settings.terminal.cursorStyle { + let blink = terminalSettings.cursorBlink + switch terminalSettings.cursorStyle { case .block: return blink ? .blinkBlock : .steadyBlock case .underline: @@ -111,7 +112,7 @@ struct TerminalEmulatorView: NSViewRepresentable { /// Returns true if the `option` key should be treated as the `meta` key. private var optionAsMeta: Bool { - settings.terminal.optionAsMeta + terminalSettings.optionAsMeta } /// Returns the mapped array of `SwiftTerm.Color` objects of ANSI Colors @@ -168,7 +169,7 @@ struct TerminalEmulatorView: NSViewRepresentable { /// returns a `NSAppearance` based on the user setting of the terminal appearance, /// `nil` if app default is not overridden private var colorAppearance: NSAppearance? { - if settings.terminal.darkAppearance { + if terminalSettings.darkAppearance { return .init(named: .darkAqua) } return nil @@ -200,7 +201,7 @@ struct TerminalEmulatorView: NSViewRepresentable { terminal.caretColor = cursorColor terminal.selectedTextBackgroundColor = selectionColor terminal.nativeForegroundColor = textColor - terminal.nativeBackgroundColor = settings.terminal.useThemeBackground ? backgroundColor : .clear + terminal.nativeBackgroundColor = terminalSettings.useThemeBackground ? backgroundColor : .clear terminal.cursorStyleChanged(source: terminal.getTerminal(), newStyle: getTerminalCursor()) terminal.layer?.backgroundColor = .clear terminal.optionAsMetaKey = optionAsMeta @@ -228,7 +229,7 @@ struct TerminalEmulatorView: NSViewRepresentable { view.caretColor = cursorColor view.selectedTextBackgroundColor = selectionColor view.nativeForegroundColor = textColor - view.nativeBackgroundColor = settings.terminal.useThemeBackground ? backgroundColor : .clear + view.nativeBackgroundColor = terminalSettings.useThemeBackground ? backgroundColor : .clear view.layer?.backgroundColor = .clear view.optionAsMetaKey = optionAsMeta view.cursorStyleChanged(source: view.getTerminal(), newStyle: getTerminalCursor()) diff --git a/CodeEdit/Features/Welcome/Views/WelcomeView.swift b/CodeEdit/Features/Welcome/Views/WelcomeView.swift index 847755c8f8..cf9f3ff415 100644 --- a/CodeEdit/Features/Welcome/Views/WelcomeView.swift +++ b/CodeEdit/Features/Welcome/Views/WelcomeView.swift @@ -13,7 +13,7 @@ struct WelcomeView: View { @Environment(\.colorScheme) var colorScheme - @AppSettings var settings + @AppSettings(\.general.reopenBehavior) var reopenBehavior @State private var repoPath = "~/" @@ -49,9 +49,9 @@ struct WelcomeView: View { private var showWhenLaunchedBinding: Binding { Binding { - settings.general.reopenBehavior == .welcome + reopenBehavior == .welcome } set: { new in - settings.general.reopenBehavior = new ? .welcome : .openPanel + reopenBehavior = new ? .welcome : .openPanel } } diff --git a/CodeEdit/Features/Welcome/Views/WelcomeWindow.swift b/CodeEdit/Features/Welcome/Views/WelcomeWindow.swift index 7c030851e5..29c2fd9d1e 100644 --- a/CodeEdit/Features/Welcome/Views/WelcomeWindow.swift +++ b/CodeEdit/Features/Welcome/Views/WelcomeWindow.swift @@ -9,6 +9,8 @@ import SwiftUI struct WelcomeWindow: Scene { + @ObservedObject var settings = Settings.shared + var body: some Scene { Window("Welcome To CodeEdit", id: SceneID.welcome.rawValue) { ContentView() @@ -21,6 +23,7 @@ struct WelcomeWindow: Scene { window.isMovableByWindowBackground = true } } + .environment(\.settings, settings.preferences) } .windowStyle(.hiddenTitleBar) .keyboardShortcut("1", modifiers: [.command, .shift]) diff --git a/CodeEdit/Features/WindowCommands/ViewCommands.swift b/CodeEdit/Features/WindowCommands/ViewCommands.swift index 29f18d082e..1f7ed533e6 100644 --- a/CodeEdit/Features/WindowCommands/ViewCommands.swift +++ b/CodeEdit/Features/WindowCommands/ViewCommands.swift @@ -8,7 +8,7 @@ import SwiftUI struct ViewCommands: Commands { - @AppSettings var settings + @AppSettings(\.textEditing.font) var font @State var windowController: CodeEditWindowController? @@ -32,20 +32,20 @@ struct ViewCommands: Commands { Button("Increase font size") { if CodeEditDocumentController.shared.documents.count > 1 { - settings.textEditing.font.size += 1 + font.size += 1 } - settings.terminal.font.size += 1 + font.size += 1 } .keyboardShortcut("+") Button("Decrease font size") { if CodeEditDocumentController.shared.documents.count > 1 { - if !(settings.textEditing.font.size <= 1) { - settings.textEditing.font.size -= 1 + if !(font.size <= 1) { + font.size -= 1 } } - if !(settings.terminal.font.size <= 1) { - settings.terminal.font.size -= 1 + if !(font.size <= 1) { + font.size -= 1 } } .keyboardShortcut("-") diff --git a/CodeEdit/WindowObserver.swift b/CodeEdit/WindowObserver.swift index 9129615c17..55d4189a55 100644 --- a/CodeEdit/WindowObserver.swift +++ b/CodeEdit/WindowObserver.swift @@ -19,7 +19,7 @@ struct WindowObserver: View { @State private var isFullscreen = false - @AppSettings var settings + @AppSettings(\.general.tabBarStyle) var tabBarStyle @State var modifierFlags: NSEvent.ModifierFlags = [] @@ -38,7 +38,7 @@ struct WindowObserver: View { self.isFullscreen = false } // When tab bar style is changed, update NSWindow configuration as follows. - .onChange(of: settings.general.tabBarStyle) { newStyle in + .onChange(of: tabBarStyle) { newStyle in DispatchQueue.main.async { if newStyle == .native { window.titlebarSeparatorStyle = .none diff --git a/CodeEdit/WorkspaceView.swift b/CodeEdit/WorkspaceView.swift index 5ac27b6729..db99d790f4 100644 --- a/CodeEdit/WorkspaceView.swift +++ b/CodeEdit/WorkspaceView.swift @@ -19,9 +19,6 @@ struct WorkspaceView: View { @EnvironmentObject private var tabManager: TabManager - @StateObject - private var prefs: Settings = .shared - @Environment(\.window) private var window