ITADN
alienator88/AlinFoundation
alienator88/AlinFoundation · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

AlinFoundation

AlinFoundation 是一个 Swift 包,包含我最常用的类、函数和工具,针对 macOS 项目进行了优化。它通过提供基础组件(包括自定义的 ColorPicker、Updater 和 PermissionsManager)来简化新项目的设置。

Features

  • Updater: 通过从指定的公共或私有 GitHub 仓库检查最新可用版本,实现无缝更新。也可与下方的 TokenManager 配合使用,从 KeyChain 应用中加载私有 GitHub API 令牌
  • TokenManager: 将密码、密钥等加密后保存到 Keychain Access
  • ColorPicker: 遵循 macOS 界面指南的极简颜色选择器
  • ThemeManager: 选择 Auto、Light、Dark 等外观模式。或选择 custom 使用上述颜色选择器设置主题颜色
  • PermissionsManager: 检查权限并显示一个视图来管理这些权限(目前支持 FDA、Accessibility、Automation)
  • Authorization: 执行 sudo shell 命令,向最终用户请求权限
  • Utilities: 多种函数和扩展
  • Styles: 一些自定义视图、buttonStyles 等

Screenshots

Screenshot 2024-07-18 at 2 00 57 PM Screenshot 2024-07-18 at 2 01 02 PM Screenshot 2024-07-18 at 2 01 07 PM Screenshot 2024-07-18 at 2 01 18 PM

Installation

要将 AlinFoundation 集成到你的 Swift 项目中,请配置你的 Package.swift 以包含以下依赖项:

dependencies: [
    .package(url: "https://github.com/alienator88/AlinFoundation.git", from: "1.0.0")
]

然后,在需要使用其功能的项目文件中导入 AlinFoundation。

Usage

Importing the Package

要在你的 Swift 项目中使用 AlinFoundation,你需要导入它以及其他必要的框架:

import SwiftUI
import AppKit
import AlinFoundation

示例

App.swift

import SwiftUI
import AppKit
import AlinFoundation

@main
struct FoundationTestingApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @StateObject private var updater = Updater(owner: "USER", repo: "REPO")
    @StateObject private var themeManager = ThemeManager.shared
    @StateObject private var permissionManager = PermissionManager.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(themeManager)
                .environmentObject(updater)
                .environmentObject(permissionManager)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(
                    themeManager.pickerColor
                )
                .onAppear{
                    themeManager.setupAppearance()
                }
                .preferredColorScheme(themeManager.displayMode.colorScheme)
        }
        .windowStyle(.hiddenTitleBar)

    }
}

ContentView.swift

import SwiftUI
import AlinFoundation

struct ContentView: View {
    @EnvironmentObject var updater: Updater
    @EnvironmentObject var themeManager: ThemeManager
    @EnvironmentObject var permissions: ThemeManager

    @Environment(\.colorScheme) var colorScheme
    @State private var token: String = ""
    @State private var tokenStatus: String = ""
    @State var show = false
    let tokenManager = TokenManager(service: Bundle.main.bundleId, account: "API-Token")

    var body: some View {

        HStack(spacing: 0) {
            ZStack {
                
                VStack {
                    Spacer()
                }
                .materialColor(themeManager: themeManager, brightness: 5, opacity: 1)

                VStack(alignment: .leading, spacing: 15) {

                    Text("Permissions Badge").font(.title2)
                    /// This shows a permission notification view if permissions are missing
                    PermissionsBadge()
                        .backgroundAF(opacity: 1)

                    Divider()

                    Text("Updater Badge").font(.title2)
                    /// This will check for an update on appear of the button and show if there's one available or not in the label
                    UpdateBadge(updater: updater)
                        .backgroundAF(opacity: 1)


                    Divider()

                    Text("Token Badge").font(.title2)
                    /// This will check if the token is valid
                    if tokenManager.tokenValid {
                        TokenBadge(buttonAction: {
                            print("Show a token view")
                        })
                        .backgroundAF(opacity: 1)
                    }


                    Text("Frequency").font(.title2)
                    /// This will allow the user to set how often to check for updates
                    FrequencyView(updater: updater)
                        .backgroundAF(opacity: 1)

                    Divider()

                    Text("Appearance").font(.title2)
                    /// Show appearance/theme mode changer
                    ThemeSettingsView(opacity: 1)
                        .backgroundAF(opacity: 1)

                    Text("ColorPicker").font(.title2)
                    /// Show a color picker
                    ColorButtonView(themeManager: themeManager)
                        .backgroundAF(opacity: 1)

                    Spacer()
                }
                .padding()
                .padding(.top, 40)
            }
            .frame(width: 350)

            Divider()


            VStack(alignment: .leading, spacing: 20) {

                Text("Updater Releases").font(.title2)
                /// This will show the last 3 versions release notes
                ReleasesView(updater: updater)
                    .frame(height: 300)
                    .backgroundAF(opacity: 0.5)

                Divider()


                /// Create and store an encrypted token in Keychain Access
                Text("Token Manager").font(.title2)

                HStack {
                    TextField(" Enter Token", text: $token)
                        .textFieldStyle(.plain)
                        .backgroundAF(opacity: 0.7)
                    Button("Create") {
                        // Save token
                        tokenManager.saveToken(token) { success in
                            if success {
                                tokenStatus = "Token saved:\n\(token)"
                            } else {
                                tokenStatus = token.isEmpty ? "Token cannot be empty" : "Failed to save token:\n\(token)"
                            }
                        }
                    }
                    .buttonStyle(AFButtonStyle(image: "plus"))

                    Button("Load") {
                        // Load a token
                        var loadedToken = ""
                        loadedToken = tokenManager.loadToken { success in
                            if success {
                                DispatchQueue.main.async {
                                    token = loadedToken
                                    tokenStatus = "Token loaded:\n\(token)"

                                    tokenManager.checkTokenValidity(token: token) { success in
                                        if success {
                                            print("Token is good")
                                        } else {
                                            print("Token is bad")
                                        }
                                    }
                                }
                            } else {
                                DispatchQueue.main.async {
                                    tokenStatus = "No token found:\n\(token)"
                                }
                            }
                        }

                    }
                    .buttonStyle(AFButtonStyle(image: "externaldrive"))

                    Button("Delete") {
                        // Delete a token
                        tokenManager.deleteToken() { success in
                            if success {
                                tokenStatus = "Token deleted:\n\(token)"
                                token = ""
                            } else {
                                tokenStatus = token.isEmpty ? "Unable to delete empty token" : "Error deleting token:\n\(token)"
                            }
                        }
                    }
                    .buttonStyle(AFButtonStyle(image: "minus"))

                }
                Text(tokenStatus)

                Spacer()

            }
            .padding()
            .onAppear {
                /// This will check for updates on load based on the update frequency
                updater.checkAndUpdateIfNeeded()
            }
            .sheet(isPresented: $updater.showSheet, content: {
                /// This will show the update sheet based on the frequency check function only
                updater.getUpdateView()
            })
        }
        .edgesIgnoringSafeArea(.all)


    }
}

许可证

根据 MIT 许可证分发。