Full Code of appcraftstudio/buymeacoffee for AI

master 20c574ac7dc0 cached
32 files
35.2 KB
9.9k tokens
1 requests
Download .txt
Repository: appcraftstudio/buymeacoffee
Branch: master
Commit: 20c574ac7dc0
Files: 32
Total size: 35.2 KB

Directory structure:
gitextract_qlxitl2w/

├── .github/
│   └── workflows/
│       └── swift.yml
├── .gitignore
├── .swiftpm/
│   └── xcode/
│       ├── package.xcworkspace/
│       │   ├── contents.xcworkspacedata
│       │   └── xcshareddata/
│       │       ├── IDEWorkspaceChecks.plist
│       │       └── WorkspaceSettings.xcsettings
│       └── xcshareddata/
│           └── xcschemes/
│               └── BuyMeACoffee.xcscheme
├── Bundle.swift
├── BuyMeACoffee.podspec
├── CODE_OF_CONDUCT.md
├── LICENSE
├── Package.swift
├── README.md
├── Sources/
│   └── BuyMeACoffee/
│       ├── BMCButton.swift
│       ├── BMCColor.swift
│       ├── BMCFont.swift
│       ├── BMCManager.swift
│       └── Resources/
│           └── Assets.xcassets/
│               ├── Colors/
│               │   ├── Contents.json
│               │   ├── black.colorset/
│               │   │   └── Contents.json
│               │   ├── blue.colorset/
│               │   │   └── Contents.json
│               │   ├── green.colorset/
│               │   │   └── Contents.json
│               │   ├── orange.colorset/
│               │   │   └── Contents.json
│               │   ├── pink.colorset/
│               │   │   └── Contents.json
│               │   ├── purple.colorset/
│               │   │   └── Contents.json
│               │   ├── red.colorset/
│               │   │   └── Contents.json
│               │   ├── white.colorset/
│               │   │   └── Contents.json
│               │   └── yellow.colorset/
│               │       └── Contents.json
│               ├── Contents.json
│               ├── cup-white.imageset/
│               │   └── Contents.json
│               └── cup-yellow.imageset/
│                   └── Contents.json
└── Tests/
    ├── BuyMeACoffeeTests/
    │   └── XCTestManifests.swift
    ├── LinuxMain.swift
    └── buymeacoffeeTests/
        └── BuyMeACoffeeTests.swift

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/swift.yml
================================================
name: Swift

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: macos-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Select Xcode 12
      run: sudo xcode-select -s /Applications/Xcode_12.app && xcodebuild -version
    - name: Linting podspec
      run: pod lib lint
    - name: Build
      run: swift build -v
    - name: Run tests
      run: swift test -v


================================================
FILE: .gitignore
================================================
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/


================================================
FILE: .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:">
   </FileRef>
</Workspace>


================================================
FILE: .swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IDEDidComputeMac32BitWarning</key>
	<true/>
</dict>
</plist>


================================================
FILE: .swiftpm/xcode/package.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
	<true/>
</dict>
</plist>


