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
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 许可证分发。