├── 1 ├── .DS_Store ├── .github ├── ISSUE_TEMPLATE │ └── feature_request.md └── workflows │ ├── iOS-test.yml │ └── macOS-test.yml ├── .gitignore ├── .swift-version ├── .swiftformat.yml ├── .swiftlint.yml ├── CODE_OF_CONDUCT.md ├── Fragment--iOS--Info.plist ├── Fragment--macOS--Info.plist ├── Fragment-iOS-Tests └── Fragment_iOS_Tests.swift ├── Fragment-macOS-Tests └── Fragment_macOS_Tests.swift ├── Fragment.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcuserdata │ │ └── danhart.xcuserdatad │ │ └── IDEFindNavigatorScopes.plist ├── xcshareddata │ ├── xcbaselines │ │ ├── 52BABB4327E7DE1900999F01.xcbaseline │ │ │ ├── 21B39069-B75E-4407-A8FF-E868E50C66DA.plist │ │ │ └── Info.plist │ │ └── 52BABB5227E7DE3300999F01.xcbaseline │ │ │ ├── AE7DEE5B-077D-4779-9906-03EA21164357.plist │ │ │ └── Info.plist │ └── xcschemes │ │ ├── iOS.xcscheme │ │ └── macOS.xcscheme └── xcuserdata │ ├── danhart.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ └── xcschememanagement.plist │ └── dhart.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── FragmentSharedTests └── TestApp.swift ├── LICENSE.md ├── README.md ├── Shared ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon-macOS.appiconset │ │ ├── Contents.json │ │ ├── Icon-1025.png │ │ ├── Icon-128.png │ │ ├── Icon-256.png │ │ ├── Icon-257.png │ │ ├── Icon-32.png │ │ ├── Icon-33.png │ │ ├── Icon-512.png │ │ ├── Icon-513.png │ │ └── Icon-65.png │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── switchify_icon_v01-1024.png │ │ ├── switchify_icon_v01-20.png │ │ ├── switchify_icon_v01-20@2x.png │ │ ├── switchify_icon_v01-20@3x.png │ │ ├── switchify_icon_v01-29.png │ │ ├── switchify_icon_v01-29@2x.png │ │ ├── switchify_icon_v01-29@3x.png │ │ ├── switchify_icon_v01-40.png │ │ ├── switchify_icon_v01-40@2x.png │ │ ├── switchify_icon_v01-40@3x.png │ │ ├── switchify_icon_v01-60@2x.png │ │ ├── switchify_icon_v01-60@3x.png │ │ ├── switchify_icon_v01-76.png │ │ ├── switchify_icon_v01-76@2x.png │ │ └── switchify_icon_v01-83.5@2x.png │ └── Contents.json ├── ClipboardHelper.swift ├── Constants.swift ├── Extensions │ ├── Collections+ifExistsAt.swift │ └── OctoKitExtensions │ │ └── GistExtensions │ │ ├── Gist+Custom.swift │ │ ├── Gist+language.swift │ │ └── Gist+text.swift ├── Fragment.xcdatamodeld │ ├── .xccurrentversion │ └── Shared.xcdatamodel │ │ └── contents ├── FragmentApp.swift ├── Handler │ └── SessionHandler.swift ├── Models │ ├── Errors │ │ └── FragmentError.swift │ ├── Language.swift │ └── Visibility.swift ├── Views │ ├── Add │ │ └── AddGistView.swift │ ├── AuthenticationView.swift │ ├── CodeViews │ │ └── CodeView.swift │ ├── Container │ │ ├── ContainerView.swift │ │ └── ListView.swift │ ├── GistViews │ │ └── GistRow.swift │ ├── MainView.swift │ ├── SettingsView.swift │ └── Support │ │ └── SupportThisAppView.swift └── WebLauncher.swift ├── Sourceless └── 2011B4FA-8E52-4464-A976-76AA07DBDDE7.json ├── autocommit.sh └── macOS └── macOS.entitlements /1: -------------------------------------------------------------------------------- 1 | Merge branch 'main' of https://github.com/dan-hart/Fragment 2 | # Please enter a commit message to explain why this merge is necessary, 3 | # especially if it merges an updated upstream into a topic branch. 4 | # 5 | # Lines starting with '#' will be ignored, and an empty message aborts 6 | # the commit. 7 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/.DS_Store -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | 22 | [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/codedbydan) 23 | -------------------------------------------------------------------------------- /.github/workflows/iOS-test.yml: -------------------------------------------------------------------------------- 1 | name: ios tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: macos-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Run ios tests 11 | run: xcodebuild test -destination 'name=iPhone 13' -scheme 'iOS' -enableCodeCoverage YES 12 | - name: Upload coverage to Codecov 13 | run: bash <(curl -s https://codecov.io/bash) -J 'Fragment' 14 | - uses: sarisia/actions-status-discord@v1 15 | if: always() 16 | with: 17 | webhook: ${{ secrets.DISCORD_WEBHOOK }} 18 | title: "iOS tests" 19 | description: "Run all iOS tests" 20 | username: Github 21 | avatar_url: ${{ secrets.AVATAR_URL }} 22 | -------------------------------------------------------------------------------- /.github/workflows/macOS-test.yml: -------------------------------------------------------------------------------- 1 | name: macOS tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: macos-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Run macOS tests 11 | run: xcodebuild test -scheme 'macOS' -enableCodeCoverage YES 12 | - name: Upload coverage to Codecov 13 | run: bash <(curl -s https://codecov.io/bash) -J 'Fragment' 14 | - uses: sarisia/actions-status-discord@v1 15 | if: always() 16 | with: 17 | webhook: ${{ secrets.DISCORD_WEBHOOK }} 18 | title: "iOS tests" 19 | description: "Run all macOS tests" 20 | username: Github 21 | avatar_url: ${{ secrets.AVATAR_URL }} 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | .DS_Store 5 | 6 | ## User settings 7 | xcuserdata/ 8 | 9 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 10 | *.xcscmblueprint 11 | *.xccheckout 12 | 13 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 14 | build/ 15 | DerivedData/ 16 | *.moved-aside 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | 29 | ## App packaging 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | # Packages/ 42 | # Package.pins 43 | # Package.resolved 44 | # *.xcodeproj 45 | # 46 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 47 | # hence it is not needed unless you have added a package configuration file to your project 48 | # .swiftpm 49 | 50 | .build/ 51 | 52 | # CocoaPods 53 | # 54 | # We recommend against adding the Pods directory to your .gitignore. However 55 | # you should judge for yourself, the pros and cons are mentioned at: 56 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 57 | # 58 | # Pods/ 59 | # 60 | # Add this line if you want to avoid checking in source code from the Xcode workspace 61 | # *.xcworkspace 62 | 63 | # Carthage 64 | # 65 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 66 | # Carthage/Checkouts 67 | 68 | Carthage/Build/ 69 | 70 | # Accio dependency management 71 | Dependencies/ 72 | .accio/ 73 | 74 | # fastlane 75 | # 76 | # It is recommended to not store the screenshots in the git repo. 77 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 78 | # For more information about the recommended setup visit: 79 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 80 | 81 | fastlane/report.xml 82 | fastlane/Preview.html 83 | fastlane/screenshots/**/*.png 84 | fastlane/test_output 85 | 86 | # Code Injection 87 | # 88 | # After new code Injection tools there's a generated folder /iOSInjectionProject 89 | # https://github.com/johnno1962/injectionforxcode 90 | 91 | iOSInjectionProject/ -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /.swiftformat.yml: -------------------------------------------------------------------------------- 1 | # See: https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md 2 | 3 | --swiftversion 5.0 4 | 5 | # format options 6 | --indent 4 7 | --wraparguments after-first 8 | --wrapparameters after-first 9 | --wrapcollections before-first 10 | --funcattributes same-line 11 | --typeattributes same-line 12 | --groupedextension MARK: - %c 13 | --categorymark MARK: - %c 14 | --lineaftermarks false 15 | 16 | # opt-in 17 | --enable \ 18 | modifierorder, \ 19 | acronyms, \ 20 | andOperator, \ 21 | blankLinesBetweenImports, \ 22 | blockComments, \ 23 | isEmpty, \ 24 | markTypes, \ 25 | organizeDeclarations, \ 26 | sortedSwitchCases, \ 27 | wrapConditionalBodies, \ 28 | wrapEnumCases, \ 29 | wrapSwitchCases 30 | 31 | # rules 32 | --disable \ 33 | blankLinesAroundMark, \ 34 | emptyBraces, \ 35 | linebreakAtEndOfFile, \ 36 | unusedArguments, \ 37 | wrapMultilineStatementBraces 38 | 39 | # See: https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md 40 | 41 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | # https://realm.github.io/SwiftLint/rule-directory.html 2 | 3 | opt_in_rules: 4 | - fatal_error_message 5 | - collection_alignment 6 | - empty_count 7 | - contains_over_filter_count 8 | - convenience_type 9 | - discarded_notification_center_observer 10 | - discouraged_assert 11 | - discouraged_object_literal 12 | - empty_collection_literal 13 | - empty_string 14 | - empty_xctest_method 15 | - file_name_no_space 16 | - function_default_parameter_at_end 17 | - ibinspectable_in_extension 18 | - identical_operands 19 | - implicitly_unwrapped_optional 20 | - missing_docs 21 | - modifier_order 22 | - multiline_arguments 23 | - multiline_parameters 24 | - orphaned_doc_comment 25 | - overridden_super_call # Very important to remember to call super.viewDidLoad() etc. 26 | - override_in_extension 27 | - redundant_nil_coalescing 28 | - redundant_type_annotation 29 | - strong_iboutlet 30 | - unneeded_parentheses_in_closure_argument 31 | - unused_import 32 | - yoda_condition 33 | 34 | disabled_rules: 35 | - function_parameter_count 36 | - statement_position 37 | - trailing_comma 38 | - unused_closure_parameter 39 | - closure_parameter_position 40 | - class_delegate_protocol 41 | - compiler_protocol_init 42 | - reduce_boolean 43 | - multiple_closures_with_trailing_closure 44 | - no_space_in_method_call 45 | - type_name 46 | - opening_brace 47 | - line_length 48 | 49 | # https://realm.github.io/SwiftLint/rule-directory.html 50 | 51 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | conduct@codedbydan.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /Fragment--iOS--Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIconName 6 | AppIcon 7 | ITSAppUsesNonExemptEncryption 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Fragment--macOS--Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIconName 6 | AppIcon-macOS 7 | ITSAppUsesNonExemptEncryption 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Fragment-iOS-Tests/Fragment_iOS_Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Fragment_iOS_Tests.swift 3 | // Fragment-iOS-Tests 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | @testable import Fragment 9 | import XCTest 10 | 11 | class Fragment_iOS_Tests: XCTestCase { 12 | func testApp() { 13 | TestApp.appTest() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Fragment-macOS-Tests/Fragment_macOS_Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Fragment_macOS_Tests.swift 3 | // Fragment-macOS-Tests 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | @testable import Fragment 9 | import XCTest 10 | 11 | class Fragment_macOS_Tests: XCTestCase { 12 | func testApp() { 13 | TestApp.appTest() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 522915B227E778300087530C /* GistRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522915B127E778300087530C /* GistRow.swift */; }; 11 | 522915B327E778300087530C /* GistRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522915B127E778300087530C /* GistRow.swift */; }; 12 | 522915C027E789E20087530C /* OctoKit in Frameworks */ = {isa = PBXBuildFile; productRef = 522915BF27E789E20087530C /* OctoKit */; }; 13 | 5254DDFF27EF8224005BAC56 /* SFSafeSymbols in Frameworks */ = {isa = PBXBuildFile; productRef = 5254DDFE27EF8224005BAC56 /* SFSafeSymbols */; }; 14 | 5254DE0127EF8331005BAC56 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5254DE0027EF8331005BAC56 /* Constants.swift */; }; 15 | 5254DE0227EF8331005BAC56 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5254DE0027EF8331005BAC56 /* Constants.swift */; }; 16 | 5254DE0427EF837A005BAC56 /* SFSafeSymbols in Frameworks */ = {isa = PBXBuildFile; productRef = 5254DE0327EF837A005BAC56 /* SFSafeSymbols */; }; 17 | 525D85E227E760A60066B147 /* FragmentApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525D85B727E760A40066B147 /* FragmentApp.swift */; }; 18 | 525D85E327E760A60066B147 /* FragmentApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525D85B727E760A40066B147 /* FragmentApp.swift */; }; 19 | 525D860327E7621D0066B147 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525D860227E7621D0066B147 /* MainView.swift */; }; 20 | 525D860527E762610066B147 /* ContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525D860427E762610066B147 /* ContainerView.swift */; }; 21 | 525D860827E762B40066B147 /* OctoKit in Frameworks */ = {isa = PBXBuildFile; productRef = 525D860727E762B40066B147 /* OctoKit */; }; 22 | 525D860927E763B50066B147 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525D860227E7621D0066B147 /* MainView.swift */; }; 23 | 525D860A27E763B80066B147 /* ContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525D860427E762610066B147 /* ContainerView.swift */; }; 24 | 526D97C327F0C25B00BD46CE /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 526D97C227F0C25B00BD46CE /* KeychainAccess */; }; 25 | 526D97C527F0C26600BD46CE /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 526D97C427F0C26600BD46CE /* KeychainAccess */; }; 26 | 526D97C827F0C5BE00BD46CE /* Highlightr in Frameworks */ = {isa = PBXBuildFile; productRef = 526D97C727F0C5BE00BD46CE /* Highlightr */; }; 27 | 526D97CA27F0C5C500BD46CE /* Highlightr in Frameworks */ = {isa = PBXBuildFile; productRef = 526D97C927F0C5C500BD46CE /* Highlightr */; }; 28 | 526D97D427F0C82D00BD46CE /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526D97D227F0C82D00BD46CE /* Language.swift */; }; 29 | 526D97DE27F0CA8600BD46CE /* Gist+text.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526D97DD27F0CA8600BD46CE /* Gist+text.swift */; }; 30 | 526D97DF27F0CA8600BD46CE /* Gist+text.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526D97DD27F0CA8600BD46CE /* Gist+text.swift */; }; 31 | 526D97E127F0CBCC00BD46CE /* CodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526D97E027F0CBCC00BD46CE /* CodeView.swift */; }; 32 | 526D97E227F0CBCC00BD46CE /* CodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526D97E027F0CBCC00BD46CE /* CodeView.swift */; }; 33 | 52769DEE27F0CD4C00F5D4E0 /* Gist+language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769DED27F0CD4C00F5D4E0 /* Gist+language.swift */; }; 34 | 52769DEF27F0CD4C00F5D4E0 /* Gist+language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769DED27F0CD4C00F5D4E0 /* Gist+language.swift */; }; 35 | 52769DF027F0D0CB00F5D4E0 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526D97D227F0C82D00BD46CE /* Language.swift */; }; 36 | 52769DFC27F0E83300F5D4E0 /* Collections+ifExistsAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769DFB27F0E83300F5D4E0 /* Collections+ifExistsAt.swift */; }; 37 | 52769DFD27F0E83300F5D4E0 /* Collections+ifExistsAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769DFB27F0E83300F5D4E0 /* Collections+ifExistsAt.swift */; }; 38 | 52769E0027F0EEE400F5D4E0 /* Visibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769DFF27F0EEE400F5D4E0 /* Visibility.swift */; }; 39 | 52769E0127F0EEE400F5D4E0 /* Visibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769DFF27F0EEE400F5D4E0 /* Visibility.swift */; }; 40 | 52769E0327F0F06900F5D4E0 /* AddGistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769E0227F0F06900F5D4E0 /* AddGistView.swift */; }; 41 | 52769E0427F0F06900F5D4E0 /* AddGistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769E0227F0F06900F5D4E0 /* AddGistView.swift */; }; 42 | 52769E0627F0FE6A00F5D4E0 /* WebLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769E0527F0FE6A00F5D4E0 /* WebLauncher.swift */; }; 43 | 52769E0727F0FE6A00F5D4E0 /* WebLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52769E0527F0FE6A00F5D4E0 /* WebLauncher.swift */; }; 44 | 5283B2E327EC0C240018F19B /* AuthenticationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5283B2E227EC0C240018F19B /* AuthenticationView.swift */; }; 45 | 5283B2E427EC0C240018F19B /* AuthenticationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5283B2E227EC0C240018F19B /* AuthenticationView.swift */; }; 46 | 52BABB2927E7DCF300999F01 /* Fragment_iOS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BABB2827E7DCF300999F01 /* Fragment_iOS_Tests.swift */; }; 47 | 52BABB3627E7DD5500999F01 /* Fragment_macOS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BABB3527E7DD5500999F01 /* Fragment_macOS_Tests.swift */; }; 48 | 52BABB3E27E7DDB200999F01 /* TestApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BABB3D27E7DDB200999F01 /* TestApp.swift */; }; 49 | 52BABB3F27E7DDB200999F01 /* TestApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BABB3D27E7DDB200999F01 /* TestApp.swift */; }; 50 | 52C9ECDA27EC1DC900021911 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 525D85BA27E760A60066B147 /* Assets.xcassets */; }; 51 | 52E3297027FBBEAD0059F82B /* SupportThisAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E3296F27FBBEAD0059F82B /* SupportThisAppView.swift */; }; 52 | 52E3297127FBBEAD0059F82B /* SupportThisAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E3296F27FBBEAD0059F82B /* SupportThisAppView.swift */; }; 53 | 5A1C6CFB27FB7E4A00EB8D91 /* SessionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1C6CFA27FB7E4A00EB8D91 /* SessionHandler.swift */; }; 54 | 5A1C6CFC27FB7E4A00EB8D91 /* SessionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A1C6CFA27FB7E4A00EB8D91 /* SessionHandler.swift */; }; 55 | 5A2387FF27FB3B1900480C20 /* FragmentError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A2387FE27FB3B1900480C20 /* FragmentError.swift */; }; 56 | 5A23880027FB3B1900480C20 /* FragmentError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A2387FE27FB3B1900480C20 /* FragmentError.swift */; }; 57 | 5A23880727FB47E300480C20 /* SwifterSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5A23880627FB47E300480C20 /* SwifterSwift */; }; 58 | 5A23880927FB47F200480C20 /* SwifterSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5A23880827FB47F200480C20 /* SwifterSwift */; }; 59 | 5A23880F27FB4C4E00480C20 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A23880E27FB4C4E00480C20 /* SettingsView.swift */; }; 60 | 5A23881027FB4C4E00480C20 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A23880E27FB4C4E00480C20 /* SettingsView.swift */; }; 61 | 5A23881627FB674C00480C20 /* ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A23881527FB674C00480C20 /* ListView.swift */; }; 62 | 5A23881727FB674C00480C20 /* ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A23881527FB674C00480C20 /* ListView.swift */; }; 63 | 5A4C7E5627F3B600006B3A4A /* CodeEditor in Frameworks */ = {isa = PBXBuildFile; productRef = 5A4C7E5527F3B600006B3A4A /* CodeEditor */; }; 64 | 5A4C7E5827F3BE78006B3A4A /* CodeEditor in Frameworks */ = {isa = PBXBuildFile; productRef = 5A4C7E5727F3BE78006B3A4A /* CodeEditor */; }; 65 | 5AD4DFF327F3AC7A003C2C61 /* DHCacheKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5AD4DFF227F3AC7A003C2C61 /* DHCacheKit */; }; 66 | 5AD4DFF527F3AC87003C2C61 /* DHCacheKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5AD4DFF427F3AC87003C2C61 /* DHCacheKit */; }; 67 | 5ADC94A627F8E00200EFE347 /* Gist+Custom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADC94A527F8E00200EFE347 /* Gist+Custom.swift */; }; 68 | 5ADC94A727F8E00200EFE347 /* Gist+Custom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADC94A527F8E00200EFE347 /* Gist+Custom.swift */; }; 69 | 5ADC94A927F8EB0600EFE347 /* ClipboardHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADC94A827F8EB0600EFE347 /* ClipboardHelper.swift */; }; 70 | 5ADC94AA27F8EB0600EFE347 /* ClipboardHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ADC94A827F8EB0600EFE347 /* ClipboardHelper.swift */; }; 71 | 5AFEF54527F80C91003FA4EE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 525D85BA27E760A60066B147 /* Assets.xcassets */; }; 72 | /* End PBXBuildFile section */ 73 | 74 | /* Begin PBXContainerItemProxy section */ 75 | 52BABB2A27E7DCF300999F01 /* PBXContainerItemProxy */ = { 76 | isa = PBXContainerItemProxy; 77 | containerPortal = 525D85B027E760A40066B147 /* Project object */; 78 | proxyType = 1; 79 | remoteGlobalIDString = 525D85BE27E760A60066B147; 80 | remoteInfo = "Fragment (iOS)"; 81 | }; 82 | 52BABB3727E7DD5500999F01 /* PBXContainerItemProxy */ = { 83 | isa = PBXContainerItemProxy; 84 | containerPortal = 525D85B027E760A40066B147 /* Project object */; 85 | proxyType = 1; 86 | remoteGlobalIDString = 525D85C427E760A60066B147; 87 | remoteInfo = "Fragment (macOS)"; 88 | }; 89 | /* End PBXContainerItemProxy section */ 90 | 91 | /* Begin PBXFileReference section */ 92 | 522915B127E778300087530C /* GistRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GistRow.swift; sourceTree = ""; }; 93 | 5254DE0027EF8331005BAC56 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 94 | 525D85B727E760A40066B147 /* FragmentApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FragmentApp.swift; sourceTree = ""; }; 95 | 525D85BA27E760A60066B147 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 96 | 525D85BF27E760A60066B147 /* Fragment.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Fragment.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | 525D85C527E760A60066B147 /* Fragment.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Fragment.app; sourceTree = BUILT_PRODUCTS_DIR; }; 98 | 525D85C727E760A60066B147 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 99 | 525D860227E7621D0066B147 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 100 | 525D860427E762610066B147 /* ContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerView.swift; sourceTree = ""; }; 101 | 526D97D227F0C82D00BD46CE /* Language.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; }; 102 | 526D97DD27F0CA8600BD46CE /* Gist+text.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gist+text.swift"; sourceTree = ""; }; 103 | 526D97E027F0CBCC00BD46CE /* CodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeView.swift; sourceTree = ""; }; 104 | 52769DED27F0CD4C00F5D4E0 /* Gist+language.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gist+language.swift"; sourceTree = ""; }; 105 | 52769DFB27F0E83300F5D4E0 /* Collections+ifExistsAt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collections+ifExistsAt.swift"; sourceTree = ""; }; 106 | 52769DFF27F0EEE400F5D4E0 /* Visibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Visibility.swift; sourceTree = ""; }; 107 | 52769E0227F0F06900F5D4E0 /* AddGistView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGistView.swift; sourceTree = ""; }; 108 | 52769E0527F0FE6A00F5D4E0 /* WebLauncher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebLauncher.swift; sourceTree = ""; }; 109 | 5283B2E227EC0C240018F19B /* AuthenticationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationView.swift; sourceTree = ""; }; 110 | 52BABB1C27E7D79E00999F01 /* .swiftformat.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftformat.yml; sourceTree = ""; }; 111 | 52BABB1D27E7D79E00999F01 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; 112 | 52BABB2627E7DCF300999F01 /* Fragment-iOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Fragment-iOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 113 | 52BABB2827E7DCF300999F01 /* Fragment_iOS_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fragment_iOS_Tests.swift; sourceTree = ""; }; 114 | 52BABB3327E7DD5500999F01 /* Fragment-macOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Fragment-macOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 115 | 52BABB3527E7DD5500999F01 /* Fragment_macOS_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fragment_macOS_Tests.swift; sourceTree = ""; }; 116 | 52BABB3D27E7DDB200999F01 /* TestApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestApp.swift; sourceTree = ""; }; 117 | 52C9ECD727EC1D5100021911 /* Fragment--iOS--Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Fragment--iOS--Info.plist"; sourceTree = ""; }; 118 | 52C9ECD827EC1D5B00021911 /* Fragment--macOS--Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Fragment--macOS--Info.plist"; sourceTree = ""; }; 119 | 52E3296F27FBBEAD0059F82B /* SupportThisAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportThisAppView.swift; sourceTree = ""; }; 120 | 5A1C6CFA27FB7E4A00EB8D91 /* SessionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionHandler.swift; sourceTree = ""; }; 121 | 5A2387FE27FB3B1900480C20 /* FragmentError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FragmentError.swift; sourceTree = ""; }; 122 | 5A23880E27FB4C4E00480C20 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 123 | 5A23881527FB674C00480C20 /* ListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListView.swift; sourceTree = ""; }; 124 | 5ADC94A527F8E00200EFE347 /* Gist+Custom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Gist+Custom.swift"; sourceTree = ""; }; 125 | 5ADC94A827F8EB0600EFE347 /* ClipboardHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardHelper.swift; sourceTree = ""; }; 126 | /* End PBXFileReference section */ 127 | 128 | /* Begin PBXFrameworksBuildPhase section */ 129 | 525D85BC27E760A60066B147 /* Frameworks */ = { 130 | isa = PBXFrameworksBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | 5A23880727FB47E300480C20 /* SwifterSwift in Frameworks */, 134 | 526D97C827F0C5BE00BD46CE /* Highlightr in Frameworks */, 135 | 525D860827E762B40066B147 /* OctoKit in Frameworks */, 136 | 5254DDFF27EF8224005BAC56 /* SFSafeSymbols in Frameworks */, 137 | 526D97C327F0C25B00BD46CE /* KeychainAccess in Frameworks */, 138 | 5A4C7E5827F3BE78006B3A4A /* CodeEditor in Frameworks */, 139 | 5AD4DFF327F3AC7A003C2C61 /* DHCacheKit in Frameworks */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | 525D85C227E760A60066B147 /* Frameworks */ = { 144 | isa = PBXFrameworksBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | 5A23880927FB47F200480C20 /* SwifterSwift in Frameworks */, 148 | 526D97CA27F0C5C500BD46CE /* Highlightr in Frameworks */, 149 | 522915C027E789E20087530C /* OctoKit in Frameworks */, 150 | 5254DE0427EF837A005BAC56 /* SFSafeSymbols in Frameworks */, 151 | 526D97C527F0C26600BD46CE /* KeychainAccess in Frameworks */, 152 | 5A4C7E5627F3B600006B3A4A /* CodeEditor in Frameworks */, 153 | 5AD4DFF527F3AC87003C2C61 /* DHCacheKit in Frameworks */, 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | 52BABB2327E7DCF300999F01 /* Frameworks */ = { 158 | isa = PBXFrameworksBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | ); 162 | runOnlyForDeploymentPostprocessing = 0; 163 | }; 164 | 52BABB3027E7DD5500999F01 /* Frameworks */ = { 165 | isa = PBXFrameworksBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXFrameworksBuildPhase section */ 172 | 173 | /* Begin PBXGroup section */ 174 | 522915B027E7781E0087530C /* GistViews */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 522915B127E778300087530C /* GistRow.swift */, 178 | ); 179 | path = GistViews; 180 | sourceTree = ""; 181 | }; 182 | 522915B427E77D290087530C /* Extensions */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 526D97DB27F0CA6300BD46CE /* OctoKitExtensions */, 186 | 52769DFB27F0E83300F5D4E0 /* Collections+ifExistsAt.swift */, 187 | ); 188 | path = Extensions; 189 | sourceTree = ""; 190 | }; 191 | 522915B827E7855E0087530C /* CodeViews */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 526D97E027F0CBCC00BD46CE /* CodeView.swift */, 195 | ); 196 | path = CodeViews; 197 | sourceTree = ""; 198 | }; 199 | 525D85AF27E760A40066B147 = { 200 | isa = PBXGroup; 201 | children = ( 202 | 52C9ECD827EC1D5B00021911 /* Fragment--macOS--Info.plist */, 203 | 52C9ECD727EC1D5100021911 /* Fragment--iOS--Info.plist */, 204 | 52BABB1C27E7D79E00999F01 /* .swiftformat.yml */, 205 | 52BABB1D27E7D79E00999F01 /* .swiftlint.yml */, 206 | 525D85B427E760A40066B147 /* Shared */, 207 | 525D85C627E760A60066B147 /* macOS */, 208 | 52BABB3C27E7DD8B00999F01 /* FragmentSharedTests */, 209 | 52BABB2727E7DCF300999F01 /* Fragment-iOS-Tests */, 210 | 52BABB3427E7DD5500999F01 /* Fragment-macOS-Tests */, 211 | 525D85C027E760A60066B147 /* Products */, 212 | 525D85FE27E761CB0066B147 /* Frameworks */, 213 | ); 214 | sourceTree = ""; 215 | }; 216 | 525D85B427E760A40066B147 /* Shared */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | 5A23880127FB3ED000480C20 /* Handler */, 220 | 525D85BA27E760A60066B147 /* Assets.xcassets */, 221 | 525D85B727E760A40066B147 /* FragmentApp.swift */, 222 | 5283B2DE27EC0A1B0018F19B /* Models */, 223 | 522915B427E77D290087530C /* Extensions */, 224 | 525D860127E762140066B147 /* Views */, 225 | 5254DE0027EF8331005BAC56 /* Constants.swift */, 226 | 52769E0527F0FE6A00F5D4E0 /* WebLauncher.swift */, 227 | 5ADC94A827F8EB0600EFE347 /* ClipboardHelper.swift */, 228 | ); 229 | path = Shared; 230 | sourceTree = ""; 231 | }; 232 | 525D85C027E760A60066B147 /* Products */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | 525D85BF27E760A60066B147 /* Fragment.app */, 236 | 525D85C527E760A60066B147 /* Fragment.app */, 237 | 52BABB2627E7DCF300999F01 /* Fragment-iOS-Tests.xctest */, 238 | 52BABB3327E7DD5500999F01 /* Fragment-macOS-Tests.xctest */, 239 | ); 240 | name = Products; 241 | sourceTree = ""; 242 | }; 243 | 525D85C627E760A60066B147 /* macOS */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | 525D85C727E760A60066B147 /* macOS.entitlements */, 247 | ); 248 | path = macOS; 249 | sourceTree = ""; 250 | }; 251 | 525D85FE27E761CB0066B147 /* Frameworks */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | ); 255 | name = Frameworks; 256 | sourceTree = ""; 257 | }; 258 | 525D860127E762140066B147 /* Views */ = { 259 | isa = PBXGroup; 260 | children = ( 261 | 52E3296E27FBBE980059F82B /* Support */, 262 | 5A23881427FB673600480C20 /* Container */, 263 | 52769DFE27F0EED100F5D4E0 /* Add */, 264 | 525D860227E7621D0066B147 /* MainView.swift */, 265 | 5283B2E227EC0C240018F19B /* AuthenticationView.swift */, 266 | 522915B827E7855E0087530C /* CodeViews */, 267 | 522915B027E7781E0087530C /* GistViews */, 268 | 5A23880E27FB4C4E00480C20 /* SettingsView.swift */, 269 | ); 270 | path = Views; 271 | sourceTree = ""; 272 | }; 273 | 526D97DB27F0CA6300BD46CE /* OctoKitExtensions */ = { 274 | isa = PBXGroup; 275 | children = ( 276 | 526D97DC27F0CA6F00BD46CE /* GistExtensions */, 277 | ); 278 | path = OctoKitExtensions; 279 | sourceTree = ""; 280 | }; 281 | 526D97DC27F0CA6F00BD46CE /* GistExtensions */ = { 282 | isa = PBXGroup; 283 | children = ( 284 | 526D97DD27F0CA8600BD46CE /* Gist+text.swift */, 285 | 52769DED27F0CD4C00F5D4E0 /* Gist+language.swift */, 286 | 5ADC94A527F8E00200EFE347 /* Gist+Custom.swift */, 287 | ); 288 | path = GistExtensions; 289 | sourceTree = ""; 290 | }; 291 | 52769DFE27F0EED100F5D4E0 /* Add */ = { 292 | isa = PBXGroup; 293 | children = ( 294 | 52769E0227F0F06900F5D4E0 /* AddGistView.swift */, 295 | ); 296 | path = Add; 297 | sourceTree = ""; 298 | }; 299 | 5283B2DE27EC0A1B0018F19B /* Models */ = { 300 | isa = PBXGroup; 301 | children = ( 302 | 5A2387FD27FB3B0200480C20 /* Errors */, 303 | 526D97D227F0C82D00BD46CE /* Language.swift */, 304 | 52769DFF27F0EEE400F5D4E0 /* Visibility.swift */, 305 | ); 306 | path = Models; 307 | sourceTree = ""; 308 | }; 309 | 52BABB2727E7DCF300999F01 /* Fragment-iOS-Tests */ = { 310 | isa = PBXGroup; 311 | children = ( 312 | 52BABB2827E7DCF300999F01 /* Fragment_iOS_Tests.swift */, 313 | ); 314 | path = "Fragment-iOS-Tests"; 315 | sourceTree = ""; 316 | }; 317 | 52BABB3427E7DD5500999F01 /* Fragment-macOS-Tests */ = { 318 | isa = PBXGroup; 319 | children = ( 320 | 52BABB3527E7DD5500999F01 /* Fragment_macOS_Tests.swift */, 321 | ); 322 | path = "Fragment-macOS-Tests"; 323 | sourceTree = ""; 324 | }; 325 | 52BABB3C27E7DD8B00999F01 /* FragmentSharedTests */ = { 326 | isa = PBXGroup; 327 | children = ( 328 | 52BABB3D27E7DDB200999F01 /* TestApp.swift */, 329 | ); 330 | path = FragmentSharedTests; 331 | sourceTree = ""; 332 | }; 333 | 52E3296E27FBBE980059F82B /* Support */ = { 334 | isa = PBXGroup; 335 | children = ( 336 | 52E3296F27FBBEAD0059F82B /* SupportThisAppView.swift */, 337 | ); 338 | path = Support; 339 | sourceTree = ""; 340 | }; 341 | 5A2387FD27FB3B0200480C20 /* Errors */ = { 342 | isa = PBXGroup; 343 | children = ( 344 | 5A2387FE27FB3B1900480C20 /* FragmentError.swift */, 345 | ); 346 | path = Errors; 347 | sourceTree = ""; 348 | }; 349 | 5A23880127FB3ED000480C20 /* Handler */ = { 350 | isa = PBXGroup; 351 | children = ( 352 | 5A1C6CFA27FB7E4A00EB8D91 /* SessionHandler.swift */, 353 | ); 354 | path = Handler; 355 | sourceTree = ""; 356 | }; 357 | 5A23881427FB673600480C20 /* Container */ = { 358 | isa = PBXGroup; 359 | children = ( 360 | 525D860427E762610066B147 /* ContainerView.swift */, 361 | 5A23881527FB674C00480C20 /* ListView.swift */, 362 | ); 363 | path = Container; 364 | sourceTree = ""; 365 | }; 366 | /* End PBXGroup section */ 367 | 368 | /* Begin PBXNativeTarget section */ 369 | 525D85BE27E760A60066B147 /* Fragment (iOS) */ = { 370 | isa = PBXNativeTarget; 371 | buildConfigurationList = 525D85EC27E760A60066B147 /* Build configuration list for PBXNativeTarget "Fragment (iOS)" */; 372 | buildPhases = ( 373 | 525D85BB27E760A60066B147 /* Sources */, 374 | 525D85BC27E760A60066B147 /* Frameworks */, 375 | 525D85BD27E760A60066B147 /* Resources */, 376 | 52BABB1E27E7D83000999F01 /* SwiftFormat */, 377 | 52BABB2027E7D84F00999F01 /* SwiftLint */, 378 | ); 379 | buildRules = ( 380 | ); 381 | dependencies = ( 382 | ); 383 | name = "Fragment (iOS)"; 384 | packageProductDependencies = ( 385 | 525D860727E762B40066B147 /* OctoKit */, 386 | 5254DDFE27EF8224005BAC56 /* SFSafeSymbols */, 387 | 526D97C227F0C25B00BD46CE /* KeychainAccess */, 388 | 526D97C727F0C5BE00BD46CE /* Highlightr */, 389 | 5AD4DFF227F3AC7A003C2C61 /* DHCacheKit */, 390 | 5A4C7E5727F3BE78006B3A4A /* CodeEditor */, 391 | 5A23880627FB47E300480C20 /* SwifterSwift */, 392 | ); 393 | productName = "Fragment (iOS)"; 394 | productReference = 525D85BF27E760A60066B147 /* Fragment.app */; 395 | productType = "com.apple.product-type.application"; 396 | }; 397 | 525D85C427E760A60066B147 /* Fragment (macOS) */ = { 398 | isa = PBXNativeTarget; 399 | buildConfigurationList = 525D85EF27E760A60066B147 /* Build configuration list for PBXNativeTarget "Fragment (macOS)" */; 400 | buildPhases = ( 401 | 525D85C127E760A60066B147 /* Sources */, 402 | 525D85C227E760A60066B147 /* Frameworks */, 403 | 525D85C327E760A60066B147 /* Resources */, 404 | 52BABB1F27E7D84000999F01 /* SwiftFormat */, 405 | 52BABB2127E7D87A00999F01 /* SwiftLint */, 406 | ); 407 | buildRules = ( 408 | ); 409 | dependencies = ( 410 | ); 411 | name = "Fragment (macOS)"; 412 | packageProductDependencies = ( 413 | 522915BF27E789E20087530C /* OctoKit */, 414 | 5254DE0327EF837A005BAC56 /* SFSafeSymbols */, 415 | 526D97C427F0C26600BD46CE /* KeychainAccess */, 416 | 526D97C927F0C5C500BD46CE /* Highlightr */, 417 | 5AD4DFF427F3AC87003C2C61 /* DHCacheKit */, 418 | 5A4C7E5527F3B600006B3A4A /* CodeEditor */, 419 | 5A23880827FB47F200480C20 /* SwifterSwift */, 420 | ); 421 | productName = "Fragment (macOS)"; 422 | productReference = 525D85C527E760A60066B147 /* Fragment.app */; 423 | productType = "com.apple.product-type.application"; 424 | }; 425 | 52BABB2527E7DCF300999F01 /* Fragment-iOS-Tests */ = { 426 | isa = PBXNativeTarget; 427 | buildConfigurationList = 52BABB2C27E7DCF300999F01 /* Build configuration list for PBXNativeTarget "Fragment-iOS-Tests" */; 428 | buildPhases = ( 429 | 52BABB2227E7DCF300999F01 /* Sources */, 430 | 52BABB2327E7DCF300999F01 /* Frameworks */, 431 | 52BABB2427E7DCF300999F01 /* Resources */, 432 | ); 433 | buildRules = ( 434 | ); 435 | dependencies = ( 436 | 52BABB2B27E7DCF300999F01 /* PBXTargetDependency */, 437 | ); 438 | name = "Fragment-iOS-Tests"; 439 | productName = "Fragment-iOS-Tests"; 440 | productReference = 52BABB2627E7DCF300999F01 /* Fragment-iOS-Tests.xctest */; 441 | productType = "com.apple.product-type.bundle.unit-test"; 442 | }; 443 | 52BABB3227E7DD5500999F01 /* Fragment-macOS-Tests */ = { 444 | isa = PBXNativeTarget; 445 | buildConfigurationList = 52BABB3927E7DD5500999F01 /* Build configuration list for PBXNativeTarget "Fragment-macOS-Tests" */; 446 | buildPhases = ( 447 | 52BABB2F27E7DD5500999F01 /* Sources */, 448 | 52BABB3027E7DD5500999F01 /* Frameworks */, 449 | 52BABB3127E7DD5500999F01 /* Resources */, 450 | ); 451 | buildRules = ( 452 | ); 453 | dependencies = ( 454 | 52BABB3827E7DD5500999F01 /* PBXTargetDependency */, 455 | ); 456 | name = "Fragment-macOS-Tests"; 457 | productName = "Fragment-macOS-Tests"; 458 | productReference = 52BABB3327E7DD5500999F01 /* Fragment-macOS-Tests.xctest */; 459 | productType = "com.apple.product-type.bundle.unit-test"; 460 | }; 461 | /* End PBXNativeTarget section */ 462 | 463 | /* Begin PBXProject section */ 464 | 525D85B027E760A40066B147 /* Project object */ = { 465 | isa = PBXProject; 466 | attributes = { 467 | BuildIndependentTargetsInParallel = 1; 468 | LastSwiftUpdateCheck = 1330; 469 | LastUpgradeCheck = 1330; 470 | TargetAttributes = { 471 | 525D85BE27E760A60066B147 = { 472 | CreatedOnToolsVersion = 13.3; 473 | }; 474 | 525D85C427E760A60066B147 = { 475 | CreatedOnToolsVersion = 13.3; 476 | }; 477 | 52BABB2527E7DCF300999F01 = { 478 | CreatedOnToolsVersion = 13.3; 479 | TestTargetID = 525D85BE27E760A60066B147; 480 | }; 481 | 52BABB3227E7DD5500999F01 = { 482 | CreatedOnToolsVersion = 13.3; 483 | TestTargetID = 525D85C427E760A60066B147; 484 | }; 485 | }; 486 | }; 487 | buildConfigurationList = 525D85B327E760A40066B147 /* Build configuration list for PBXProject "Fragment" */; 488 | compatibilityVersion = "Xcode 13.0"; 489 | developmentRegion = en; 490 | hasScannedForEncodings = 0; 491 | knownRegions = ( 492 | en, 493 | Base, 494 | ); 495 | mainGroup = 525D85AF27E760A40066B147; 496 | packageReferences = ( 497 | 525D860627E762B40066B147 /* XCRemoteSwiftPackageReference "octokit" */, 498 | 5254DDFD27EF8224005BAC56 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, 499 | 526D97C127F0C25B00BD46CE /* XCRemoteSwiftPackageReference "KeychainAccess" */, 500 | 526D97C627F0C5BE00BD46CE /* XCRemoteSwiftPackageReference "Highlightr" */, 501 | 5AD4DFF127F3AC7A003C2C61 /* XCRemoteSwiftPackageReference "DHCacheKit" */, 502 | 5A4C7E5427F3B600006B3A4A /* XCRemoteSwiftPackageReference "CodeEditor" */, 503 | 5A23880527FB47E300480C20 /* XCRemoteSwiftPackageReference "SwifterSwift" */, 504 | 52E3296927FBBE840059F82B /* XCRemoteSwiftPackageReference "buymeacoffee" */, 505 | ); 506 | productRefGroup = 525D85C027E760A60066B147 /* Products */; 507 | projectDirPath = ""; 508 | projectRoot = ""; 509 | targets = ( 510 | 525D85BE27E760A60066B147 /* Fragment (iOS) */, 511 | 525D85C427E760A60066B147 /* Fragment (macOS) */, 512 | 52BABB2527E7DCF300999F01 /* Fragment-iOS-Tests */, 513 | 52BABB3227E7DD5500999F01 /* Fragment-macOS-Tests */, 514 | ); 515 | }; 516 | /* End PBXProject section */ 517 | 518 | /* Begin PBXResourcesBuildPhase section */ 519 | 525D85BD27E760A60066B147 /* Resources */ = { 520 | isa = PBXResourcesBuildPhase; 521 | buildActionMask = 2147483647; 522 | files = ( 523 | 5AFEF54527F80C91003FA4EE /* Assets.xcassets in Resources */, 524 | ); 525 | runOnlyForDeploymentPostprocessing = 0; 526 | }; 527 | 525D85C327E760A60066B147 /* Resources */ = { 528 | isa = PBXResourcesBuildPhase; 529 | buildActionMask = 2147483647; 530 | files = ( 531 | 52C9ECDA27EC1DC900021911 /* Assets.xcassets in Resources */, 532 | ); 533 | runOnlyForDeploymentPostprocessing = 0; 534 | }; 535 | 52BABB2427E7DCF300999F01 /* Resources */ = { 536 | isa = PBXResourcesBuildPhase; 537 | buildActionMask = 2147483647; 538 | files = ( 539 | ); 540 | runOnlyForDeploymentPostprocessing = 0; 541 | }; 542 | 52BABB3127E7DD5500999F01 /* Resources */ = { 543 | isa = PBXResourcesBuildPhase; 544 | buildActionMask = 2147483647; 545 | files = ( 546 | ); 547 | runOnlyForDeploymentPostprocessing = 0; 548 | }; 549 | /* End PBXResourcesBuildPhase section */ 550 | 551 | /* Begin PBXShellScriptBuildPhase section */ 552 | 52BABB1E27E7D83000999F01 /* SwiftFormat */ = { 553 | isa = PBXShellScriptBuildPhase; 554 | buildActionMask = 2147483647; 555 | files = ( 556 | ); 557 | inputFileListPaths = ( 558 | ); 559 | inputPaths = ( 560 | ); 561 | name = SwiftFormat; 562 | outputFileListPaths = ( 563 | ); 564 | outputPaths = ( 565 | ); 566 | runOnlyForDeploymentPostprocessing = 0; 567 | shellPath = /bin/sh; 568 | shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which swiftformat >/dev/null; then\n swiftformat .\nelse\n echo \"warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat\"\nfi\n"; 569 | }; 570 | 52BABB1F27E7D84000999F01 /* SwiftFormat */ = { 571 | isa = PBXShellScriptBuildPhase; 572 | buildActionMask = 2147483647; 573 | files = ( 574 | ); 575 | inputFileListPaths = ( 576 | ); 577 | inputPaths = ( 578 | ); 579 | name = SwiftFormat; 580 | outputFileListPaths = ( 581 | ); 582 | outputPaths = ( 583 | ); 584 | runOnlyForDeploymentPostprocessing = 0; 585 | shellPath = /bin/sh; 586 | shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which swiftformat >/dev/null; then\n swiftformat .\nelse\n echo \"warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat\"\nfi\n"; 587 | }; 588 | 52BABB2027E7D84F00999F01 /* SwiftLint */ = { 589 | isa = PBXShellScriptBuildPhase; 590 | buildActionMask = 2147483647; 591 | files = ( 592 | ); 593 | inputFileListPaths = ( 594 | ); 595 | inputPaths = ( 596 | ); 597 | name = SwiftLint; 598 | outputFileListPaths = ( 599 | ); 600 | outputPaths = ( 601 | ); 602 | runOnlyForDeploymentPostprocessing = 0; 603 | shellPath = /bin/sh; 604 | shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; 605 | }; 606 | 52BABB2127E7D87A00999F01 /* SwiftLint */ = { 607 | isa = PBXShellScriptBuildPhase; 608 | buildActionMask = 2147483647; 609 | files = ( 610 | ); 611 | inputFileListPaths = ( 612 | ); 613 | inputPaths = ( 614 | ); 615 | name = SwiftLint; 616 | outputFileListPaths = ( 617 | ); 618 | outputPaths = ( 619 | ); 620 | runOnlyForDeploymentPostprocessing = 0; 621 | shellPath = /bin/sh; 622 | shellScript = "export PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; 623 | }; 624 | /* End PBXShellScriptBuildPhase section */ 625 | 626 | /* Begin PBXSourcesBuildPhase section */ 627 | 525D85BB27E760A60066B147 /* Sources */ = { 628 | isa = PBXSourcesBuildPhase; 629 | buildActionMask = 2147483647; 630 | files = ( 631 | 5A23880F27FB4C4E00480C20 /* SettingsView.swift in Sources */, 632 | 526D97E127F0CBCC00BD46CE /* CodeView.swift in Sources */, 633 | 525D860527E762610066B147 /* ContainerView.swift in Sources */, 634 | 526D97DE27F0CA8600BD46CE /* Gist+text.swift in Sources */, 635 | 525D85E227E760A60066B147 /* FragmentApp.swift in Sources */, 636 | 52769DFC27F0E83300F5D4E0 /* Collections+ifExistsAt.swift in Sources */, 637 | 5283B2E327EC0C240018F19B /* AuthenticationView.swift in Sources */, 638 | 5A1C6CFB27FB7E4A00EB8D91 /* SessionHandler.swift in Sources */, 639 | 525D860327E7621D0066B147 /* MainView.swift in Sources */, 640 | 5ADC94A627F8E00200EFE347 /* Gist+Custom.swift in Sources */, 641 | 52769DEE27F0CD4C00F5D4E0 /* Gist+language.swift in Sources */, 642 | 5A2387FF27FB3B1900480C20 /* FragmentError.swift in Sources */, 643 | 52E3297027FBBEAD0059F82B /* SupportThisAppView.swift in Sources */, 644 | 52769E0027F0EEE400F5D4E0 /* Visibility.swift in Sources */, 645 | 522915B227E778300087530C /* GistRow.swift in Sources */, 646 | 52769E0627F0FE6A00F5D4E0 /* WebLauncher.swift in Sources */, 647 | 5ADC94A927F8EB0600EFE347 /* ClipboardHelper.swift in Sources */, 648 | 5A23881627FB674C00480C20 /* ListView.swift in Sources */, 649 | 52769E0327F0F06900F5D4E0 /* AddGistView.swift in Sources */, 650 | 5254DE0127EF8331005BAC56 /* Constants.swift in Sources */, 651 | 52769DF027F0D0CB00F5D4E0 /* Language.swift in Sources */, 652 | ); 653 | runOnlyForDeploymentPostprocessing = 0; 654 | }; 655 | 525D85C127E760A60066B147 /* Sources */ = { 656 | isa = PBXSourcesBuildPhase; 657 | buildActionMask = 2147483647; 658 | files = ( 659 | 5A23881027FB4C4E00480C20 /* SettingsView.swift in Sources */, 660 | 525D860A27E763B80066B147 /* ContainerView.swift in Sources */, 661 | 526D97DF27F0CA8600BD46CE /* Gist+text.swift in Sources */, 662 | 525D85E327E760A60066B147 /* FragmentApp.swift in Sources */, 663 | 5283B2E427EC0C240018F19B /* AuthenticationView.swift in Sources */, 664 | 52769DFD27F0E83300F5D4E0 /* Collections+ifExistsAt.swift in Sources */, 665 | 525D860927E763B50066B147 /* MainView.swift in Sources */, 666 | 5A1C6CFC27FB7E4A00EB8D91 /* SessionHandler.swift in Sources */, 667 | 5ADC94A727F8E00200EFE347 /* Gist+Custom.swift in Sources */, 668 | 522915B327E778300087530C /* GistRow.swift in Sources */, 669 | 5A23880027FB3B1900480C20 /* FragmentError.swift in Sources */, 670 | 52769E0127F0EEE400F5D4E0 /* Visibility.swift in Sources */, 671 | 52E3297127FBBEAD0059F82B /* SupportThisAppView.swift in Sources */, 672 | 5254DE0227EF8331005BAC56 /* Constants.swift in Sources */, 673 | 52769E0727F0FE6A00F5D4E0 /* WebLauncher.swift in Sources */, 674 | 5ADC94AA27F8EB0600EFE347 /* ClipboardHelper.swift in Sources */, 675 | 526D97D427F0C82D00BD46CE /* Language.swift in Sources */, 676 | 5A23881727FB674C00480C20 /* ListView.swift in Sources */, 677 | 52769E0427F0F06900F5D4E0 /* AddGistView.swift in Sources */, 678 | 52769DEF27F0CD4C00F5D4E0 /* Gist+language.swift in Sources */, 679 | 526D97E227F0CBCC00BD46CE /* CodeView.swift in Sources */, 680 | ); 681 | runOnlyForDeploymentPostprocessing = 0; 682 | }; 683 | 52BABB2227E7DCF300999F01 /* Sources */ = { 684 | isa = PBXSourcesBuildPhase; 685 | buildActionMask = 2147483647; 686 | files = ( 687 | 52BABB2927E7DCF300999F01 /* Fragment_iOS_Tests.swift in Sources */, 688 | 52BABB3E27E7DDB200999F01 /* TestApp.swift in Sources */, 689 | ); 690 | runOnlyForDeploymentPostprocessing = 0; 691 | }; 692 | 52BABB2F27E7DD5500999F01 /* Sources */ = { 693 | isa = PBXSourcesBuildPhase; 694 | buildActionMask = 2147483647; 695 | files = ( 696 | 52BABB3627E7DD5500999F01 /* Fragment_macOS_Tests.swift in Sources */, 697 | 52BABB3F27E7DDB200999F01 /* TestApp.swift in Sources */, 698 | ); 699 | runOnlyForDeploymentPostprocessing = 0; 700 | }; 701 | /* End PBXSourcesBuildPhase section */ 702 | 703 | /* Begin PBXTargetDependency section */ 704 | 52BABB2B27E7DCF300999F01 /* PBXTargetDependency */ = { 705 | isa = PBXTargetDependency; 706 | target = 525D85BE27E760A60066B147 /* Fragment (iOS) */; 707 | targetProxy = 52BABB2A27E7DCF300999F01 /* PBXContainerItemProxy */; 708 | }; 709 | 52BABB3827E7DD5500999F01 /* PBXTargetDependency */ = { 710 | isa = PBXTargetDependency; 711 | target = 525D85C427E760A60066B147 /* Fragment (macOS) */; 712 | targetProxy = 52BABB3727E7DD5500999F01 /* PBXContainerItemProxy */; 713 | }; 714 | /* End PBXTargetDependency section */ 715 | 716 | /* Begin XCBuildConfiguration section */ 717 | 525D85EA27E760A60066B147 /* Debug */ = { 718 | isa = XCBuildConfiguration; 719 | buildSettings = { 720 | ALWAYS_SEARCH_USER_PATHS = NO; 721 | CLANG_ANALYZER_NONNULL = YES; 722 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 723 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 724 | CLANG_ENABLE_MODULES = YES; 725 | CLANG_ENABLE_OBJC_ARC = YES; 726 | CLANG_ENABLE_OBJC_WEAK = YES; 727 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 728 | CLANG_WARN_BOOL_CONVERSION = YES; 729 | CLANG_WARN_COMMA = YES; 730 | CLANG_WARN_CONSTANT_CONVERSION = YES; 731 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 732 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 733 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 734 | CLANG_WARN_EMPTY_BODY = YES; 735 | CLANG_WARN_ENUM_CONVERSION = YES; 736 | CLANG_WARN_INFINITE_RECURSION = YES; 737 | CLANG_WARN_INT_CONVERSION = YES; 738 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 739 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 740 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 741 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 742 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 743 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 744 | CLANG_WARN_STRICT_PROTOTYPES = YES; 745 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 746 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 747 | CLANG_WARN_UNREACHABLE_CODE = YES; 748 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 749 | COPY_PHASE_STRIP = NO; 750 | DEBUG_INFORMATION_FORMAT = dwarf; 751 | ENABLE_STRICT_OBJC_MSGSEND = YES; 752 | ENABLE_TESTABILITY = YES; 753 | GCC_C_LANGUAGE_STANDARD = gnu11; 754 | GCC_DYNAMIC_NO_PIC = NO; 755 | GCC_NO_COMMON_BLOCKS = YES; 756 | GCC_OPTIMIZATION_LEVEL = 0; 757 | GCC_PREPROCESSOR_DEFINITIONS = ( 758 | "DEBUG=1", 759 | "$(inherited)", 760 | ); 761 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 762 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 763 | GCC_WARN_UNDECLARED_SELECTOR = YES; 764 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 765 | GCC_WARN_UNUSED_FUNCTION = YES; 766 | GCC_WARN_UNUSED_VARIABLE = YES; 767 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 768 | MTL_FAST_MATH = YES; 769 | ONLY_ACTIVE_ARCH = YES; 770 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 771 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 772 | }; 773 | name = Debug; 774 | }; 775 | 525D85EB27E760A60066B147 /* Release */ = { 776 | isa = XCBuildConfiguration; 777 | buildSettings = { 778 | ALWAYS_SEARCH_USER_PATHS = NO; 779 | CLANG_ANALYZER_NONNULL = YES; 780 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 781 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 782 | CLANG_ENABLE_MODULES = YES; 783 | CLANG_ENABLE_OBJC_ARC = YES; 784 | CLANG_ENABLE_OBJC_WEAK = YES; 785 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 786 | CLANG_WARN_BOOL_CONVERSION = YES; 787 | CLANG_WARN_COMMA = YES; 788 | CLANG_WARN_CONSTANT_CONVERSION = YES; 789 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 790 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 791 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 792 | CLANG_WARN_EMPTY_BODY = YES; 793 | CLANG_WARN_ENUM_CONVERSION = YES; 794 | CLANG_WARN_INFINITE_RECURSION = YES; 795 | CLANG_WARN_INT_CONVERSION = YES; 796 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 797 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 798 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 799 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 800 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 801 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 802 | CLANG_WARN_STRICT_PROTOTYPES = YES; 803 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 804 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 805 | CLANG_WARN_UNREACHABLE_CODE = YES; 806 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 807 | COPY_PHASE_STRIP = NO; 808 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 809 | ENABLE_NS_ASSERTIONS = NO; 810 | ENABLE_STRICT_OBJC_MSGSEND = YES; 811 | GCC_C_LANGUAGE_STANDARD = gnu11; 812 | GCC_NO_COMMON_BLOCKS = YES; 813 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 814 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 815 | GCC_WARN_UNDECLARED_SELECTOR = YES; 816 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 817 | GCC_WARN_UNUSED_FUNCTION = YES; 818 | GCC_WARN_UNUSED_VARIABLE = YES; 819 | MTL_ENABLE_DEBUG_INFO = NO; 820 | MTL_FAST_MATH = YES; 821 | SWIFT_COMPILATION_MODE = wholemodule; 822 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 823 | }; 824 | name = Release; 825 | }; 826 | 525D85ED27E760A60066B147 /* Debug */ = { 827 | isa = XCBuildConfiguration; 828 | buildSettings = { 829 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 830 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 831 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; 832 | CODE_SIGN_STYLE = Automatic; 833 | CURRENT_PROJECT_VERSION = 1; 834 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 835 | ENABLE_PREVIEWS = YES; 836 | GENERATE_INFOPLIST_FILE = YES; 837 | INFOPLIST_FILE = "Fragment--iOS--Info.plist"; 838 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 839 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 840 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 841 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 842 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 843 | IPHONEOS_DEPLOYMENT_TARGET = 15.4; 844 | LD_RUNPATH_SEARCH_PATHS = ( 845 | "$(inherited)", 846 | "@executable_path/Frameworks", 847 | ); 848 | MARKETING_VERSION = 0.1.2; 849 | PRODUCT_BUNDLE_IDENTIFIER = com.codedbydan.FragmentSnippetManager; 850 | PRODUCT_NAME = Fragment; 851 | SDKROOT = iphoneos; 852 | SWIFT_EMIT_LOC_STRINGS = YES; 853 | SWIFT_VERSION = 5.0; 854 | TARGETED_DEVICE_FAMILY = "1,2"; 855 | }; 856 | name = Debug; 857 | }; 858 | 525D85EE27E760A60066B147 /* Release */ = { 859 | isa = XCBuildConfiguration; 860 | buildSettings = { 861 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 862 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 863 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; 864 | CODE_SIGN_STYLE = Automatic; 865 | CURRENT_PROJECT_VERSION = 1; 866 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 867 | ENABLE_PREVIEWS = YES; 868 | GENERATE_INFOPLIST_FILE = YES; 869 | INFOPLIST_FILE = "Fragment--iOS--Info.plist"; 870 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 871 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 872 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 873 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 874 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 875 | IPHONEOS_DEPLOYMENT_TARGET = 15.4; 876 | LD_RUNPATH_SEARCH_PATHS = ( 877 | "$(inherited)", 878 | "@executable_path/Frameworks", 879 | ); 880 | MARKETING_VERSION = 0.1.2; 881 | PRODUCT_BUNDLE_IDENTIFIER = com.codedbydan.FragmentSnippetManager; 882 | PRODUCT_NAME = Fragment; 883 | SDKROOT = iphoneos; 884 | SWIFT_EMIT_LOC_STRINGS = YES; 885 | SWIFT_VERSION = 5.0; 886 | TARGETED_DEVICE_FAMILY = "1,2"; 887 | VALIDATE_PRODUCT = YES; 888 | }; 889 | name = Release; 890 | }; 891 | 525D85F027E760A60066B147 /* Debug */ = { 892 | isa = XCBuildConfiguration; 893 | buildSettings = { 894 | ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-macOS"; 895 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 896 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; 897 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; 898 | CODE_SIGN_STYLE = Automatic; 899 | COMBINE_HIDPI_IMAGES = YES; 900 | CURRENT_PROJECT_VERSION = 1; 901 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 902 | ENABLE_HARDENED_RUNTIME = YES; 903 | ENABLE_PREVIEWS = YES; 904 | GENERATE_INFOPLIST_FILE = YES; 905 | INFOPLIST_FILE = "Fragment--macOS--Info.plist"; 906 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; 907 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 908 | LD_RUNPATH_SEARCH_PATHS = ( 909 | "$(inherited)", 910 | "@executable_path/../Frameworks", 911 | ); 912 | MACOSX_DEPLOYMENT_TARGET = 12.3; 913 | MARKETING_VERSION = 0.1.2; 914 | PRODUCT_BUNDLE_IDENTIFIER = com.codedbydan.FragmentSnippetManager; 915 | PRODUCT_NAME = Fragment; 916 | SDKROOT = macosx; 917 | SWIFT_EMIT_LOC_STRINGS = YES; 918 | SWIFT_VERSION = 5.0; 919 | }; 920 | name = Debug; 921 | }; 922 | 525D85F127E760A60066B147 /* Release */ = { 923 | isa = XCBuildConfiguration; 924 | buildSettings = { 925 | ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-macOS"; 926 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 927 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; 928 | CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; 929 | CODE_SIGN_STYLE = Automatic; 930 | COMBINE_HIDPI_IMAGES = YES; 931 | CURRENT_PROJECT_VERSION = 1; 932 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 933 | ENABLE_HARDENED_RUNTIME = YES; 934 | ENABLE_PREVIEWS = YES; 935 | GENERATE_INFOPLIST_FILE = YES; 936 | INFOPLIST_FILE = "Fragment--macOS--Info.plist"; 937 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; 938 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 939 | LD_RUNPATH_SEARCH_PATHS = ( 940 | "$(inherited)", 941 | "@executable_path/../Frameworks", 942 | ); 943 | MACOSX_DEPLOYMENT_TARGET = 12.3; 944 | MARKETING_VERSION = 0.1.2; 945 | PRODUCT_BUNDLE_IDENTIFIER = com.codedbydan.FragmentSnippetManager; 946 | PRODUCT_NAME = Fragment; 947 | SDKROOT = macosx; 948 | SWIFT_EMIT_LOC_STRINGS = YES; 949 | SWIFT_VERSION = 5.0; 950 | }; 951 | name = Release; 952 | }; 953 | 52BABB2D27E7DCF300999F01 /* Debug */ = { 954 | isa = XCBuildConfiguration; 955 | buildSettings = { 956 | BUNDLE_LOADER = "$(TEST_HOST)"; 957 | CODE_SIGN_STYLE = Automatic; 958 | CURRENT_PROJECT_VERSION = 1; 959 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 960 | GENERATE_INFOPLIST_FILE = YES; 961 | IPHONEOS_DEPLOYMENT_TARGET = 15.4; 962 | MARKETING_VERSION = 1.0; 963 | PRODUCT_BUNDLE_IDENTIFIER = "com.codedbydan.Fragment-iOS-Tests"; 964 | PRODUCT_NAME = "$(TARGET_NAME)"; 965 | SDKROOT = iphoneos; 966 | SWIFT_EMIT_LOC_STRINGS = NO; 967 | SWIFT_VERSION = 5.0; 968 | TARGETED_DEVICE_FAMILY = "1,2"; 969 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Fragment.app/Fragment"; 970 | }; 971 | name = Debug; 972 | }; 973 | 52BABB2E27E7DCF300999F01 /* Release */ = { 974 | isa = XCBuildConfiguration; 975 | buildSettings = { 976 | BUNDLE_LOADER = "$(TEST_HOST)"; 977 | CODE_SIGN_STYLE = Automatic; 978 | CURRENT_PROJECT_VERSION = 1; 979 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 980 | GENERATE_INFOPLIST_FILE = YES; 981 | IPHONEOS_DEPLOYMENT_TARGET = 15.4; 982 | MARKETING_VERSION = 1.0; 983 | PRODUCT_BUNDLE_IDENTIFIER = "com.codedbydan.Fragment-iOS-Tests"; 984 | PRODUCT_NAME = "$(TARGET_NAME)"; 985 | SDKROOT = iphoneos; 986 | SWIFT_EMIT_LOC_STRINGS = NO; 987 | SWIFT_VERSION = 5.0; 988 | TARGETED_DEVICE_FAMILY = "1,2"; 989 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Fragment.app/Fragment"; 990 | VALIDATE_PRODUCT = YES; 991 | }; 992 | name = Release; 993 | }; 994 | 52BABB3A27E7DD5500999F01 /* Debug */ = { 995 | isa = XCBuildConfiguration; 996 | buildSettings = { 997 | BUNDLE_LOADER = "$(TEST_HOST)"; 998 | CODE_SIGN_STYLE = Automatic; 999 | CURRENT_PROJECT_VERSION = 1; 1000 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 1001 | GENERATE_INFOPLIST_FILE = YES; 1002 | MACOSX_DEPLOYMENT_TARGET = 12.3; 1003 | MARKETING_VERSION = 1.0; 1004 | PRODUCT_BUNDLE_IDENTIFIER = "com.codedbydan.Fragment-macOS-Tests"; 1005 | PRODUCT_NAME = "$(TARGET_NAME)"; 1006 | SDKROOT = macosx; 1007 | SWIFT_EMIT_LOC_STRINGS = NO; 1008 | SWIFT_VERSION = 5.0; 1009 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Fragment.app/Contents/MacOS/Fragment"; 1010 | }; 1011 | name = Debug; 1012 | }; 1013 | 52BABB3B27E7DD5500999F01 /* Release */ = { 1014 | isa = XCBuildConfiguration; 1015 | buildSettings = { 1016 | BUNDLE_LOADER = "$(TEST_HOST)"; 1017 | CODE_SIGN_STYLE = Automatic; 1018 | CURRENT_PROJECT_VERSION = 1; 1019 | DEVELOPMENT_TEAM = WRJ8J85K4Q; 1020 | GENERATE_INFOPLIST_FILE = YES; 1021 | MACOSX_DEPLOYMENT_TARGET = 12.3; 1022 | MARKETING_VERSION = 1.0; 1023 | PRODUCT_BUNDLE_IDENTIFIER = "com.codedbydan.Fragment-macOS-Tests"; 1024 | PRODUCT_NAME = "$(TARGET_NAME)"; 1025 | SDKROOT = macosx; 1026 | SWIFT_EMIT_LOC_STRINGS = NO; 1027 | SWIFT_VERSION = 5.0; 1028 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Fragment.app/Contents/MacOS/Fragment"; 1029 | }; 1030 | name = Release; 1031 | }; 1032 | /* End XCBuildConfiguration section */ 1033 | 1034 | /* Begin XCConfigurationList section */ 1035 | 525D85B327E760A40066B147 /* Build configuration list for PBXProject "Fragment" */ = { 1036 | isa = XCConfigurationList; 1037 | buildConfigurations = ( 1038 | 525D85EA27E760A60066B147 /* Debug */, 1039 | 525D85EB27E760A60066B147 /* Release */, 1040 | ); 1041 | defaultConfigurationIsVisible = 0; 1042 | defaultConfigurationName = Release; 1043 | }; 1044 | 525D85EC27E760A60066B147 /* Build configuration list for PBXNativeTarget "Fragment (iOS)" */ = { 1045 | isa = XCConfigurationList; 1046 | buildConfigurations = ( 1047 | 525D85ED27E760A60066B147 /* Debug */, 1048 | 525D85EE27E760A60066B147 /* Release */, 1049 | ); 1050 | defaultConfigurationIsVisible = 0; 1051 | defaultConfigurationName = Release; 1052 | }; 1053 | 525D85EF27E760A60066B147 /* Build configuration list for PBXNativeTarget "Fragment (macOS)" */ = { 1054 | isa = XCConfigurationList; 1055 | buildConfigurations = ( 1056 | 525D85F027E760A60066B147 /* Debug */, 1057 | 525D85F127E760A60066B147 /* Release */, 1058 | ); 1059 | defaultConfigurationIsVisible = 0; 1060 | defaultConfigurationName = Release; 1061 | }; 1062 | 52BABB2C27E7DCF300999F01 /* Build configuration list for PBXNativeTarget "Fragment-iOS-Tests" */ = { 1063 | isa = XCConfigurationList; 1064 | buildConfigurations = ( 1065 | 52BABB2D27E7DCF300999F01 /* Debug */, 1066 | 52BABB2E27E7DCF300999F01 /* Release */, 1067 | ); 1068 | defaultConfigurationIsVisible = 0; 1069 | defaultConfigurationName = Release; 1070 | }; 1071 | 52BABB3927E7DD5500999F01 /* Build configuration list for PBXNativeTarget "Fragment-macOS-Tests" */ = { 1072 | isa = XCConfigurationList; 1073 | buildConfigurations = ( 1074 | 52BABB3A27E7DD5500999F01 /* Debug */, 1075 | 52BABB3B27E7DD5500999F01 /* Release */, 1076 | ); 1077 | defaultConfigurationIsVisible = 0; 1078 | defaultConfigurationName = Release; 1079 | }; 1080 | /* End XCConfigurationList section */ 1081 | 1082 | /* Begin XCRemoteSwiftPackageReference section */ 1083 | 5254DDFD27EF8224005BAC56 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = { 1084 | isa = XCRemoteSwiftPackageReference; 1085 | repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols"; 1086 | requirement = { 1087 | kind = upToNextMajorVersion; 1088 | minimumVersion = 2.0.0; 1089 | }; 1090 | }; 1091 | 525D860627E762B40066B147 /* XCRemoteSwiftPackageReference "octokit" */ = { 1092 | isa = XCRemoteSwiftPackageReference; 1093 | repositoryURL = "https://github.com/nerdishbynature/octokit.swift"; 1094 | requirement = { 1095 | kind = upToNextMajorVersion; 1096 | minimumVersion = 0.9.0; 1097 | }; 1098 | }; 1099 | 526D97C127F0C25B00BD46CE /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { 1100 | isa = XCRemoteSwiftPackageReference; 1101 | repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess"; 1102 | requirement = { 1103 | kind = upToNextMajorVersion; 1104 | minimumVersion = 4.0.0; 1105 | }; 1106 | }; 1107 | 526D97C627F0C5BE00BD46CE /* XCRemoteSwiftPackageReference "Highlightr" */ = { 1108 | isa = XCRemoteSwiftPackageReference; 1109 | repositoryURL = "https://github.com/raspu/Highlightr"; 1110 | requirement = { 1111 | kind = upToNextMajorVersion; 1112 | minimumVersion = 2.0.0; 1113 | }; 1114 | }; 1115 | 52E3296927FBBE840059F82B /* XCRemoteSwiftPackageReference "buymeacoffee" */ = { 1116 | isa = XCRemoteSwiftPackageReference; 1117 | repositoryURL = "https://github.com/dan-hart/buymeacoffee"; 1118 | requirement = { 1119 | branch = master; 1120 | kind = branch; 1121 | }; 1122 | }; 1123 | 5A23880527FB47E300480C20 /* XCRemoteSwiftPackageReference "SwifterSwift" */ = { 1124 | isa = XCRemoteSwiftPackageReference; 1125 | repositoryURL = "https://github.com/SwifterSwift/SwifterSwift"; 1126 | requirement = { 1127 | kind = upToNextMajorVersion; 1128 | minimumVersion = 5.0.0; 1129 | }; 1130 | }; 1131 | 5A4C7E5427F3B600006B3A4A /* XCRemoteSwiftPackageReference "CodeEditor" */ = { 1132 | isa = XCRemoteSwiftPackageReference; 1133 | repositoryURL = "https://github.com/ZeeZide/CodeEditor"; 1134 | requirement = { 1135 | kind = upToNextMajorVersion; 1136 | minimumVersion = 1.0.0; 1137 | }; 1138 | }; 1139 | 5AD4DFF127F3AC7A003C2C61 /* XCRemoteSwiftPackageReference "DHCacheKit" */ = { 1140 | isa = XCRemoteSwiftPackageReference; 1141 | repositoryURL = "https://github.com/dan-hart/DHCacheKit"; 1142 | requirement = { 1143 | kind = exactVersion; 1144 | version = 0.0.3; 1145 | }; 1146 | }; 1147 | /* End XCRemoteSwiftPackageReference section */ 1148 | 1149 | /* Begin XCSwiftPackageProductDependency section */ 1150 | 522915BF27E789E20087530C /* OctoKit */ = { 1151 | isa = XCSwiftPackageProductDependency; 1152 | package = 525D860627E762B40066B147 /* XCRemoteSwiftPackageReference "octokit" */; 1153 | productName = OctoKit; 1154 | }; 1155 | 5254DDFE27EF8224005BAC56 /* SFSafeSymbols */ = { 1156 | isa = XCSwiftPackageProductDependency; 1157 | package = 5254DDFD27EF8224005BAC56 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; 1158 | productName = SFSafeSymbols; 1159 | }; 1160 | 5254DE0327EF837A005BAC56 /* SFSafeSymbols */ = { 1161 | isa = XCSwiftPackageProductDependency; 1162 | package = 5254DDFD27EF8224005BAC56 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; 1163 | productName = SFSafeSymbols; 1164 | }; 1165 | 525D860727E762B40066B147 /* OctoKit */ = { 1166 | isa = XCSwiftPackageProductDependency; 1167 | package = 525D860627E762B40066B147 /* XCRemoteSwiftPackageReference "octokit" */; 1168 | productName = OctoKit; 1169 | }; 1170 | 526D97C227F0C25B00BD46CE /* KeychainAccess */ = { 1171 | isa = XCSwiftPackageProductDependency; 1172 | package = 526D97C127F0C25B00BD46CE /* XCRemoteSwiftPackageReference "KeychainAccess" */; 1173 | productName = KeychainAccess; 1174 | }; 1175 | 526D97C427F0C26600BD46CE /* KeychainAccess */ = { 1176 | isa = XCSwiftPackageProductDependency; 1177 | package = 526D97C127F0C25B00BD46CE /* XCRemoteSwiftPackageReference "KeychainAccess" */; 1178 | productName = KeychainAccess; 1179 | }; 1180 | 526D97C727F0C5BE00BD46CE /* Highlightr */ = { 1181 | isa = XCSwiftPackageProductDependency; 1182 | package = 526D97C627F0C5BE00BD46CE /* XCRemoteSwiftPackageReference "Highlightr" */; 1183 | productName = Highlightr; 1184 | }; 1185 | 526D97C927F0C5C500BD46CE /* Highlightr */ = { 1186 | isa = XCSwiftPackageProductDependency; 1187 | package = 526D97C627F0C5BE00BD46CE /* XCRemoteSwiftPackageReference "Highlightr" */; 1188 | productName = Highlightr; 1189 | }; 1190 | 5A23880627FB47E300480C20 /* SwifterSwift */ = { 1191 | isa = XCSwiftPackageProductDependency; 1192 | package = 5A23880527FB47E300480C20 /* XCRemoteSwiftPackageReference "SwifterSwift" */; 1193 | productName = SwifterSwift; 1194 | }; 1195 | 5A23880827FB47F200480C20 /* SwifterSwift */ = { 1196 | isa = XCSwiftPackageProductDependency; 1197 | package = 5A23880527FB47E300480C20 /* XCRemoteSwiftPackageReference "SwifterSwift" */; 1198 | productName = SwifterSwift; 1199 | }; 1200 | 5A4C7E5527F3B600006B3A4A /* CodeEditor */ = { 1201 | isa = XCSwiftPackageProductDependency; 1202 | package = 5A4C7E5427F3B600006B3A4A /* XCRemoteSwiftPackageReference "CodeEditor" */; 1203 | productName = CodeEditor; 1204 | }; 1205 | 5A4C7E5727F3BE78006B3A4A /* CodeEditor */ = { 1206 | isa = XCSwiftPackageProductDependency; 1207 | package = 5A4C7E5427F3B600006B3A4A /* XCRemoteSwiftPackageReference "CodeEditor" */; 1208 | productName = CodeEditor; 1209 | }; 1210 | 5AD4DFF227F3AC7A003C2C61 /* DHCacheKit */ = { 1211 | isa = XCSwiftPackageProductDependency; 1212 | package = 5AD4DFF127F3AC7A003C2C61 /* XCRemoteSwiftPackageReference "DHCacheKit" */; 1213 | productName = DHCacheKit; 1214 | }; 1215 | 5AD4DFF427F3AC87003C2C61 /* DHCacheKit */ = { 1216 | isa = XCSwiftPackageProductDependency; 1217 | package = 5AD4DFF127F3AC7A003C2C61 /* XCRemoteSwiftPackageReference "DHCacheKit" */; 1218 | productName = DHCacheKit; 1219 | }; 1220 | /* End XCSwiftPackageProductDependency section */ 1221 | }; 1222 | rootObject = 525D85B027E760A40066B147 /* Project object */; 1223 | } 1224 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "buymeacoffee", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/dan-hart/buymeacoffee", 7 | "state" : { 8 | "branch" : "master", 9 | "revision" : "850b6346dcdc96fe761a5bf953294d3885ffac7d" 10 | } 11 | }, 12 | { 13 | "identity" : "codeeditor", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/ZeeZide/CodeEditor", 16 | "state" : { 17 | "revision" : "5856fac22b0a2174dbdea212784567c8c9cd1129", 18 | "version" : "1.2.0" 19 | } 20 | }, 21 | { 22 | "identity" : "dhcachekit", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/dan-hart/DHCacheKit", 25 | "state" : { 26 | "revision" : "4317aa6d9ae4db33325b51aa2ea2e6f6d09b3b40", 27 | "version" : "0.0.3" 28 | } 29 | }, 30 | { 31 | "identity" : "filekit", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/nvzqz/FileKit", 34 | "state" : { 35 | "revision" : "826d9161b184509f80d85c28cd612d630646de98", 36 | "version" : "6.0.0" 37 | } 38 | }, 39 | { 40 | "identity" : "highlightr", 41 | "kind" : "remoteSourceControl", 42 | "location" : "https://github.com/raspu/Highlightr", 43 | "state" : { 44 | "revision" : "93199b9e434f04bda956a613af8f571933f9f037", 45 | "version" : "2.1.2" 46 | } 47 | }, 48 | { 49 | "identity" : "keychainaccess", 50 | "kind" : "remoteSourceControl", 51 | "location" : "https://github.com/kishikawakatsumi/KeychainAccess", 52 | "state" : { 53 | "revision" : "84e546727d66f1adc5439debad16270d0fdd04e7", 54 | "version" : "4.2.2" 55 | } 56 | }, 57 | { 58 | "identity" : "octokit.swift", 59 | "kind" : "remoteSourceControl", 60 | "location" : "https://github.com/nerdishbynature/octokit.swift", 61 | "state" : { 62 | "revision" : "9521cdff919053868ab13cd08a228f7bc1bde2a9", 63 | "version" : "0.11.0" 64 | } 65 | }, 66 | { 67 | "identity" : "requestkit", 68 | "kind" : "remoteSourceControl", 69 | "location" : "https://github.com/nerdishbynature/RequestKit.git", 70 | "state" : { 71 | "revision" : "fd5e9e99aada7432170366c9e95967011ce13bad", 72 | "version" : "2.4.0" 73 | } 74 | }, 75 | { 76 | "identity" : "sfsafesymbols", 77 | "kind" : "remoteSourceControl", 78 | "location" : "https://github.com/SFSafeSymbols/SFSafeSymbols", 79 | "state" : { 80 | "revision" : "c61de7a6e9eb1520d32316b06d5932accd974e70", 81 | "version" : "2.1.3" 82 | } 83 | }, 84 | { 85 | "identity" : "swifterswift", 86 | "kind" : "remoteSourceControl", 87 | "location" : "https://github.com/SwifterSwift/SwifterSwift", 88 | "state" : { 89 | "revision" : "dc813f3aa92f904a009fe543b99d5649dce7c134", 90 | "version" : "5.2.0" 91 | } 92 | } 93 | ], 94 | "version" : 2 95 | } 96 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/project.xcworkspace/xcuserdata/danhart.xcuserdatad/IDEFindNavigatorScopes.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcshareddata/xcbaselines/52BABB4327E7DE1900999F01.xcbaseline/21B39069-B75E-4407-A8FF-E868E50C66DA.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | classNames 6 | 7 | Fragment_macOS_UITests 8 | 9 | testLaunchPerformance() 10 | 11 | com.apple.dt.XCTMetric_ApplicationLaunch-ApplicationLaunch.duration 12 | 13 | baselineAverage 14 | 1.008654 15 | baselineIntegrationDisplayName 16 | Local Baseline 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcshareddata/xcbaselines/52BABB4327E7DE1900999F01.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | runDestinationsByUUID 6 | 7 | 21B39069-B75E-4407-A8FF-E868E50C66DA 8 | 9 | localComputer 10 | 11 | busSpeedInMHz 12 | 400 13 | cpuCount 14 | 1 15 | cpuKind 16 | 6-Core Intel Core i5 17 | cpuSpeedInMHz 18 | 3000 19 | logicalCPUCoresPerPackage 20 | 6 21 | modelCode 22 | iMac19,1 23 | physicalCPUCoresPerPackage 24 | 6 25 | platformIdentifier 26 | com.apple.platform.macosx 27 | 28 | targetArchitecture 29 | x86_64 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcshareddata/xcbaselines/52BABB5227E7DE3300999F01.xcbaseline/AE7DEE5B-077D-4779-9906-03EA21164357.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | classNames 6 | 7 | Fragment_iOS_UITests 8 | 9 | testLaunchPerformance() 10 | 11 | com.apple.dt.XCTMetric_ApplicationLaunch-AppLaunch.duration 12 | 13 | baselineAverage 14 | 1.329440 15 | baselineIntegrationDisplayName 16 | Local Baseline 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcshareddata/xcbaselines/52BABB5227E7DE3300999F01.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | runDestinationsByUUID 6 | 7 | AE7DEE5B-077D-4779-9906-03EA21164357 8 | 9 | localComputer 10 | 11 | busSpeedInMHz 12 | 400 13 | cpuCount 14 | 1 15 | cpuKind 16 | 6-Core Intel Core i5 17 | cpuSpeedInMHz 18 | 3000 19 | logicalCPUCoresPerPackage 20 | 6 21 | modelCode 22 | iMac19,1 23 | physicalCPUCoresPerPackage 24 | 6 25 | platformIdentifier 26 | com.apple.platform.macosx 27 | 28 | targetArchitecture 29 | x86_64 30 | targetDevice 31 | 32 | modelCode 33 | iPhone14,6 34 | platformIdentifier 35 | com.apple.platform.iphonesimulator 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 35 | 41 | 42 | 43 | 44 | 45 | 55 | 57 | 63 | 64 | 65 | 66 | 72 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcshareddata/xcschemes/macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 35 | 41 | 42 | 43 | 44 | 45 | 55 | 57 | 63 | 64 | 65 | 66 | 72 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcuserdata/danhart.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcuserdata/danhart.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Build-and-Test-all.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 6 11 | 12 | Examples (Playground) 1.xcscheme 13 | 14 | isShown 15 | 16 | orderHint 17 | 6 18 | 19 | Examples (Playground) 2.xcscheme 20 | 21 | isShown 22 | 23 | orderHint 24 | 7 25 | 26 | Examples (Playground).xcscheme 27 | 28 | isShown 29 | 30 | orderHint 31 | 5 32 | 33 | FileKit (Playground) 1.xcscheme 34 | 35 | isShown 36 | 37 | orderHint 38 | 3 39 | 40 | FileKit (Playground) 2.xcscheme 41 | 42 | isShown 43 | 44 | orderHint 45 | 4 46 | 47 | FileKit (Playground) 3.xcscheme 48 | 49 | isShown 50 | 51 | orderHint 52 | 7 53 | 54 | FileKit (Playground) 4.xcscheme 55 | 56 | isShown 57 | 58 | orderHint 59 | 8 60 | 61 | FileKit (Playground) 5.xcscheme 62 | 63 | isShown 64 | 65 | orderHint 66 | 9 67 | 68 | FileKit (Playground) 6.xcscheme 69 | 70 | isShown 71 | 72 | orderHint 73 | 3 74 | 75 | FileKit (Playground) 7.xcscheme 76 | 77 | isShown 78 | 79 | orderHint 80 | 10 81 | 82 | FileKit (Playground) 8.xcscheme 83 | 84 | isShown 85 | 86 | orderHint 87 | 11 88 | 89 | FileKit (Playground).xcscheme 90 | 91 | isShown 92 | 93 | orderHint 94 | 2 95 | 96 | Playground_iOS (Playground) 1.xcscheme 97 | 98 | isShown 99 | 100 | orderHint 101 | 3 102 | 103 | Playground_iOS (Playground) 2.xcscheme 104 | 105 | isShown 106 | 107 | orderHint 108 | 4 109 | 110 | Playground_iOS (Playground).xcscheme 111 | 112 | isShown 113 | 114 | orderHint 115 | 2 116 | 117 | Playground_macOS (Playground) 1.xcscheme 118 | 119 | isShown 120 | 121 | orderHint 122 | 6 123 | 124 | Playground_macOS (Playground) 2.xcscheme 125 | 126 | isShown 127 | 128 | orderHint 129 | 7 130 | 131 | Playground_macOS (Playground).xcscheme 132 | 133 | isShown 134 | 135 | orderHint 136 | 5 137 | 138 | iOS.xcscheme_^#shared#^_ 139 | 140 | orderHint 141 | 0 142 | 143 | macOS.xcscheme_^#shared#^_ 144 | 145 | orderHint 146 | 1 147 | 148 | 149 | SuppressBuildableAutocreation 150 | 151 | 525D85BE27E760A60066B147 152 | 153 | primary 154 | 155 | 156 | 525D85C427E760A60066B147 157 | 158 | primary 159 | 160 | 161 | 525D85CB27E760A60066B147 162 | 163 | primary 164 | 165 | 166 | 52BABB3227E7DD5500999F01 167 | 168 | primary 169 | 170 | 171 | 52BABB4327E7DE1900999F01 172 | 173 | primary 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /Fragment.xcodeproj/xcuserdata/dhart.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Examples (Playground) 1.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 7 13 | 14 | Examples (Playground) 2.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 8 20 | 21 | Examples (Playground) 3.xcscheme 22 | 23 | isShown 24 | 25 | orderHint 26 | 11 27 | 28 | Examples (Playground) 4.xcscheme 29 | 30 | isShown 31 | 32 | orderHint 33 | 12 34 | 35 | Examples (Playground) 5.xcscheme 36 | 37 | isShown 38 | 39 | orderHint 40 | 13 41 | 42 | Examples (Playground).xcscheme 43 | 44 | isShown 45 | 46 | orderHint 47 | 2 48 | 49 | FileKit (Playground) 1.xcscheme 50 | 51 | isShown 52 | 53 | orderHint 54 | 4 55 | 56 | FileKit (Playground) 2.xcscheme 57 | 58 | isShown 59 | 60 | orderHint 61 | 5 62 | 63 | FileKit (Playground) 3.xcscheme 64 | 65 | isShown 66 | 67 | orderHint 68 | 6 69 | 70 | FileKit (Playground) 4.xcscheme 71 | 72 | isShown 73 | 74 | orderHint 75 | 9 76 | 77 | FileKit (Playground) 5.xcscheme 78 | 79 | isShown 80 | 81 | orderHint 82 | 10 83 | 84 | FileKit (Playground).xcscheme 85 | 86 | isShown 87 | 88 | orderHint 89 | 3 90 | 91 | iOS.xcscheme_^#shared#^_ 92 | 93 | orderHint 94 | 0 95 | 96 | macOS.xcscheme_^#shared#^_ 97 | 98 | orderHint 99 | 1 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /FragmentSharedTests/TestApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestApp.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | @testable import Fragment 9 | import XCTest 10 | 11 | class TestApp: XCTestCase { 12 | static func appTest() { 13 | let app = FragmentApp() 14 | XCTAssertNotNil(app) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU General Public License 2 | ========================== 3 | 4 | _Version 3, 29 June 2007_ 5 | _Copyright © 2007 Free Software Foundation, Inc. <>_ 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this license 8 | document, but changing it is not allowed. 9 | 10 | ## Preamble 11 | 12 | The GNU General Public License is a free, copyleft license for software and other 13 | kinds of works. 14 | 15 | The licenses for most software and other practical works are designed to take away 16 | your freedom to share and change the works. By contrast, the GNU General Public 17 | License is intended to guarantee your freedom to share and change all versions of a 18 | program--to make sure it remains free software for all its users. We, the Free 19 | Software Foundation, use the GNU General Public License for most of our software; it 20 | applies also to any other work released this way by its authors. You can apply it to 21 | your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not price. Our General 24 | Public Licenses are designed to make sure that you have the freedom to distribute 25 | copies of free software (and charge for them if you wish), that you receive source 26 | code or can get it if you want it, that you can change the software or use pieces of 27 | it in new free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you these rights or 30 | asking you to surrender the rights. Therefore, you have certain responsibilities if 31 | you distribute copies of the software, or if you modify it: responsibilities to 32 | respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether gratis or for a fee, 35 | you must pass on to the recipients the same freedoms that you received. You must make 36 | sure that they, too, receive or can get the source code. And you must show them these 37 | terms so they know their rights. 38 | 39 | Developers that use the GNU GPL protect your rights with two steps: **(1)** assert 40 | copyright on the software, and **(2)** offer you this License giving you legal permission 41 | to copy, distribute and/or modify it. 42 | 43 | For the developers' and authors' protection, the GPL clearly explains that there is 44 | no warranty for this free software. For both users' and authors' sake, the GPL 45 | requires that modified versions be marked as changed, so that their problems will not 46 | be attributed erroneously to authors of previous versions. 47 | 48 | Some devices are designed to deny users access to install or run modified versions of 49 | the software inside them, although the manufacturer can do so. This is fundamentally 50 | incompatible with the aim of protecting users' freedom to change the software. The 51 | systematic pattern of such abuse occurs in the area of products for individuals to 52 | use, which is precisely where it is most unacceptable. Therefore, we have designed 53 | this version of the GPL to prohibit the practice for those products. If such problems 54 | arise substantially in other domains, we stand ready to extend this provision to 55 | those domains in future versions of the GPL, as needed to protect the freedom of 56 | users. 57 | 58 | Finally, every program is threatened constantly by software patents. States should 59 | not allow patents to restrict development and use of software on general-purpose 60 | computers, but in those that do, we wish to avoid the special danger that patents 61 | applied to a free program could make it effectively proprietary. To prevent this, the 62 | GPL assures that patents cannot be used to render the program non-free. 63 | 64 | The precise terms and conditions for copying, distribution and modification follow. 65 | 66 | ## TERMS AND CONDITIONS 67 | 68 | ### 0. Definitions 69 | 70 | “This License” refers to version 3 of the GNU General Public License. 71 | 72 | “Copyright” also means copyright-like laws that apply to other kinds of 73 | works, such as semiconductor masks. 74 | 75 | “The Program” refers to any copyrightable work licensed under this 76 | License. Each licensee is addressed as “you”. “Licensees” and 77 | “recipients” may be individuals or organizations. 78 | 79 | To “modify” a work means to copy from or adapt all or part of the work in 80 | a fashion requiring copyright permission, other than the making of an exact copy. The 81 | resulting work is called a “modified version” of the earlier work or a 82 | work “based on” the earlier work. 83 | 84 | A “covered work” means either the unmodified Program or a work based on 85 | the Program. 86 | 87 | To “propagate” a work means to do anything with it that, without 88 | permission, would make you directly or secondarily liable for infringement under 89 | applicable copyright law, except executing it on a computer or modifying a private 90 | copy. Propagation includes copying, distribution (with or without modification), 91 | making available to the public, and in some countries other activities as well. 92 | 93 | To “convey” a work means any kind of propagation that enables other 94 | parties to make or receive copies. Mere interaction with a user through a computer 95 | network, with no transfer of a copy, is not conveying. 96 | 97 | An interactive user interface displays “Appropriate Legal Notices” to the 98 | extent that it includes a convenient and prominently visible feature that **(1)** 99 | displays an appropriate copyright notice, and **(2)** tells the user that there is no 100 | warranty for the work (except to the extent that warranties are provided), that 101 | licensees may convey the work under this License, and how to view a copy of this 102 | License. If the interface presents a list of user commands or options, such as a 103 | menu, a prominent item in the list meets this criterion. 104 | 105 | ### 1. Source Code 106 | 107 | The “source code” for a work means the preferred form of the work for 108 | making modifications to it. “Object code” means any non-source form of a 109 | work. 110 | 111 | A “Standard Interface” means an interface that either is an official 112 | standard defined by a recognized standards body, or, in the case of interfaces 113 | specified for a particular programming language, one that is widely used among 114 | developers working in that language. 115 | 116 | The “System Libraries” of an executable work include anything, other than 117 | the work as a whole, that **(a)** is included in the normal form of packaging a Major 118 | Component, but which is not part of that Major Component, and **(b)** serves only to 119 | enable use of the work with that Major Component, or to implement a Standard 120 | Interface for which an implementation is available to the public in source code form. 121 | A “Major Component”, in this context, means a major essential component 122 | (kernel, window system, and so on) of the specific operating system (if any) on which 123 | the executable work runs, or a compiler used to produce the work, or an object code 124 | interpreter used to run it. 125 | 126 | The “Corresponding Source” for a work in object code form means all the 127 | source code needed to generate, install, and (for an executable work) run the object 128 | code and to modify the work, including scripts to control those activities. However, 129 | it does not include the work's System Libraries, or general-purpose tools or 130 | generally available free programs which are used unmodified in performing those 131 | activities but which are not part of the work. For example, Corresponding Source 132 | includes interface definition files associated with source files for the work, and 133 | the source code for shared libraries and dynamically linked subprograms that the work 134 | is specifically designed to require, such as by intimate data communication or 135 | control flow between those subprograms and other parts of the work. 136 | 137 | The Corresponding Source need not include anything that users can regenerate 138 | automatically from other parts of the Corresponding Source. 139 | 140 | The Corresponding Source for a work in source code form is that same work. 141 | 142 | ### 2. Basic Permissions 143 | 144 | All rights granted under this License are granted for the term of copyright on the 145 | Program, and are irrevocable provided the stated conditions are met. This License 146 | explicitly affirms your unlimited permission to run the unmodified Program. The 147 | output from running a covered work is covered by this License only if the output, 148 | given its content, constitutes a covered work. This License acknowledges your rights 149 | of fair use or other equivalent, as provided by copyright law. 150 | 151 | You may make, run and propagate covered works that you do not convey, without 152 | conditions so long as your license otherwise remains in force. You may convey covered 153 | works to others for the sole purpose of having them make modifications exclusively 154 | for you, or provide you with facilities for running those works, provided that you 155 | comply with the terms of this License in conveying all material for which you do not 156 | control copyright. Those thus making or running the covered works for you must do so 157 | exclusively on your behalf, under your direction and control, on terms that prohibit 158 | them from making any copies of your copyrighted material outside their relationship 159 | with you. 160 | 161 | Conveying under any other circumstances is permitted solely under the conditions 162 | stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 163 | 164 | ### 3. Protecting Users' Legal Rights From Anti-Circumvention Law 165 | 166 | No covered work shall be deemed part of an effective technological measure under any 167 | applicable law fulfilling obligations under article 11 of the WIPO copyright treaty 168 | adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention 169 | of such measures. 170 | 171 | When you convey a covered work, you waive any legal power to forbid circumvention of 172 | technological measures to the extent such circumvention is effected by exercising 173 | rights under this License with respect to the covered work, and you disclaim any 174 | intention to limit operation or modification of the work as a means of enforcing, 175 | against the work's users, your or third parties' legal rights to forbid circumvention 176 | of technological measures. 177 | 178 | ### 4. Conveying Verbatim Copies 179 | 180 | You may convey verbatim copies of the Program's source code as you receive it, in any 181 | medium, provided that you conspicuously and appropriately publish on each copy an 182 | appropriate copyright notice; keep intact all notices stating that this License and 183 | any non-permissive terms added in accord with section 7 apply to the code; keep 184 | intact all notices of the absence of any warranty; and give all recipients a copy of 185 | this License along with the Program. 186 | 187 | You may charge any price or no price for each copy that you convey, and you may offer 188 | support or warranty protection for a fee. 189 | 190 | ### 5. Conveying Modified Source Versions 191 | 192 | You may convey a work based on the Program, or the modifications to produce it from 193 | the Program, in the form of source code under the terms of section 4, provided that 194 | you also meet all of these conditions: 195 | 196 | * **a)** The work must carry prominent notices stating that you modified it, and giving a 197 | relevant date. 198 | * **b)** The work must carry prominent notices stating that it is released under this 199 | License and any conditions added under section 7. This requirement modifies the 200 | requirement in section 4 to “keep intact all notices”. 201 | * **c)** You must license the entire work, as a whole, under this License to anyone who 202 | comes into possession of a copy. This License will therefore apply, along with any 203 | applicable section 7 additional terms, to the whole of the work, and all its parts, 204 | regardless of how they are packaged. This License gives no permission to license the 205 | work in any other way, but it does not invalidate such permission if you have 206 | separately received it. 207 | * **d)** If the work has interactive user interfaces, each must display Appropriate Legal 208 | Notices; however, if the Program has interactive interfaces that do not display 209 | Appropriate Legal Notices, your work need not make them do so. 210 | 211 | A compilation of a covered work with other separate and independent works, which are 212 | not by their nature extensions of the covered work, and which are not combined with 213 | it such as to form a larger program, in or on a volume of a storage or distribution 214 | medium, is called an “aggregate” if the compilation and its resulting 215 | copyright are not used to limit the access or legal rights of the compilation's users 216 | beyond what the individual works permit. Inclusion of a covered work in an aggregate 217 | does not cause this License to apply to the other parts of the aggregate. 218 | 219 | ### 6. Conveying Non-Source Forms 220 | 221 | You may convey a covered work in object code form under the terms of sections 4 and 222 | 5, provided that you also convey the machine-readable Corresponding Source under the 223 | terms of this License, in one of these ways: 224 | 225 | * **a)** Convey the object code in, or embodied in, a physical product (including a 226 | physical distribution medium), accompanied by the Corresponding Source fixed on a 227 | durable physical medium customarily used for software interchange. 228 | * **b)** Convey the object code in, or embodied in, a physical product (including a 229 | physical distribution medium), accompanied by a written offer, valid for at least 230 | three years and valid for as long as you offer spare parts or customer support for 231 | that product model, to give anyone who possesses the object code either **(1)** a copy of 232 | the Corresponding Source for all the software in the product that is covered by this 233 | License, on a durable physical medium customarily used for software interchange, for 234 | a price no more than your reasonable cost of physically performing this conveying of 235 | source, or **(2)** access to copy the Corresponding Source from a network server at no 236 | charge. 237 | * **c)** Convey individual copies of the object code with a copy of the written offer to 238 | provide the Corresponding Source. This alternative is allowed only occasionally and 239 | noncommercially, and only if you received the object code with such an offer, in 240 | accord with subsection 6b. 241 | * **d)** Convey the object code by offering access from a designated place (gratis or for 242 | a charge), and offer equivalent access to the Corresponding Source in the same way 243 | through the same place at no further charge. You need not require recipients to copy 244 | the Corresponding Source along with the object code. If the place to copy the object 245 | code is a network server, the Corresponding Source may be on a different server 246 | (operated by you or a third party) that supports equivalent copying facilities, 247 | provided you maintain clear directions next to the object code saying where to find 248 | the Corresponding Source. Regardless of what server hosts the Corresponding Source, 249 | you remain obligated to ensure that it is available for as long as needed to satisfy 250 | these requirements. 251 | * **e)** Convey the object code using peer-to-peer transmission, provided you inform 252 | other peers where the object code and Corresponding Source of the work are being 253 | offered to the general public at no charge under subsection 6d. 254 | 255 | A separable portion of the object code, whose source code is excluded from the 256 | Corresponding Source as a System Library, need not be included in conveying the 257 | object code work. 258 | 259 | A “User Product” is either **(1)** a “consumer product”, which 260 | means any tangible personal property which is normally used for personal, family, or 261 | household purposes, or **(2)** anything designed or sold for incorporation into a 262 | dwelling. In determining whether a product is a consumer product, doubtful cases 263 | shall be resolved in favor of coverage. For a particular product received by a 264 | particular user, “normally used” refers to a typical or common use of 265 | that class of product, regardless of the status of the particular user or of the way 266 | in which the particular user actually uses, or expects or is expected to use, the 267 | product. A product is a consumer product regardless of whether the product has 268 | substantial commercial, industrial or non-consumer uses, unless such uses represent 269 | the only significant mode of use of the product. 270 | 271 | “Installation Information” for a User Product means any methods, 272 | procedures, authorization keys, or other information required to install and execute 273 | modified versions of a covered work in that User Product from a modified version of 274 | its Corresponding Source. The information must suffice to ensure that the continued 275 | functioning of the modified object code is in no case prevented or interfered with 276 | solely because modification has been made. 277 | 278 | If you convey an object code work under this section in, or with, or specifically for 279 | use in, a User Product, and the conveying occurs as part of a transaction in which 280 | the right of possession and use of the User Product is transferred to the recipient 281 | in perpetuity or for a fixed term (regardless of how the transaction is 282 | characterized), the Corresponding Source conveyed under this section must be 283 | accompanied by the Installation Information. But this requirement does not apply if 284 | neither you nor any third party retains the ability to install modified object code 285 | on the User Product (for example, the work has been installed in ROM). 286 | 287 | The requirement to provide Installation Information does not include a requirement to 288 | continue to provide support service, warranty, or updates for a work that has been 289 | modified or installed by the recipient, or for the User Product in which it has been 290 | modified or installed. Access to a network may be denied when the modification itself 291 | materially and adversely affects the operation of the network or violates the rules 292 | and protocols for communication across the network. 293 | 294 | Corresponding Source conveyed, and Installation Information provided, in accord with 295 | this section must be in a format that is publicly documented (and with an 296 | implementation available to the public in source code form), and must require no 297 | special password or key for unpacking, reading or copying. 298 | 299 | ### 7. Additional Terms 300 | 301 | “Additional permissions” are terms that supplement the terms of this 302 | License by making exceptions from one or more of its conditions. Additional 303 | permissions that are applicable to the entire Program shall be treated as though they 304 | were included in this License, to the extent that they are valid under applicable 305 | law. If additional permissions apply only to part of the Program, that part may be 306 | used separately under those permissions, but the entire Program remains governed by 307 | this License without regard to the additional permissions. 308 | 309 | When you convey a copy of a covered work, you may at your option remove any 310 | additional permissions from that copy, or from any part of it. (Additional 311 | permissions may be written to require their own removal in certain cases when you 312 | modify the work.) You may place additional permissions on material, added by you to a 313 | covered work, for which you have or can give appropriate copyright permission. 314 | 315 | Notwithstanding any other provision of this License, for material you add to a 316 | covered work, you may (if authorized by the copyright holders of that material) 317 | supplement the terms of this License with terms: 318 | 319 | * **a)** Disclaiming warranty or limiting liability differently from the terms of 320 | sections 15 and 16 of this License; or 321 | * **b)** Requiring preservation of specified reasonable legal notices or author 322 | attributions in that material or in the Appropriate Legal Notices displayed by works 323 | containing it; or 324 | * **c)** Prohibiting misrepresentation of the origin of that material, or requiring that 325 | modified versions of such material be marked in reasonable ways as different from the 326 | original version; or 327 | * **d)** Limiting the use for publicity purposes of names of licensors or authors of the 328 | material; or 329 | * **e)** Declining to grant rights under trademark law for use of some trade names, 330 | trademarks, or service marks; or 331 | * **f)** Requiring indemnification of licensors and authors of that material by anyone 332 | who conveys the material (or modified versions of it) with contractual assumptions of 333 | liability to the recipient, for any liability that these contractual assumptions 334 | directly impose on those licensors and authors. 335 | 336 | All other non-permissive additional terms are considered “further 337 | restrictions” within the meaning of section 10. If the Program as you received 338 | it, or any part of it, contains a notice stating that it is governed by this License 339 | along with a term that is a further restriction, you may remove that term. If a 340 | license document contains a further restriction but permits relicensing or conveying 341 | under this License, you may add to a covered work material governed by the terms of 342 | that license document, provided that the further restriction does not survive such 343 | relicensing or conveying. 344 | 345 | If you add terms to a covered work in accord with this section, you must place, in 346 | the relevant source files, a statement of the additional terms that apply to those 347 | files, or a notice indicating where to find the applicable terms. 348 | 349 | Additional terms, permissive or non-permissive, may be stated in the form of a 350 | separately written license, or stated as exceptions; the above requirements apply 351 | either way. 352 | 353 | ### 8. Termination 354 | 355 | You may not propagate or modify a covered work except as expressly provided under 356 | this License. Any attempt otherwise to propagate or modify it is void, and will 357 | automatically terminate your rights under this License (including any patent licenses 358 | granted under the third paragraph of section 11). 359 | 360 | However, if you cease all violation of this License, then your license from a 361 | particular copyright holder is reinstated **(a)** provisionally, unless and until the 362 | copyright holder explicitly and finally terminates your license, and **(b)** permanently, 363 | if the copyright holder fails to notify you of the violation by some reasonable means 364 | prior to 60 days after the cessation. 365 | 366 | Moreover, your license from a particular copyright holder is reinstated permanently 367 | if the copyright holder notifies you of the violation by some reasonable means, this 368 | is the first time you have received notice of violation of this License (for any 369 | work) from that copyright holder, and you cure the violation prior to 30 days after 370 | your receipt of the notice. 371 | 372 | Termination of your rights under this section does not terminate the licenses of 373 | parties who have received copies or rights from you under this License. If your 374 | rights have been terminated and not permanently reinstated, you do not qualify to 375 | receive new licenses for the same material under section 10. 376 | 377 | ### 9. Acceptance Not Required for Having Copies 378 | 379 | You are not required to accept this License in order to receive or run a copy of the 380 | Program. Ancillary propagation of a covered work occurring solely as a consequence of 381 | using peer-to-peer transmission to receive a copy likewise does not require 382 | acceptance. However, nothing other than this License grants you permission to 383 | propagate or modify any covered work. These actions infringe copyright if you do not 384 | accept this License. Therefore, by modifying or propagating a covered work, you 385 | indicate your acceptance of this License to do so. 386 | 387 | ### 10. Automatic Licensing of Downstream Recipients 388 | 389 | Each time you convey a covered work, the recipient automatically receives a license 390 | from the original licensors, to run, modify and propagate that work, subject to this 391 | License. You are not responsible for enforcing compliance by third parties with this 392 | License. 393 | 394 | An “entity transaction” is a transaction transferring control of an 395 | organization, or substantially all assets of one, or subdividing an organization, or 396 | merging organizations. If propagation of a covered work results from an entity 397 | transaction, each party to that transaction who receives a copy of the work also 398 | receives whatever licenses to the work the party's predecessor in interest had or 399 | could give under the previous paragraph, plus a right to possession of the 400 | Corresponding Source of the work from the predecessor in interest, if the predecessor 401 | has it or can get it with reasonable efforts. 402 | 403 | You may not impose any further restrictions on the exercise of the rights granted or 404 | affirmed under this License. For example, you may not impose a license fee, royalty, 405 | or other charge for exercise of rights granted under this License, and you may not 406 | initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging 407 | that any patent claim is infringed by making, using, selling, offering for sale, or 408 | importing the Program or any portion of it. 409 | 410 | ### 11. Patents 411 | 412 | A “contributor” is a copyright holder who authorizes use under this 413 | License of the Program or a work on which the Program is based. The work thus 414 | licensed is called the contributor's “contributor version”. 415 | 416 | A contributor's “essential patent claims” are all patent claims owned or 417 | controlled by the contributor, whether already acquired or hereafter acquired, that 418 | would be infringed by some manner, permitted by this License, of making, using, or 419 | selling its contributor version, but do not include claims that would be infringed 420 | only as a consequence of further modification of the contributor version. For 421 | purposes of this definition, “control” includes the right to grant patent 422 | sublicenses in a manner consistent with the requirements of this License. 423 | 424 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent license 425 | under the contributor's essential patent claims, to make, use, sell, offer for sale, 426 | import and otherwise run, modify and propagate the contents of its contributor 427 | version. 428 | 429 | In the following three paragraphs, a “patent license” is any express 430 | agreement or commitment, however denominated, not to enforce a patent (such as an 431 | express permission to practice a patent or covenant not to sue for patent 432 | infringement). To “grant” such a patent license to a party means to make 433 | such an agreement or commitment not to enforce a patent against the party. 434 | 435 | If you convey a covered work, knowingly relying on a patent license, and the 436 | Corresponding Source of the work is not available for anyone to copy, free of charge 437 | and under the terms of this License, through a publicly available network server or 438 | other readily accessible means, then you must either **(1)** cause the Corresponding 439 | Source to be so available, or **(2)** arrange to deprive yourself of the benefit of the 440 | patent license for this particular work, or **(3)** arrange, in a manner consistent with 441 | the requirements of this License, to extend the patent license to downstream 442 | recipients. “Knowingly relying” means you have actual knowledge that, but 443 | for the patent license, your conveying the covered work in a country, or your 444 | recipient's use of the covered work in a country, would infringe one or more 445 | identifiable patents in that country that you have reason to believe are valid. 446 | 447 | If, pursuant to or in connection with a single transaction or arrangement, you 448 | convey, or propagate by procuring conveyance of, a covered work, and grant a patent 449 | license to some of the parties receiving the covered work authorizing them to use, 450 | propagate, modify or convey a specific copy of the covered work, then the patent 451 | license you grant is automatically extended to all recipients of the covered work and 452 | works based on it. 453 | 454 | A patent license is “discriminatory” if it does not include within the 455 | scope of its coverage, prohibits the exercise of, or is conditioned on the 456 | non-exercise of one or more of the rights that are specifically granted under this 457 | License. You may not convey a covered work if you are a party to an arrangement with 458 | a third party that is in the business of distributing software, under which you make 459 | payment to the third party based on the extent of your activity of conveying the 460 | work, and under which the third party grants, to any of the parties who would receive 461 | the covered work from you, a discriminatory patent license **(a)** in connection with 462 | copies of the covered work conveyed by you (or copies made from those copies), or **(b)** 463 | primarily for and in connection with specific products or compilations that contain 464 | the covered work, unless you entered into that arrangement, or that patent license 465 | was granted, prior to 28 March 2007. 466 | 467 | Nothing in this License shall be construed as excluding or limiting any implied 468 | license or other defenses to infringement that may otherwise be available to you 469 | under applicable patent law. 470 | 471 | ### 12. No Surrender of Others' Freedom 472 | 473 | If conditions are imposed on you (whether by court order, agreement or otherwise) 474 | that contradict the conditions of this License, they do not excuse you from the 475 | conditions of this License. If you cannot convey a covered work so as to satisfy 476 | simultaneously your obligations under this License and any other pertinent 477 | obligations, then as a consequence you may not convey it at all. For example, if you 478 | agree to terms that obligate you to collect a royalty for further conveying from 479 | those to whom you convey the Program, the only way you could satisfy both those terms 480 | and this License would be to refrain entirely from conveying the Program. 481 | 482 | ### 13. Use with the GNU Affero General Public License 483 | 484 | Notwithstanding any other provision of this License, you have permission to link or 485 | combine any covered work with a work licensed under version 3 of the GNU Affero 486 | General Public License into a single combined work, and to convey the resulting work. 487 | The terms of this License will continue to apply to the part which is the covered 488 | work, but the special requirements of the GNU Affero General Public License, section 489 | 13, concerning interaction through a network will apply to the combination as such. 490 | 491 | ### 14. Revised Versions of this License 492 | 493 | The Free Software Foundation may publish revised and/or new versions of the GNU 494 | General Public License from time to time. Such new versions will be similar in spirit 495 | to the present version, but may differ in detail to address new problems or concerns. 496 | 497 | Each version is given a distinguishing version number. If the Program specifies that 498 | a certain numbered version of the GNU General Public License “or any later 499 | version” applies to it, you have the option of following the terms and 500 | conditions either of that numbered version or of any later version published by the 501 | Free Software Foundation. If the Program does not specify a version number of the GNU 502 | General Public License, you may choose any version ever published by the Free 503 | Software Foundation. 504 | 505 | If the Program specifies that a proxy can decide which future versions of the GNU 506 | General Public License can be used, that proxy's public statement of acceptance of a 507 | version permanently authorizes you to choose that version for the Program. 508 | 509 | Later license versions may give you additional or different permissions. However, no 510 | additional obligations are imposed on any author or copyright holder as a result of 511 | your choosing to follow a later version. 512 | 513 | ### 15. Disclaimer of Warranty 514 | 515 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 516 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 517 | PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER 518 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 519 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE 520 | QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE 521 | DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 522 | 523 | ### 16. Limitation of Liability 524 | 525 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY 526 | COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS 527 | PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, 528 | INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 529 | PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE 530 | OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE 531 | WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 532 | POSSIBILITY OF SUCH DAMAGES. 533 | 534 | ### 17. Interpretation of Sections 15 and 16 535 | 536 | If the disclaimer of warranty and limitation of liability provided above cannot be 537 | given local legal effect according to their terms, reviewing courts shall apply local 538 | law that most closely approximates an absolute waiver of all civil liability in 539 | connection with the Program, unless a warranty or assumption of liability accompanies 540 | a copy of the Program in return for a fee. 541 | 542 | _END OF TERMS AND CONDITIONS_ 543 | 544 | ## How to Apply These Terms to Your New Programs 545 | 546 | If you develop a new program, and you want it to be of the greatest possible use to 547 | the public, the best way to achieve this is to make it free software which everyone 548 | can redistribute and change under these terms. 549 | 550 | To do so, attach the following notices to the program. It is safest to attach them 551 | to the start of each source file to most effectively state the exclusion of warranty; 552 | and each file should have at least the “copyright” line and a pointer to 553 | where the full notice is found. 554 | 555 | 556 | Copyright (C) 557 | 558 | This program is free software: you can redistribute it and/or modify 559 | it under the terms of the GNU General Public License as published by 560 | the Free Software Foundation, either version 3 of the License, or 561 | (at your option) any later version. 562 | 563 | This program is distributed in the hope that it will be useful, 564 | but WITHOUT ANY WARRANTY; without even the implied warranty of 565 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 566 | GNU General Public License for more details. 567 | 568 | You should have received a copy of the GNU General Public License 569 | along with this program. If not, see . 570 | 571 | Also add information on how to contact you by electronic and paper mail. 572 | 573 | If the program does terminal interaction, make it output a short notice like this 574 | when it starts in an interactive mode: 575 | 576 | Copyright (C) 577 | This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. 578 | This is free software, and you are welcome to redistribute it 579 | under certain conditions; type 'show c' for details. 580 | 581 | The hypothetical commands `show w` and `show c` should show the appropriate parts of 582 | the General Public License. Of course, your program's commands might be different; 583 | for a GUI interface, you would use an “about box”. 584 | 585 | You should also get your employer (if you work as a programmer) or school, if any, to 586 | sign a “copyright disclaimer” for the program, if necessary. For more 587 | information on this, and how to apply and follow the GNU GPL, see 588 | <>. 589 | 590 | The GNU General Public License does not permit incorporating your program into 591 | proprietary programs. If your program is a subroutine library, you may consider it 592 | more useful to permit linking proprietary applications with the library. If this is 593 | what you want to do, use the GNU Lesser General Public License instead of this 594 | License. But first, please read 595 | <>. 596 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fragment 2 | [![GitHub issues](https://img.shields.io/github/issues/dan-hart/Fragment)](https://github.com/dan-hart/Fragment/issues) 3 | [![GitHub forks](https://img.shields.io/github/forks/dan-hart/Fragment)](https://github.com/dan-hart/Fragment/network) 4 | [![GitHub stars](https://img.shields.io/github/stars/dan-hart/Fragment)](https://github.com/dan-hart/Fragment/stargazers) 5 | [![GitHub license](https://img.shields.io/github/license/dan-hart/Fragment)](https://github.com/dan-hart/Fragment) 6 | [![Maintainability](https://api.codeclimate.com/v1/badges/abb6d83c6dafb22f3bef/maintainability)](https://codeclimate.com/github/dan-hart/Fragment/maintainability) 7 | [![ios tests](https://github.com/dan-hart/Fragment/actions/workflows/iOS-test.yml/badge.svg)](https://github.com/dan-hart/Fragment/actions/workflows/iOS-test.yml) 8 | [![macOS tests](https://github.com/dan-hart/Fragment/actions/workflows/macOS-test.yml/badge.svg)](https://github.com/dan-hart/Fragment/actions/workflows/macOS-test.yml) 9 | ### iOS & macOS Gist manager using Github 10 | 11 | ![screen shot 2022-04-04 at 18 32 07](https://user-images.githubusercontent.com/13913605/161664604-ead728bc-cac4-4a39-914c-147e1af2399f.png) 12 | 13 | [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/codedbydan) 14 | -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "extended-srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.412", 9 | "green" : "0.271", 10 | "red" : "0.769" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "extended-srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.412", 27 | "green" : "0.271", 28 | "red" : "0.958" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "filename" : "Icon-33.png", 10 | "idiom" : "mac", 11 | "scale" : "2x", 12 | "size" : "16x16" 13 | }, 14 | { 15 | "filename" : "Icon-32.png", 16 | "idiom" : "mac", 17 | "scale" : "1x", 18 | "size" : "32x32" 19 | }, 20 | { 21 | "filename" : "Icon-65.png", 22 | "idiom" : "mac", 23 | "scale" : "2x", 24 | "size" : "32x32" 25 | }, 26 | { 27 | "filename" : "Icon-128.png", 28 | "idiom" : "mac", 29 | "scale" : "1x", 30 | "size" : "128x128" 31 | }, 32 | { 33 | "filename" : "Icon-257.png", 34 | "idiom" : "mac", 35 | "scale" : "2x", 36 | "size" : "128x128" 37 | }, 38 | { 39 | "filename" : "Icon-256.png", 40 | "idiom" : "mac", 41 | "scale" : "1x", 42 | "size" : "256x256" 43 | }, 44 | { 45 | "filename" : "Icon-513.png", 46 | "idiom" : "mac", 47 | "scale" : "2x", 48 | "size" : "256x256" 49 | }, 50 | { 51 | "filename" : "Icon-512.png", 52 | "idiom" : "mac", 53 | "scale" : "1x", 54 | "size" : "512x512" 55 | }, 56 | { 57 | "filename" : "Icon-1025.png", 58 | "idiom" : "mac", 59 | "scale" : "2x", 60 | "size" : "512x512" 61 | } 62 | ], 63 | "info" : { 64 | "author" : "xcode", 65 | "version" : 1 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-1025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-1025.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-128.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-256.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-257.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-257.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-32.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-33.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-512.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-513.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-65.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon-macOS.appiconset/Icon-65.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "switchify_icon_v01-20@2x.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "switchify_icon_v01-20@3x.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "switchify_icon_v01-29@2x.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "switchify_icon_v01-29@3x.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "switchify_icon_v01-40@2x.png", 29 | "idiom" : "iphone", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "filename" : "switchify_icon_v01-40@3x.png", 35 | "idiom" : "iphone", 36 | "scale" : "3x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "switchify_icon_v01-60@2x.png", 41 | "idiom" : "iphone", 42 | "scale" : "2x", 43 | "size" : "60x60" 44 | }, 45 | { 46 | "filename" : "switchify_icon_v01-60@3x.png", 47 | "idiom" : "iphone", 48 | "scale" : "3x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "switchify_icon_v01-20.png", 53 | "idiom" : "ipad", 54 | "scale" : "1x", 55 | "size" : "20x20" 56 | }, 57 | { 58 | "filename" : "switchify_icon_v01-20@2x.png", 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "20x20" 62 | }, 63 | { 64 | "filename" : "switchify_icon_v01-29.png", 65 | "idiom" : "ipad", 66 | "scale" : "1x", 67 | "size" : "29x29" 68 | }, 69 | { 70 | "filename" : "switchify_icon_v01-29@2x.png", 71 | "idiom" : "ipad", 72 | "scale" : "2x", 73 | "size" : "29x29" 74 | }, 75 | { 76 | "filename" : "switchify_icon_v01-40.png", 77 | "idiom" : "ipad", 78 | "scale" : "1x", 79 | "size" : "40x40" 80 | }, 81 | { 82 | "filename" : "switchify_icon_v01-40@2x.png", 83 | "idiom" : "ipad", 84 | "scale" : "2x", 85 | "size" : "40x40" 86 | }, 87 | { 88 | "filename" : "switchify_icon_v01-76.png", 89 | "idiom" : "ipad", 90 | "scale" : "1x", 91 | "size" : "76x76" 92 | }, 93 | { 94 | "filename" : "switchify_icon_v01-76@2x.png", 95 | "idiom" : "ipad", 96 | "scale" : "2x", 97 | "size" : "76x76" 98 | }, 99 | { 100 | "filename" : "switchify_icon_v01-83.5@2x.png", 101 | "idiom" : "ipad", 102 | "scale" : "2x", 103 | "size" : "83.5x83.5" 104 | }, 105 | { 106 | "filename" : "switchify_icon_v01-1024.png", 107 | "idiom" : "ios-marketing", 108 | "scale" : "1x", 109 | "size" : "1024x1024" 110 | } 111 | ], 112 | "info" : { 113 | "author" : "xcode", 114 | "version" : 1 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-1024.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-20.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-20@2x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-20@3x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-29.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-29@2x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-29@3x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-40.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-40@2x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-40@3x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-60@2x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-60@3x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-76.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-76@2x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dan-hart/Fragment/31ccd2626d1b2abf94e282f0a50940e83afb6d16/Shared/Assets.xcassets/AppIcon.appiconset/switchify_icon_v01-83.5@2x.png -------------------------------------------------------------------------------- /Shared/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Shared/ClipboardHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClipboardHelper.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 4/2/22. 6 | // 7 | 8 | import Foundation 9 | #if canImport(UIKit) 10 | import UIKit 11 | #endif 12 | #if canImport(AppKit) 13 | import AppKit 14 | #endif 15 | 16 | enum ClipboardHelper { 17 | static func getText() -> String? { 18 | #if canImport(UIKit) 19 | return UIPasteboard.general.string 20 | #else 21 | var clipboardItems: [String] = [] 22 | for element in NSPasteboard.general.pasteboardItems! { 23 | if let str = element.string(forType: NSPasteboard.PasteboardType(rawValue: "public.utf8-plain-text")) { 24 | clipboardItems.append(str) 25 | } 26 | } 27 | 28 | // Access the item in the clipboard 29 | return clipboardItems[ifExistsAt: 0] 30 | #endif 31 | } 32 | 33 | static func set(text: String) { 34 | #if canImport(UIKit) 35 | UIPasteboard.general.string = text 36 | #else 37 | let pasteBoard = NSPasteboard.general 38 | pasteBoard.clearContents() 39 | pasteBoard.writeObjects([text as NSString]) 40 | #endif 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Shared/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/26/22. 6 | // 7 | 8 | import Foundation 9 | #if canImport(UIKit) 10 | import UIKit 11 | #endif 12 | 13 | // swiftlint:disable line_length 14 | enum Constants { 15 | static let appName = "Fragment" 16 | static let buyMeACoffeeUsername = "codedbydan" 17 | 18 | enum URL: String { 19 | case repositoryOnGitHub = "https://github.com/dan-hart/Fragment" 20 | case buyMeACoffee = "https://www.buymeacoffee.com/codedbydan" 21 | case githubHowToPersonalAccessToken = "https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token" 22 | } 23 | 24 | enum Feature { 25 | // False 26 | static var ifNoGistsEnableCreateButton = false 27 | static var ifNoGistsEnablePullButton = false 28 | 29 | // True 30 | static var settingsEnabled = true 31 | } 32 | 33 | /// Is the current device running macOS or is it an iPad 34 | static func isMacOrPad() -> Bool { 35 | #if os(macOS) 36 | return true 37 | #endif 38 | 39 | #if canImport(UIKit) 40 | if UIDevice.current.userInterfaceIdiom == .pad { 41 | return true 42 | } else { 43 | return false 44 | } 45 | #endif 46 | } 47 | } 48 | 49 | // swiftlint:enable line_length 50 | -------------------------------------------------------------------------------- /Shared/Extensions/Collections+ifExistsAt.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Collections+ifExistsAt.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/27/22. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Collection where Indices.Iterator.Element == Index { 11 | /// Returns the element at the specified index if it is within bounds, otherwise nil. 12 | subscript(ifExistsAt index: Index) -> Iterator.Element? { 13 | return indices.contains(index) ? self[index] : nil 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Shared/Extensions/OctoKitExtensions/GistExtensions/Gist+Custom.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Gist+Custom.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 4/2/22. 6 | // 7 | 8 | import Foundation 9 | import OctoKit 10 | 11 | public extension Gist { 12 | /// Non-optional identifier for a gist, uses a UUID as fallback 13 | var identifier: String { 14 | id ?? UUID().uuidString 15 | } 16 | 17 | /// The first filename 18 | var filename: String { 19 | "\(files.first?.key ?? "")" 20 | } 21 | 22 | /// The extension with no leading `.` of the filename of the first gist 23 | var fileExtension: String? { 24 | let filename = "\(files.first?.key ?? "")" 25 | if filename.isEmpty { return nil } 26 | return filename.pathExtension 27 | } 28 | 29 | // MARK: - Functions 30 | 31 | /// Does this gist meet the search criteria based on the search text 32 | func meetsSearchCriteria(text: String) -> Bool { 33 | let lowercasedSearchText = text.lowercased() 34 | let descriptionContainsText = description?.lowercased().contains(lowercasedSearchText) ?? false 35 | let fileExtensionContainsText = fileExtension?.lowercased().contains(lowercasedSearchText) ?? false 36 | let filenameContainsText = files.first?.value.filename?.lowercased().contains(lowercasedSearchText) ?? false 37 | 38 | if descriptionContainsText || 39 | filenameContainsText || 40 | fileExtensionContainsText 41 | { 42 | return true 43 | } else { 44 | return false 45 | } 46 | } 47 | } 48 | 49 | extension Gist: Equatable { 50 | public static func == (lhs: Gist, rhs: Gist) -> Bool { 51 | lhs.identifier == rhs.identifier 52 | } 53 | } 54 | 55 | extension Gist: Hashable { 56 | public func hash(into hasher: inout Hasher) { 57 | hasher.combine(identifier) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Shared/Extensions/OctoKitExtensions/GistExtensions/Gist+language.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Gist+language.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/27/22. 6 | // 7 | 8 | import Foundation 9 | import OctoKit 10 | 11 | extension Gist { 12 | var language: Language? { 13 | if let fileURL = url { 14 | return Language(url: fileURL) 15 | } else { 16 | return nil 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Shared/Extensions/OctoKitExtensions/GistExtensions/Gist+text.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Gist+text.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/27/22. 6 | // 7 | 8 | import Foundation 9 | import Highlightr 10 | import OctoKit 11 | 12 | extension Gist { 13 | var text: String { 14 | if let file = files.first, let url = file.value.rawURL, let text = try? String(contentsOf: url) { 15 | return text 16 | } else { 17 | return "" 18 | } 19 | } 20 | 21 | var lines: [String] { 22 | text.components(separatedBy: "\n") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Shared/Fragment.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Shared/Fragment.xcdatamodeld/Shared.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Shared/FragmentApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FragmentApp.swift 3 | // Shared 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct FragmentApp: App { 12 | @StateObject var sessionHandler = SessionHandler() 13 | 14 | @State var isLoading = false 15 | @State var isSettingsLoading = false 16 | 17 | var body: some Scene { 18 | WindowGroup { 19 | MainView(isLoading: $isLoading) 20 | .environmentObject(sessionHandler) 21 | .alert(isPresented: $sessionHandler.isShowingAlert) { 22 | sessionHandler.alert ?? Alert(title: Text("")) 23 | } 24 | .onAppear { 25 | sessionHandler.callTask { 26 | isLoading = true 27 | try await sessionHandler.startSession(with: sessionHandler.token) 28 | isLoading = false 29 | } 30 | } 31 | } 32 | 33 | #if os(macOS) 34 | Settings { 35 | if Constants.Feature.settingsEnabled { 36 | SettingsView(isLoading: $isSettingsLoading) 37 | .environmentObject(sessionHandler) 38 | .frame(width: 400, height: 400) 39 | .redacted(reason: isSettingsLoading ? .placeholder : []) 40 | } 41 | } 42 | #endif 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Shared/Handler/SessionHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionHandler.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 4/4/22. 6 | // 7 | 8 | import Foundation 9 | import KeychainAccess 10 | import OctoKit 11 | import SwiftUI 12 | 13 | class SessionHandler: ObservableObject { 14 | var keychainKeyIdentifier = "FRAGMENT_GITHUB_API_TOKEN" 15 | 16 | // MARK: - Publishable data 17 | 18 | @Published public var isAuthenticated = false 19 | @Published public var gists: [Gist] = [] 20 | 21 | private var configuration = TokenConfiguration() 22 | 23 | // MARK: - Computed 24 | 25 | var bundleID: String { 26 | Bundle.main.bundleIdentifier ?? "" 27 | } 28 | 29 | private var keychain: Keychain { 30 | Keychain(service: bundleID) 31 | } 32 | 33 | var token: String? { 34 | keychain[keychainKeyIdentifier] 35 | } 36 | 37 | // MARK: - Alerts 38 | 39 | @Published var alert: Alert? { 40 | didSet { isShowingAlert = alert != nil } 41 | } 42 | 43 | @Published var isShowingAlert = false 44 | 45 | // MARK: - Settings 46 | 47 | @AppStorage("fontSize") var fontSize: Int = 12 { 48 | didSet { 49 | cgFloatFontSize = CGFloat(fontSize) 50 | } 51 | } 52 | 53 | @Published var cgFloatFontSize: CGFloat = 12 54 | 55 | // MARK: - Initialization 56 | 57 | init() { 58 | cgFloatFontSize = CGFloat(fontSize) 59 | } 60 | 61 | // MARK: - Methods 62 | 63 | func invalidateSession() { 64 | keychain[keychainKeyIdentifier] = nil 65 | isAuthenticated = false 66 | } 67 | 68 | func startSession(with optionalToken: String? = nil) async throws { 69 | if let token = optionalToken { 70 | // Continue existing session 71 | configuration = try await authenticate(using: token) 72 | keychain[keychainKeyIdentifier] = token 73 | } else { 74 | // No token. Start a new session by providing one. 75 | } 76 | } 77 | 78 | // MARK: - Authentication 79 | 80 | private func getToken() throws -> String { 81 | guard let token = keychain[keychainKeyIdentifier] else { 82 | throw FragmentError.nilToken 83 | } 84 | 85 | return token 86 | } 87 | 88 | @MainActor 89 | private func authenticate(using token: String?) async throws -> TokenConfiguration { 90 | guard let token = token, !token.isEmpty else { 91 | throw FragmentError.nilToken 92 | } 93 | 94 | let configuration = TokenConfiguration(token) 95 | let response = await withCheckedContinuation { continuation in 96 | Octokit(configuration).me { response in 97 | continuation.resume(returning: response) 98 | } 99 | } 100 | 101 | switch response { 102 | case .success: 103 | isAuthenticated = true 104 | return configuration 105 | case let .failure(error): 106 | throw error 107 | } 108 | } 109 | 110 | // MARK: - Gist CRU 111 | 112 | func update( 113 | _ identifier: String, 114 | _ description: String, 115 | _ filename: String, 116 | _ content: String 117 | ) async throws -> Gist { 118 | try await validate() 119 | 120 | let response = await withCheckedContinuation { continuation in 121 | Octokit(configuration).patchGistFile(id: identifier, 122 | description: description, 123 | filename: filename, 124 | fileContent: content) 125 | { response in 126 | continuation.resume(returning: response) 127 | } 128 | } 129 | 130 | switch response { 131 | case let .success(gist): 132 | return gist 133 | case let .failure(error): 134 | throw error 135 | } 136 | } 137 | 138 | func create( 139 | gist filename: String, 140 | _ description: String, 141 | _ content: String, 142 | _ visibility: Visibility 143 | ) async throws -> Gist { 144 | try await validate() 145 | 146 | let response = await withCheckedContinuation { continuation in 147 | Octokit(configuration).postGistFile( 148 | description: description, 149 | filename: filename, 150 | fileContent: content, 151 | publicAccess: visibility == .public ? true : false 152 | ) { response in 153 | continuation.resume(returning: response) 154 | } 155 | } 156 | 157 | switch response { 158 | case let .success(gist): 159 | return gist 160 | case let .failure(error): 161 | throw error 162 | } 163 | } 164 | 165 | @MainActor 166 | func refreshGists() async throws { 167 | try await validate() 168 | gists = try await myGists() 169 | } 170 | 171 | func myGists() async throws -> [Gist] { 172 | try await validate() 173 | 174 | let response = await withCheckedContinuation { continuation in 175 | Octokit(configuration).myGists { response in 176 | continuation.resume(returning: response) 177 | } 178 | } 179 | 180 | switch response { 181 | case let .success(gists): 182 | return gists 183 | case .failure: 184 | throw FragmentError.couldNotFetchData 185 | } 186 | } 187 | 188 | // MARK: - Profile 189 | 190 | func me() async throws -> User { 191 | try await validate() 192 | 193 | let response = await withCheckedContinuation { continuation in 194 | Octokit(configuration).me { response in 195 | continuation.resume(returning: response) 196 | } 197 | } 198 | 199 | switch response { 200 | case let .success(user): 201 | return user 202 | case let .failure(error): 203 | throw error 204 | } 205 | } 206 | 207 | // MARK: - Helpers 208 | 209 | func validate() async throws { 210 | if !isAuthenticated { throw FragmentError.notAuthenticated } 211 | } 212 | 213 | func call(thisAsyncThrowingCode: @escaping () async throws -> Void) async { 214 | do { 215 | try await thisAsyncThrowingCode() 216 | } catch { 217 | var errorMessage = "" 218 | if error is FragmentError { 219 | errorMessage = (error as? FragmentError)?.rawValue ?? "Error" 220 | } else { 221 | errorMessage = error.localizedDescription 222 | } 223 | 224 | alert = Alert(title: Text("Oops!").font(.system(.body, design: .monospaced)), message: Text(errorMessage).font(.system(.caption, design: .monospaced))) 225 | } 226 | } 227 | 228 | func callTask(thisAsyncThrowingCode: @escaping () async throws -> Void) { 229 | Task { 230 | await call(thisAsyncThrowingCode: thisAsyncThrowingCode) 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /Shared/Models/Errors/FragmentError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FragmentError.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 4/4/22. 6 | // 7 | 8 | import Foundation 9 | 10 | enum FragmentError: String, Error { 11 | case nilToken = "Empty Token" 12 | case nilConfiguratioin = "Invalid Configuration" 13 | case invalidToken = "Provided Token is invalid" 14 | case notAuthenticated = "Not Authenticated" 15 | 16 | // MARK: - Data 17 | 18 | case couldNotFetchData = "Could not get data. Check your network connection." 19 | } 20 | -------------------------------------------------------------------------------- /Shared/Models/Language.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // swiftlint:disable identifier_name 4 | enum Language: String, CaseIterable { 5 | case abnf 6 | case accesslog 7 | case actionscript 8 | case ada 9 | case angelscript 10 | case apache 11 | case applescript 12 | case arcade 13 | case cpp 14 | case arduino 15 | case armasm 16 | case xml 17 | case asciidoc 18 | case aspectj 19 | case autohotkey 20 | case autoit 21 | case avrasm 22 | case awk 23 | case axapta 24 | case bash 25 | case basic 26 | case bnf 27 | case brainfuck 28 | case cal 29 | case capnproto 30 | case ceylon 31 | case clean 32 | case clojure 33 | case cmake 34 | case coffeescript 35 | case coq 36 | case cos 37 | case crmsh 38 | case crystal 39 | case cs 40 | case csp 41 | case css 42 | case d 43 | case markdown 44 | case dart 45 | case delphi 46 | case diff 47 | case django 48 | case dns 49 | case dockerfile 50 | case dos 51 | case dsconfig 52 | case dts 53 | case dust 54 | case ebnf 55 | case elixir 56 | case elm 57 | case ruby 58 | case erb 59 | case erlang 60 | case excel 61 | case fix 62 | case flix 63 | case fortran 64 | case fsharp 65 | case gams 66 | case gauss 67 | case gcode 68 | case gherkin 69 | case glsl 70 | case gml 71 | case go 72 | case golo 73 | case gradle 74 | case groovy 75 | case haml 76 | case handlebars 77 | case haskell 78 | case haxe 79 | case hsp 80 | case htmlbars 81 | case html 82 | case http 83 | case hy 84 | case inform7 85 | case ini 86 | case irpf90 87 | case isbl 88 | case java 89 | case javascript 90 | case json 91 | case julia 92 | case kotlin 93 | case lasso 94 | case ldif 95 | case leaf 96 | case less 97 | case lisp 98 | case livecodeserver 99 | case livescript 100 | case llvm 101 | case lsl 102 | case lua 103 | case makefile 104 | case mathematica 105 | case matlab 106 | case maxima 107 | case mel 108 | case mercury 109 | case mipsasm 110 | case mizar 111 | case perl 112 | case mojolicious 113 | case monkey 114 | case moonscript 115 | case n1ql 116 | case nginx 117 | case nimrod 118 | case nix 119 | case nsis 120 | case objectivec 121 | case ocaml 122 | case openscad 123 | case oxygene 124 | case parser3 125 | case pf 126 | case pgsql 127 | case php 128 | case plaintext = "txt" 129 | case pony 130 | case powershell 131 | case processing 132 | case profile 133 | case prolog 134 | case properties 135 | case protobuf 136 | case puppet 137 | case purebasic 138 | case python 139 | case q 140 | case qml 141 | case r 142 | case reasonml 143 | case rib 144 | case roboconf 145 | case routeros 146 | case rsl 147 | case ruleslanguage 148 | case rust 149 | case sas 150 | case scala 151 | case scheme 152 | case scilab 153 | case scss 154 | case shell = "sh" 155 | case smali 156 | case smalltalk 157 | case sml 158 | case sqf 159 | case sql 160 | case stan 161 | case stata 162 | case step21 163 | case stylus 164 | case subunit 165 | case swift 166 | case taggerscript 167 | case yaml 168 | case tap 169 | case tcl 170 | case tex 171 | case thrift 172 | case tp 173 | case twig 174 | case typescript 175 | case vala 176 | case vbnet 177 | case vbscript 178 | case verilog 179 | case vhdl 180 | case vim 181 | case x86asm 182 | case xl 183 | case xquery 184 | case zephir 185 | case clojureRepl = "clojure-repl" 186 | case vbscriptHtml = "vbscript-html" 187 | case juliaRepl = "julia-repl" 188 | case jbossCli = "jboss-cli" 189 | case erlangRepl = "erlang-repl" 190 | case oneC = "1c" 191 | 192 | init?(url: URL) { 193 | let fileExtension = url.pathExtension.lowercased() 194 | switch fileExtension { 195 | case "js": self = .javascript 196 | case "tf": self = .typescript 197 | case "md": self = .markdown 198 | case "py": self = .python 199 | case "bat": self = .dos 200 | case "cxx", "h", "hpp", "hxx": self = .cpp 201 | case "scpt", "scptd", "applescript": self = .applescript 202 | case "pl": self = .perl 203 | case "txt": self = .plaintext 204 | default: self.init(rawValue: fileExtension) 205 | } 206 | } 207 | } 208 | 209 | // swiftlint:enable identifier_name 210 | -------------------------------------------------------------------------------- /Shared/Models/Visibility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Visibility.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/27/22. 6 | // 7 | 8 | import Foundation 9 | import SFSafeSymbols 10 | import SwiftUI 11 | 12 | enum Visibility: String, CaseIterable { 13 | case `public` 14 | case secret 15 | 16 | init(isPublic: Bool?) { 17 | if isPublic ?? false { 18 | self = .public 19 | } else { 20 | self = .secret 21 | } 22 | } 23 | 24 | var body: some View { 25 | var symbol: SFSymbol = .star 26 | switch self { 27 | case .public: 28 | symbol = .network 29 | case .secret: 30 | symbol = .lock 31 | } 32 | 33 | return HStack { 34 | Image(systemSymbol: symbol) 35 | Text(rawValue) 36 | .font(.system(.footnote, design: .monospaced)) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Shared/Views/Add/AddGistView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AddGistView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/27/22. 6 | // 7 | 8 | import CodeEditor 9 | import OctoKit 10 | import SwifterSwift 11 | import SwiftUI 12 | 13 | struct AddGistView: View { 14 | @EnvironmentObject var sessionHandler: SessionHandler 15 | 16 | @Environment(\.presentationMode) private var presentationMode: Binding 17 | 18 | @State var language: Language = .swift 19 | @State var filename: String 20 | @State var description: String 21 | @AppStorage("addingGistDefaultVisibility") var visibility: Visibility = .public 22 | @State var content: String 23 | 24 | @State var isAddingData = true 25 | @State var error: String? 26 | 27 | var didAdd: (Gist) -> Void 28 | 29 | let clipboard = ClipboardHelper.getText() 30 | 31 | @ViewBuilder 32 | func getSaveButton() -> some View { 33 | Button { 34 | let ext = ".\(language.rawValue)" 35 | if !$filename.wrappedValue.ends(with: ext) { 36 | filename.append(ext) 37 | } 38 | Task { 39 | do { 40 | let gist = try await sessionHandler.create(gist: filename, description, content, visibility) 41 | didAdd(gist) 42 | presentationMode.wrappedValue.dismiss() 43 | 44 | } catch { 45 | self.error = error.localizedDescription 46 | } 47 | } 48 | } label: { 49 | HStack { 50 | Text("Save") 51 | .font(.system(.body, design: .monospaced)) 52 | } 53 | } 54 | } 55 | 56 | var body: some View { 57 | Form { 58 | Section(header: Text("Details").font(.system(.caption, design: .monospaced))) { 59 | TextField("File Name", text: $filename) 60 | .onChange(of: filename) { newValue in 61 | let filename: NSString = newValue as NSString 62 | let pathExtention = filename.pathExtension 63 | if let lang = Language(rawValue: pathExtention) { 64 | language = lang 65 | } 66 | } 67 | Picker("Language", selection: $language) { 68 | ForEach(Language.allCases, id: \.self) { language in 69 | Text(language.rawValue) 70 | .font(.system(.footnote, design: .monospaced)) 71 | .tag(language.rawValue) 72 | } 73 | } 74 | TextField("Description", text: $description) 75 | Picker("Visibility", selection: $visibility) { 76 | ForEach(Visibility.allCases, id: \.self) { access in 77 | access.body.tag(access) 78 | } 79 | } 80 | } 81 | .font(.system(.caption, design: .monospaced)) 82 | 83 | if clipboard != nil, !content.isEmpty { 84 | Button { 85 | content = "" 86 | } label: { 87 | Text("Clear Code") 88 | .font(.system(.body, design: .monospaced)) 89 | } 90 | } 91 | 92 | Section(header: Text("Code").font(.system(.caption, design: .monospaced))) { 93 | CodeEditor(source: $content, language: CodeEditor.Language(rawValue: language.rawValue), fontSize: $sessionHandler.cgFloatFontSize) 94 | .font(.system(.caption, design: .monospaced)) 95 | .frame(minHeight: 200) 96 | } 97 | .onAppear { 98 | if let clipboardText = clipboard { 99 | content = clipboardText 100 | } 101 | } 102 | 103 | getSaveButton() 104 | 105 | if error != nil { 106 | Section(header: Text("Error").font(.system(.body, design: .monospaced))) { 107 | Text(error ?? "") 108 | .font(.system(.body, design: .monospaced)) 109 | } 110 | } 111 | } 112 | .toolbar { 113 | ToolbarItem(placement: .cancellationAction) { 114 | Button { 115 | presentationMode.wrappedValue.dismiss() 116 | } label: { 117 | Text("Cancel") 118 | .font(.system(.body, design: .monospaced)) 119 | } 120 | } 121 | 122 | ToolbarItem(placement: .primaryAction) { 123 | getSaveButton() 124 | } 125 | } 126 | 127 | .navigationTitle(isAddingData ? "Add Gist" : "Edit Gist") 128 | } 129 | } 130 | 131 | struct EditGistView_Previews: PreviewProvider { 132 | static var previews: some View { 133 | AddGistView( 134 | filename: "", 135 | description: "", 136 | visibility: .public, 137 | content: "" 138 | ) { _ in 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Shared/Views/AuthenticationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AuthenticationView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/23/22. 6 | // 7 | 8 | import SFSafeSymbols 9 | import SwiftUI 10 | 11 | struct AuthenticationView: View { 12 | @EnvironmentObject var sessionHandler: SessionHandler 13 | 14 | @Binding var isLoading: Bool 15 | 16 | @State var token: String = "" 17 | @State var isShowingSupportThisAppView = false 18 | 19 | var body: some View { 20 | VStack(alignment: .center) { 21 | Spacer() 22 | Text("Github Personal Access Token") 23 | .font(.system(.body, design: .monospaced)) 24 | SecureField(text: $token, 25 | prompt: Text("uZnVflqpqr2U1M9x984h3985a48dn74n").font(.system(.body, design: .monospaced))) { 26 | Text("Token") 27 | .font(.system(.body, design: .monospaced)) 28 | } 29 | .onSubmit { 30 | go() 31 | } 32 | 33 | Button { 34 | go() 35 | } label: { 36 | HStack { 37 | Image(systemSymbol: SFSymbol.lock) 38 | Text("Validate") 39 | .font(.system(.body, design: .monospaced)) 40 | } 41 | } 42 | Spacer() 43 | if let url = URL(string: Constants.URL.githubHowToPersonalAccessToken.rawValue) { 44 | Button { 45 | WebLauncher.go(to: url) 46 | } label: { 47 | HStack { 48 | Image(systemSymbol: SFSymbol.questionmarkCircle) 49 | Text("How To") 50 | .font(.system(.body, design: .monospaced)) 51 | } 52 | } 53 | .padding(.bottom) 54 | } 55 | Divider() 56 | Button { 57 | isShowingSupportThisAppView = true 58 | } label: { 59 | HStack { 60 | Image(systemSymbol: SFSymbol.person3) 61 | Text("Support this app") 62 | .font(.system(.body, design: .monospaced)) 63 | } 64 | } 65 | .padding(.top) 66 | Spacer() 67 | } 68 | .sheet(isPresented: $isShowingSupportThisAppView) { 69 | NavigationView { 70 | SupportThisAppView(showCancelButton: true) 71 | } 72 | } 73 | .redacted(reason: isLoading ? .placeholder : []) 74 | .padding() 75 | 76 | .navigationTitle("Authentication") 77 | } 78 | 79 | func go() { 80 | sessionHandler.callTask { 81 | try await sessionHandler.startSession(with: token) 82 | } 83 | } 84 | } 85 | 86 | struct AuthenticationView_Previews: PreviewProvider { 87 | static var previews: some View { 88 | AuthenticationView(isLoading: .constant(false)) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Shared/Views/CodeViews/CodeView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CodeView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | import CodeEditor 9 | import Foundation 10 | import Highlightr 11 | import OctoKit 12 | import SFSafeSymbols 13 | import SwiftUI 14 | 15 | struct CodeView: View { 16 | @EnvironmentObject var sessionHandler: SessionHandler 17 | 18 | @Environment(\.colorScheme) var colorScheme 19 | 20 | var theme: CodeEditor.ThemeName { 21 | colorScheme == .dark ? .atelierSavannaDark : .atelierSavannaLight 22 | } 23 | 24 | @Binding var gist: Gist 25 | @Binding var isLoadingParent: Bool 26 | 27 | @State var loadedSourceCode = "" 28 | @State var sourceCode = "" 29 | 30 | var body: some View { 31 | ScrollView([.horizontal, .vertical]) { 32 | ScrollViewReader { reader in 33 | CodeEditor(source: $sourceCode, language: CodeEditor.Language(rawValue: gist.fileExtension ?? ""), theme: theme, fontSize: $sessionHandler.cgFloatFontSize, flags: .defaultEditorFlags, indentStyle: .system, autoPairs: nil, inset: nil) 34 | .onAppear { 35 | reader.scrollTo(0, anchor: .topLeading) 36 | } 37 | } 38 | } 39 | .content.offset(x: 0, y: 0) 40 | .onAppear { 41 | loadedSourceCode = gist.text 42 | sourceCode = gist.text 43 | } 44 | .toolbar { 45 | ToolbarItem { 46 | HStack { 47 | if loadedSourceCode != sourceCode { 48 | Button { 49 | guard let identifier = gist.id, 50 | let description = gist.description, 51 | let filename = gist.files.first?.key 52 | else { 53 | return 54 | } 55 | 56 | isLoadingParent = true 57 | sessionHandler.callTask { 58 | let updatedGist = try await sessionHandler.update(identifier, description, filename, sourceCode) 59 | self.isLoadingParent = false 60 | await MainActor.run { 61 | self.sourceCode = updatedGist.text 62 | self.loadedSourceCode = updatedGist.text 63 | } 64 | } 65 | } label: { 66 | Text("Save") 67 | .font(.system(.body, design: .monospaced)) 68 | } 69 | } 70 | 71 | Menu { 72 | // Menu Content 73 | Button { 74 | ClipboardHelper.set(text: gist.text) 75 | } label: { 76 | HStack { 77 | Image(systemSymbol: SFSymbol.docOnDoc) 78 | Text("Copy File Contents") 79 | .font(.system(.body, design: .monospaced)) 80 | } 81 | } 82 | 83 | if let url = gist.htmlURL { 84 | Button { 85 | WebLauncher.go(to: url) 86 | } label: { 87 | HStack { 88 | Image(systemSymbol: SFSymbol.docRichtext) 89 | Text("Open on Web") 90 | .font(.system(.body, design: .monospaced)) 91 | } 92 | } 93 | } 94 | // End Menu Content 95 | } label: { 96 | Image(systemSymbol: .ellipsisCircle) 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Shared/Views/Container/ContainerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContainerView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | import OctoKit 9 | import SFSafeSymbols 10 | import SwiftUI 11 | 12 | struct ContainerView: View { 13 | @EnvironmentObject var sessionHandler: SessionHandler 14 | 15 | @Binding var isLoading: Bool 16 | 17 | @State var isShowingAddModal = false 18 | @State var searchText = "" 19 | 20 | var body: some View { 21 | NavigationView { 22 | ListView(isLoading: $isLoading, searchText: $searchText, isShowingAddModal: $isShowingAddModal) 23 | SupportThisAppView(showCancelButton: false) 24 | } 25 | .sheet(isPresented: $isShowingAddModal) { 26 | #if os(iOS) 27 | NavigationView { 28 | AddGistView(filename: "", description: "", visibility: .public, content: "") { newGist in 29 | sessionHandler.gists.insert(newGist, at: 0) 30 | } 31 | } 32 | #endif 33 | #if os(macOS) 34 | AddGistView(filename: "", description: "", content: "") { newGist in 35 | sessionHandler.gists.insert(newGist, at: 0) 36 | } 37 | .frame(minWidth: 800, minHeight: 800) 38 | .padding() 39 | #endif 40 | } 41 | .toolbar { 42 | ToolbarItem(placement: .navigation) { 43 | Button { 44 | toggleSidebar() 45 | } label: { 46 | Image(systemSymbol: .sidebarLeading) 47 | } 48 | } 49 | } 50 | } 51 | 52 | private func toggleSidebar() { 53 | #if os(iOS) 54 | #else 55 | NSApp.keyWindow?.firstResponder?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil) 56 | #endif 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Shared/Views/Container/ListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 4/4/22. 6 | // 7 | 8 | import OctoKit 9 | import SFSafeSymbols 10 | import SwiftUI 11 | 12 | struct ListView: View { 13 | @EnvironmentObject var sessionHandler: SessionHandler 14 | 15 | @Binding var isLoading: Bool 16 | @Binding var searchText: String 17 | @Binding var isShowingAddModal: Bool 18 | 19 | @AppStorage("visibility") var visibility: Visibility = .public 20 | 21 | @State var isShowingSupportThisAppView = false 22 | @State var isShowingPreferencesView = false 23 | 24 | var filteredGists: [Gist] { 25 | let withVisibility = sessionHandler.gists.filter { gist in 26 | let gistVisibility = Visibility(isPublic: gist.publicGist) 27 | return gistVisibility == visibility 28 | } 29 | 30 | if searchText.isEmpty { 31 | return withVisibility 32 | } else { 33 | return withVisibility.filter { gist in 34 | gist.meetsSearchCriteria(text: searchText) 35 | } 36 | } 37 | } 38 | 39 | var body: some View { 40 | List { 41 | Picker("Visibility", selection: $visibility) { 42 | ForEach(Visibility.allCases, id: \.self) { access in 43 | Text(access.rawValue) 44 | .font(.system(.body, design: .monospaced)) 45 | } 46 | } 47 | .pickerStyle(.segmented) 48 | .labelsHidden() 49 | 50 | .navigationTitle("Gists") 51 | 52 | if sessionHandler.gists.isEmpty { 53 | VStack { 54 | Text(isLoading ? "Loading..." : "No Gists") 55 | .font(.system(.body, design: .monospaced)) 56 | 57 | if Constants.Feature.ifNoGistsEnableCreateButton { 58 | HStack { 59 | if sessionHandler.isAuthenticated { 60 | Button { 61 | isShowingAddModal.toggle() 62 | } label: { 63 | HStack { 64 | #if !os(macOS) 65 | Image(systemSymbol: .plusCircle) 66 | #endif 67 | Text("Create Gist") 68 | .font(.system(.body, design: .monospaced)) 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | if Constants.Feature.ifNoGistsEnablePullButton, sessionHandler.isAuthenticated { 76 | VStack { 77 | Text("If this is unexpected, try pulling.") 78 | .padding() 79 | Button { 80 | sessionHandler.callTask { 81 | try await sessionHandler.refreshGists() 82 | } 83 | } label: { 84 | HStack { 85 | #if os(iOS) 86 | Image(systemSymbol: .arrowDownCircle) 87 | #endif 88 | Text("Pull") 89 | .font(.system(.body, design: .monospaced)) 90 | #if os(macOS) 91 | .padding() 92 | #endif 93 | } 94 | } 95 | .padding() 96 | } 97 | .font(.system(.footnote, design: .monospaced)) 98 | .padding(5) 99 | .overlay( 100 | RoundedRectangle(cornerRadius: 8) 101 | .strokeBorder() 102 | .foregroundColor(.gray) 103 | ) 104 | } 105 | } 106 | } else { 107 | if !searchText.isEmpty { 108 | Text("Results") 109 | .font(.system(.body, design: .monospaced)) 110 | } 111 | ForEach(filteredGists, id: \.self) { gist in 112 | NavigationLink { 113 | CodeView(gist: .constant(gist), isLoadingParent: $isLoading) 114 | .navigationTitle(gist.filename) 115 | } label: { 116 | GistRow(data: .constant(gist)) 117 | .padding() 118 | } 119 | } 120 | } 121 | } 122 | .sheet(isPresented: $isShowingSupportThisAppView) { 123 | NavigationView { 124 | SupportThisAppView(showCancelButton: true) 125 | } 126 | } 127 | .sheet(isPresented: $isShowingPreferencesView) { 128 | NavigationView { 129 | SettingsView(isLoading: $isLoading) 130 | 131 | .navigationTitle("Settings") 132 | } 133 | } 134 | .onAppear { 135 | if !isLoading { 136 | sessionHandler.callTask { 137 | try await sessionHandler.refreshGists() 138 | } 139 | } 140 | } 141 | .refreshable { 142 | sessionHandler.callTask { 143 | try await sessionHandler.refreshGists() 144 | } 145 | } 146 | .searchable(text: $searchText) 147 | .redacted(reason: isLoading ? .placeholder : []) 148 | .toolbar { 149 | #if os(iOS) 150 | ToolbarItem(placement: .navigationBarLeading) { 151 | Menu { 152 | Button { 153 | isShowingSupportThisAppView = true 154 | } label: { 155 | HStack { 156 | Image(systemSymbol: SFSymbol.person2Circle) 157 | Text("Support this app") 158 | .font(.system(.body, design: .monospaced)) 159 | } 160 | } 161 | 162 | Button { 163 | WebLauncher.go(to: URL(string: Constants.URL.buyMeACoffee.rawValue)) 164 | } label: { 165 | HStack { 166 | Image(systemSymbol: .dollarsignCircle) 167 | Text("Donate") 168 | .font(.system(.body, design: .monospaced)) 169 | } 170 | } 171 | 172 | if Constants.Feature.settingsEnabled { 173 | Button { 174 | isShowingPreferencesView = true 175 | } label: { 176 | HStack { 177 | Image(systemSymbol: .gearshape) 178 | Text("Preferences") 179 | .font(.system(.body, design: .monospaced)) 180 | } 181 | } 182 | } 183 | } label: { 184 | Image(systemSymbol: .gearshape) 185 | } 186 | } 187 | #endif 188 | 189 | ToolbarItem(placement: .primaryAction) { 190 | HStack { 191 | if sessionHandler.isAuthenticated { 192 | Button { 193 | isShowingAddModal.toggle() 194 | } label: { 195 | HStack { 196 | Image(systemSymbol: .plusCircle) 197 | Text("Create") 198 | .font(.system(.body, design: .monospaced)) 199 | } 200 | } 201 | #if os(macOS) 202 | .frame(minWidth: 100) 203 | #endif 204 | } 205 | } 206 | } 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Shared/Views/GistViews/GistRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GistRow.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | import OctoKit 9 | import SFSafeSymbols 10 | import SwiftUI 11 | 12 | struct GistRow: View { 13 | @Binding var data: Gist 14 | 15 | var filenameNoExtension: String? { 16 | ((data.files.first?.key ?? "") as NSString).deletingPathExtension 17 | } 18 | 19 | var body: some View { 20 | VStack(alignment: .leading) { 21 | Text(filenameNoExtension ?? (data.files.first?.key ?? "Unknown")) 22 | .font(.system(.headline, design: .monospaced)) 23 | .lineLimit(1) 24 | .truncationMode(.middle) 25 | Spacer() 26 | if let description = data.description, !description.isEmpty { 27 | Text("\(description)") 28 | .font(.system(.caption, design: .monospaced)) 29 | .lineLimit(2) 30 | .truncationMode(.middle) 31 | } 32 | Spacer() 33 | if let updated = data.updatedAt { 34 | Text("Updated \(updated.formatted(date: .abbreviated, time: .standard))") 35 | .font(.system(.caption2, design: .monospaced)) 36 | .lineLimit(2) 37 | .truncationMode(.middle) 38 | } 39 | Spacer() 40 | HStack { 41 | Visibility(isPublic: data.publicGist).body 42 | Spacer() 43 | if let `extension` = data.fileExtension, !`extension`.isEmpty { 44 | Text(`extension`) 45 | .font(.system(.footnote, design: .monospaced)) 46 | .lineLimit(1) 47 | .truncationMode(.middle) 48 | .padding(5) 49 | .overlay( 50 | RoundedRectangle(cornerRadius: 8) 51 | .strokeBorder() 52 | .foregroundColor(.gray) 53 | ) 54 | } 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Shared/Views/MainView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/20/22. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MainView: View { 11 | @EnvironmentObject var sessionHandler: SessionHandler 12 | 13 | @Binding var isLoading: Bool 14 | 15 | var body: some View { 16 | if sessionHandler.isAuthenticated { 17 | ContainerView(isLoading: $isLoading) 18 | } else { 19 | if isLoading { 20 | ContainerView(isLoading: $isLoading) // Permanet loading 21 | .redacted(reason: .placeholder) // 22 | } else { 23 | NavigationView { 24 | #if os(macOS) 25 | EmptyView() 26 | AuthenticationView(isLoading: $isLoading) 27 | .padding() 28 | #endif 29 | #if os(iOS) 30 | AuthenticationView(isLoading: $isLoading) 31 | .padding() 32 | Text("Enter Github personal access token on the lefthand sidebar") 33 | .font(.system(.body, design: .monospaced)) 34 | #endif 35 | } 36 | } 37 | } 38 | } 39 | } 40 | 41 | struct MainView_Previews: PreviewProvider { 42 | static var previews: some View { 43 | MainView(isLoading: .constant(false)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Shared/Views/SettingsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 4/4/22. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct SettingsView: View { 11 | @EnvironmentObject var sessionHandler: SessionHandler 12 | @Environment(\.presentationMode) private var presentationMode: Binding 13 | 14 | @Binding var isLoading: Bool 15 | 16 | @State var name: String? 17 | 18 | var body: some View { 19 | TabView { 20 | if sessionHandler.isAuthenticated { 21 | VStack { 22 | Form { 23 | Section("General") { 24 | EmptyView() 25 | } 26 | 27 | Section { 28 | Button { 29 | sessionHandler.callTask { 30 | try await sessionHandler.refreshGists() 31 | } 32 | } label: { 33 | HStack { 34 | Image(systemSymbol: .arrowDownCircle) 35 | Text("Refresh") 36 | .font(.system(.body, design: .monospaced)) 37 | } 38 | } 39 | } footer: { 40 | Text("Get new Gists from Github or use pull-to-refresh on the list") 41 | } 42 | .padding(.bottom) 43 | 44 | Section { 45 | Button { 46 | WebLauncher.go(to: URL(string: Constants.URL.buyMeACoffee.rawValue)) 47 | } label: { 48 | HStack { 49 | Image(systemSymbol: .dollarsignCircle) 50 | Text("Donate") 51 | .font(.system(.body, design: .monospaced)) 52 | } 53 | } 54 | .padding(.vertical) 55 | } footer: { 56 | Text("Support this app") 57 | } 58 | } 59 | } 60 | .tabItem { 61 | Label("General", systemImage: "gearshape") 62 | } 63 | } 64 | 65 | VStack { 66 | Form { 67 | Section { 68 | Stepper("Code Font Size: \(sessionHandler.fontSize)", value: $sessionHandler.fontSize, in: 8 ... 72) 69 | .padding() 70 | } footer: { 71 | Text("Affects areas where code is being used. Go to Settings to adjust other text size.") 72 | } 73 | } 74 | } 75 | .tabItem { 76 | Label("Appearance", systemImage: "paintpalette") 77 | } 78 | 79 | if sessionHandler.isAuthenticated { 80 | VStack { 81 | Form { 82 | Section("You") { 83 | Text(name ?? "Loading...") 84 | } 85 | 86 | Section { 87 | Button { 88 | sessionHandler.invalidateSession() 89 | } label: { 90 | HStack { 91 | Image(systemSymbol: .xmarkCircle) 92 | Text("Clear Token") 93 | .font(.system(.body, design: .monospaced)) 94 | } 95 | } 96 | } footer: { 97 | Text("Clears all gists and discards your personal access token") 98 | } 99 | } 100 | } 101 | .task { 102 | isLoading = true 103 | 104 | sessionHandler.callTask { 105 | let user = try await sessionHandler.me() 106 | self.name = user.name 107 | } 108 | 109 | isLoading = false 110 | } 111 | .tabItem { 112 | Label("Profile", systemImage: "person.crop.circle") 113 | } 114 | 115 | VStack { 116 | Form { 117 | Section { 118 | Toggle("Disable Local Caching", isOn: .constant(false)) 119 | .disabled(true) 120 | } footer: { 121 | Text("Not implemented yet") 122 | } 123 | } 124 | } 125 | .tabItem { 126 | Label("Privacy", systemImage: "hand.raised") 127 | } 128 | } 129 | 130 | SupportThisAppView(showCancelButton: false) 131 | .tabItem { 132 | Label("Support", systemImage: "person.3") 133 | } 134 | } 135 | #if os(iOS) 136 | .toolbar { 137 | ToolbarItem(placement: .primaryAction) { 138 | Button { 139 | presentationMode.wrappedValue.dismiss() 140 | } label: { 141 | Text("Done") 142 | .font(.system(.body, design: .monospaced)) 143 | } 144 | } 145 | } 146 | #endif 147 | } 148 | } 149 | 150 | struct SettingsView_Previews: PreviewProvider { 151 | static var previews: some View { 152 | SettingsView(isLoading: .constant(false)) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Shared/Views/Support/SupportThisAppView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SupportThisAppView.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 4/4/22. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct SupportThisAppView: View { 11 | @Environment(\.presentationMode) private var presentationMode: Binding 12 | 13 | var showCancelButton: Bool 14 | 15 | var body: some View { 16 | VStack(alignment: .leading) { 17 | Spacer() 18 | Text("Support this project") 19 | .font(.system(.title, design: .monospaced)) 20 | .padding(.bottom) 21 | Text("\(Constants.appName) will always be free and open-source.") 22 | .font(.system(.headline, design: .monospaced)) 23 | .padding(.bottom) 24 | Text("If you have found this app useful, please consider:") 25 | .font(.system(.subheadline, design: .monospaced)) 26 | Button { 27 | WebLauncher.go(to: URL(string: Constants.URL.repositoryOnGitHub.rawValue)) 28 | } label: { 29 | Text("Contributing on Github ") 30 | } 31 | .padding() 32 | Text("or") 33 | .font(.system(.subheadline, design: .monospaced)) 34 | .padding(.horizontal) 35 | Button { 36 | WebLauncher.go(to: URL(string: Constants.URL.buyMeACoffee.rawValue)) 37 | } label: { 38 | Text("☕️ Buying Me A Coffee") 39 | } 40 | .padding() 41 | Text("Thank you,\nDan") 42 | .font(.system(.subheadline, design: .monospaced)) 43 | Spacer() 44 | } 45 | .padding() 46 | .toolbar { 47 | ToolbarItem(placement: .cancellationAction) { 48 | if showCancelButton { 49 | Button { 50 | presentationMode.wrappedValue.dismiss() 51 | } label: { 52 | Text("Cancel") 53 | .font(.system(.body, design: .monospaced)) 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | struct SupportView_Previews: PreviewProvider { 62 | static var previews: some View { 63 | SupportThisAppView(showCancelButton: false) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Shared/WebLauncher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WebLauncher.swift 3 | // Fragment 4 | // 5 | // Created by Dan Hart on 3/27/22. 6 | // 7 | 8 | import Foundation 9 | #if canImport(UIKit) 10 | import UIKit 11 | #else 12 | import AppKit 13 | #endif 14 | 15 | enum WebLauncher { 16 | static func go(to url: URL?) { 17 | guard let url = url else { 18 | return 19 | } 20 | 21 | #if canImport(UIKit) 22 | Task { 23 | if await UIApplication.shared.open(url) { 24 | print("default browser was successfully opened") 25 | } 26 | } 27 | #else 28 | if NSWorkspace.shared.open(url) { 29 | print("default browser was successfully opened") 30 | } 31 | #endif 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sourceless/2011B4FA-8E52-4464-A976-76AA07DBDDE7.json: -------------------------------------------------------------------------------- 1 | {"iv":"b520b4eae4c5eb548d3425d94ac4cc0d","cryptKey":"705349475148785a737a373033686c77","cryptValue":"73f121ecb73229ba3c0a8453e9b3f16f0360d7d92a710550278b19d6ab1787033317fe40a40d7dcb0e4cba4a20521f0df3ebd3b28796867531c2045438c4ebef"} -------------------------------------------------------------------------------- /autocommit.sh: -------------------------------------------------------------------------------- 1 | # LANG=C.UTF-8 or any UTF-8 English locale supported by your OS may be used 2 | rm -f .git/index.lock 3 | git add . 4 | LANG=C git -c color.status=false status \ 5 | | sed -n -r -e '1,/Changes to be committed:/ d' \ 6 | -e '1,1 d' \ 7 | -e '/^Untracked files:/,$ d' \ 8 | -e 's/^\s*//' \ 9 | -e '/./p' \ 10 | | git commit -F - -------------------------------------------------------------------------------- /macOS/macOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------