================================================
FILE: .swiftpm/xcode/xcshareddata/xcschemes/BuyMeACoffee.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
   LastUpgradeVersion = "1200"
   version = "1.7">
   <BuildAction
      parallelizeBuildables = "YES"
      buildImplicitDependencies = "YES">
      <BuildActionEntries>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "BuyMeACoffee_BuyMeACoffee"
               BuildableName = "BuyMeACoffee_BuyMeACoffee"
               BlueprintName = "BuyMeACoffee_BuyMeACoffee"
               ReferencedContainer = "container:">
            </BuildableReference>
         </BuildActionEntry>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "YES"
            buildForArchiving = "YES"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "BuyMeACoffee"
               BuildableName = "BuyMeACoffee"
               BlueprintName = "BuyMeACoffee"
               ReferencedContainer = "container:">
            </BuildableReference>
         </BuildActionEntry>
         <BuildActionEntry
            buildForTesting = "YES"
            buildForRunning = "YES"
            buildForProfiling = "NO"
            buildForArchiving = "NO"
            buildForAnalyzing = "YES">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "BuyMeACoffeeTests"
               BuildableName = "BuyMeACoffeeTests"
               BlueprintName = "BuyMeACoffeeTests"
               ReferencedContainer = "container:">
            </BuildableReference>
         </BuildActionEntry>
      </BuildActionEntries>
   </BuildAction>
   <TestAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      shouldUseLaunchSchemeArgsEnv = "YES">
      <PostActions>
         <ExecutionAction
            ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
            <ActionContent
               title = "Run Script"
               scriptText = "cp ~/Library/Developer/CoreSimulator/Devices/$TARGET_DEVICE_IDENTIFIER/data/Library/Caches/snapshot-bmc-button.png $WORKSPACE_PATH/../../../Images&#10;">
               <EnvironmentBuildable>
                  <BuildableReference
                     BuildableIdentifier = "primary"
                     BlueprintIdentifier = "BuyMeACoffeeTests"
                     BuildableName = "BuyMeACoffeeTests"
                     BlueprintName = "BuyMeACoffeeTests"
                     ReferencedContainer = "container:">
                  </BuildableReference>
               </EnvironmentBuildable>
            </ActionContent>
         </ExecutionAction>
      </PostActions>
      <Testables>
         <TestableReference
            skipped = "NO">
            <BuildableReference
               BuildableIdentifier = "primary"
               BlueprintIdentifier = "BuyMeACoffeeTests"
               BuildableName = "BuyMeACoffeeTests"
               BlueprintName = "BuyMeACoffeeTests"
               ReferencedContainer = "container:">
            </BuildableReference>
         </TestableReference>
      </Testables>
   </TestAction>
   <LaunchAction
      buildConfiguration = "Debug"
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
      launchStyle = "0"
      useCustomWorkingDirectory = "NO"
      ignoresPersistentStateOnLaunch = "NO"
      debugDocumentVersioning = "YES"
      debugServiceExtension = "internal"
      allowLocationSimulation = "YES">
   </LaunchAction>
   <ProfileAction
      buildConfiguration = "Release"
      shouldUseLaunchSchemeArgsEnv = "YES"
      savedToolIdentifier = ""
      useCustomWorkingDirectory = "NO"
      debugDocumentVersioning = "YES">
      <MacroExpansion>
         <BuildableReference
            BuildableIdentifier = "primary"
            BlueprintIdentifier = "BuyMeACoffee_BuyMeACoffee"
            BuildableName = "BuyMeACoffee_BuyMeACoffee"
            BlueprintName = "BuyMeACoffee_BuyMeACoffee"
            ReferencedContainer = "container:">
         </BuildableReference>
      </MacroExpansion>
   </ProfileAction>
   <AnalyzeAction
      buildConfiguration = "Debug">
   </AnalyzeAction>
   <ArchiveAction
      buildConfiguration = "Release"
      revealArchiveInOrganizer = "YES">
   </ArchiveAction>
</Scheme>


================================================
FILE: Bundle.swift
================================================
//
//  Bundle.swift
//  BuyMeACoffee
//
//  Created by François Boulais on 01/07/2020.
//  Copyright © 2020 App Craft Studio. All rights reserved.
//

import Foundation

internal extension Bundle {
    static let module = Bundle(for: BMCManager.self)
}


================================================
FILE: BuyMeACoffee.podspec
================================================
Pod::Spec.new do |spec|
  spec.name                  = 'BuyMeACoffee'
  spec.version               = '1.0.6'
  spec.license               = { :type => "MIT", :file => "LICENSE" }
                               
  spec.homepage              = 'https://www.buymeacoffee.com'
  spec.author                = { 'François Boulais' => 'francois@appcraftstudio.com' }
  spec.social_media_url      = 'https://twitter.com/frboulais'

  spec.summary               = 'Buy Me a Coffee framework for iOS'
  spec.source                = { :git => 'https://github.com/appcraftstudio/buymeacoffee.git', :tag => "#{spec.version}" }
  
  spec.screenshots           = [ 'https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/screenshot-buymeacoffee-home.png',
                                 'https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/screenshot-buymeacoffee-apple-pay.png' ]
                                 
  spec.ios.deployment_target = '11.0'
  spec.platform              = :ios, '11.0'
  spec.swift_version         = '5.0'

  spec.source_files          = 'Sources/**/*.swift', 'Bundle.swift'
  spec.resources             = 'Sources/**/Resources/*'

  spec.ios.framework         = 'UIKit', 'WebKit'
  
  spec.test_spec 'BuyMeACoffeeTests' do |test_spec|
    test_spec.source_files   = 'Tests/BuyMeACoffeeTests/*.{swift}'
  end
