diff --git a/Podfile b/Podfile index e22ae3c2..373ccd7f 100644 --- a/Podfile +++ b/Podfile @@ -5,9 +5,13 @@ target 'alt-tab-macos' do pod 'LetsMove', '1.24' pod 'Sparkle', '1.23.0' pod 'ShortcutRecorder', :git => 'https://github.com/Kentzo/ShortcutRecorder.git', :branch => 'issue-114' + pod 'SwiftyMarkdown', '1.1.0' post_install do |installer| - require 'fileutils' - FileUtils.cp_r('Pods/Target Support Files/Pods-alt-tab-macos/Pods-alt-tab-macos-acknowledgements.markdown', 'docs/ACKNOWLEDGMENTS.md', :remove_destination => true) + # remove incorrect whitespace from ShortcutRecorder license + system('cat -s Pods/Target\\ Support\\ Files/Pods-alt-tab-macos/Pods-alt-tab-macos-acknowledgements.markdown'\ + '| tail -n +2 '\ + '| sed -e "s/^ \{12\}/ /" '\ + '| sed -e "s/^ \{7\}/ /" > docs/ACKNOWLEDGMENTS.md') end end diff --git a/Podfile.lock b/Podfile.lock index f81737b9..79b64423 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -2,16 +2,19 @@ PODS: - LetsMove (1.24) - ShortcutRecorder (3.1) - Sparkle (1.23.0) + - SwiftyMarkdown (1.1.0) DEPENDENCIES: - LetsMove (= 1.24) - ShortcutRecorder (from `https://github.com/Kentzo/ShortcutRecorder.git`, branch `issue-114`) - Sparkle (= 1.23.0) + - SwiftyMarkdown (= 1.1.0) SPEC REPOS: trunk: - LetsMove - Sparkle + - SwiftyMarkdown EXTERNAL SOURCES: ShortcutRecorder: @@ -27,7 +30,8 @@ SPEC CHECKSUMS: LetsMove: fefe56bc7bc7fb7d37049e28a14f297961229fc5 ShortcutRecorder: fdf620aca34101b0cba3b10fca815e0459254189 Sparkle: 55b1a87ba69d56913375a281546b7c82dec95bb0 + SwiftyMarkdown: 033abc9dad9a37903f81aec5188cade436f40520 -PODFILE CHECKSUM: b63a7ff603634bab29a50eda75a4c4679013948f +PODFILE CHECKSUM: d29f0025654055db94e7dd7750d82117c7c685ad COCOAPODS: 1.8.4 diff --git a/alt-tab-macos.xcodeproj/project.pbxproj b/alt-tab-macos.xcodeproj/project.pbxproj index a909c627..e996e9e0 100644 --- a/alt-tab-macos.xcodeproj/project.pbxproj +++ b/alt-tab-macos.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ D04BA570E7806F28741B1472 /* SF-Pro-Text-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = D04BA0CDCFF1F0B1A77E3E86 /* SF-Pro-Text-Regular.otf */; }; D04BA5863E8AD08C36B52F80 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAC86E60B1B850059BC54 /* Localizable.strings */; }; D04BA6187A91A847844B6ABB /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA015A45DE7AFDC9794FE /* Window.swift */; }; + D04BA69012A483201B375D46 /* ACKNOWLEDGMENTS.md in Resources */ = {isa = PBXBuildFile; fileRef = D04BAADF01EB8FF8A15AECC6 /* ACKNOWLEDGMENTS.md */; }; D04BA691CB6082A3C39CBC89 /* TabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAE757BB2B605234FBF58 /* TabViewController.swift */; }; D04BA69D47B5E60A6AD9CBD9 /* ThumbnailTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD1297730B191E96E7FE /* ThumbnailTitleView.swift */; }; D04BA737008AA2CD4E230A21 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA10777505D8A67ABD186 /* Application.swift */; }; @@ -45,11 +46,13 @@ D04BA76A74267B1346D23687 /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA6D57A1456C07318B8EA /* GridView.swift */; }; D04BA775CF3F8D9394A1E256 /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA68C2561D9EE4FD851B8 /* Screen.swift */; }; D04BA78B5D288BF072050C43 /* Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAA857B1AB33FBCC59A86 /* Keyboard.swift */; }; + D04BA7B8D599E1A7A27FF5AE /* AcknowledgmentsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA788228BA86D9EFBD1ED /* AcknowledgmentsTab.swift */; }; D04BA7BE7F3DD24D58ACE942 /* AppearanceTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA64F1F344007EA13BA05 /* AppearanceTab.swift */; }; D04BA7F86F1926FBE31F44BF /* BaseLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA53992F116E5E704CAB3 /* BaseLabel.swift */; }; D04BA8092885B40CE3527370 /* UpdatesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD60C97E609A759E721E /* UpdatesTab.swift */; }; D04BA8480A8FF466CA89DA5B /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA70746DEEC3D30B43F81 /* main.swift */; }; D04BA867733CC32975EEDA7B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA64436BF69C58372968C /* InfoPlist.strings */; }; + D04BA8757C9F20F25EB50785 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA5BD11C365C19461458C /* TextField.swift */; }; D04BA8D6055F6F2E42C976EA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA5DE6536C4A6558FD80C /* InfoPlist.strings */; }; D04BA9557A6C9E192D228150 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA2C08725A5F2C34EB809 /* InfoPlist.strings */; }; D04BAABE804F3769CE22BEB6 /* HyperlinkLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA49E45BFFF3D9FC60E43 /* HyperlinkLabel.swift */; }; @@ -69,7 +72,6 @@ D04BAD2A7F2E8BF64EE982E9 /* TextArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA7C836A8CE8C0B8D128B /* TextArea.swift */; }; D04BAD451966B43720120D2E /* Menubar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD905546AA93E5117B0A /* Menubar.swift */; }; D04BADADBE35CA2E78483F72 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA6EC52A66DFFD4DF79C1 /* Localizable.strings */; }; - D04BADBA0F0146443761D778 /* ACKNOWLEDGMENTS.md in Resources */ = {isa = PBXBuildFile; fileRef = D04BAADF01EB8FF8A15AECC6 /* ACKNOWLEDGMENTS.md */; }; D04BADBCF20CD72057E7CF09 /* TabViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA27C87B86C4484A5B15B /* TabViewItem.swift */; }; D04BADCDA9F9A6C3D6499877 /* SystemPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA7C6F2519091717F4B4E /* SystemPermissions.swift */; }; D04BAE6A13DBAE85B8F7CB6A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BABF92E92F093C18BB1A1 /* Localizable.strings */; }; @@ -130,6 +132,7 @@ D04BA53992F116E5E704CAB3 /* BaseLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseLabel.swift; sourceTree = ""; }; D04BA55D1B2C8BFF61954466 /* generate_selfsigned_certificate.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = generate_selfsigned_certificate.sh; sourceTree = ""; }; D04BA5ABFA5457A86536E2E4 /* 5 windows - 1 line.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "5 windows - 1 line.jpg"; sourceTree = ""; }; + D04BA5BD11C365C19461458C /* TextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = ""; }; D04BA5C401AFA55CC67C7188 /* PrivateApis.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateApis.swift; sourceTree = ""; }; D04BA5C8373D1480280B71A6 /* tr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = tr; path = InfoPlist.strings; sourceTree = ""; }; D04BA5D2FD6E26D82721C574 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = InfoPlist.strings; sourceTree = ""; }; @@ -144,6 +147,7 @@ D04BA6EF1954DCE80E539142 /* base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = ""; }; D04BA6F823BC0EDA9AA4B80A /* AXUIElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AXUIElement.swift; sourceTree = ""; }; D04BA70746DEEC3D30B43F81 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + D04BA788228BA86D9EFBD1ED /* AcknowledgmentsTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AcknowledgmentsTab.swift; sourceTree = ""; }; D04BA7957E5E02FB09BCE10C /* de */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = de; path = InfoPlist.strings; sourceTree = ""; }; D04BA7C25BD7B68BCEEE38B5 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = ""; }; D04BA7C6F2519091717F4B4E /* SystemPermissions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SystemPermissions.swift; sourceTree = ""; }; @@ -362,6 +366,7 @@ D04BA4A26987F67DD94C827F /* AboutTab.swift */, D04BACE22DC907F03D193075 /* GeneralTab.swift */, D04BAD60C97E609A759E721E /* UpdatesTab.swift */, + D04BA788228BA86D9EFBD1ED /* AcknowledgmentsTab.swift */, ); path = tabs; sourceTree = ""; @@ -538,6 +543,7 @@ D04BA49E45BFFF3D9FC60E43 /* HyperlinkLabel.swift */, D04BA7C836A8CE8C0B8D128B /* TextArea.swift */, D04BA53992F116E5E704CAB3 /* BaseLabel.swift */, + D04BA5BD11C365C19461458C /* TextField.swift */, ); path = text; sourceTree = ""; @@ -727,7 +733,7 @@ D04BAE6A13DBAE85B8F7CB6A /* Localizable.strings in Resources */, D04BA867733CC32975EEDA7B /* InfoPlist.strings in Resources */, D04BA5863E8AD08C36B52F80 /* Localizable.strings in Resources */, - D04BADBA0F0146443761D778 /* ACKNOWLEDGMENTS.md in Resources */, + D04BA69012A483201B375D46 /* ACKNOWLEDGMENTS.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -785,6 +791,7 @@ "${BUILT_PRODUCTS_DIR}/ShortcutRecorder/ShortcutRecorder.framework", "${PODS_ROOT}/Sparkle/Sparkle.framework", "${PODS_ROOT}/Sparkle/Sparkle.framework.dSYM", + "${BUILT_PRODUCTS_DIR}/SwiftyMarkdown/SwiftyMarkdown.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( @@ -792,6 +799,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ShortcutRecorder.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sparkle.framework", "${DWARF_DSYM_FOLDER_PATH}/Sparkle.framework.dSYM", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyMarkdown.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -846,6 +854,8 @@ D04BA1621718FF26F8D5E75D /* UnclearableRecorderControl.swift in Sources */, D04BA78B5D288BF072050C43 /* Keyboard.swift in Sources */, D04BA1637E125D38546C26E2 /* StackView.swift in Sources */, + D04BA7B8D599E1A7A27FF5AE /* AcknowledgmentsTab.swift in Sources */, + D04BA8757C9F20F25EB50785 /* TextField.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/docs/ACKNOWLEDGMENTS.md b/docs/ACKNOWLEDGMENTS.md index 59a5aebd..cfa780c1 100644 --- a/docs/ACKNOWLEDGMENTS.md +++ b/docs/ACKNOWLEDGMENTS.md @@ -1,4 +1,3 @@ -# Acknowledgements This application makes use of the following third party libraries: ## ShortcutRecorder @@ -14,7 +13,6 @@ these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. - Section 1 -- Definitions. a. Adapted Material means material subject to Copyright and Similar @@ -78,83 +76,81 @@ Section 1 -- Definitions. k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. - Section 2 -- Scope. a. License grant. - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: - a. reproduce and Share the Licensed Material, in whole or - in part; and + a. reproduce and Share the Licensed Material, in whole or + in part; and - b. produce, reproduce, and Share Adapted Material. + b. produce, reproduce, and Share Adapted Material. - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. - 3. Term. The term of this Public License is specified in Section - 6(a). + 3. Term. The term of this Public License is specified in Section + 6(a). - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. - 5. Downstream recipients. + 5. Downstream recipients. - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. - b. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). b. Other rights. - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. + 2. Patent and trademark rights are not licensed under this + Public License. + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. Section 3 -- License Conditions. @@ -163,50 +159,49 @@ following conditions. a. Attribution. - 1. If You Share the Licensed Material (including in modified - form), You must: + 1. If You Share the Licensed Material (including in modified + form), You must: - a. retain the following if it is supplied by the Licensor - with the Licensed Material: + a. retain the following if it is supplied by the Licensor + with the Licensed Material: - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); - ii. a copyright notice; + ii. a copyright notice; - iii. a notice that refers to this Public License; + iii. a notice that refers to this Public License; - iv. a notice that refers to the disclaimer of - warranties; + iv. a notice that refers to the disclaimer of + warranties; - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - 4. If You Share Adapted Material You produce, the Adapter's - License You apply must not prevent recipients of the Adapted - Material from complying with this Public License. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. Section 4 -- Sui Generis Database Rights. @@ -229,7 +224,6 @@ For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. - Section 5 -- Disclaimer of Warranties and Limitation of Liability. a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE @@ -258,7 +252,6 @@ Section 5 -- Disclaimer of Warranties and Limitation of Liability. possible, most closely approximates an absolute disclaimer and waiver of all liability. - Section 6 -- Term and Termination. a. This Public License applies for the term of the Copyright and @@ -269,11 +262,11 @@ Section 6 -- Term and Termination. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or - 2. upon express reinstatement by the Licensor. + 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations @@ -287,7 +280,6 @@ Section 6 -- Term and Termination. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. - Section 7 -- Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different @@ -297,7 +289,6 @@ Section 7 -- Other Terms and Conditions. Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. - Section 8 -- Interpretation. a. For the avoidance of doubt, this Public License does not, and @@ -321,7 +312,6 @@ Section 8 -- Interpretation. that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. - ======================================================================= Creative Commons is not a party to its public @@ -341,7 +331,6 @@ understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. - ## Sparkle Copyright (c) 2006-2013 Andy Matuschak. @@ -406,4 +395,28 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +## SwiftyMarkdown + +The MIT License (MIT) + +Copyright (c) 2016 Simon Fairbairn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + Generated by CocoaPods - https://cocoapods.org diff --git a/src/ui/FeedbackWindow.swift b/src/ui/FeedbackWindow.swift index 5b7eca84..30d1d729 100644 --- a/src/ui/FeedbackWindow.swift +++ b/src/ui/FeedbackWindow.swift @@ -45,13 +45,13 @@ class FeedbackWindow: NSWindow { sendButton, ]) buttons.spacing = GridView.interPadding - body = TextArea(80, 12, NSLocalizedString("I think the app could be improved with…", comment: ""), { + body = TextArea(80, 12, NSLocalizedString("I think the app could be improved with…", comment: ""), { () -> Void in self.sendButton.isEnabled = !self.body.stringValue.isEmpty }) email = TextArea(80, 1, NSLocalizedString("Optional: email (if you want a reply)", comment: "")) debugProfile = NSButton(checkboxWithTitle: NSLocalizedString("Send debug profile (CPU, memory, etc)", comment: ""), target: nil, action: nil) debugProfile.state = .on - let view = GridView.make([ + let view = GridView([ [header], [body], [email], diff --git a/src/ui/generic-components/GridView.swift b/src/ui/generic-components/GridView.swift index aba8e5de..9c58741f 100644 --- a/src/ui/generic-components/GridView.swift +++ b/src/ui/generic-components/GridView.swift @@ -1,21 +1,19 @@ import Cocoa -class GridView { +class GridView: NSGridView { static let padding = CGFloat(20) static let interPadding = CGFloat(10) - static let indentPadding = padding * 2 - static func make(_ controls: [[NSView]]) -> NSGridView { - let gridView = NSGridView(views: controls) - gridView.translatesAutoresizingMaskIntoConstraints = false - gridView.yPlacement = .fill - gridView.rowAlignment = .firstBaseline - gridView.columnSpacing = interPadding - gridView.rowSpacing = interPadding - gridView.column(at: 0).leadingPadding = padding - gridView.column(at: gridView.numberOfColumns - 1).trailingPadding = padding - gridView.row(at: 0).topPadding = padding - gridView.row(at: gridView.numberOfRows - 1).bottomPadding = padding - return gridView + convenience init(_ controls: [[NSView]]) { + self.init(views: controls) + translatesAutoresizingMaskIntoConstraints = false + yPlacement = .fill + rowAlignment = .firstBaseline + columnSpacing = GridView.interPadding + rowSpacing = GridView.interPadding + column(at: 0).leadingPadding = GridView.padding + column(at: numberOfColumns - 1).trailingPadding = GridView.padding + row(at: 0).topPadding = GridView.padding + row(at: numberOfRows - 1).bottomPadding = GridView.padding } } diff --git a/src/ui/generic-components/text/TextField.swift b/src/ui/generic-components/text/TextField.swift new file mode 100644 index 00000000..099b1d81 --- /dev/null +++ b/src/ui/generic-components/text/TextField.swift @@ -0,0 +1,12 @@ +import Cocoa + +class TextField: NSTextField { + let insets = NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) + + convenience init(_ attributedString: NSAttributedString) { + self.init(labelWithAttributedString: attributedString) + } + + // NSTextField has 2px insets left and right by default; we remove those + override var alignmentRectInsets: NSEdgeInsets { insets } +} diff --git a/src/ui/main-window/ThumbnailsView.swift b/src/ui/main-window/ThumbnailsView.swift index 20570846..1e7752f7 100644 --- a/src/ui/main-window/ThumbnailsView.swift +++ b/src/ui/main-window/ThumbnailsView.swift @@ -29,8 +29,8 @@ class ThumbnailsView: NSVisualEffectView { guard window.shouldShowTheUser else { continue } let view = ThumbnailsView.recycledViews[index] view.updateRecycledCellWithNewContent(window, - { App.app.focusSelectedWindow(window) }, - { Windows.updateFocusedWindowIndex(index) }, + { () -> Void in App.app.focusSelectedWindow(window) }, + { () -> Void in Windows.updateFocusedWindowIndex(index) }, height, screen) let width = view.frame.size.width if (currentX + Preferences.interCellPadding + width).rounded(.down) > widthMax { diff --git a/src/ui/preferences-window/PreferencesWindow.swift b/src/ui/preferences-window/PreferencesWindow.swift index 388cc8bd..45ab0f8f 100644 --- a/src/ui/preferences-window/PreferencesWindow.swift +++ b/src/ui/preferences-window/PreferencesWindow.swift @@ -17,10 +17,11 @@ class PreferencesWindow: NSWindow { private func setupTabViews() { contentViewController = tabViewController tabViewController.tabStyle = .toolbar - tabViewController.addTabViewItem(GeneralTab.make()) - tabViewController.addTabViewItem(AppearanceTab.make()) - tabViewController.addTabViewItem(UpdatesTab.make()) - tabViewController.addTabViewItem(AboutTab.make()) + tabViewController.addTabViewItem(TabViewItem(NSLocalizedString("General", comment: ""), NSImage.preferencesGeneralName, GeneralTab.makeView())) + tabViewController.addTabViewItem(TabViewItem(NSLocalizedString("Appearance", comment: ""), NSImage.colorPanelName, AppearanceTab.makeView())) + tabViewController.addTabViewItem(TabViewItem(NSLocalizedString("Updates", comment: ""), NSImage.refreshTemplateName, UpdatesTab.makeView())) + tabViewController.addTabViewItem(TabViewItem(NSLocalizedString("About", comment: ""), NSImage.infoName, AboutTab.makeView())) + tabViewController.addTabViewItem(TabViewItem(NSLocalizedString("Acknowledgments", comment: ""), NSImage.userAccountsName, AcknowledgmentsTab.makeView())) } func show() { diff --git a/src/ui/preferences-window/TabViewItem.swift b/src/ui/preferences-window/TabViewItem.swift index b7282c3b..d3f92a5f 100644 --- a/src/ui/preferences-window/TabViewItem.swift +++ b/src/ui/preferences-window/TabViewItem.swift @@ -1,12 +1,11 @@ import Cocoa -class TabViewItem { - static func make(_ label: String, _ imageNAme: NSImage.Name, _ view: NSView) -> NSTabViewItem { +class TabViewItem: NSTabViewItem { + convenience init(_ label: String, _ imageName: NSImage.Name, _ view: NSView) { let viewController = NSViewController() - let tabViewItem = NSTabViewItem(viewController: viewController) + self.init(viewController: viewController) viewController.view = view - tabViewItem.label = label - tabViewItem.image = NSImage(named: imageNAme) - return tabViewItem + self.label = label + image = NSImage(named: imageName) } } diff --git a/src/ui/preferences-window/tabs/AboutTab.swift b/src/ui/preferences-window/tabs/AboutTab.swift index 77f74df1..c44773c0 100644 --- a/src/ui/preferences-window/tabs/AboutTab.swift +++ b/src/ui/preferences-window/tabs/AboutTab.swift @@ -1,10 +1,6 @@ import Cocoa class AboutTab: NSObject { - static func make() -> NSTabViewItem { - return TabViewItem.make(NSLocalizedString("About", comment: ""), NSImage.infoName, makeView()) - } - static func makeView() -> NSGridView { let appIcon = NSImageView(image: NSImage(named: "app-icon")!.resizedCopy(150, 150)) appIcon.imageScaling = .scaleNone @@ -22,7 +18,7 @@ class AboutTab: NSObject { appInfo.spacing = GridView.interPadding appInfo.alignment = .centerY let sendFeedback = NSButton(title: NSLocalizedString("Send feedback…", comment: ""), target: self, action: #selector(feedbackCallback)) - let grid = GridView.make([ + let grid = GridView([ [appInfo], [sendFeedback], ]) diff --git a/src/ui/preferences-window/tabs/AcknowledgmentsTab.swift b/src/ui/preferences-window/tabs/AcknowledgmentsTab.swift new file mode 100644 index 00000000..df7c4fc7 --- /dev/null +++ b/src/ui/preferences-window/tabs/AcknowledgmentsTab.swift @@ -0,0 +1,23 @@ +import Cocoa +import SwiftyMarkdown + +class AcknowledgmentsTab: NSObject { + static func makeView() -> NSGridView { + let markdownFileUrl = Bundle.main.url(forResource: "ACKNOWLEDGMENTS", withExtension: "md")! + let md = SwiftyMarkdown(url: markdownFileUrl)! + md.h2.fontSize = 20 + let textView = TextField(md.attributedString()) + + let scrollView = ScrollView() + scrollView.scrollerKnobStyle = .default + scrollView.documentView!.subviews = [textView] + scrollView.frame.size = NSSize(width: textView.fittingSize.width, height: textView.fittingSize.width) + scrollView.contentView.frame.size = textView.fittingSize + scrollView.documentView!.frame.size = textView.fittingSize + scrollView.fit(textView.fittingSize.width, textView.fittingSize.width) + + let grid = GridView([[scrollView]]) + grid.fit() + return grid + } +} diff --git a/src/ui/preferences-window/tabs/AppearanceTab.swift b/src/ui/preferences-window/tabs/AppearanceTab.swift index f7c5b2b7..21a6b9b1 100644 --- a/src/ui/preferences-window/tabs/AppearanceTab.swift +++ b/src/ui/preferences-window/tabs/AppearanceTab.swift @@ -3,12 +3,8 @@ import Cocoa class AppearanceTab { private static let rowHeight = CGFloat(20) - static func make() -> NSTabViewItem { - return TabViewItem.make(NSLocalizedString("Appearance", comment: ""), NSImage.colorPanelName, makeView()) - } - - private static func makeView() -> NSGridView { - let grid = GridView.make([ + static func makeView() -> NSGridView { + let grid = GridView([ LabelAndControl.makeLabelWithDropdown(NSLocalizedString("Theme", comment: ""), "theme", ThemePreference.allCases), LabelAndControl.makeLabelWithDropdown(NSLocalizedString("Align windows", comment: ""), "alignThumbnails", AlignThumbnailsPreference.allCases), LabelAndControl.makeLabelWithSlider(NSLocalizedString("Max size on screen", comment: ""), "maxScreenUsage", 10, 100, 10, true, "%"), diff --git a/src/ui/preferences-window/tabs/GeneralTab.swift b/src/ui/preferences-window/tabs/GeneralTab.swift index 5b6a52b5..c76b3bfa 100644 --- a/src/ui/preferences-window/tabs/GeneralTab.swift +++ b/src/ui/preferences-window/tabs/GeneralTab.swift @@ -6,11 +6,7 @@ class GeneralTab { static var shortcutActions = [String: ShortcutAction]() static var shortcutsDependentOnHoldShortcut = [NSControl]() - static func make() -> NSTabViewItem { - return TabViewItem.make(NSLocalizedString("General", comment: ""), NSImage.preferencesGeneralName, makeView()) - } - - private static func makeView() -> NSView { + static func makeView() -> NSView { let startAtLogin = LabelAndControl.makeLabelWithCheckbox(NSLocalizedString("Start at login", comment: ""), "startAtLogin", extraAction: startAtLoginCallback) var holdShortcut = LabelAndControl.makeLabelWithRecorder(NSLocalizedString("Hold", comment: ""), "holdShortcut", Preferences.holdShortcut, true, labelPosition: .leftWithoutSeparator) holdShortcut.append(LabelAndControl.makeLabel(NSLocalizedString("then press:", comment: ""))) @@ -33,7 +29,7 @@ class GeneralTab { let toShowExplanations = LabelAndControl.makeLabel(NSLocalizedString("Show the following windows:", comment: "")) let toShow = StackView([toShowDropdowns, toShowCheckboxes], .vertical) - let grid = GridView.make([ + let grid = GridView([ startAtLogin, [holdAndPress, shortcuts], [checkboxesExplanations, checkboxes], diff --git a/src/ui/preferences-window/tabs/UpdatesTab.swift b/src/ui/preferences-window/tabs/UpdatesTab.swift index 03926fe1..804fbd31 100644 --- a/src/ui/preferences-window/tabs/UpdatesTab.swift +++ b/src/ui/preferences-window/tabs/UpdatesTab.swift @@ -9,16 +9,12 @@ class UpdatesTab: NSObject { // this helps prevent double-dipping (i.e. user updates the UI > changes the preference > updates the UI) static var policyLock = false - static func make() -> NSTabViewItem { - return TabViewItem.make(NSLocalizedString("Updates", comment: ""), NSImage.refreshTemplateName, makeView()) - } - static func observeUserDefaults() { UserDefaults.standard.addObserver(UpdatesTab.policyObserver, forKeyPath: "SUAutomaticallyUpdate", options: [.initial, .new], context: nil) UserDefaults.standard.addObserver(UpdatesTab.policyObserver, forKeyPath: "SUEnableAutomaticChecks", options: [.initial, .new], context: nil) } - static private func makeView() -> NSGridView { + static func makeView() -> NSGridView { dontPeriodicallyCheck = NSButton(radioButtonWithTitle: NSLocalizedString("Don't check for updates periodically", comment: ""), target: self, action: #selector(updatePolicyCallback)) dontPeriodicallyCheck.fit() periodicallyCheck = NSButton(radioButtonWithTitle: NSLocalizedString("Check for updates periodically", comment: ""), target: self, action: #selector(updatePolicyCallback)) @@ -30,7 +26,7 @@ class UpdatesTab: NSObject { policies.alignment = .left policies.orientation = .vertical policies.spacing = GridView.interPadding / 2 - let grid = GridView.make([ + let grid = GridView([ [policyLabel, policies], [NSButton(title: NSLocalizedString("Check for updates now…", comment: ""), target: self, action: #selector(checkForUpdatesNow))], ])