From 1c6072a0fbc327bc2bdf88776bbfea4861f7f520 Mon Sep 17 00:00:00 2001 From: luah5 Date: Tue, 4 Apr 2023 17:43:10 +0100 Subject: [PATCH] Refactor of the new ventura settings --- CodeEdit.xcodeproj/project.pbxproj | 246 +++++++++--- .../Model/Terminal/TerminalPreferences.swift | 3 + .../AccountPreferencesView.swift | 5 +- .../GeneralPreferencesView.swift | 37 +- .../SourceControlPreferencesGeneralView.swift | 189 ++++++++++ .../SourceControlPreferencesGitView.swift | 126 +++++++ .../SourceControlPreferencesView.swift | 4 +- .../TerminalPreferencesView.swift | 38 +- .../TextEditingPreferencesView.swift | 166 ++++---- .../ThemePreferences/EditorThemeView.swift | 60 ++- .../ThemePreferences/PreviewThemeView.swift | 37 +- .../ThemePreferences/TerminalThemeView.swift | 27 +- .../ThemePreferencesView.swift | 68 ++-- .../ThemePreferences/ThemePreviewIcon.swift | 44 +-- .../HelperViews/SettingsColorPicker.swift | 28 ++ .../GeneralSettings/GeneralSettingsView.swift | 356 ++++++++++++++++++ .../LocationsSettingsView.swift | 68 ++++ .../SourceControlGeneralView.swift | 122 ++++++ .../SourceControlGitView.swift | 84 +++++ .../SourceControlSettingsView.swift | 19 + .../TerminalSettingsView.swift | 99 +++++ .../TextEditingSettingsView.swift | 150 ++++++++ .../ThemeSettingsColorPreviewColor.swift | 33 ++ .../ThemeSettings/ThemeSettingThemeRow.swift | 51 +++ .../ThemeSettingsColorPreview.swift | 80 ++++ .../ThemeSettingsThemeDetails.swift | 147 ++++++++ .../ThemeSettings/ThemeSettingsView.swift | 176 +++++++++ .../Features/Settings/SettingPageView.swift | 50 +++ CodeEdit/Features/Settings/SettingsPage.swift | 52 +++ CodeEdit/Features/Settings/SettingsView.swift | 90 +++++ .../Features/Settings/SettingsWindow.swift | 31 ++ .../View+ConstrainHeightToWindow.swift | 38 ++ .../WindowCommands/MainCommands.swift | 4 +- 33 files changed, 2507 insertions(+), 221 deletions(-) create mode 100644 CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGeneralView.swift create mode 100644 CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGitView.swift create mode 100644 CodeEdit/Features/Settings/HelperViews/SettingsColorPicker.swift create mode 100644 CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift create mode 100644 CodeEdit/Features/Settings/Pages/LocationsSettings/LocationsSettingsView.swift create mode 100644 CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift create mode 100644 CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift create mode 100644 CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlSettingsView.swift create mode 100644 CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift create mode 100644 CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift create mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/Model/ThemeSettingsColorPreviewColor.swift create mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingThemeRow.swift create mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsColorPreview.swift create mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsThemeDetails.swift create mode 100644 CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift create mode 100644 CodeEdit/Features/Settings/SettingPageView.swift create mode 100644 CodeEdit/Features/Settings/SettingsPage.swift create mode 100644 CodeEdit/Features/Settings/SettingsView.swift create mode 100644 CodeEdit/Features/Settings/SettingsWindow.swift create mode 100644 CodeEdit/Features/Settings/View+ConstrainHeightToWindow.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 393bec64b0..ddad6c1fff 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -236,18 +236,12 @@ 58F2EAE7292FB2B0004A9BDE /* GeneralPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAA2292FB2B0004A9BDE /* GeneralPreferencesView.swift */; }; 58F2EAE8292FB2B0004A9BDE /* TerminalPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAA4292FB2B0004A9BDE /* TerminalPreferencesView.swift */; }; 58F2EAE9292FB2B0004A9BDE /* SourceControlPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAA6292FB2B0004A9BDE /* SourceControlPreferencesView.swift */; }; - 58F2EAEA292FB2B0004A9BDE /* SourceControlGeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAA7292FB2B0004A9BDE /* SourceControlGeneralView.swift */; }; - 58F2EAEB292FB2B0004A9BDE /* SourceControlGitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAA8292FB2B0004A9BDE /* SourceControlGitView.swift */; }; + 58F2EAEA292FB2B0004A9BDE /* SourceControlPreferencesGeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAA7292FB2B0004A9BDE /* SourceControlPreferencesGeneralView.swift */; }; + 58F2EAEB292FB2B0004A9BDE /* SourceControlPreferencesGitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAA8292FB2B0004A9BDE /* SourceControlPreferencesGitView.swift */; }; 58F2EAEC292FB2B0004A9BDE /* IgnoredFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAAA292FB2B0004A9BDE /* IgnoredFiles.swift */; }; 58F2EAED292FB2B0004A9BDE /* IgnoredFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAAB292FB2B0004A9BDE /* IgnoredFileView.swift */; }; 58F2EAEE292FB2B0004A9BDE /* TextEditingPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAAD292FB2B0004A9BDE /* TextEditingPreferencesView.swift */; }; - 58F2EAEF292FB2B0004A9BDE /* ThemePreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAAF292FB2B0004A9BDE /* ThemePreferencesView.swift */; }; - 58F2EAF0292FB2B0004A9BDE /* PreviewThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAB0292FB2B0004A9BDE /* PreviewThemeView.swift */; }; - 58F2EAF1292FB2B0004A9BDE /* TerminalThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAB1292FB2B0004A9BDE /* TerminalThemeView.swift */; }; - 58F2EAF2292FB2B0004A9BDE /* EditorThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAB2292FB2B0004A9BDE /* EditorThemeView.swift */; }; - 58F2EAF3292FB2B0004A9BDE /* ThemePreviewIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAB3292FB2B0004A9BDE /* ThemePreviewIcon.swift */; }; - 58F2EAF4292FB2B0004A9BDE /* ThemeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAB5292FB2B0004A9BDE /* ThemeModel.swift */; }; - 58F2EAF5292FB2B0004A9BDE /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAB6292FB2B0004A9BDE /* Theme.swift */; }; + 58F2EAEF292FB2B0004A9BDE /* ThemeSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAAF292FB2B0004A9BDE /* ThemeSettingsView.swift */; }; 58F2EAF6292FB2B0004A9BDE /* AccountPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EAB8292FB2B0004A9BDE /* AccountPreferencesView.swift */; }; 58F2EAF7292FB2B0004A9BDE /* SourceControlProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EABA292FB2B0004A9BDE /* SourceControlProvider.swift */; }; 58F2EAF8292FB2B0004A9BDE /* AccountListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F2EABC292FB2B0004A9BDE /* AccountListItemView.swift */; }; @@ -331,7 +325,13 @@ 6CFF967829BEBCF600182D6F /* MainCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFF967729BEBCF600182D6F /* MainCommands.swift */; }; 6CFF967A29BEBD2400182D6F /* ViewCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFF967929BEBD2400182D6F /* ViewCommands.swift */; }; 6CFF967C29BEBD5200182D6F /* WindowCommands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CFF967B29BEBD5200182D6F /* WindowCommands.swift */; }; + 850C631029D6B01D00E1444C /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850C630F29D6B01D00E1444C /* SettingsView.swift */; }; + 850C631229D6B03400E1444C /* SettingsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850C631129D6B03400E1444C /* SettingsPage.swift */; }; + 858316B329DC778A00540A18 /* ThemeSettingsColorPreviewColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858316B229DC778A00540A18 /* ThemeSettingsColorPreviewColor.swift */; }; + B6041F4D29D7A4E9000F3454 /* SettingPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6041F4C29D7A4E9000F3454 /* SettingPageView.swift */; }; + B6041F5229D7D6D6000F3454 /* SettingsWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6041F5129D7D6D6000F3454 /* SettingsWindow.swift */; }; B60BE8BD297A167600841125 /* AcknowledgementRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60BE8BC297A167600841125 /* AcknowledgementRowView.swift */; }; + B61DA9DF29D929E100BF4A43 /* GeneralSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B61DA9DE29D929E100BF4A43 /* GeneralSettingsView.swift */; }; B658FB3427DA9E1000EA4DBD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B658FB3327DA9E1000EA4DBD /* Assets.xcassets */; }; B658FB3727DA9E1000EA4DBD /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B658FB3627DA9E1000EA4DBD /* Preview Assets.xcassets */; }; B66A4E4529C8E86D004573B4 /* CommandsFixes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66A4E4429C8E86D004573B4 /* CommandsFixes.swift */; }; @@ -346,8 +346,26 @@ B6C6A43029771F7100A3D28F /* TabBarItemBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C6A42F29771F7100A3D28F /* TabBarItemBackground.swift */; }; B6D7EA592971078500301FAC /* InspectorSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D7EA582971078500301FAC /* InspectorSection.swift */; }; B6D7EA5C297107DD00301FAC /* InspectorField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D7EA5B297107DD00301FAC /* InspectorField.swift */; }; + B6EA1FE529DA33DB001BF195 /* ThemeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FE429DA33DB001BF195 /* ThemeModel.swift */; }; + B6EA1FE729DA341D001BF195 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FE629DA341D001BF195 /* Theme.swift */; }; + B6EA1FEC29DA344F001BF195 /* PreviewThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FE829DA344F001BF195 /* PreviewThemeView.swift */; }; + B6EA1FED29DA344F001BF195 /* TerminalThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FE929DA344F001BF195 /* TerminalThemeView.swift */; }; + B6EA1FEE29DA344F001BF195 /* ThemePreviewIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FEA29DA344F001BF195 /* ThemePreviewIcon.swift */; }; + B6EA1FEF29DA344F001BF195 /* EditorThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FEB29DA344F001BF195 /* EditorThemeView.swift */; }; + B6EA1FF129DA35A7001BF195 /* ThemePreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FF029DA35A7001BF195 /* ThemePreferencesView.swift */; }; + B6EA1FF529DA380E001BF195 /* TextEditingSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FF429DA380E001BF195 /* TextEditingSettingsView.swift */; }; + B6EA1FF829DB78DB001BF195 /* ThemeSettingThemeRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FF729DB78DB001BF195 /* ThemeSettingThemeRow.swift */; }; + B6EA1FFB29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FFA29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift */; }; + B6EA1FFD29DB792C001BF195 /* ThemeSettingsColorPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FFC29DB792C001BF195 /* ThemeSettingsColorPreview.swift */; }; + B6EA200029DB7966001BF195 /* SettingsColorPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA1FFF29DB7966001BF195 /* SettingsColorPicker.swift */; }; + B6EA200229DB7F81001BF195 /* View+ConstrainHeightToWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EA200129DB7F81001BF195 /* View+ConstrainHeightToWindow.swift */; }; B6EE989027E8879A00CDD8AB /* InspectorSidebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EE988F27E8879A00CDD8AB /* InspectorSidebarView.swift */; }; B6EE989227E887C600CDD8AB /* InspectorSidebarToolbarTop.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EE989127E887C600CDD8AB /* InspectorSidebarToolbarTop.swift */; }; + B6F0517029D9E36800D72287 /* LocationsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F0516F29D9E36800D72287 /* LocationsSettingsView.swift */; }; + B6F0517729D9E3AD00D72287 /* SourceControlGeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F0517629D9E3AD00D72287 /* SourceControlGeneralView.swift */; }; + B6F0517929D9E3C900D72287 /* SourceControlGitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F0517829D9E3C900D72287 /* SourceControlGitView.swift */; }; + B6F0517B29D9E46400D72287 /* SourceControlSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F0517A29D9E46400D72287 /* SourceControlSettingsView.swift */; }; + B6F0517D29D9E4B100D72287 /* TerminalSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F0517C29D9E4B100D72287 /* TerminalSettingsView.swift */; }; D7012EE827E757850001E1EF /* FindNavigatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7012EE727E757850001E1EF /* FindNavigatorView.swift */; }; D7211D4327E066CE008F2ED7 /* Localized+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7211D4227E066CE008F2ED7 /* Localized+Ex.swift */; }; D7211D4727E06BFE008F2ED7 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D7211D4927E06BFE008F2ED7 /* Localizable.strings */; }; @@ -643,18 +661,12 @@ 58F2EAA2292FB2B0004A9BDE /* GeneralPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralPreferencesView.swift; sourceTree = ""; }; 58F2EAA4292FB2B0004A9BDE /* TerminalPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TerminalPreferencesView.swift; sourceTree = ""; }; 58F2EAA6292FB2B0004A9BDE /* SourceControlPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceControlPreferencesView.swift; sourceTree = ""; }; - 58F2EAA7292FB2B0004A9BDE /* SourceControlGeneralView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceControlGeneralView.swift; sourceTree = ""; }; - 58F2EAA8292FB2B0004A9BDE /* SourceControlGitView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceControlGitView.swift; sourceTree = ""; }; + 58F2EAA7292FB2B0004A9BDE /* SourceControlPreferencesGeneralView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceControlPreferencesGeneralView.swift; sourceTree = ""; }; + 58F2EAA8292FB2B0004A9BDE /* SourceControlPreferencesGitView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceControlPreferencesGitView.swift; sourceTree = ""; }; 58F2EAAA292FB2B0004A9BDE /* IgnoredFiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IgnoredFiles.swift; sourceTree = ""; }; 58F2EAAB292FB2B0004A9BDE /* IgnoredFileView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IgnoredFileView.swift; sourceTree = ""; }; 58F2EAAD292FB2B0004A9BDE /* TextEditingPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEditingPreferencesView.swift; sourceTree = ""; }; - 58F2EAAF292FB2B0004A9BDE /* ThemePreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemePreferencesView.swift; sourceTree = ""; }; - 58F2EAB0292FB2B0004A9BDE /* PreviewThemeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewThemeView.swift; sourceTree = ""; }; - 58F2EAB1292FB2B0004A9BDE /* TerminalThemeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TerminalThemeView.swift; sourceTree = ""; }; - 58F2EAB2292FB2B0004A9BDE /* EditorThemeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorThemeView.swift; sourceTree = ""; }; - 58F2EAB3292FB2B0004A9BDE /* ThemePreviewIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemePreviewIcon.swift; sourceTree = ""; }; - 58F2EAB5292FB2B0004A9BDE /* ThemeModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeModel.swift; sourceTree = ""; }; - 58F2EAB6292FB2B0004A9BDE /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; + 58F2EAAF292FB2B0004A9BDE /* ThemeSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeSettingsView.swift; sourceTree = ""; }; 58F2EAB8292FB2B0004A9BDE /* AccountPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountPreferencesView.swift; sourceTree = ""; }; 58F2EABA292FB2B0004A9BDE /* SourceControlProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceControlProvider.swift; sourceTree = ""; }; 58F2EABC292FB2B0004A9BDE /* AccountListItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountListItemView.swift; sourceTree = ""; }; @@ -729,7 +741,13 @@ 6CFF967729BEBCF600182D6F /* MainCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainCommands.swift; sourceTree = ""; }; 6CFF967929BEBD2400182D6F /* ViewCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewCommands.swift; sourceTree = ""; }; 6CFF967B29BEBD5200182D6F /* WindowCommands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowCommands.swift; sourceTree = ""; }; + 850C630F29D6B01D00E1444C /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 850C631129D6B03400E1444C /* SettingsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPage.swift; sourceTree = ""; }; + 858316B229DC778A00540A18 /* ThemeSettingsColorPreviewColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsColorPreviewColor.swift; sourceTree = ""; }; + B6041F4C29D7A4E9000F3454 /* SettingPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingPageView.swift; sourceTree = ""; }; + B6041F5129D7D6D6000F3454 /* SettingsWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsWindow.swift; sourceTree = ""; }; B60BE8BC297A167600841125 /* AcknowledgementRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcknowledgementRowView.swift; sourceTree = ""; }; + B61DA9DE29D929E100BF4A43 /* GeneralSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsView.swift; sourceTree = ""; }; B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CodeEdit.app; sourceTree = BUILT_PRODUCTS_DIR; }; B658FB3127DA9E0F00EA4DBD /* WorkspaceView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = WorkspaceView.swift; sourceTree = ""; tabWidth = 4; }; B658FB3327DA9E1000EA4DBD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -749,8 +767,26 @@ B6C6A42F29771F7100A3D28F /* TabBarItemBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarItemBackground.swift; sourceTree = ""; }; B6D7EA582971078500301FAC /* InspectorSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorSection.swift; sourceTree = ""; }; B6D7EA5B297107DD00301FAC /* InspectorField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorField.swift; sourceTree = ""; }; + B6EA1FE429DA33DB001BF195 /* ThemeModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeModel.swift; sourceTree = ""; }; + B6EA1FE629DA341D001BF195 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; + B6EA1FE829DA344F001BF195 /* PreviewThemeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewThemeView.swift; sourceTree = ""; }; + B6EA1FE929DA344F001BF195 /* TerminalThemeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TerminalThemeView.swift; sourceTree = ""; }; + B6EA1FEA29DA344F001BF195 /* ThemePreviewIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemePreviewIcon.swift; sourceTree = ""; }; + B6EA1FEB29DA344F001BF195 /* EditorThemeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditorThemeView.swift; sourceTree = ""; }; + B6EA1FF029DA35A7001BF195 /* ThemePreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemePreferencesView.swift; sourceTree = ""; }; + B6EA1FF429DA380E001BF195 /* TextEditingSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEditingSettingsView.swift; sourceTree = ""; }; + B6EA1FF729DB78DB001BF195 /* ThemeSettingThemeRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingThemeRow.swift; sourceTree = ""; }; + B6EA1FFA29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsThemeDetails.swift; sourceTree = ""; }; + B6EA1FFC29DB792C001BF195 /* ThemeSettingsColorPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsColorPreview.swift; sourceTree = ""; }; + B6EA1FFF29DB7966001BF195 /* SettingsColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsColorPicker.swift; sourceTree = ""; }; + B6EA200129DB7F81001BF195 /* View+ConstrainHeightToWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ConstrainHeightToWindow.swift"; sourceTree = ""; }; B6EE988F27E8879A00CDD8AB /* InspectorSidebarView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = InspectorSidebarView.swift; sourceTree = ""; tabWidth = 4; }; B6EE989127E887C600CDD8AB /* InspectorSidebarToolbarTop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorSidebarToolbarTop.swift; sourceTree = ""; }; + B6F0516F29D9E36800D72287 /* LocationsSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationsSettingsView.swift; sourceTree = ""; }; + B6F0517629D9E3AD00D72287 /* SourceControlGeneralView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceControlGeneralView.swift; sourceTree = ""; }; + B6F0517829D9E3C900D72287 /* SourceControlGitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceControlGitView.swift; sourceTree = ""; }; + B6F0517A29D9E46400D72287 /* SourceControlSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceControlSettingsView.swift; sourceTree = ""; }; + B6F0517C29D9E4B100D72287 /* TerminalSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalSettingsView.swift; sourceTree = ""; }; D7012EE727E757850001E1EF /* FindNavigatorView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = FindNavigatorView.swift; sourceTree = ""; tabWidth = 4; }; D7211D4227E066CE008F2ED7 /* Localized+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Localized+Ex.swift"; sourceTree = ""; }; D7211D4827E06BFE008F2ED7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; @@ -1078,6 +1114,7 @@ 582213EE2918345500EFE361 /* About */, 5878DA7D291862BC00DD95A3 /* Acknowledgements */, 284DC84B2978B5EB00BF2770 /* Contributors */, + B67B270029D7868000FB9301 /* Settings */, 58F2EA9E292FB2B0004A9BDE /* AppPreferences */, 5878DAAB291D627C00DD95A3 /* PathBar */, 587B9D50292FC27A00AC7927 /* CodeEditExtension */, @@ -1884,7 +1921,7 @@ 58F2EAA3292FB2B0004A9BDE /* TerminalPreferences */, 58F2EAA5292FB2B0004A9BDE /* SourceControlPreferences */, 58F2EAAC292FB2B0004A9BDE /* TextEditingPreferences */, - 58F2EAAE292FB2B0004A9BDE /* ThemePreferences */, + B6F0517F29DA29F900D72287 /* ThemePreferences */, 58F2EAB7292FB2B0004A9BDE /* AccountsPreferences */, 58F2EAC6292FB2B0004A9BDE /* KeybindingsPreferences */, 58F2EAC8292FB2B0004A9BDE /* LocationsPreferences */, @@ -1914,8 +1951,8 @@ 58F2EAA9292FB2B0004A9BDE /* Model */, 58F2EAAB292FB2B0004A9BDE /* IgnoredFileView.swift */, 58F2EAA6292FB2B0004A9BDE /* SourceControlPreferencesView.swift */, - 58F2EAA7292FB2B0004A9BDE /* SourceControlGeneralView.swift */, - 58F2EAA8292FB2B0004A9BDE /* SourceControlGitView.swift */, + 58F2EAA7292FB2B0004A9BDE /* SourceControlPreferencesGeneralView.swift */, + 58F2EAA8292FB2B0004A9BDE /* SourceControlPreferencesGitView.swift */, ); path = SourceControlPreferences; sourceTree = ""; @@ -1936,26 +1973,16 @@ path = TextEditingPreferences; sourceTree = ""; }; - 58F2EAAE292FB2B0004A9BDE /* ThemePreferences */ = { + 58F2EAAE292FB2B0004A9BDE /* ThemeSettings */ = { isa = PBXGroup; children = ( - 58F2EAB4292FB2B0004A9BDE /* Model */, - 58F2EAAF292FB2B0004A9BDE /* ThemePreferencesView.swift */, - 58F2EAB0292FB2B0004A9BDE /* PreviewThemeView.swift */, - 58F2EAB1292FB2B0004A9BDE /* TerminalThemeView.swift */, - 58F2EAB2292FB2B0004A9BDE /* EditorThemeView.swift */, - 58F2EAB3292FB2B0004A9BDE /* ThemePreviewIcon.swift */, + 858316B129DC774900540A18 /* Model */, + 58F2EAAF292FB2B0004A9BDE /* ThemeSettingsView.swift */, + B6EA1FF729DB78DB001BF195 /* ThemeSettingThemeRow.swift */, + B6EA1FFA29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift */, + B6EA1FFC29DB792C001BF195 /* ThemeSettingsColorPreview.swift */, ); - path = ThemePreferences; - sourceTree = ""; - }; - 58F2EAB4292FB2B0004A9BDE /* Model */ = { - isa = PBXGroup; - children = ( - 58F2EAB6292FB2B0004A9BDE /* Theme.swift */, - 58F2EAB5292FB2B0004A9BDE /* ThemeModel.swift */, - ); - path = Model; + path = ThemeSettings; sourceTree = ""; }; 58F2EAB7292FB2B0004A9BDE /* AccountsPreferences */ = { @@ -2235,6 +2262,35 @@ path = Text; sourceTree = ""; }; + 858316B129DC774900540A18 /* Model */ = { + isa = PBXGroup; + children = ( + 858316B229DC778A00540A18 /* ThemeSettingsColorPreviewColor.swift */, + ); + path = Model; + sourceTree = ""; + }; + B61DA9DD29D929BF00BF4A43 /* Pages */ = { + isa = PBXGroup; + children = ( + B6EA1FF329DA37D3001BF195 /* TextEditingSettings */, + B6F0516E29D9E35300D72287 /* LocationsSettings */, + B6F0516D29D9E34200D72287 /* SourceControlSettings */, + B6F0516C29D9E32700D72287 /* TerminalSettings */, + 58F2EAAE292FB2B0004A9BDE /* ThemeSettings */, + B61DA9E129D929F900BF4A43 /* GeneralSettings */, + ); + path = Pages; + sourceTree = ""; + }; + B61DA9E129D929F900BF4A43 /* GeneralSettings */ = { + isa = PBXGroup; + children = ( + B61DA9DE29D929E100BF4A43 /* GeneralSettingsView.swift */, + ); + path = GeneralSettings; + sourceTree = ""; + }; B658FB2327DA9E0F00EA4DBD = { isa = PBXGroup; children = ( @@ -2293,6 +2349,36 @@ path = "Preview Content"; sourceTree = ""; }; + B67B270029D7868000FB9301 /* Settings */ = { + isa = PBXGroup; + children = ( + B6EA1FFE29DB7955001BF195 /* HelperViews */, + B61DA9DD29D929BF00BF4A43 /* Pages */, + 850C630F29D6B01D00E1444C /* SettingsView.swift */, + B6041F4C29D7A4E9000F3454 /* SettingPageView.swift */, + 850C631129D6B03400E1444C /* SettingsPage.swift */, + B6041F5129D7D6D6000F3454 /* SettingsWindow.swift */, + B6EA200129DB7F81001BF195 /* View+ConstrainHeightToWindow.swift */, + ); + path = Settings; + sourceTree = ""; + }; + B6EA1FF329DA37D3001BF195 /* TextEditingSettings */ = { + isa = PBXGroup; + children = ( + B6EA1FF429DA380E001BF195 /* TextEditingSettingsView.swift */, + ); + path = TextEditingSettings; + sourceTree = ""; + }; + B6EA1FFE29DB7955001BF195 /* HelperViews */ = { + isa = PBXGroup; + children = ( + B6EA1FFF29DB7966001BF195 /* SettingsColorPicker.swift */, + ); + path = HelperViews; + sourceTree = ""; + }; B6EE988E27E8877C00CDD8AB /* InspectorSidebar */ = { isa = PBXGroup; children = ( @@ -2306,6 +2392,54 @@ path = InspectorSidebar; sourceTree = ""; }; + B6F0516C29D9E32700D72287 /* TerminalSettings */ = { + isa = PBXGroup; + children = ( + B6F0517C29D9E4B100D72287 /* TerminalSettingsView.swift */, + ); + path = TerminalSettings; + sourceTree = ""; + }; + B6F0516D29D9E34200D72287 /* SourceControlSettings */ = { + isa = PBXGroup; + children = ( + B6F0517A29D9E46400D72287 /* SourceControlSettingsView.swift */, + B6F0517629D9E3AD00D72287 /* SourceControlGeneralView.swift */, + B6F0517829D9E3C900D72287 /* SourceControlGitView.swift */, + ); + path = SourceControlSettings; + sourceTree = ""; + }; + B6F0516E29D9E35300D72287 /* LocationsSettings */ = { + isa = PBXGroup; + children = ( + B6F0516F29D9E36800D72287 /* LocationsSettingsView.swift */, + ); + path = LocationsSettings; + sourceTree = ""; + }; + B6F0517F29DA29F900D72287 /* ThemePreferences */ = { + isa = PBXGroup; + children = ( + B6F0518D29DA29F900D72287 /* Model */, + B6EA1FEB29DA344F001BF195 /* EditorThemeView.swift */, + B6EA1FE829DA344F001BF195 /* PreviewThemeView.swift */, + B6EA1FE929DA344F001BF195 /* TerminalThemeView.swift */, + B6EA1FEA29DA344F001BF195 /* ThemePreviewIcon.swift */, + B6EA1FF029DA35A7001BF195 /* ThemePreferencesView.swift */, + ); + path = ThemePreferences; + sourceTree = ""; + }; + B6F0518D29DA29F900D72287 /* Model */ = { + isa = PBXGroup; + children = ( + B6EA1FE629DA341D001BF195 /* Theme.swift */, + B6EA1FE429DA33DB001BF195 /* ThemeModel.swift */, + ); + path = Model; + sourceTree = ""; + }; D7012EE627E757660001E1EF /* FindNavigator */ = { isa = PBXGroup; children = ( @@ -2599,6 +2733,7 @@ 58822534292C280D00E83CDE /* CursorLocation.swift in Sources */, 201169E52837B40300F92B46 /* SourceControlNavigatorRepositoriesView.swift in Sources */, 587B9E6A29301D8F00AC7927 /* GitLabPermissions.swift in Sources */, + B6EA1FF529DA380E001BF195 /* TextEditingSettingsView.swift in Sources */, D7DC4B76298FFBE900D6C83D /* OutlintViewController+OutlineTableViewCellDelegate.swift in Sources */, 587B9E9229301D8F00AC7927 /* BitBucketAccount.swift in Sources */, 58F2EAFE292FB2B0004A9BDE /* GitHubEnterpriseLoginView.swift in Sources */, @@ -2627,11 +2762,13 @@ 587B9E6F29301D8F00AC7927 /* GitLabProjectAccess.swift in Sources */, 587B9E6929301D8F00AC7927 /* GitLabEvent.swift in Sources */, 587B9E5E29301D8F00AC7927 /* GitLabCommitRouter.swift in Sources */, - 58F2EAF4292FB2B0004A9BDE /* ThemeModel.swift in Sources */, 58F2EB0D292FB2B0004A9BDE /* ThemePreferences.swift in Sources */, 587B9D9F29300ABD00AC7927 /* SegmentedControl.swift in Sources */, 6C7256D729A3D7D000C2D3E0 /* SplitViewControllerView.swift in Sources */, + B6EA1FE529DA33DB001BF195 /* ThemeModel.swift in Sources */, + B6EA200029DB7966001BF195 /* SettingsColorPicker.swift in Sources */, 58FD7609291EA1CB0051D6E4 /* CommandPaletteView.swift in Sources */, + B6EA1FED29DA344F001BF195 /* TerminalThemeView.swift in Sources */, 58F2EAFC292FB2B0004A9BDE /* GitAccountItemView.swift in Sources */, 587B9E8F29301D8F00AC7927 /* BitBucketUserRouter.swift in Sources */, B66A4E5129C917D5004573B4 /* AboutWindow.swift in Sources */, @@ -2670,7 +2807,6 @@ 587B9E9429301D8F00AC7927 /* BitBucketTokenConfiguration.swift in Sources */, 581BFB672926431000D251EC /* WelcomeWindowView.swift in Sources */, 58A5DFA329339F6400D1BD5D /* CommandManager.swift in Sources */, - 58F2EAF5292FB2B0004A9BDE /* Theme.swift in Sources */, 2072FA1C280D874000C7F8D4 /* IndentUsing.swift in Sources */, 58798284292ED0FB0085B254 /* TerminalEmulatorView.swift in Sources */, 6C82D6B329BFD88700495C54 /* NavigateCommands.swift in Sources */, @@ -2681,6 +2817,7 @@ 201169E72837B5CA00F92B46 /* SourceControlModel.swift in Sources */, 58822528292C280D00E83CDE /* StatusBarEncodingSelector.swift in Sources */, B6C6A43029771F7100A3D28F /* TabBarItemBackground.swift in Sources */, + B6F0517D29D9E4B100D72287 /* TerminalSettingsView.swift in Sources */, 58F2EB0F292FB2B0004A9BDE /* PreferencesSection.swift in Sources */, 587B9E8C29301D8F00AC7927 /* GitHubOpenness.swift in Sources */, 587B9E8229301D8F00AC7927 /* GitHubPreviewHeader.swift in Sources */, @@ -2689,13 +2826,16 @@ 58F2EB06292FB2B0004A9BDE /* KeybindingsPreferences.swift in Sources */, 200412EF280F3EAC00BCAF5C /* HistoryInspectorNoHistoryView.swift in Sources */, 587B9E8E29301D8F00AC7927 /* BitBucketRepositoryRouter.swift in Sources */, + B61DA9DF29D929E100BF4A43 /* GeneralSettingsView.swift in Sources */, B6D7EA5C297107DD00301FAC /* InspectorField.swift in Sources */, 043C321427E31FF6006AE443 /* CodeEditDocumentController.swift in Sources */, 587B9E6629301D8F00AC7927 /* GitLabProjectHook.swift in Sources */, 587B9E9329301D8F00AC7927 /* BitBucketOAuthConfiguration.swift in Sources */, 6C18620A298BF5A800C663EA /* RecentProjectsListView.swift in Sources */, 58F2EB0A292FB2B0004A9BDE /* AppPreferences.swift in Sources */, + B6EA1FEC29DA344F001BF195 /* PreviewThemeView.swift in Sources */, 20EBB503280C327C00F3A5DA /* HistoryInspectorView.swift in Sources */, + B6EA1FE729DA341D001BF195 /* Theme.swift in Sources */, 587B9E7529301D8F00AC7927 /* String+QueryParameters.swift in Sources */, 58798219292D92370085B254 /* SearchModeModel.swift in Sources */, B66A4E4F29C917B8004573B4 /* WelcomeWindow.swift in Sources */, @@ -2711,11 +2851,13 @@ 587B9E8729301D8F00AC7927 /* GitHubRepositories.swift in Sources */, 587B9DA329300ABD00AC7927 /* SettingsTextEditor.swift in Sources */, 2072FA1A280D872600C7F8D4 /* LineEndings.swift in Sources */, + B6F0517B29D9E46400D72287 /* SourceControlSettingsView.swift in Sources */, 6C147C4D29A32AA30089B630 /* WorkspaceTabGroupView.swift in Sources */, 58F2EAFB292FB2B0004A9BDE /* GitLabLoginView.swift in Sources */, 587B9E7B29301D8F00AC7927 /* GitHubRouter.swift in Sources */, 201169E22837B3D800F92B46 /* SourceControlNavigatorChangesView.swift in Sources */, 20EBB507280C32D300F3A5DA /* QuickHelpInspectorView.swift in Sources */, + 850C631029D6B01D00E1444C /* SettingsView.swift in Sources */, DE6405A62817734700881FDF /* TabBarNative.swift in Sources */, 587B9E5C29301D8F00AC7927 /* Parameters.swift in Sources */, 58798235292E30B90085B254 /* FeedbackModel.swift in Sources */, @@ -2735,6 +2877,7 @@ 587D9B782933BF5700BF7490 /* Interface.swift in Sources */, 6CFF967A29BEBD2400182D6F /* ViewCommands.swift in Sources */, 2072FA1E280D891500C7F8D4 /* FileLocation.swift in Sources */, + 850C631229D6B03400E1444C /* SettingsPage.swift in Sources */, 587B9E6729301D8F00AC7927 /* GitLabEventData.swift in Sources */, B66A4E4529C8E86D004573B4 /* CommandsFixes.swift in Sources */, 5882252F292C280D00E83CDE /* StatusBarClearButton.swift in Sources */, @@ -2754,6 +2897,7 @@ D7E201B227E8D50000CB86D0 /* FindNavigatorModeSelector.swift in Sources */, 287776E927E34BC700D46668 /* TabBarView.swift in Sources */, B60BE8BD297A167600841125 /* AcknowledgementRowView.swift in Sources */, + B6F0517029D9E36800D72287 /* LocationsSettingsView.swift in Sources */, 587B9E6329301D8F00AC7927 /* GitLabAccount.swift in Sources */, 285FEC7027FE4B9800E57D53 /* OutlineTableViewCell.swift in Sources */, 6CB9144B29BEC7F100BC47F2 /* (null) in Sources */, @@ -2763,11 +2907,13 @@ 6C5AB9D729C1496E003B5F96 /* SceneID.swift in Sources */, 587B9DA429300ABD00AC7927 /* OverlayPanel.swift in Sources */, 58F2EAEE292FB2B0004A9BDE /* TextEditingPreferencesView.swift in Sources */, + B6EA1FF129DA35A7001BF195 /* ThemePreferencesView.swift in Sources */, 58D01C95293167DC00C5B6B4 /* Bundle+Info.swift in Sources */, 587D9B762933BF5700BF7490 /* Mocks.swift in Sources */, B6C6A42A297716A500A3D28F /* TabBarItemCloseButton.swift in Sources */, 58A5DF7D2931787A00D1BD5D /* ShellClient.swift in Sources */, 5879821A292D92370085B254 /* SearchResultModel.swift in Sources */, + B6F0517729D9E3AD00D72287 /* SourceControlGeneralView.swift in Sources */, 587B9E8929301D8F00AC7927 /* GitHubGist.swift in Sources */, 0485EB1F27E7458B00138301 /* WorkspaceCodeFileView.swift in Sources */, 58D01C94293167DC00C5B6B4 /* Color+HEX.swift in Sources */, @@ -2787,8 +2933,8 @@ 58F2EAF6292FB2B0004A9BDE /* AccountPreferencesView.swift in Sources */, 20EBB501280C325D00F3A5DA /* FileInspectorView.swift in Sources */, 58822531292C280D00E83CDE /* View+isHovering.swift in Sources */, + B6EA1FEE29DA344F001BF195 /* ThemePreviewIcon.swift in Sources */, 587B9E9929301D8F00AC7927 /* GitChangedFile.swift in Sources */, - 58F2EAF2292FB2B0004A9BDE /* EditorThemeView.swift in Sources */, 6C147C4B29A32A7B0089B630 /* Environment+SplitEditor.swift in Sources */, 2897E1C72979A29200741E32 /* OffsettableScrollView.swift in Sources */, 58F2EB0E292FB2B0004A9BDE /* SoftwareUpdater.swift in Sources */, @@ -2801,13 +2947,14 @@ 587B9DA629300ABD00AC7927 /* ToolbarBranchPicker.swift in Sources */, 58F2EB05292FB2B0004A9BDE /* AppPreferencesModel.swift in Sources */, 6CBD1BC62978DE53006639D5 /* Font+Caption3.swift in Sources */, - 58F2EAF1292FB2B0004A9BDE /* TerminalThemeView.swift in Sources */, 287776EF27E3515300D46668 /* TabBarItemView.swift in Sources */, 2806E9022979588B000040F4 /* Contributor.swift in Sources */, 58D01C98293167DC00C5B6B4 /* String+RemoveOccurrences.swift in Sources */, 5878DAA8291AE76700DD95A3 /* QuickOpenItem.swift in Sources */, 58FD7608291EA1CB0051D6E4 /* CommandPaletteViewModel.swift in Sources */, 5878DA872918642F00DD95A3 /* AcknowledgementsViewModel.swift in Sources */, + B6EA1FFB29DB78F6001BF195 /* ThemeSettingsThemeDetails.swift in Sources */, + B6EA1FEF29DA344F001BF195 /* EditorThemeView.swift in Sources */, 587B9E7029301D8F00AC7927 /* GitLabUser.swift in Sources */, 04660F6A27E51E5C00477777 /* CodeEditWindowController.swift in Sources */, 58798218292D92370085B254 /* String+SafeOffset.swift in Sources */, @@ -2819,13 +2966,17 @@ 58F2EB09292FB2B0004A9BDE /* TerminalPreferences.swift in Sources */, 587D9B742933BF5700BF7490 /* FileItem+Array.swift in Sources */, 587D9B772933BF5700BF7490 /* Live.swift in Sources */, + B6EA200229DB7F81001BF195 /* View+ConstrainHeightToWindow.swift in Sources */, 6C48D8F42972DB1A00D6D205 /* Env+Window.swift in Sources */, 2072FA18280D871200C7F8D4 /* TextEncoding.swift in Sources */, - 58F2EAF3292FB2B0004A9BDE /* ThemePreviewIcon.swift in Sources */, 58F2EB07292FB2B0004A9BDE /* GeneralPreferences.swift in Sources */, + B6041F4D29D7A4E9000F3454 /* SettingPageView.swift in Sources */, 587B9E9A29301D8F00AC7927 /* GitType.swift in Sources */, 58D01C97293167DC00C5B6B4 /* String+SHA256.swift in Sources */, + B6EA1FFD29DB792C001BF195 /* ThemeSettingsColorPreview.swift in Sources */, 2806E904297958B9000040F4 /* ContributorRowView.swift in Sources */, + B6041F5229D7D6D6000F3454 /* SettingsWindow.swift in Sources */, + B6EA1FF829DB78DB001BF195 /* ThemeSettingThemeRow.swift in Sources */, 587B9E7629301D8F00AC7927 /* GitTime.swift in Sources */, 2072FA16280D83A500C7F8D4 /* FileTypeList.swift in Sources */, 587B9E5D29301D8F00AC7927 /* GitLabUserRouter.swift in Sources */, @@ -2834,7 +2985,7 @@ 6C147C4929A32A080089B630 /* EditorView.swift in Sources */, 6C147C4129A328BF0089B630 /* TabGroup.swift in Sources */, B6D7EA592971078500301FAC /* InspectorSection.swift in Sources */, - 58F2EAEF292FB2B0004A9BDE /* ThemePreferencesView.swift in Sources */, + 58F2EAEF292FB2B0004A9BDE /* ThemeSettingsView.swift in Sources */, B6EE989027E8879A00CDD8AB /* InspectorSidebarView.swift in Sources */, 587B9DA229300ABD00AC7927 /* EffectView.swift in Sources */, 6C97EBCC2978760400302F95 /* AcknowledgementsWindowController.swift in Sources */, @@ -2842,6 +2993,7 @@ 58798250292E78D80085B254 /* CodeFile.swift in Sources */, 5878DAA5291AE76700DD95A3 /* QuickOpenView.swift in Sources */, 201169D72837B2E300F92B46 /* SourceControlNavigatorView.swift in Sources */, + B6F0517929D9E3C900D72287 /* SourceControlGitView.swift in Sources */, 587B9E8329301D8F00AC7927 /* GitHubPullRequest.swift in Sources */, 5878DA82291863F900DD95A3 /* AcknowledgementsView.swift in Sources */, 587B9E8529301D8F00AC7927 /* GitHubReview.swift in Sources */, @@ -2850,11 +3002,11 @@ 587B9E5A29301D8F00AC7927 /* GitCloneView.swift in Sources */, 58D01C99293167DC00C5B6B4 /* String+MD5.swift in Sources */, 20EBB505280C329800F3A5DA /* HistoryInspectorItemView.swift in Sources */, - 58F2EAEA292FB2B0004A9BDE /* SourceControlGeneralView.swift in Sources */, + 58F2EAEA292FB2B0004A9BDE /* SourceControlPreferencesGeneralView.swift in Sources */, 5878DAB2291D627C00DD95A3 /* PathBarView.swift in Sources */, 043C321627E3201F006AE443 /* WorkspaceDocument.swift in Sources */, 58F2EAEC292FB2B0004A9BDE /* IgnoredFiles.swift in Sources */, - 58F2EAEB292FB2B0004A9BDE /* SourceControlGitView.swift in Sources */, + 58F2EAEB292FB2B0004A9BDE /* SourceControlPreferencesGitView.swift in Sources */, 58798236292E30B90085B254 /* FeedbackType.swift in Sources */, 587B9E6D29301D8F00AC7927 /* GitLabEventNote.swift in Sources */, 587B9E9129301D8F00AC7927 /* BitBucketOAuthRouter.swift in Sources */, @@ -2865,6 +3017,7 @@ 5878DAA6291AE76700DD95A3 /* QuickOpenPreviewView.swift in Sources */, 58798286292ED0FB0085B254 /* SwiftTerm+Color+Init.swift in Sources */, 6CFF967C29BEBD5200182D6F /* WindowCommands.swift in Sources */, + 858316B329DC778A00540A18 /* ThemeSettingsColorPreviewColor.swift in Sources */, 587B9E7229301D8F00AC7927 /* GitJSONPostRouter.swift in Sources */, 5878DAB0291D627C00DD95A3 /* PathBarMenu.swift in Sources */, 587B9DA529300ABD00AC7927 /* PressActionsModifier.swift in Sources */, @@ -2878,7 +3031,6 @@ 58F2EB11292FB2B0004A9BDE /* PreferencesToolbar.swift in Sources */, 6C147C4229A328C10089B630 /* TabGroupData.swift in Sources */, 6C2C155829B4F49100EA60A5 /* SplitViewItem.swift in Sources */, - 58F2EAF0292FB2B0004A9BDE /* PreviewThemeView.swift in Sources */, 58F2EAFF292FB2B0004A9BDE /* KeybindingsPreferencesView.swift in Sources */, 6CDA84AD284C1BA000C1CC3A /* TabBarContextMenu.swift in Sources */, 6C81916729B3E80700B75C92 /* ModifierKeysObserver.swift in Sources */, diff --git a/CodeEdit/Features/AppPreferences/Model/Terminal/TerminalPreferences.swift b/CodeEdit/Features/AppPreferences/Model/Terminal/TerminalPreferences.swift index d8842c47c1..c0f48f1626 100644 --- a/CodeEdit/Features/AppPreferences/Model/Terminal/TerminalPreferences.swift +++ b/CodeEdit/Features/AppPreferences/Model/Terminal/TerminalPreferences.swift @@ -12,6 +12,9 @@ extension AppPreferences { /// The global settings for the terminal emulator struct TerminalPreferences: Codable { + /// If true terminal will use editor theme. + var useEditorTheme: Bool = true + /// If true terminal appearance will always be `dark`. Otherwise it adapts to the system setting. var darkAppearance: Bool = false diff --git a/CodeEdit/Features/AppPreferences/Sections/AccountsPreferences/AccountPreferencesView.swift b/CodeEdit/Features/AppPreferences/Sections/AccountsPreferences/AccountPreferencesView.swift index f70e0996b0..0124a7a59f 100644 --- a/CodeEdit/Features/AppPreferences/Sections/AccountsPreferences/AccountPreferencesView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/AccountsPreferences/AccountPreferencesView.swift @@ -7,7 +7,6 @@ import SwiftUI -// swiftlint:disable for_where struct AccountPreferencesView: View { @StateObject private var prefs: AppPreferencesModel = .shared @@ -40,7 +39,10 @@ struct AccountPreferencesView: View { .padding() } } +} +// swiftlint:disable for_where +private extension AccountPreferencesView { private var accountSelectionView: some View { VStack(alignment: .leading, spacing: 1) { PreferencesToolbar { @@ -174,5 +176,4 @@ struct AccountPreferencesView: View { } } } - } diff --git a/CodeEdit/Features/AppPreferences/Sections/GeneralPreferences/GeneralPreferencesView.swift b/CodeEdit/Features/AppPreferences/Sections/GeneralPreferences/GeneralPreferencesView.swift index 9221beae2b..f32b8ddf44 100644 --- a/CodeEdit/Features/AppPreferences/Sections/GeneralPreferences/GeneralPreferencesView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/GeneralPreferences/GeneralPreferencesView.swift @@ -62,7 +62,10 @@ struct GeneralPreferencesView: View { } } +/// The extension of the view with all the preferences private extension GeneralPreferencesView { + // MARK: - Sections + var appearanceSection: some View { PreferencesSection("Appearance") { Picker("Appearance", selection: $prefs.preferences.general.appAppearance) { @@ -294,6 +297,18 @@ private extension GeneralPreferencesView { } } + var autoSaveSection: some View { + PreferencesSection("Auto Save Behavior", hideLabels: false) { + Toggle( + "Automatically save changes to disk", + isOn: $prefs.preferences.general.isAutoSaveOn + ) + .toggleStyle(.checkbox) + } + } + + // MARK: - Preference Views + private var lastUpdatedString: String { if let lastUpdatedDate = updater.lastUpdateCheckDate { return Self.formatter.string(from: lastUpdatedDate) @@ -308,21 +323,6 @@ private extension GeneralPreferencesView { return copy } - private static let formatter = configure(DateFormatter()) { - $0.dateStyle = .medium - $0.timeStyle = .medium - } - - var autoSaveSection: some View { - PreferencesSection("Auto Save Behavior", hideLabels: false) { - Toggle( - "Automatically save changes to disk", - isOn: $prefs.preferences.general.isAutoSaveOn - ) - .toggleStyle(.checkbox) - } - } - func fallbackShellInstallation(commandPath: String, destinationPath: String) { let cmd = [ "osascript", @@ -372,4 +372,11 @@ private extension GeneralPreferencesView { .toggleStyle(.checkbox) } } + + // MARK: - Formatters + + private static let formatter = configure(DateFormatter()) { + $0.dateStyle = .medium + $0.timeStyle = .medium + } } diff --git a/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGeneralView.swift b/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGeneralView.swift new file mode 100644 index 0000000000..75f42c9c43 --- /dev/null +++ b/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGeneralView.swift @@ -0,0 +1,189 @@ +// +// SourceControlGeneralView.swift +// CodeEditModules/AppPreferences +// +// Created by Nanshi Li on 2022/04/01. +// + +import SwiftUI + +struct SourceControlPreferencesGeneralView: View { + + // MARK: - View + + var body: some View { + VStack { + sourceControlSection + textEditingSection + reportingSection + comparisonViewSection + sourceControlNavigator + defaultBranchNameSection + } + .frame(height: 350) + .background(EffectView(.contentBackground)) + } + + private let inputWidth: Double = 200 + + @StateObject + private var prefs: AppPreferencesModel = .shared + + @State + var isChecked: Bool + + @State + var branchName: String +} + +private extension SourceControlPreferencesGeneralView { + + // MARK: - Sections + + private var sourceControlSection: some View { + PreferencesSection("Source Control", hideLabels: false) { + enableSourceControl + + VStack(alignment: .leading) { + refreshLocalStatusAuto + fetchRefreshStatusAuto + addRemoveFilesAuto + selectFilesToCommitAuto + } + .padding(.leading, 20) + } + } + + private var textEditingSection: some View { + PreferencesSection("Text Editing", hideLabels: false) { + showSourceControlChanges + includeUpstreamChanges + } + } + + private var reportingSection: some View { + PreferencesSection("Reporting", hideLabels: false) { + openCreatedIssueInBrowser + } + } + + private var comparisonViewSection: some View { + PreferencesSection("Comparison View", hideLabels: true) { + comparisonView + } + } + + private var sourceControlNavigatorSection: some View { + PreferencesSection("Source Control Navigator", hideLabels: true) { + sourceControlNavigator + } + } + + private var defaultBranchNameSection: some View { + PreferencesSection("Default Branch Name", hideLabels: false) { + defaultBranchName + } + } + + // MARK: - Preference Views + + private var enableSourceControl: some View { + Toggle( + "Enable Source Control", + isOn: $prefs.preferences.sourceControl.general.enableSourceControl + ) + .toggleStyle(.checkbox) + } + + private var refreshLocalStatusAuto: some View { + Toggle( + "Refresh local status automatically", + isOn: $prefs.preferences.sourceControl.general.refreshStatusLocally + ) + .toggleStyle(.checkbox) + } + + private var fetchRefreshStatusAuto: some View { + Toggle( + "Fetch and refresh server status automatically", + isOn: $prefs.preferences.sourceControl.general.fetchRefreshServerStatus + ) + .toggleStyle(.checkbox) + } + + private var addRemoveFilesAuto: some View { + Toggle( + "Add and remove files automatically", + isOn: $prefs.preferences.sourceControl.general.addRemoveAutomatically + ) + .toggleStyle(.checkbox) + } + + private var selectFilesToCommitAuto: some View { + Toggle( + "Select files to commit automatically", + isOn: $prefs.preferences.sourceControl.general.selectFilesToCommit + ) + .toggleStyle(.checkbox) + } + + private var showSourceControlChanges: some View { + Toggle( + "Show Source Control changes", + isOn: $prefs.preferences.sourceControl.general.showSourceControlChanges + ) + .toggleStyle(.checkbox) + } + + private var includeUpstreamChanges: some View { + Toggle( + "Include upstream changes", + isOn: $prefs.preferences.sourceControl.general.includeUpstreamChanges + ) + .toggleStyle(.checkbox) + .padding(.leading, 20) + } + + private var openCreatedIssueInBrowser: some View { + Toggle( + "Open created issue in the browser", + isOn: $prefs.preferences.sourceControl.general.openFeedbackInBrowser + ) + .toggleStyle(.checkbox) + } + + private var comparisonView: some View { + Picker( + "Comparison View", + selection: $prefs.preferences.sourceControl.general.revisionComparisonLayout + ) { + Text("Local Revision on Left Side") + .tag(AppPreferences.RevisionComparisonLayout.localLeft) + Text("Local Revision on Right Side") + .tag(AppPreferences.RevisionComparisonLayout.localRight) + } + .frame(width: inputWidth) + } + + private var sourceControlNavigator: some View { + Picker( + "Source Control Navigator", + selection: $prefs.preferences.sourceControl.general.controlNavigatorOrder + ) { + Text("Sort by Name") + .tag(AppPreferences.ControlNavigatorOrder.sortByName) + Text("Sort by Date") + .tag(AppPreferences.ControlNavigatorOrder.sortByDate) + } + .frame(width: inputWidth) + } + + @ViewBuilder + private var defaultBranchName: some View { + TextField("main", text: $branchName) + .frame(width: inputWidth) + Text("Branch names cannot contain spaces, backslashes, or other symbols") + .font(.system(size: 12)) + .foregroundColor(.secondary) + } +} diff --git a/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGitView.swift b/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGitView.swift new file mode 100644 index 0000000000..8373cfb96a --- /dev/null +++ b/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesGitView.swift @@ -0,0 +1,126 @@ +// +// SourceControlGitView.swift +// CodeEditModules/AppPreferences +// +// Created by Nanshi Li on 2022/04/01. +// + +import SwiftUI + +struct SourceControlPreferencesGitView: View { + private let inputWidth: Double = 280 + + @StateObject + private var prefs: AppPreferencesModel = .shared + + @State + var ignoredFileSelection: IgnoredFiles.ID? + + var body: some View { + VStack { + authorNameSection + authorEmailSection + ignoredFilesSection + optionsSection + } + .frame(height: 350) + .background(EffectView(.contentBackground)) + } +} + +private extension SourceControlPreferencesGitView { + private var authorNameSection: some View { + PreferencesSection("Author Name", hideLabels: false) { + gitAuthorName + } + } + + private var authorEmailSection: some View { + PreferencesSection("Author Email", hideLabels: false) { + gitEmail + } + } + + private var ignoredFilesSection: some View { + PreferencesSection("Ignored Files", hideLabels: false, align: .top) { + VStack(spacing: 1) { + ignoredFiles + } + .frame(width: inputWidth) + .padding(1) + .background(Rectangle().foregroundColor(Color(NSColor.separatorColor))) + } + } + + private var optionsSection: some View { + PreferencesSection("Options", hideLabels: false) { + preferToRebaseWhenPulling + showMergeCommitsInPerFileLog + } + } + + private var gitAuthorName: some View { + TextField("Git Author Name", text: $prefs.preferences.sourceControl.git.authorName) + .frame(width: inputWidth) + } + + private var gitEmail: some View { + TextField("Git Email", text: $prefs.preferences.sourceControl.git.authorEmail) + .frame(width: inputWidth) + } + + @ViewBuilder + private var ignoredFiles: some View { + List( + $prefs.preferences.sourceControl.git.ignoredFiles, + selection: $ignoredFileSelection + ) { ignoredFile in + IgnoredFileView(ignoredFile: ignoredFile) + } + .overlay(Group { + if prefs.preferences.sourceControl.git.ignoredFiles.isEmpty { + Text("No Ignored Files") + .foregroundColor(.secondary) + .font(.system(size: 11)) + } + }) + .frame(height: 150) + PreferencesToolbar(height: 22) { + bottomToolbar + } + } + + private var preferToRebaseWhenPulling: some View { + Toggle( + "Prefer to rebase when pulling", + isOn: $prefs.preferences.sourceControl.git.preferRebaseWhenPulling + ) + .toggleStyle(.checkbox) + .frame(width: inputWidth, alignment: .leading) + } + + private var showMergeCommitsInPerFileLog: some View { + Toggle( + "Show merge commits in per-file log", + isOn: $prefs.preferences.sourceControl.git.showMergeCommitsPerFileLog + ) + .toggleStyle(.checkbox) + .frame(width: inputWidth, alignment: .leading) + } + + private var bottomToolbar: some View { + HStack(spacing: 12) { + Button {} label: { + Image(systemName: "plus") + .foregroundColor(Color.secondary) + } + .buttonStyle(.plain) + Button {} label: { + Image(systemName: "minus") + } + .disabled(true) + .buttonStyle(.plain) + Spacer() + } + } +} diff --git a/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesView.swift b/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesView.swift index 44e97ea59e..19af24a265 100644 --- a/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/SourceControlPreferences/SourceControlPreferencesView.swift @@ -18,10 +18,10 @@ struct SourceControlPreferencesView: View { SegmentedControl($selectedSection, options: ["General", "Git"]) } if selectedSection == 0 { - SourceControlGeneralView(isChecked: true, branchName: "main") + SourceControlPreferencesGeneralView(isChecked: true, branchName: "main") } if selectedSection == 1 { - SourceControlGitView() + SourceControlPreferencesGitView() } } .padding(1) diff --git a/CodeEdit/Features/AppPreferences/Sections/TerminalPreferences/TerminalPreferencesView.swift b/CodeEdit/Features/AppPreferences/Sections/TerminalPreferences/TerminalPreferencesView.swift index 2c81484c8f..d944ba3c8a 100644 --- a/CodeEdit/Features/AppPreferences/Sections/TerminalPreferences/TerminalPreferencesView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/TerminalPreferences/TerminalPreferencesView.swift @@ -19,20 +19,35 @@ struct TerminalPreferencesView: View { var body: some View { PreferencesContent { - PreferencesSection("Shell") { - shellSelector - optionAsMetaToggle - } - PreferencesSection("Font") { - fontSelector - } - PreferencesSection("Cursor") { - cursorStyle - cursorBlink - } + shellSection + fontSection + cursorSection + } + } +} + +private extension TerminalPreferencesView { + private var shellSection: some View { + PreferencesSection("Shell") { + shellSelector + optionAsMetaToggle + } + } + + private var fontSection: some View { + PreferencesSection("Font") { + fontSelector + } + } + + private var cursorSection: some View { + PreferencesSection("Cursor") { + cursorStyle + cursorBlink } } + @ViewBuilder private var shellSelector: some View { Picker("Shell:", selection: $prefs.preferences.terminal.shell) { Text("System Default") @@ -45,6 +60,7 @@ struct TerminalPreferencesView: View { } .frame(width: inputWidth) } + private var cursorStyle: some View { Picker("Terminal Cursor Style: ", selection: $prefs.preferences.terminal.cursorStyle) { Text("Block") diff --git a/CodeEdit/Features/AppPreferences/Sections/TextEditingPreferences/TextEditingPreferencesView.swift b/CodeEdit/Features/AppPreferences/Sections/TextEditingPreferences/TextEditingPreferencesView.swift index 2034f6ee42..fc95bce6ec 100644 --- a/CodeEdit/Features/AppPreferences/Sections/TextEditingPreferences/TextEditingPreferencesView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/TextEditingPreferences/TextEditingPreferencesView.swift @@ -12,86 +12,68 @@ struct TextEditingPreferencesView: View { @StateObject private var prefs: AppPreferencesModel = .shared - /// only allows integer values in the range of `[1...8]` - private var tabWidthFormatter: NumberFormatter { - let formatter = NumberFormatter() - formatter.allowsFloats = false - formatter.minimum = 1 - formatter.maximum = 8 - - return formatter + var body: some View { + PreferencesContent { + tabWidthSection + fontSection + lineHeightSection + codeCompletionSection + lineWrappingSection + } } +} - /// only allows float values in the range of `[0.75...2.00]` - /// and formats to 2 decimal places. - private var lineHeightFormatter: NumberFormatter { - let formatter = NumberFormatter() - formatter.allowsFloats = true - formatter.maximumFractionDigits = 2 - formatter.minimumFractionDigits = 2 - formatter.minimum = 0.75 - formatter.maximum = 2.0 +private extension TextEditingPreferencesView { + private var tabWidthSection: some View { + PreferencesSection("Default Tab Width") { + defaultTabWidth + } + } - return formatter + private var fontSection: some View { + PreferencesSection("Font") { + fontSelector + fontSizeSelector + } } - private var fontSizeFormatter: NumberFormatter { - let formatter = NumberFormatter() - formatter.allowsFloats = false - formatter.minimum = 1 - formatter.maximum = 288 + private var lineHeightSection: some View { + PreferencesSection("Line Height") { + lineHeight + } + } - return formatter + private var codeCompletionSection: some View { + PreferencesSection("Code completion") { + autocompleteBraces + enableTypeOverCompletion + } } - var body: some View { - PreferencesContent { - PreferencesSection("Default Tab Width") { - HStack(spacing: 5) { - TextField("", value: $prefs.preferences.textEditing.defaultTabWidth, formatter: tabWidthFormatter) - .multilineTextAlignment(.trailing) - .frame(width: 40) - Stepper( - "Default Tab Width:", - value: $prefs.preferences.textEditing.defaultTabWidth, - in: 1...8 - ) - Text("spaces") - } - } - PreferencesSection("Font") { - fontSelector - } - PreferencesSection("Font Size") { - fontSizeSelector - } - PreferencesSection("Line Height") { - lineHeight - } - PreferencesSection("Code completion") { - autocompleteBraces - enableTypeOverCompletion - } - PreferencesSection("Line Wrapping") { - wrapLinesToEditorWidth - } + private var lineWrappingSection: some View { + PreferencesSection("Line Wrapping") { + wrapLinesToEditorWidth } } + // MARK: - Preference Views + @ViewBuilder private var fontSelector: some View { - Picker("Font:", selection: $prefs.preferences.textEditing.font.customFont) { - Text("System Font") - .tag(false) - Text("Custom") - .tag(true) - } - .fixedSize() - if prefs.preferences.textEditing.font.customFont { - FontPicker( - "\(prefs.preferences.textEditing.font.name) \(prefs.preferences.textEditing.font.size)", - name: $prefs.preferences.textEditing.font.name, size: $prefs.preferences.textEditing.font.size - ) + HStack { + Picker("Font:", selection: $prefs.preferences.textEditing.font.customFont) { + Text("System Font") + .tag(false) + Text("Custom") + .tag(true) + } + .fixedSize() + if prefs.preferences.textEditing.font.customFont { + FontPicker( + "\(prefs.preferences.textEditing.font.name) \(prefs.preferences.textEditing.font.size)", + name: $prefs.preferences.textEditing.font.name, size: $prefs.preferences.textEditing.font.size + ) + } } } @@ -143,4 +125,54 @@ struct TextEditingPreferencesView: View { ) } } + + private var defaultTabWidth: some View { + HStack(spacing: 5) { + TextField("", value: $prefs.preferences.textEditing.defaultTabWidth, formatter: tabWidthFormatter) + .multilineTextAlignment(.trailing) + .frame(width: 40) + Stepper( + "Default Tab Width:", + value: $prefs.preferences.textEditing.defaultTabWidth, + in: 1...8 + ) + Text("spaces") + } + } + + // MARK: - Formatters + + /// Only allows integer values in the range of `[1...8]` + private var tabWidthFormatter: NumberFormatter { + let formatter = NumberFormatter() + formatter.allowsFloats = false + formatter.minimum = 1 + formatter.maximum = 8 + + return formatter + } + + /// Only allows float values in the range of `[0.75...2.00]` + /// And formats to 2 decimal places. + private var lineHeightFormatter: NumberFormatter { + let formatter = NumberFormatter() + formatter.allowsFloats = true + formatter.maximumFractionDigits = 2 + formatter.minimumFractionDigits = 2 + formatter.minimum = 0.75 + formatter.maximum = 2.0 + + return formatter + } + + /// Formatter for the font size in the range `[1...288]` + /// Increases by 1 + private var fontSizeFormatter: NumberFormatter { + let formatter = NumberFormatter() + formatter.allowsFloats = false + formatter.minimum = 1 + formatter.maximum = 288 + + return formatter + } } diff --git a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/EditorThemeView.swift b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/EditorThemeView.swift index 4f455f1987..bf45185e9a 100644 --- a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/EditorThemeView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/EditorThemeView.swift @@ -7,21 +7,33 @@ import SwiftUI +/// A view that implements the `Editor theme` preference section struct EditorThemeView: View { + + // MARK: - View + + var body: some View { + editorThemeViewSection + } + @StateObject private var themeModel: ThemeModel = .shared @StateObject private var prefs: AppPreferencesModel = .shared +} - var body: some View { +private extension EditorThemeView { + + // MARK: - Sections + + private var editorThemeViewSection: some View { ZStack(alignment: .topLeading) { EffectView(.contentBackground) if let selectedTheme = themeModel.selectedTheme, let index = themeModel.themes.firstIndex(of: selectedTheme) { VStack(alignment: .leading, spacing: 0) { - Toggle("Use theme background ", isOn: $prefs.preferences.theme.useThemeBackground) - .padding(.bottom, 20) + useThemeBackground HStack(spacing: 0) { VStack(alignment: .leading, spacing: 10) { PreferencesColorPicker( @@ -37,7 +49,8 @@ struct EditorThemeView: View { label: "Invisibles" ) } - .frame(maxWidth: .infinity, alignment: .leading) + .frame(maxWidth: .infinity, alignment: .leading) + VStack(alignment: .leading, spacing: 10) { PreferencesColorPicker( $themeModel.themes[index].editor.background.swiftColor, @@ -52,13 +65,11 @@ struct EditorThemeView: View { label: "Selection" ) } - .frame(maxWidth: .infinity, alignment: .leading) + .frame(maxWidth: .infinity, alignment: .leading) } - .padding(.bottom, 20) - Text("Syntax") - .font(.system(size: 13, weight: .semibold)) - .foregroundColor(.secondary) - .padding(.bottom, 10) + .padding(.bottom, 20) + + syntaxText HStack(spacing: 0) { VStack(alignment: .leading, spacing: 10) { PreferencesColorPicker( @@ -82,7 +93,8 @@ struct EditorThemeView: View { label: "Variables" ) } - .frame(maxWidth: .infinity, alignment: .leading) + .frame(maxWidth: .infinity, alignment: .leading) + VStack(alignment: .leading, spacing: 10) { PreferencesColorPicker( $themeModel.themes[index].editor.values.swiftColor, @@ -105,15 +117,33 @@ struct EditorThemeView: View { label: "Comments" ) } - .frame(maxWidth: .infinity, alignment: .leading) + .frame(maxWidth: .infinity, alignment: .leading) } } .padding(20) } else { - Text("Select a Theme") - .foregroundColor(.secondary) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + selectTheme } } } + + // MARK: - Preference Views + + private var useThemeBackground: some View { + Toggle("Use theme background ", isOn: $prefs.preferences.theme.useThemeBackground) + .padding(.bottom, 20) + } + + private var selectTheme: some View { + Text("Select a Theme") + .foregroundColor(.secondary) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + } + + private var syntaxText: some View { + Text("Syntax") + .font(.system(size: 13, weight: .semibold)) + .foregroundColor(.secondary) + .padding(.bottom, 10) + } } diff --git a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/PreviewThemeView.swift b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/PreviewThemeView.swift index 38486229fb..71bf6dfc6a 100644 --- a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/PreviewThemeView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/PreviewThemeView.swift @@ -7,22 +7,45 @@ import SwiftUI +/// A view that implements the `Preview theme` preference section struct PreviewThemeView: View { + + // MARK: - View + + var body: some View { + previewTheme + } + @StateObject private var themeModel: ThemeModel = .shared +} - var body: some View { +private extension PreviewThemeView { + + // MARK: - Sections + + private var previewTheme: some View { ZStack(alignment: .topLeading) { EffectView(.contentBackground) if themeModel.selectedTheme == nil { - Text("Select a Theme") - .foregroundColor(.secondary) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + selectTheme } else { - Text("Preview is not yet implemented") - .foregroundColor(.secondary) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + previewNotYetImplemented } } } + + // MARK: - Preferences Views + + private var selectTheme: some View { + Text("Select a Theme") + .foregroundColor(.secondary) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + } + + private var previewNotYetImplemented: some View { + Text("Preview is not yet implemented") + .foregroundColor(.secondary) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + } } diff --git a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/TerminalThemeView.swift b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/TerminalThemeView.swift index 6d481bb4f2..88f750dfd4 100644 --- a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/TerminalThemeView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/TerminalThemeView.swift @@ -7,20 +7,31 @@ import SwiftUI +/// A view that implements the `Terminal theme` preference section struct TerminalThemeView: View { + + // MARK: - View + + var body: some View { + terminalThemeView + } + @StateObject private var prefs: AppPreferencesModel = .shared @StateObject private var themeModel: ThemeModel = .shared +} - var body: some View { +private extension TerminalThemeView { + + // MARK: - Sections + + private var terminalThemeView: some View { ZStack(alignment: .topLeading) { EffectView(.contentBackground) if themeModel.selectedTheme == nil { - Text("Select a Theme") - .foregroundColor(.secondary) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + selectTheme } else { VStack(alignment: .leading, spacing: 15) { topToggles @@ -32,6 +43,14 @@ struct TerminalThemeView: View { } } + // MARK: - Preference Views + + private var selectTheme: some View { + Text("Select a Theme") + .foregroundColor(.secondary) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) + } + private var topToggles: some View { VStack(alignment: .leading) { Toggle("Always use dark terminal appearance", isOn: $prefs.preferences.terminal.darkAppearance) diff --git a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreferencesView.swift b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreferencesView.swift index 1e57d7bed6..20b61c6ab3 100644 --- a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreferencesView.swift +++ b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreferencesView.swift @@ -23,34 +23,22 @@ struct ThemePreferencesView: View { private var listView: Bool = false var body: some View { + themePreferencesSection + } +} + +private extension ThemePreferencesView { + + // MARK: - Sections + + private var themePreferencesSection: some View { VStack(spacing: 20) { frame HStack(alignment: .center) { - Toggle( - "Automatically change theme based on system appearance", - isOn: $prefs.preferences.theme.mirrorSystemAppearance - ) - .onChange(of: prefs.preferences.theme.mirrorSystemAppearance) { value in - if value { - if colorScheme == .dark { - themeModel.selectedTheme = themeModel.selectedDarkTheme - } else { - themeModel.selectedTheme = themeModel.selectedLightTheme - } - } else { - themeModel.selectedTheme = themeModel.themes.first { - $0.name == prefs.preferences.theme.selectedTheme - } - } - } - + changeThemeOnSystemAppearance Spacer() - Button("Get More Themes...") {} - .disabled(true) - .help("Not yet implemented") - HelpButton {} - .disabled(true) - .help("Not yet implemented") + getMoreThemes + } } .frame(width: 872) @@ -60,6 +48,8 @@ struct ThemePreferencesView: View { } } + // MARK: - Preference Views + private var frame: some View { VStack(alignment: .leading, spacing: 16) { HStack(spacing: 1) { @@ -72,6 +62,36 @@ struct ThemePreferencesView: View { } } + private var changeThemeOnSystemAppearance: some View { + Toggle( + "Automatically change theme based on system appearance", + isOn: $prefs.preferences.theme.mirrorSystemAppearance + ) + .onChange(of: prefs.preferences.theme.mirrorSystemAppearance) { value in + if value { + if colorScheme == .dark { + themeModel.selectedTheme = themeModel.selectedDarkTheme + } else { + themeModel.selectedTheme = themeModel.selectedLightTheme + } + } else { + themeModel.selectedTheme = themeModel.themes.first { + $0.name == prefs.preferences.theme.selectedTheme + } + } + } + } + + @ViewBuilder + private var getMoreThemes: some View { + Button("Get More Themes...") {} + .disabled(true) + .help("Not yet implemented") + HelpButton {} + .disabled(true) + .help("Not yet implemented") + } + private var sidebar: some View { VStack(spacing: 1) { PreferencesToolbar { diff --git a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreviewIcon.swift b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreviewIcon.swift index b0ce9219ef..17e622a8e1 100644 --- a/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreviewIcon.swift +++ b/CodeEdit/Features/AppPreferences/Sections/ThemePreferences/ThemePreviewIcon.swift @@ -7,6 +7,7 @@ import SwiftUI +/// A view that implements the `Theme Preview` preference section struct ThemePreviewIcon: View { var theme: Theme var colorScheme: ColorScheme @@ -23,8 +24,7 @@ struct ThemePreviewIcon: View { var body: some View { VStack { ZStack(alignment: .topLeading) { - RoundedRectangle(cornerRadius: 3) - .foregroundColor(Color(hex: colorScheme == .dark ? 0x4c4c4c : 0xbbbbbb)) + circularRectangle HStack(spacing: 1) { sidebar @@ -41,12 +41,7 @@ struct ThemePreviewIcon: View { .strokeBorder(lineWidth: 2) .foregroundColor(selection == theme ? .accentColor : .clear) } - Text(theme.displayName) - .font(.subheadline) - .padding(.horizontal, 7) - .padding(.vertical, 2) - .foregroundColor(selection == theme ? .white : .primary) - .background(Capsule().foregroundColor(selection == theme ? .accentColor : .clear)) + themeDisplayName } .help(theme.metadataDescription) .onTapGesture { @@ -55,6 +50,22 @@ struct ThemePreviewIcon: View { } } } +} + +private extension ThemePreviewIcon { + private var circularRectangle: some View { + RoundedRectangle(cornerRadius: 3) + .foregroundColor(Color(hex: colorScheme == .dark ? 0x4c4c4c : 0xbbbbbb)) + } + + private var themeDisplayName: some View { + Text(theme.displayName) + .font(.subheadline) + .padding(.horizontal, 7) + .padding(.vertical, 2) + .foregroundColor(selection == theme ? .white : .primary) + .background(Capsule().foregroundColor(selection == theme ? .accentColor : .clear)) + } private var sidebar: some View { ZStack(alignment: .topLeading) { @@ -107,26 +118,9 @@ struct ThemePreviewIcon: View { codeStatement(theme.editor.keywords.color, length: 6) codeStatement(theme.editor.variables.color, length: 6) codeStatement(theme.editor.text.color, length: 1) - codeStatement(theme.editor.text.color, length: 1) - codeStatement(theme.editor.values.color, length: 8) - codeStatement(theme.editor.text.color, length: 1) codeStatement(theme.editor.values.color, length: 8) - codeStatement(theme.editor.text.color, length: 1) - codeStatement(theme.editor.keywords.color, length: 6) codeStatement(theme.editor.strings.color, length: 7) } - HStack(spacing: 1) { - codeStatement(theme.editor.keywords.color, length: 6) - codeStatement(theme.editor.variables.color, length: 8) - codeStatement(theme.editor.keywords.color, length: 6) - codeStatement(theme.editor.strings.color, length: 12) - codeStatement(theme.editor.text.color, length: 1) - } - HStack(spacing: 1) { - codeStatement(theme.editor.keywords.color, length: 6) - codeStatement(theme.editor.strings.color, length: 14) - codeStatement(theme.editor.text.color, length: 1) - } } } diff --git a/CodeEdit/Features/Settings/HelperViews/SettingsColorPicker.swift b/CodeEdit/Features/Settings/HelperViews/SettingsColorPicker.swift new file mode 100644 index 0000000000..cefeb9c789 --- /dev/null +++ b/CodeEdit/Features/Settings/HelperViews/SettingsColorPicker.swift @@ -0,0 +1,28 @@ +// +// SettingsColorPicker.swift +// CodeEdit +// +// Created by Austin Condiff on 4/3/23. +// + +import SwiftUI + +/// A view that implements a `Color Picker` +struct SettingsColorPicker: View { + @Binding + var color: Color + + private let label: String + + init(_ label: String, color: Binding) { + self._color = color + self.label = label + } + + var body: some View { + LabeledContent(label) { + ColorPicker(selection: $color, supportsOpacity: false) { } + .labelsHidden() + } + } +} diff --git a/CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift b/CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift new file mode 100644 index 0000000000..aec977ee35 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/GeneralSettings/GeneralSettingsView.swift @@ -0,0 +1,356 @@ +// +// GeneralSettingsView.swift +// CodeEdit +// +// Created by Austin Condiff on 4/1/23. +// + +import SwiftUI + +/// A view that implements the `General` settings page +struct GeneralSettingsView: View { + private let inputWidth: Double = 160 + private let textEditorWidth: Double = 220 + private let textEditorHeight: Double = 30 + + @EnvironmentObject + var updater: SoftwareUpdater + + @StateObject + private var prefs: AppPreferencesModel = .shared + + @State + private var openInCodeEdit: Bool = true + + init() { + guard let defaults = UserDefaults.init( + suiteName: "austincondiff.CodeEdit.shared" + ) else { + print("Failed to get/init shared defaults") + return + } + + self.openInCodeEdit = defaults.bool(forKey: "enableOpenInCE") + } + + var body: some View { + Form { + Section { + appearance + fileIconStyle + tabBarStyle + } + Section { + showIssues + showLiveIssues + } + Section { + autoSave + revealFileOnFocusChangeToggle + reopenBehavior + afterWindowsCloseBehaviour + fileExtensions + } + Section { + projectNavigatorSize + findNavigatorDetail + issueNavigatorDetail + } + Section { + openInCodeEditToggle + shellCommand + dialogWarnings + + } + Section { + updateChecker + autoUpdateToggle + prereleaseToggle + } + } + .formStyle(.grouped) + } +} + +/// The extension of the view with all the preferences +private extension GeneralSettingsView { + // MARK: - Sections + + private var appearance: some View { + Picker("Appearance", selection: $prefs.preferences.general.appAppearance) { + Text("System") + .tag(AppPreferences.Appearances.system) + Divider() + Text("Light") + .tag(AppPreferences.Appearances.light) + Text("Dark") + .tag(AppPreferences.Appearances.dark) + } + .onChange(of: prefs.preferences.general.appAppearance) { tag in + tag.applyAppearance() + } + } + + // TODO: Implement reflecting Show Issues preference and remove disabled modifier + private var showIssues: some View { + Picker("Show Issues", selection: $prefs.preferences.general.showIssues) { + Text("Show Inline") + .tag(AppPreferences.Issues.inline) + Text("Show Minimized") + .tag(AppPreferences.Issues.minimized) + } + } + + private var showLiveIssues: some View { + Toggle("Show Live Issues", isOn: $prefs.preferences.general.showLiveIssues) + } + + private var fileExtensions: some View { + Group { + Picker("File Extensions", selection: $prefs.preferences.general.fileExtensionsVisibility) { + Text("Hide all") + .tag(AppPreferences.FileExtensionsVisibility.hideAll) + Text("Show all") + .tag(AppPreferences.FileExtensionsVisibility.showAll) + Divider() + Text("Show only") + .tag(AppPreferences.FileExtensionsVisibility.showOnly) + Text("Hide only") + .tag(AppPreferences.FileExtensionsVisibility.hideOnly) + } + if case .showOnly = prefs.preferences.general.fileExtensionsVisibility { + SettingsTextEditor(text: $prefs.preferences.general.shownFileExtensions.string) + .frame(height: textEditorHeight) + } + if case .hideOnly = prefs.preferences.general.fileExtensionsVisibility { + SettingsTextEditor(text: $prefs.preferences.general.hiddenFileExtensions.string) + .frame(height: textEditorHeight) + } + } + } + + private var fileIconStyle: some View { + Picker("File Icon Style", selection: $prefs.preferences.general.fileIconStyle) { + Text("Color") + .tag(AppPreferences.FileIconStyle.color) + Text("Monochrome") + .tag(AppPreferences.FileIconStyle.monochrome) + } + .pickerStyle(.radioGroup) + } + + private var tabBarStyle: some View { + Picker("Tab Bar Style", selection: $prefs.preferences.general.tabBarStyle) { + Text("Xcode") + .tag(AppPreferences.TabBarStyle.xcode) + Text("Native") + .tag(AppPreferences.TabBarStyle.native) + } + .pickerStyle(.radioGroup) + } + + private var reopenBehavior: some View { + Picker("Reopen Behavior", selection: $prefs.preferences.general.reopenBehavior) { + Text("Welcome Screen") + .tag(AppPreferences.ReopenBehavior.welcome) + Divider() + Text("Open Panel") + .tag(AppPreferences.ReopenBehavior.openPanel) + Text("New Document") + .tag(AppPreferences.ReopenBehavior.newDocument) + } + } + + private var afterWindowsCloseBehaviour: some View { + Picker( + "After the last window is closed", + selection: $prefs.preferences.general.reopenWindowAfterClose + ) { + Text("Do nothing") + .tag(AppPreferences.ReopenWindowBehavior.doNothing) + Divider() + Text("Show Welcome Window") + .tag(AppPreferences.ReopenWindowBehavior.showWelcomeWindow) + Text("Quit") + .tag(AppPreferences.ReopenWindowBehavior.quit) + } + } + + private var projectNavigatorSize: some View { + Picker("Project Navigator Size", selection: $prefs.preferences.general.projectNavigatorSize) { + Text("Small") + .tag(AppPreferences.ProjectNavigatorSize.small) + Text("Medium") + .tag(AppPreferences.ProjectNavigatorSize.medium) + Text("Large") + .tag(AppPreferences.ProjectNavigatorSize.large) + } + } + + private var findNavigatorDetail: some View { + Picker("Find Navigator Detail", selection: $prefs.preferences.general.findNavigatorDetail) { + ForEach(AppPreferences.NavigatorDetail.allCases, id: \.self) { tag in + Text(tag.label).tag(tag) + } + } + } + + // TODO: Implement reflecting Issue Navigator Detail preference and remove disabled modifier + private var issueNavigatorDetail: some View { + Picker("Issue Navigator Detail", selection: $prefs.preferences.general.issueNavigatorDetail) { + ForEach(AppPreferences.NavigatorDetail.allCases, id: \.self) { tag in + Text(tag.label).tag(tag) + } + } + .disabled(true) + } + + // TODO: Implement reset for Don't Ask Me warnings Button and remove disabled modifier + private var dialogWarnings: some View { + LabeledContent("Dialog Warnings") { + Button(action: { + }, label: { + Text("Reset \"Don't Ask Me\" Warnings") + }) + .buttonStyle(.bordered) + } + .disabled(true) + } + + private var shellCommand: some View { + LabeledContent("Shell Command") { + Button(action: installShellCommand, label: { + Text("Install 'codeedit' command") + }) + .buttonStyle(.bordered) + } + } + + private var updateChecker: some View { + Section { + LabeledContent { + Button("Check Now") { + updater.checkForUpdates() + } + } label: { + Text("Check for updates") + Text("Last checked: \(lastUpdatedString)") + } + } + } + + // MARK: - Preference Views + private var autoUpdateToggle: some View { + Toggle("Automatically check for app updates", isOn: $updater.automaticallyChecksForUpdates) + } + + private var prereleaseToggle: some View { + Toggle("Include pre-release versions", isOn: $updater.includePrereleaseVersions) + } + + private var autoSave: some View { + Toggle( + "Automatically save changes to disk", + isOn: $prefs.preferences.general.isAutoSaveOn + ) + } + + private var lastUpdatedString: String { + if let lastUpdatedDate = updater.lastUpdateCheckDate { + return Self.formatter.string(from: lastUpdatedDate) + } else { + return "Never" + } + } + + private var openInCodeEditToggle: some View { + Toggle("Show “Open With CodeEdit” option in Finder", isOn: $openInCodeEdit) + .onChange(of: openInCodeEdit) { newValue in + guard let defaults = UserDefaults.init( + suiteName: "austincondiff.CodeEdit.shared" + ) else { + print("Failed to get/init shared defaults") + return + } + + defaults.set(newValue, forKey: "enableOpenInCE") + } + } + + private var revealFileOnFocusChangeToggle: some View { + Toggle("Automatically reveal in project navigator", isOn: $prefs.preferences.general.revealFileOnFocusChange) + } + + // MARK: - Functions + private static func configure(_ subject: Subject, configuration: (inout Subject) -> Void) -> Subject { + var copy = subject + configuration(©) + return copy + } + + private func fallbackShellInstallation(commandPath: String, destinationPath: String) { + let cmd = [ + "osascript", + "-e", + "\"do shell script \\\"mkdir -p /usr/local/bin && ln -sf \'\(commandPath)\' \'\(destinationPath)\'\\\"\"", + "with administrator privileges" + ] + + let cmdStr = cmd.joined(separator: " ") + + let task = Process() + let pipe = Pipe() + + task.standardOutput = pipe + task.standardError = pipe + task.arguments = ["-c", cmdStr] + task.executableURL = URL(fileURLWithPath: "/bin/zsh") + task.standardInput = nil + + do { + try task.run() + } catch { + print(error) + } + } + + private func installShellCommand() { + do { + let url = Bundle.main.url(forResource: "codeedit", withExtension: nil, subdirectory: "Resources") + let destination = "/usr/local/bin/codeedit" + + if FileManager.default.fileExists(atPath: destination) { + try FileManager.default.removeItem(atPath: destination) + } + + guard let shellUrl = url?.path else { + print("Failed to get URL to shell command") + return + } + + NSWorkspace.shared.requestAuthorization(to: .createSymbolicLink) { auth, error in + guard let auth, error == nil else { + fallbackShellInstallation(commandPath: shellUrl, destinationPath: destination) + return + } + + do { + try FileManager(authorization: auth).createSymbolicLink( + atPath: destination, withDestinationPath: shellUrl + ) + } catch { + fallbackShellInstallation(commandPath: shellUrl, destinationPath: destination) + } + } + } catch { + print(error) + } + } + + // MARK: - Formatters + + private static let formatter = configure(DateFormatter()) { + $0.dateStyle = .medium + $0.timeStyle = .medium + } +} diff --git a/CodeEdit/Features/Settings/Pages/LocationsSettings/LocationsSettingsView.swift b/CodeEdit/Features/Settings/Pages/LocationsSettings/LocationsSettingsView.swift new file mode 100644 index 0000000000..9008dc0eee --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/LocationsSettings/LocationsSettingsView.swift @@ -0,0 +1,68 @@ +// +// LocationSettingsView.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 02/04/23. +// + +import SwiftUI + +/// A view that implements the `Locations` settings page +struct LocationsSettingsView: View { + var body: some View { + Form { + Section { + locations + } + } + .formStyle(.grouped) + } +} + +private extension LocationsSettingsView { + // MARK: Sections + + @ViewBuilder + private var locations: some View { + settingsLocation + themesLocation + } + + // MARK: Preference Views + + @ViewBuilder + private var settingsLocation: some View { + Group { + HStack { + Text("Settings Location: \(AppPreferencesModel.shared.baseURL.path)") + .foregroundColor(.secondary) + Button { + NSWorkspace.shared.selectFile( + nil, + inFileViewerRootedAtPath: AppPreferencesModel.shared.baseURL.path + ) + } label: { + Image(systemName: "arrow.right.circle.fill") + } + .buttonStyle(.plain) + .foregroundColor(.secondary) + } + } + } + + private var themesLocation: some View { + Group { + HStack { + Text("Themes Location: \(ThemeModel.shared.themesURL.path)") + .foregroundColor(.secondary) + Button { + NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: ThemeModel.shared.themesURL.path) + } label: { + Image(systemName: "arrow.right.circle.fill") + } + .buttonStyle(.plain) + .foregroundColor(.secondary) + } + } + } +} diff --git a/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift new file mode 100644 index 0000000000..fea7493916 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGeneralView.swift @@ -0,0 +1,122 @@ +// +// SourceControlGeneralView.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 02/04/23. +// + +import SwiftUI + +/// A view that implements the `General` area of the `Source Control` settings page +struct SourceControlGeneralView: View { + @StateObject + private var prefs: AppPreferencesModel = .shared + + @State + private var defaultBranch: String = "main" + + var body: some View { + Group { + Section { + enableSourceControl + refreshLocalStatusAuto + fetchRefreshStatusAuto + addRemoveFilesAuto + selectFilesToCommitAuto + } + Section { + showSourceControlChanges + includeUpstreamChanges + } + Section { + comparisonView + sourceControlNavigator + defaultBranchName + } + } + .formStyle(.grouped) + } +} + +private extension SourceControlGeneralView { + // MARK: - Preference Views + private var enableSourceControl: some View { + Toggle( + "Enable source control", + isOn: $prefs.preferences.sourceControl.general.enableSourceControl + ) + } + + private var refreshLocalStatusAuto: some View { + Toggle( + "Refresh local status automatically", + isOn: $prefs.preferences.sourceControl.general.refreshStatusLocally + ) + } + + private var fetchRefreshStatusAuto: some View { + Toggle( + "Fetch and refresh server status automatically", + isOn: $prefs.preferences.sourceControl.general.fetchRefreshServerStatus + ) + } + + private var addRemoveFilesAuto: some View { + Toggle( + "Add and remove files automatically", + isOn: $prefs.preferences.sourceControl.general.addRemoveAutomatically + ) + } + + private var selectFilesToCommitAuto: some View { + Toggle( + "Select files to commit automatically", + isOn: $prefs.preferences.sourceControl.general.selectFilesToCommit + ) + } + + private var showSourceControlChanges: some View { + Toggle( + "Show source control changes", + isOn: $prefs.preferences.sourceControl.general.showSourceControlChanges + ) + } + + private var includeUpstreamChanges: some View { + Toggle( + "Include upstream changes", + isOn: $prefs.preferences.sourceControl.general.includeUpstreamChanges + ) + } + + private var comparisonView: some View { + Picker( + "Comparison view", + selection: $prefs.preferences.sourceControl.general.revisionComparisonLayout + ) { + Text("Local Revision on Left Side") + .tag(AppPreferences.RevisionComparisonLayout.localLeft) + Text("Local Revision on Right Side") + .tag(AppPreferences.RevisionComparisonLayout.localRight) + } + } + + private var sourceControlNavigator: some View { + Picker( + "Source control navigator", + selection: $prefs.preferences.sourceControl.general.controlNavigatorOrder + ) { + Text("Sort by Name") + .tag(AppPreferences.ControlNavigatorOrder.sortByName) + Text("Sort by Date") + .tag(AppPreferences.ControlNavigatorOrder.sortByDate) + } + } + + private var defaultBranchName: some View { + TextField(text: $defaultBranch) { + Text("Default branch name") + Text("Cannot contain spaces, backslashes, or other symbols") + } + } +} diff --git a/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift new file mode 100644 index 0000000000..36c1475434 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlGitView.swift @@ -0,0 +1,84 @@ +// +// SourceControlGitView.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 02/04/23. +// + +import SwiftUI + +/// A view that implements the `Git` area of the `Source Control` settings page +struct SourceControlGitView: View { + @StateObject + private var prefs: AppPreferencesModel = .shared + + var body: some View { + Group { + Section("Git") { + authorNameAndEmail + } + Section { + ignoredFiles + } + Section { + options + } + } + .formStyle(.grouped) + } +} + +private extension SourceControlGitView { + // MARK: - Sections + @ViewBuilder + private var authorNameAndEmail: some View { + gitAuthorName + gitEmail + } + + private var ignoredFiles: some View { + ignoredFilesText + } + + @ViewBuilder + private var options: some View { + preferToRebaseWhenPulling + showMergeCommitsInPerFileLog + } + + // MARK: - Preference Views + private var gitAuthorName: some View { + TextField("Git Author Name", text: $prefs.preferences.sourceControl.git.authorName) + } + + private var gitEmail: some View { + TextField("Git Email", text: $prefs.preferences.sourceControl.git.authorEmail) + } + + @ViewBuilder + private var ignoredFilesText: some View { + HStack { + Text("Ignored files") + Spacer() + Button("Select files...") { + // TODO: Implement a view for this + } + .disabled(true) + .help("Not implemented yet") + } + } + + private var preferToRebaseWhenPulling: some View { + Toggle( + "Prefer to rebase when pulling", + isOn: $prefs.preferences.sourceControl.git.preferRebaseWhenPulling + ) + } + + private var showMergeCommitsInPerFileLog: some View { + Toggle( + "Show merge commits in per-file log", + isOn: $prefs.preferences.sourceControl.git.showMergeCommitsPerFileLog + ) + } +} diff --git a/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlSettingsView.swift b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlSettingsView.swift new file mode 100644 index 0000000000..4ded06c912 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/SourceControlSettings/SourceControlSettingsView.swift @@ -0,0 +1,19 @@ +// +// SourceControlSettingsView.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 02/04/23. +// + +import SwiftUI + +/// A view that implements the `Source Control` settings page +struct SourceControlSettingsView: View { + var body: some View { + Form { + SourceControlGeneralView() + SourceControlGitView() + } + .formStyle(.grouped) + } +} diff --git a/CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift b/CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift new file mode 100644 index 0000000000..ecfec9e236 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/TerminalSettings/TerminalSettingsView.swift @@ -0,0 +1,99 @@ +// +// TerminalSettingsView.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 02/04/23. +// + +import SwiftUI + +/// A view that implements the `Terminal` settings page +struct TerminalSettingsView: View { + @StateObject + private var prefs: AppPreferencesModel = .shared + + var body: some View { + Form { + shell + font + cursor + } + .formStyle(.grouped) + } +} + +private extension TerminalSettingsView { + // MARK: Sections + + @ViewBuilder + private var shell: some View { + shellSelector + optionAsMetaToggle + } + + private var font: some View { + fontSelector + } + + @ViewBuilder + private var cursor: some View { + cursorStyle + cursorBlink + } + + // MARK: Preference Views + + @ViewBuilder + private var shellSelector: some View { + Picker("Shell", selection: $prefs.preferences.terminal.shell) { + Text("System Default") + .tag(AppPreferences.TerminalShell.system) + Divider() + Text("ZSH") + .tag(AppPreferences.TerminalShell.zsh) + Text("Bash") + .tag(AppPreferences.TerminalShell.bash) + } + } + + private var cursorStyle: some View { + Picker("Terminal Cursor Style", selection: $prefs.preferences.terminal.cursorStyle) { + Text("Block") + .tag(AppPreferences.TerminalCursorStyle.block) + Text("Underline") + .tag(AppPreferences.TerminalCursorStyle.underline) + Text("Bar") + .tag(AppPreferences.TerminalCursorStyle.bar) + } + } + + private var cursorBlink: some View { + Group { + Toggle("Blink Cursor", isOn: $prefs.preferences.terminal.cursorBlink) + } + } + + private var optionAsMetaToggle: some View { + Group { + Toggle("Use \"Option\" key as \"Meta\"", isOn: $prefs.preferences.terminal.optionAsMeta) + } + } + + @ViewBuilder + private var fontSelector: some View { + Group { + Picker("Font", selection: $prefs.preferences.terminal.font.customFont) { + Text("System Font") + .tag(false) + Text("Custom") + .tag(true) + } + } + if prefs.preferences.terminal.font.customFont { + FontPicker( + "\(prefs.preferences.terminal.font.name) \(prefs.preferences.terminal.font.size)", + name: $prefs.preferences.terminal.font.name, size: $prefs.preferences.terminal.font.size + ) + } + } +} diff --git a/CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift b/CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift new file mode 100644 index 0000000000..208aed993c --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/TextEditingSettings/TextEditingSettingsView.swift @@ -0,0 +1,150 @@ +// +// TextEditingSettingsView.swift +// CodeEdit +// +// Created by Austin Condiff on 4/2/23. +// + +import SwiftUI + +/// A view that implements the `Text Editing` settings page +struct TextEditingSettingsView: View { + @StateObject + private var prefs: AppPreferencesModel = .shared + + var body: some View { + Form { + Section { + defaultTabWidth + wrapLinesToEditorWidth + } + Section { + fontSelector + fontSizeSelector + lineHeight + } + Section { + autocompleteBraces + enableTypeOverCompletion + } + } + .formStyle(.grouped) + } +} + +private extension TextEditingSettingsView { + // MARK: - Preference Views + + @ViewBuilder + private var fontSelector: some View { + Picker("Font", selection: $prefs.preferences.textEditing.font.customFont) { + Text("System Font") + .tag(false) + Text("Custom") + .tag(true) + } + if prefs.preferences.textEditing.font.customFont { + FontPicker( + "\(prefs.preferences.textEditing.font.name) \(prefs.preferences.textEditing.font.size)", + name: $prefs.preferences.textEditing.font.name, size: $prefs.preferences.textEditing.font.size + ) + } + } + + private var fontSizeSelector: some View { + LabeledContent("Font Size") { + TextField("", value: $prefs.preferences.textEditing.font.size, formatter: fontSizeFormatter) + .labelsHidden() + Stepper( + "", + value: $prefs.preferences.textEditing.font.size, + in: 1...288, + step: 1 + ) + .labelsHidden() + } + } + + private var autocompleteBraces: some View { + Toggle(isOn: $prefs.preferences.textEditing.autocompleteBraces) { + Text("Autocomplete braces") + Text("Automatically insert closing braces (\"}\")") + } + } + + private var enableTypeOverCompletion: some View { + Toggle("Enable type-over completion", isOn: $prefs.preferences.textEditing.enableTypeOverCompletion) + } + + private var wrapLinesToEditorWidth: some View { + Toggle("Wrap lines to editor width", isOn: $prefs.preferences.textEditing.wrapLinesToEditorWidth) + } + + private var lineHeight: some View { + LabeledContent("Line Height") { + TextField( + "", + value: $prefs.preferences.textEditing.lineHeightMultiple, + formatter: lineHeightFormatter + ) + .labelsHidden() + Stepper( + "", + value: $prefs.preferences.textEditing.lineHeightMultiple, + in: 0.75...2.0, + step: 0.05 + ) + .labelsHidden() + } + } + + private var defaultTabWidth: some View { + LabeledContent("Default Tab Width") { + TextField("", value: $prefs.preferences.textEditing.defaultTabWidth, formatter: tabWidthFormatter) + .labelsHidden() + Stepper("", value: $prefs.preferences.textEditing.defaultTabWidth, in: 1...8) + .labelsHidden() + Text("spaces") + .fixedSize(horizontal: true, vertical: false) + .foregroundColor(.secondary) + .textSelection(.disabled) + } + } + + // MARK: - Formatters + + /// Only allows integer values in the range of `[1...8]` + /// Does not allow float values + private var tabWidthFormatter: NumberFormatter { + let formatter = NumberFormatter() + formatter.allowsFloats = false + formatter.minimum = 1 + formatter.maximum = 8 + + return formatter + } + + /// Only allows float values in the range of `[0.75...2.00]` + /// And formats to 2 decimal places. + private var lineHeightFormatter: NumberFormatter { + let formatter = NumberFormatter() + formatter.allowsFloats = true + formatter.maximumFractionDigits = 2 + formatter.minimumFractionDigits = 2 + formatter.minimum = 0.75 + formatter.maximum = 2.0 + + return formatter + } + + /// Formatter for the font size in the range `[1...288]` + /// Increases by 1 and does not allow float values + private var fontSizeFormatter: NumberFormatter { + let formatter = NumberFormatter() + formatter.allowsFloats = false + formatter.minimum = 1 + formatter.maximum = 288 + + return formatter + } +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/Model/ThemeSettingsColorPreviewColor.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/Model/ThemeSettingsColorPreviewColor.swift new file mode 100644 index 0000000000..a89f9fde5b --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/Model/ThemeSettingsColorPreviewColor.swift @@ -0,0 +1,33 @@ +// +// ThemeSettingsColorPreviewColor.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 04/04/23. +// + +import Foundation +import SwiftUI + +struct ThemeSettingsColorPreviewColor: View { + private var color: Color + + init(_ color: Color) { + self.color = color + } + + var body: some View { + color + .frame(width: 5, height: 5) + .cornerRadius(5) + .overlay { + ZStack { + Circle() + .stroke(Color(.black).opacity(0.2), lineWidth: 0.5) + .frame(width: 5, height: 5) + Circle() + .strokeBorder(Color(.white).opacity(0.2), lineWidth: 0.5) + .frame(width: 5, height: 5) + } + } + } +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingThemeRow.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingThemeRow.swift new file mode 100644 index 0000000000..f01b67550f --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingThemeRow.swift @@ -0,0 +1,51 @@ +// +// ThemeSettingThemeRow.swift +// CodeEdit +// +// Created by Austin Condiff on 4/3/23. +// + +import SwiftUI + +/// A view that implements the `Rows` in the `Themes` settings page +struct ThemeSettingsThemeRow: View { + @Binding var theme: Theme + var active: Bool + var action: () -> Void + + @State private var presentingDetails: Bool = false + @State private var isHovering = false + + var body: some View { + HStack { + Image(systemName: "checkmark") + .opacity(active ? 1 : 0) + .font(.system(size: 10.5, weight: .bold)) + VStack(alignment: .leading) { + Text(theme.displayName) + Text("CodeEdit") + .foregroundColor(.secondary) + .font(.footnote) + } + .frame(maxWidth: .infinity, alignment: .leading) + Button { + presentingDetails = true + } label: { + Text("Details...") + } + .buttonStyle(.bordered) + .opacity(isHovering ? 1 : 0) + ThemeSettingsColorPreview(theme) + } + .padding(10) + .onHover { hovering in + isHovering = hovering + } + .onTapGesture { + action() + } + .sheet(isPresented: $presentingDetails) { + ThemeSettingsThemeDetails($theme) + } + } +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsColorPreview.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsColorPreview.swift new file mode 100644 index 0000000000..41ade03bcc --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsColorPreview.swift @@ -0,0 +1,80 @@ +// +// ThemeSettingsColorPreview.swift +// CodeEdit +// +// Created by Austin Condiff on 4/3/23. +// + +import SwiftUI + +/// A view that implements the `Previews` of the `Themes` settings page +struct ThemeSettingsColorPreview: View { + var theme: Theme + + @StateObject + private var themeModel: ThemeModel = .shared + + @State + private var displayName: String + + init(_ theme: Theme) { + self.theme = theme + self.displayName = theme.displayName + } + + var body: some View { + HStack(spacing: 5) { + previewColors + } + .padding(12) + .background(theme.editor.background.swiftColor) + .clipShape(Capsule()) + .overlay { + ZStack { + Capsule() + .stroke(Color(.black).opacity(0.2), lineWidth: 0.5) + .frame(maxWidth: .infinity, maxHeight: .infinity) + Capsule() + .strokeBorder(Color(.white).opacity(0.2), lineWidth: 0.5) + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + } + } +} + +private extension ThemeSettingsColorPreview { + // MARK: - Sections + @ViewBuilder + private var previewColors: some View { + ThemeSettingsColorPreviewColor( + theme.editor.keywords.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.commands.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.types.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.attributes.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.variables.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.values.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.numbers.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.strings.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.characters.swiftColor + ) + ThemeSettingsColorPreviewColor( + theme.editor.comments.swiftColor + ) + } +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsThemeDetails.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsThemeDetails.swift new file mode 100644 index 0000000000..a1dc520480 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsThemeDetails.swift @@ -0,0 +1,147 @@ +// +// ThemeSettingsThemeDetails.swift +// CodeEdit +// +// Created by Austin Condiff on 4/3/23. +// + +import SwiftUI + +/// A view that implements the `Theme Details/Editor` of the `Themes` settings page +struct ThemeSettingsThemeDetails: View { + @Environment(\.dismiss) var dismiss + + @Binding var theme: Theme + + @State private var initialTheme: Theme + + @StateObject + private var themeModel: ThemeModel = .shared + + init(_ theme: Binding) { + _theme = theme + _initialTheme = State(initialValue: theme.wrappedValue) + } + + var body: some View { + VStack(spacing: 0) { + Form { + Section { + TextField("Name", text: $theme.displayName) + } + Section { + textColorPickers + } + Section { + rulerAndBackgroundColorPickers + } + Section { + editorColorPickers + } + }.formStyle(.grouped) + Divider() + HStack { + saveOptions + } + .padding() + } + .constrainHeightToWindow() + } +} + +private extension ThemeSettingsThemeDetails { + // MARK: - Sections + @ViewBuilder + private var textColorPickers: some View { + SettingsColorPicker( + "Text", + color: $theme.editor.text.swiftColor + ) + SettingsColorPicker( + "Cursor", + color: $theme.editor.insertionPoint.swiftColor + ) + SettingsColorPicker( + "Invisibles", + color: $theme.editor.invisibles.swiftColor + ) + } + + @ViewBuilder + private var rulerAndBackgroundColorPickers: some View { + SettingsColorPicker( + "Background", + color: $theme.editor.background.swiftColor + ) + SettingsColorPicker( + "Current Line", + color: $theme.editor.lineHighlight.swiftColor + ) + SettingsColorPicker( + "Selection", + color: $theme.editor.selection.swiftColor + ) + } + + @ViewBuilder + private var editorColorPickers: some View { + SettingsColorPicker( + "Keywords", + color: $theme.editor.keywords.swiftColor + ) + SettingsColorPicker( + "Commands", + color: $theme.editor.commands.swiftColor + ) + SettingsColorPicker( + "Types", + color: $theme.editor.types.swiftColor + ) + SettingsColorPicker( + "Attributes", + color: $theme.editor.attributes.swiftColor + ) + SettingsColorPicker( + "Variables", + color: $theme.editor.variables.swiftColor + ) + SettingsColorPicker( + "Values", + color: $theme.editor.values.swiftColor + ) + SettingsColorPicker( + "Numbers", + color: $theme.editor.numbers.swiftColor + ) + SettingsColorPicker( + "Strings", + color: $theme.editor.strings.swiftColor + ) + SettingsColorPicker( + "Characters", + color: $theme.editor.characters.swiftColor + ) + SettingsColorPicker( + "Comments", + color: $theme.editor.comments.swiftColor + ) + } + + @ViewBuilder + private var saveOptions: some View { + Spacer() + Button { + theme = initialTheme + dismiss() + } label: { + Text("Cancel") + } + .buttonStyle(.bordered) + Button { + dismiss() + } label: { + Text("Done") + } + .buttonStyle(.borderedProminent) + } +} diff --git a/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift new file mode 100644 index 0000000000..6dc979aeb6 --- /dev/null +++ b/CodeEdit/Features/Settings/Pages/ThemeSettings/ThemeSettingsView.swift @@ -0,0 +1,176 @@ +// +// ThemePreferencesView.swift +// CodeEdit +// +// Created by Lukas Pistrol on 30.03.22. +// + +import SwiftUI +import Preferences + +/// A view that implements the `Theme` settings page +struct ThemeSettingsView: View { + @Environment(\.colorScheme) + var colorScheme + + @ObservedObject + private var themeModel: ThemeModel = .shared + + @ObservedObject + private var prefs: AppPreferencesModel = .shared + + @State + private var listView: Bool = false + + @State + private var selectedAppearance: ThemeSettingsAppearances = .dark + + enum ThemeSettingsAppearances: String, CaseIterable { + case light = "Light Appearance" + case dark = "Dark Appearance" + } + + var body: some View { + Form { + Section { + terminalThemeOptions + } + Section("Editor Theme") { + editorTheme + } + terminalThemeOptions + if !prefs.preferences.terminal.useEditorTheme { + Section { + terminalTheme + } + } + } + .formStyle(.grouped) + } +} + +private extension ThemeSettingsView { + // MARK: - Sections + + private var editorTheme: some View { + VStack(spacing: 0) { + if prefs.preferences.theme.mirrorSystemAppearance { + Picker("", selection: $selectedAppearance) { + ForEach(ThemeSettingsAppearances.allCases, id: \.self) { tab in + Text(tab.rawValue) + .tag(tab) + } + } + .pickerStyle(.segmented) + .labelsHidden() + .padding(10) + } + VStack(spacing: 0) { + ForEach(selectedAppearance == .dark ? themeModel.darkThemes : themeModel.lightThemes) { theme in + Divider() + ThemeSettingsThemeRow( + theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], + active: themeModel.selectedTheme == theme, + action: { themeModel.selectedTheme = theme } + ).id(theme) + } + ForEach(selectedAppearance == .dark ? themeModel.lightThemes : themeModel.darkThemes) { theme in + Divider() + ThemeSettingsThemeRow( + theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], + active: themeModel.selectedTheme == theme, + action: { themeModel.selectedTheme = theme } + ).id(theme) + } + } + } + .padding(-10) + } + + private var terminalTheme: some View { + VStack(spacing: 0) { + if prefs.preferences.theme.mirrorSystemAppearance + && !prefs.preferences.terminal.darkAppearance { + Picker("", selection: $selectedAppearance) { + ForEach(ThemeSettingsAppearances.allCases, id: \.self) { tab in + Text(tab.rawValue) + .tag(tab) + } + } + .pickerStyle(.segmented) + .labelsHidden() + .padding(10) + } + VStack(spacing: 0) { + ForEach( + selectedAppearance == .dark || prefs.preferences.terminal.darkAppearance + ? themeModel.darkThemes + : themeModel.lightThemes + ) { theme in + Divider() + ThemeSettingsThemeRow( + theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], + active: themeModel.selectedTheme == theme, + action: { themeModel.selectedTheme = theme } + ).id(theme) + } + if !prefs.preferences.terminal.darkAppearance { + ForEach( + selectedAppearance == .dark + ? themeModel.lightThemes + : themeModel.darkThemes + ) { theme in + Divider() + ThemeSettingsThemeRow( + theme: $themeModel.themes[themeModel.themes.firstIndex(of: theme)!], + active: themeModel.selectedTheme == theme, + action: { themeModel.selectedTheme = theme } + ).id(theme) + } + } + } + } + .padding(-10) + } + + private var terminalThemeOptions: some View { + Section("Terminal Theme") { + useEditorThemeToggle + alwaysUseDarkTerminalAppearanceToggle + } + } + + // MARK: - Preference Views + + private var alwaysUseDarkTerminalAppearanceToggle: some View { + Toggle("Always use dark terminal appearance", isOn: $prefs.preferences.terminal.darkAppearance) + } + + private var useEditorThemeToggle: some View { + Toggle("Use editor theme", isOn: $prefs.preferences.terminal.useEditorTheme) + } + + private var useThemeBackgroundToggle: some View { + Toggle("Use theme background ", isOn: $prefs.preferences.theme.useThemeBackground) + } + + private var changeThemeOnSystemAppearanceToggle: some View { + Toggle( + "Automatically change theme based on system appearance", + isOn: $prefs.preferences.theme.mirrorSystemAppearance + ) + .onChange(of: prefs.preferences.theme.mirrorSystemAppearance) { value in + if value { + if colorScheme == .dark { + themeModel.selectedTheme = themeModel.selectedDarkTheme + } else { + themeModel.selectedTheme = themeModel.selectedLightTheme + } + } else { + themeModel.selectedTheme = themeModel.themes.first { + $0.name == prefs.preferences.theme.selectedTheme + } + } + } + } +} diff --git a/CodeEdit/Features/Settings/SettingPageView.swift b/CodeEdit/Features/Settings/SettingPageView.swift new file mode 100644 index 0000000000..4d98ce1ddc --- /dev/null +++ b/CodeEdit/Features/Settings/SettingPageView.swift @@ -0,0 +1,50 @@ +// +// SettingPageView.swift +// CodeEdit +// +// Created by Austin Condiff on 3/31/23. +// + +import SwiftUI + +/// A sidebar view that shows an Icon and a background gradient +struct SettingsPageView: View { + var page: SettingsPage + + init(_ page: SettingsPage) { + self.page = page + } + + var body: some View { + NavigationLink(value: page) { + Label { + Text(page.nameString) + .padding(.leading, 2) + } icon: { + if let icon = page.icon { + Group { + switch icon { + case .system(let name): + Image(systemName: name) + case .asset(let name): + Image(name) + .resizable() + .padding(2) + } + } + .foregroundColor(.primary) + .frame(width: 20, height: 20) + .background( + RoundedRectangle( + cornerRadius: 5, + style: .continuous + ) + .fill(page.baseColor.gradient) + ) + } else { + EmptyView() + } + } + } + } +} diff --git a/CodeEdit/Features/Settings/SettingsPage.swift b/CodeEdit/Features/Settings/SettingsPage.swift new file mode 100644 index 0000000000..9f53da73cf --- /dev/null +++ b/CodeEdit/Features/Settings/SettingsPage.swift @@ -0,0 +1,52 @@ +// +// SettingsPage.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 30/03/23. +// + +import SwiftUI + +/// A struct for a settings page in the NavigationSplitView sidebar +struct SettingsPage: Hashable, Identifiable { + /// Default intializer + internal init(_ name: Name, baseColor: Color? = nil, icon: IconResource? = nil, children: [SettingsPage] = []) { + self.children = children + self.name = name + self.baseColor = baseColor ?? .red + self.icon = icon ?? .system("questionmark.app") + } + + var id: String { name.rawValue } + + /// Variables for the view representation, including: name, color, children (optional) and the icon + let name: Name + let baseColor: Color + let children: [SettingsPage] + var nameString: LocalizedStringKey { LocalizedStringKey(name.rawValue) } + let icon: IconResource? + + /// A struct for a sidebar icon, with a base color and SF Symbol + enum IconResource: Equatable, Hashable { + case system(_ name: String) + case asset(_ name: String) + } + + /// An enum of all the preferences tabs + enum Name: String { + // MARK: - App Preferences + + case general = "General" + case account = "Accounts" + case behaviors = "Behaviors" + case navigation = "Navigation" + case themes = "Themes" + case textEditing = "Text Editing" + case terminal = "Terminal" + case keybindings = "Key Bindings" + case sourceControl = "Source Control" + case components = "Components" + case locations = "Locations" + case advanced = "Advanced" + } +} diff --git a/CodeEdit/Features/Settings/SettingsView.swift b/CodeEdit/Features/Settings/SettingsView.swift new file mode 100644 index 0000000000..f598a60f51 --- /dev/null +++ b/CodeEdit/Features/Settings/SettingsView.swift @@ -0,0 +1,90 @@ +// +// SettingsView.swift +// CodeEdit +// +// Created by Raymond Vleeshouwer on 26/03/23. +// + +import SwiftUI +import AppKit + +/// A struct for `SettingsView` +struct SettingsView: View { + + /// An array of NavigationItems + private static let pages: [SettingsPage] = [ + .init(.general, baseColor: .gray, icon: .system("gear")), + .init(.account, baseColor: .blue, icon: .system("at")), + .init(.behaviors, baseColor: .orange, icon: .system("flowchart")), + .init(.navigation, baseColor: .green, icon: .system("arrow.triangle.turn.up.right.diamond")), + .init(.themes, baseColor: .pink, icon: .system("paintbrush")), + .init(.textEditing, baseColor: .blue, icon: .system("square.and.pencil")), + .init(.terminal, baseColor: .blue, icon: .system("terminal")), + .init(.keybindings, baseColor: .gray, icon: .system("keyboard")), + .init(.sourceControl, baseColor: .blue, icon: .system("arrow.triangle.pull")), + .init(.components, baseColor: .blue, icon: .system("puzzlepiece")), + .init(.locations, baseColor: .green, icon: .system("externaldrive")), + .init(.advanced, baseColor: .gray, icon: .system("gearshape.2")) + /* + .init(.extensionsSection, children: [ + // iterate over extensions + .init(.advanced, baseColor: .gray, icon: .system("gearshape.2")) + .init(.advanced, baseColor: .gray, icon: .system("gearshape.2")) + .init(.advanced, baseColor: .gray, icon: .system("gearshape.2")) + ]) + */ + ] + + /// Variables for the selected Page, the current search text and software updater + @State private var selectedPage = pages.first! + @State private var searchText: String = "" + + let updater: SoftwareUpdater + + var body: some View { + NavigationSplitView { + List(Self.pages, selection: $selectedPage) { item in + if item.children.isEmpty { + if searchText.isEmpty || item.name.rawValue.lowercased().contains(searchText.lowercased()) { + SettingsPageView(item) + } + } else { + Section(item.nameString) { + ForEach(item.children) { child in + if searchText.isEmpty || child.name.rawValue.lowercased().contains( + searchText.lowercased() + ) { + SettingsPageView(child) + } + } + } + } + } + .navigationSplitViewColumnWidth(215) + } detail: { + Group { + switch selectedPage.name { + case .general: + GeneralSettingsView() + .environmentObject(updater) + case .themes: + ThemeSettingsView() + case .textEditing: + TextEditingSettingsView() + case .terminal: + TerminalSettingsView() + case .sourceControl: + SourceControlSettingsView() + case .locations: + LocationsSettingsView() + default: + Text("Implementation Needed") + .frame(alignment: .center) + } + } + .navigationSplitViewColumnWidth(500) + } + // .searchable(text: $searchText, placement: .sidebar) + .navigationTitle(selectedPage.name.rawValue) + } +} diff --git a/CodeEdit/Features/Settings/SettingsWindow.swift b/CodeEdit/Features/Settings/SettingsWindow.swift new file mode 100644 index 0000000000..e95abb26d0 --- /dev/null +++ b/CodeEdit/Features/Settings/SettingsWindow.swift @@ -0,0 +1,31 @@ +// +// SettingsWindow.swift +// CodeEdit +// +// Created by Austin Condiff on 3/31/23. +// + +import SwiftUI + +/// The settings window to display settings +struct SettingsWindow: Scene { + private let updater = SoftwareUpdater() + + var body: some Scene { + Settings { + SettingsView(updater: updater) + .frame(minWidth: 715, maxWidth: 715) + .task { + let window = NSApp.windows.first { $0.identifier?.rawValue == "com_apple_SwiftUI_Settings_window" }! + window.toolbarStyle = .unified + window.titlebarSeparatorStyle = .automatic + + let sidebaritem = "com.apple.SwiftUI.navigationSplitView.toggleSidebar" + let index = window.toolbar?.items.firstIndex { $0.itemIdentifier.rawValue == sidebaritem } + if let index { + window.toolbar?.removeItem(at: index) + } + } + } + } +} diff --git a/CodeEdit/Features/Settings/View+ConstrainHeightToWindow.swift b/CodeEdit/Features/Settings/View+ConstrainHeightToWindow.swift new file mode 100644 index 0000000000..465c505317 --- /dev/null +++ b/CodeEdit/Features/Settings/View+ConstrainHeightToWindow.swift @@ -0,0 +1,38 @@ +// +// View+ConstrainHeightToWindow.swift +// CodeEdit +// +// Created by Austin Condiff on 4/3/23. +// + +import SwiftUI + +extension NSWindow { + var isSettingsWindow: Bool { + self.identifier?.rawValue == "com_apple_SwiftUI_Settings_window" + } +} + +extension NSApplication { + var settingsWindow: NSWindow? { + NSApp.windows.first { $0.isSettingsWindow } + } +} + +extension View { + func constrainHeightToWindow() -> some View { + modifier(ConstrainHeightToWindowViewModifier()) + } +} + +struct ConstrainHeightToWindowViewModifier: ViewModifier { + @State var height: CGFloat = 100 + + func body(content: Content) -> some View { + content + .frame(height: height - 100) + .onReceive(NSApp.settingsWindow!.publisher(for: \.frame)) { newValue in + height = newValue.height + } + } +} diff --git a/CodeEdit/Features/WindowCommands/MainCommands.swift b/CodeEdit/Features/WindowCommands/MainCommands.swift index 4f7d902923..ab8edb24dc 100644 --- a/CodeEdit/Features/WindowCommands/MainCommands.swift +++ b/CodeEdit/Features/WindowCommands/MainCommands.swift @@ -24,12 +24,12 @@ struct MainCommands: Commands { } CommandGroup(replacing: .appSettings) { - Button("Settings...") { + Button("Preferences...") { NSApp.sendAction(#selector(AppDelegate.openPreferences(_:)), to: nil, from: nil) } .keyboardShortcut(",") - Button("New Settings...") { + Button("Settings...") { NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil) } .keyboardShortcut(",", modifiers: [.command, .option, .hidden])