end


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or
 advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
 address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
 professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at francois@appcraftstudio.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 App Craft Studio

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Package.swift
================================================
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "BuyMeACoffee",
    platforms: [
        .iOS(.v11)
    ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(name: "BuyMeACoffee", targets: ["BuyMeACoffee"]),
        .library(name: "BuyMeACoffeeDynamic", type: .dynamic, targets: ["BuyMeACoffee"])
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "BuyMeACoffee",
            dependencies: [],
            resources: [
                .process("Resources/Assets.xcassets"),
                .process("Resources/Cookie-Regular.ttf"),
                .process("Resources/Lato-Regular.ttf")
            ]),
        .testTarget(
            name: "BuyMeACoffeeTests",
            dependencies: ["BuyMeACoffee"]),
    ]
)


================================================
FILE: README.md
================================================
![Swift](https://github.com/appcraftstudio/buymeacoffee/workflows/Swift/badge.svg)

# A supporter is  worth a thousand  followers. 

### [Buy Me a Coffee](https://www.buymeacoffee.com) is a modern creator platform. It takes two minutes to start your page and has all the features that you need to build your creative business.

**Donations :moneybag:**  
Give your audience a friendly way to thank you.

**Memberships :spiral_calendar:**  
Earn recurring revenue by offering a monthly or yearly membership.

**Sell Extras :sparkles:**  
A new, creative way to offer Zoom calls, art commissions, anything.  

<p align="center">
<br>
<img src="https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/screenshot-buymeacoffee-home.png" width="320">
<img src="https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/screenshot-buymeacoffee-apple-pay.png" width="320">
</p>

## Features

- [X] Apple Pay
- [X] iCloud Keychain

## Requirements

CocoaPods | Swift Package Manager
:---: | :---:
Swift 5.0 | Swift 5.3
Xcode 11.x | Xcode 12.x

## App Store Review 

These are the two App Store Review Guidelines articles you have to know before using this framework:

[3.1.1 In-App Purchase](https://developer.apple.com/app-store/review/guidelines/#in-app-purchase)
> - Apps may use in-app purchase currencies to enable customers to “tip” digital content providers in the app.

[3.2.1 Acceptable](https://developer.apple.com/app-store/review/guidelines/#acceptable):
> **(vii)** Apps may enable individual users to give a monetary gift to another individual without using in-app purchase, provided that (a) the gift is a completely optional choice by the giver, and (b) 100% of the funds go to the receiver of the gift. However, a gift that is connected to or associated at any point in time with receiving digital content or services must use in-app purchase.

## Implement Buy Me a Coffee

1. Import the BuyMeACoffee framework in your `UIApplicationDelegate`:
```swift
import BuyMeACoffee
```
2. Configure the `BMCManager` shared instance with the username you've chosen on www.buymeacoffee.com, typically in your app's `application:didFinishLaunchingWithOptions:` method:
```swift
BMCManager.shared.configure(username: "appcraftstudio")
```
3. In the view controller, override the `viewDidLoad` method to set the presenting view controller of the `BMCManager` object.
```swift
BMCManager.shared.presentingViewController = self
// You can also set a custom thank you message
BMCManager.shared.thankYouMessage = "Thank you for supporting 🎉 App Craft Studio !"
```
4. Add a `BMCButton` to your storyboard, XIB file, or instantiate it programmatically. To add the button to your storyboard or XIB file, add a View and set its custom class to `BMCButton`.
5. **Optional**: If you want to customize the button, do the following:
```swift
let configuration = BMCButton.Configuration(color: .orange, font: .cookie)
let button = BMCButton(configuration: configuration)
// or set the burtton configuration later
button.configure(with: configuration)
```

<p align="center">
<br>
<img src="https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/snapshot-bmc-button.png" width="300">
</p>

## (Optional) Configure In-App Purchase

Depending the legal receiver of the gift configured on Buy Me a Coffee, App Store reviewers can ask for In-App Purchase implementation.  
If the following In-App Purchase if configured for your application, it will be displayed as primary flow when user tap on the `BMCButton`.

**If the framework can't retrieve In-App Purchase informations, the web flow will be used as fallback.**

### App Store Connect

Go to [App Store Connect](https://appstoreconnect.apple.com), search for the *In-App Purchases* section of your app, and then, create a new one with the following informations:

|||
| --- | --- |
| **Type** | Consumable |
| **Reference Name** | *Buy Me a Coffee* |
| **Product ID** | `your.app.bundle.identifier`*.buymeacoffee* |
| **Cleared for Sale** | :white_check_mark: |
| **Price** | Tier 4 |
| **Display Name** | *Buy Me a Coffee* |
| **Description** | *Hey there! You can now buy me a coffee!*
| **Promotional Image** | [download here](https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/%20in-app-purchase-promotional-image.jpg) |
| **Review Screenshot** | [download here](https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/%20in-app-purchase-review-screenshot.png) |
| **Review Notes** | *Buy Me a Coffee enable customers to “tip” digital content providers in the app.* |

### Capabilities

1. Select the current workspace in the project navigator.
2. Then, select the app target in the left panel.
3. Go to the *Signing & Capabilities* tab.
4. Add the *In-App Purchase* capability.

<p align="center">
<img src="https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/screenshot-xcode-capabilities.png" width="600">
</p>

## Installation

### [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html)

You want to add pod `'BuyMeACoffee', '~> 1.0'` similar to the following to your Podfile:
```rb
target 'MyApp' do
  pod 'BuyMeACoffee', '~> 1.0'
end
```
Then run a `pod install` inside your terminal, or from CocoaPods.app.

### [Swift Package Manager](https://swift.org/package-manager/)

1. Using Xcode 11 or above go to *File* > *Swift Packages* > *Add Package Dependency*
2. Paste the project URL: https://github.com/appcraftstudio/buymeacoffee.git
3. Click on next and select the project target

![Swift Package Manager](https://github.com/appcraftstudio/buymeacoffee/raw/master/Images/screenshot-xcode-spm.png)

---

<a href="https://www.producthunt.com/posts/buy-me-a-coffee-framework-for-ios?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-buy-me-a-coffee-framework-for-ios" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=233953&theme=dark" alt="Buy Me a Coffee framework for iOS - Embed Buy Me a Coffee framework in your applications | Product Hunt Embed" style="width: 250px; height: 54px;" width="250px" height="54px" /></a>

<a href="https://www.buymeacoffee.com/appcraftstudio" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>

Copyright © 2020 App Craft Studio. All rights reserved.


================================================
FILE: Sources/BuyMeACoffee/BMCButton.swift
================================================
//
//  BMCButton.swift
//
//  Created by François Boulais on 26/06/2020.
//  Copyright © 2020 App Craft Studio. All rights reserved.
//

#if canImport(UIKit)
import UIKit

@IBDesignable
public class BMCButton: UIButton {
    public struct Configuration {
        let color: BMCColor
        let font: BMCFont
        let title: String
        
        public init(color: BMCColor, font: BMCFont, title: String = "Buy me a coffee") {
            self.color = color
            self.font = font
            self.title = title
        }
        
        public static let `default`: Self = .init(color: .default, font: .default)
    }
    
    private lazy var numberFormatter: NumberFormatter = {
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .currency
        return numberFormatter
    }()
    
    private var _configuration: Configuration = .default
    
    public override var isHighlighted: Bool {
        didSet {
            alpha = isHighlighted ? 0.85 : 1
        }
    }
    
    public convenience init(configuration: Configuration) {
        self.init(type: .custom)
        
        self._configuration = configuration
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setup()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        
        setup()
    }
    
    // MARK: - Interface Builder
    
    public override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        
        setup()
    }
    
    // MARK: - Public functions
    
    public func configure(with configuration: Configuration) {
        titleLabel?.font = configuration.font.value
        setTitleColor(configuration.color.title, for: .normal)
        setImage(configuration.color.cup, for: .normal)
        backgroundColor = configuration.color.background
        
        var title = configuration.title
        if let product = BMCManager.shared.product {
            numberFormatter.locale = product.priceLocale
            if let price = numberFormatter.string(from: product.price) {
                title.append(" (\(price))")
            }
        }

        setTitle(title, for: .normal)
    }
    
    // MARK: - Private functions
    
    private func setup() {
        layer.shadowOffset = .init(width: 4, height: 4)
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOpacity = 0.1
        layer.shadowRadius = 2
        layer.cornerRadius = 5

        contentEdgeInsets = .init(top: 8, left: 12, bottom: 8, right: 12)
        titleEdgeInsets = .init(top: 0, left: 6, bottom: 0, right: -6)
        imageEdgeInsets = .init(top: 0, left: -6, bottom: 0, right: 6)
        
        imageView?.contentMode = .scaleAspectFit
        
        registerFonts()
        
        adjustsImageWhenHighlighted = false
        
        addTarget(BMCManager.shared, action: #selector(BMCManager.shared.start), for: .touchUpInside)
        
        configure(with: _configuration)
    }
    
    private func registerFonts() {
        if let url = Bundle.module.url(forResource: "Cookie-Regular", withExtension: "ttf") {
            CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
        }
        
        if let url = Bundle.module.url(forResource: "Lato-Regular", withExtension: "ttf") {
            CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
        }
    }
}
#endif


================================================
FILE: Sources/BuyMeACoffee/BMCColor.swift
================================================
//
//  BMCColor.swift
//
//  Created by François Boulais on 30/06/2020.
//  Copyright © 2020 App Craft Studio. All rights reserved.
//

#if canImport(UIKit)
import UIKit

public enum BMCColor: String, CaseIterable {
    case orange
    case yellow
    case purple
    case black
    case white
    case blue
    case green
    case red
    case pink
    
    public static let `default`: Self = .yellow
    
    internal var background: UIColor? {
        UIColor(named: rawValue, in: .module, compatibleWith: nil)
    }
    
    internal var title: UIColor {
        switch self {
        case .orange, .purple, .black, .blue, .green, .red, .pink:
            return .white
        case .yellow, .white:
            return .black
        }
    }
    
    internal var cup: UIImage? {
        switch self {
        case .yellow:
            return UIImage(named: "cup-white", in: .module, compatibleWith: nil)
        default:
            return UIImage(named: "cup-yellow", in: .module, compatibleWith: nil)
        }
    }

}
#endif


================================================
FILE: Sources/BuyMeACoffee/BMCFont.swift
================================================
//
//  BMCFont.swift
//  
//  Created by François Boulais on 30/06/2020.
//  Copyright © 2020 App Craft Studio. All rights reserved.
//

#if canImport(UIKit)
import UIKit

public enum BMCFont: String, CaseIterable {
    case cookie
    case lato
    case arial
    
    public static let `default`: Self = .cookie
    
    internal var value: UIFont? {
        switch self {
        case .cookie:
            return UIFont(name: rawValue.capitalized, size: 26)
        case .lato:
            return UIFont(name: rawValue.capitalized, size: 20)
        case .arial:
            return UIFont(name: rawValue.capitalized, size: 20)
        }
    }
}
#endif


================================================
FILE: Sources/BuyMeACoffee/BMCManager.swift
================================================
//
//  BMCManager.swift
//
//  Created by François Boulais on 30/06/2020.
//  Copyright © 2020 App Craft Studio. All rights reserved.
//

#if canImport(UIKit)
import UIKit
import SafariServices
import StoreKit

public final class BMCManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
    public static let shared = BMCManager()
    
    // MARK: - Public properties
    
    /// The view controller used to present donation flow.
    public var presentingViewController: UIViewController?
    
    /// This text is displayed to supporters immediately after they make a payment.
    public var thankYouMessage: String?
    
    // MARK: - Internal properties
    
    internal var product: SKProduct?

    // MARK: - Private properties
    
    private var username = "appcraftstudio"
    private var productsRequest: SKProductsRequest?
    
    private lazy var loadingViewController: UIViewController = {
        let activityIndicatorView: UIActivityIndicatorView
        if #available(iOS 13.0, *) {
            activityIndicatorView = UIActivityIndicatorView(style: .large)
        } else {
            activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge)
        }
        
        activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
        activityIndicatorView.color = BMCColor.default.background
        activityIndicatorView.startAnimating()
        
        let viewController = UIViewController()
        viewController.view.backgroundColor = .white
        viewController.view.addSubview(activityIndicatorView)
        viewController.modalPresentationStyle = .formSheet
        
        if #available(iOS 13.0, *) {
            viewController.isModalInPresentation = true
        }

        NSLayoutConstraint.activate([
            activityIndicatorView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor),
            activityIndicatorView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor)
        ])
        
        return viewController
    }()

    private var url: URL? {
        URL(string: "https://www.buymeacoffee.com/".appending(username))
    }
        
    // MARK: - Public functions
    
    /**
     Configure the manager for future donation requests.
     - parameters:
        - username: The username you've chosen on www.buymeacoffee.com.
     */
    public func configure(username: String) {
        self.username = username

        guard SKPaymentQueue.canMakePayments() else {
            return
        }
        
        if let productIdentifier = Bundle.main.bundleIdentifier?.appending(".buymeacoffee") {
            productsRequest?.cancel()
            productsRequest = SKProductsRequest(productIdentifiers: [productIdentifier])
            productsRequest?.delegate = self
            productsRequest?.start()
        }
    }
    
    /**
     Start the donation flow on presenting view controller.
     */
    @objc public func start() {
        guard let presentingViewController = presentingViewController else {
            fatalError("presentingViewController must be set.")
        }
        
        guard SKPaymentQueue.canMakePayments(), let product = product else {
            return fallback()
        }
        
        presentingViewController.present(loadingViewController, animated: true) {
            let payment = SKPayment(product: product)
            SKPaymentQueue.default().add(self)
            SKPaymentQueue.default().add(payment)
        }
    }
    
    // MARK: - Private functions
    
    private override init() { }
    
    private func fallback() {
        guard let url = url else {
            return
        }
        
        let viewController = SFSafariViewController(url: url)
        viewController.preferredControlTintColor = BMCColor.default.background
        viewController.modalPresentationStyle = .formSheet
        presentingViewController?.present(viewController, animated: true)
    }
    
    private func showPurchasedMessage() {
        let message = thankYouMessage ?? "Thank you for supporting 🎉"
        let alertController = UIAlertController(title: "Buy Me a Coffee", message: message, preferredStyle: .alert)
        
        alertController.addAction(.init(title: "Close", style: .default, handler: { [weak self] _ in
            self?.loadingViewController.dismiss(animated: true)
        }))
        
        alertController.view.tintColor = BMCColor.default.background
        loadingViewController.present(alertController, animated: true)
    }
    
    // MARK: - SKProductsRequestDelegate
    
    public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        product = response.products.first
        productsRequest = nil
    }
    
    // MARK: - SKPaymentTransactionObserver
    
    public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case .purchased:
                showPurchasedMessage()
                SKPaymentQueue.default().finishTransaction(transaction)
            case .failed:
                loadingViewController.dismiss(animated: true) { [weak self] in
                    if (transaction.error as? SKError)?.code != .paymentCancelled {
                        self?.fallback()
                    }
                }
            case .restored:
                break
            case .deferred:
                break
            case .purchasing:
                break
            @unknown default:
                break
            }
        }
    }
    
    public func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
        true
    }
}
#endif


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/Contents.json
================================================
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/black.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "0.000",
          "green" : "0.000",
          "red" : "0.000"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/blue.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "1.000",
          "green" : "0.498",
          "red" : "0.373"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/green.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "0.710",
          "green" : "0.839",
          "red" : "0.475"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/orange.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "0.247",
          "green" : "0.506",
          "red" : "1.000"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/pink.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "1.000",
          "green" : "0.443",
          "red" : "0.957"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/purple.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "1.000",
          "green" : "0.373",
          "red" : "0.741"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/red.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "0.373",
          "green" : "0.373",
          "red" : "1.000"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/white.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "1.000",
          "green" : "1.000",
          "red" : "1.000"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/yellow.colorset/Contents.json
================================================
{
  "colors" : [
    {
      "color" : {
        "color-space" : "srgb",
        "components" : {
          "alpha" : "1.000",
          "blue" : "0.000",
          "green" : "0.867",
          "red" : "1.000"
        }
      },
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/Contents.json
================================================
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/cup-white.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "cup-white.pdf",
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: Sources/BuyMeACoffee/Resources/Assets.xcassets/cup-yellow.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "cup-yellow.pdf",
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  },
  "properties" : {
    "template-rendering-intent" : "original"
  }
}


================================================
FILE: Tests/BuyMeACoffeeTests/XCTestManifests.swift
================================================
import XCTest

#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
    return [
        testCase(buymeacoffeeTests.allTests),
    ]
}
#endif


================================================
FILE: Tests/LinuxMain.swift
================================================
import XCTest

import BuyMeACoffeeTests

var tests = [XCTestCaseEntry]()
#if canImport(UIKit)
tests += BuyMeACoffeeTests.allTests()
#endif
XCTMain(tests)


================================================
FILE: Tests/buymeacoffeeTests/BuyMeACoffeeTests.swift
================================================
import Foundation
import XCTest
@testable import BuyMeACoffee

#if canImport(UIKit)
final class BuyMeACoffeeTests: XCTestCase {
    private let fileManager: FileManager = .default
    
    func testSnapshotButton() {
        guard let url = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first else {
            XCTFail()
            return
        }
        
        var isDirectory: ObjCBool = false
        if !fileManager.fileExists(atPath: url.path, isDirectory: &isDirectory) || !isDirectory.boolValue {
            XCTAssertNoThrow(try fileManager.createDirectory(at: url, withIntermediateDirectories: false))
        }
        
        let button = BMCButton(frame: .init(x: 0, y: 0, width: 200, height: 50))
        button.configure(with: .default)
                
        if let data = button.snapshot().pngData() {
            let url = url.appendingPathComponent("snapshot-bmc-button").appendingPathExtension("png")
            print(url.path)
            XCTAssertNoThrow(try data.write(to: url))
        } else {
            XCTFail()
        }
    }

    static var allTests = [
        ("snapshot button", testSnapshotButton),
    ]
}

fileprivate extension BMCButton {
    var size: CGSize {
        bounds.insetBy(dx: -layer.shadowOffset.width, dy: -layer.shadowOffset.height).size
    }
    
    func snapshot() -> UIImage {
        UIGraphicsImageRenderer(size: size).image { context in
            layer.render(in: context.cgContext)
        }
    }
}
#endif
Download .txt
gitextract_qlxitl2w/

├── .github/
│   └── workflows/
│       └── swift.yml
├── .gitignore
├── .swiftpm/
│   └── xcode/
│       ├── package.xcworkspace/
│       │   ├── contents.xcworkspacedata
│       │   └── xcshareddata/
│       │       ├── IDEWorkspaceChecks.plist
│       │       └── WorkspaceSettings.xcsettings
│       └── xcshareddata/
│           └── xcschemes/
│               └── BuyMeACoffee.xcscheme
├── Bundle.swift
├── BuyMeACoffee.podspec
├── CODE_OF_CONDUCT.md
├── LICENSE
├── Package.swift
├── README.md
├── Sources/
│   └── BuyMeACoffee/
│       ├── BMCButton.swift
│       ├── BMCColor.swift
│       ├── BMCFont.swift
│       ├── BMCManager.swift
│       └── Resources/
│           └── Assets.xcassets/
│               ├── Colors/
│               │   ├── Contents.json
│               │   ├── black.colorset/
│               │   │   └── Contents.json
│               │   ├── blue.colorset/
│               │   │   └── Contents.json
│               │   ├── green.colorset/
│               │   │   └── Contents.json
│               │   ├── orange.colorset/
│               │   │   └── Contents.json
│               │   ├── pink.colorset/
│               │   │   └── Contents.json
│               │   ├── purple.colorset/
│               │   │   └── Contents.json
│               │   ├── red.colorset/
│               │   │   └── Contents.json
│               │   ├── white.colorset/
│               │   │   └── Contents.json
│               │   └── yellow.colorset/
│               │       └── Contents.json
│               ├── Contents.json
│               ├── cup-white.imageset/
│               │   └── Contents.json
│               └── cup-yellow.imageset/
│                   └── Contents.json
└── Tests/
    ├── BuyMeACoffeeTests/
    │   └── XCTestManifests.swift
    ├── LinuxMain.swift
    └── buymeacoffeeTests/
        └── BuyMeACoffeeTests.swift
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (40K chars).
[
  {
    "path": ".github/workflows/swift.yml",
    "chars": 450,
    "preview": "name: Swift\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n    runs-on: "
  },
  {
    "path": ".gitignore",
    "chars": 53,
    "preview": ".DS_Store\n/.build\n/Packages\n/*.xcodeproj\nxcuserdata/\n"
  },
  {
    "path": ".swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata",
    "chars": 135,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef"
  },
  {
    "path": ".swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": ".swiftpm/xcode/package.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "chars": 263,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": ".swiftpm/xcode/xcshareddata/xcschemes/BuyMeACoffee.xcscheme",
    "chars": 4841,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1200\"\n   version = \"1.7\">\n   <BuildAction\n      "
  },
  {
    "path": "Bundle.swift",
    "chars": 253,
    "preview": "//\n//  Bundle.swift\n//  BuyMeACoffee\n//\n//  Created by François Boulais on 01/07/2020.\n//  Copyright © 2020 App Craft St"
  },
  {
    "path": "BuyMeACoffee.podspec",
    "chars": 1351,
    "preview": "Pod::Spec.new do |spec|\n  spec.name                  = 'BuyMeACoffee'\n  spec.version               = '1.0.6'\n  spec.lice"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3359,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "MIT License\n\nCopyright (c) 2020 App Craft Studio\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "Package.swift",
    "chars": 1349,
    "preview": "// swift-tools-version:5.3\n// The swift-tools-version declares the minimum version of Swift required to build this packa"
  },
  {
    "path": "README.md",
    "chars": 6386,
    "preview": "![Swift](https://github.com/appcraftstudio/buymeacoffee/workflows/Swift/badge.svg)\n\n# A supporter is  worth a thousand  "
  },
  {
    "path": "Sources/BuyMeACoffee/BMCButton.swift",
    "chars": 3456,
    "preview": "//\n//  BMCButton.swift\n//\n//  Created by François Boulais on 26/06/2020.\n//  Copyright © 2020 App Craft Studio. All righ"
  },
  {
    "path": "Sources/BuyMeACoffee/BMCColor.swift",
    "chars": 1035,
    "preview": "//\n//  BMCColor.swift\n//\n//  Created by François Boulais on 30/06/2020.\n//  Copyright © 2020 App Craft Studio. All right"
  },
  {
    "path": "Sources/BuyMeACoffee/BMCFont.swift",
    "chars": 655,
    "preview": "//\n//  BMCFont.swift\n//  \n//  Created by François Boulais on 30/06/2020.\n//  Copyright © 2020 App Craft Studio. All righ"
  },
  {
    "path": "Sources/BuyMeACoffee/BMCManager.swift",
    "chars": 5854,
    "preview": "//\n//  BMCManager.swift\n//\n//  Created by François Boulais on 30/06/2020.\n//  Copyright © 2020 App Craft Studio. All rig"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/Contents.json",
    "chars": 63,
    "preview": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/black.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/blue.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/green.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/orange.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/pink.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/purple.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/red.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/white.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Colors/yellow.colorset/Contents.json",
    "chars": 329,
    "preview": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/Contents.json",
    "chars": 63,
    "preview": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/cup-white.imageset/Contents.json",
    "chars": 159,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"cup-white.pdf\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"auth"
  },
  {
    "path": "Sources/BuyMeACoffee/Resources/Assets.xcassets/cup-yellow.imageset/Contents.json",
    "chars": 229,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"cup-yellow.pdf\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"aut"
  },
  {
    "path": "Tests/BuyMeACoffeeTests/XCTestManifests.swift",
    "chars": 162,
    "preview": "import XCTest\n\n#if !canImport(ObjectiveC)\npublic func allTests() -> [XCTestCaseEntry] {\n    return [\n        testCase(bu"
  },
  {
    "path": "Tests/LinuxMain.swift",
    "chars": 154,
    "preview": "import XCTest\n\nimport BuyMeACoffeeTests\n\nvar tests = [XCTestCaseEntry]()\n#if canImport(UIKit)\ntests += BuyMeACoffeeTests"
  },
  {
    "path": "Tests/buymeacoffeeTests/BuyMeACoffeeTests.swift",
    "chars": 1496,
    "preview": "import Foundation\nimport XCTest\n@testable import BuyMeACoffee\n\n#if canImport(UIKit)\nfinal class BuyMeACoffeeTests: XCTes"
  }
]

About this extraction

This page contains the full source code of the appcraftstudio/buymeacoffee GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (35.2 KB), approximately 9.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!