{"id":22034995,"url":"https://github.com/alienator88/alinfoundation","last_synced_at":"2025-05-07T19:09:37.148Z","repository":{"id":247856799,"uuid":"826552997","full_name":"alienator88/AlinFoundation","owner":"alienator88","description":"Swift package that houses commonly used functions, extensions, views, classes, etc.","archived":false,"fork":false,"pushed_at":"2025-04-29T17:14:51.000Z","size":182,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-07T19:03:58.591Z","etag":null,"topics":["foundation","swift","swiftui","utilities","utility"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alienator88.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-07-09T23:50:01.000Z","updated_at":"2025-04-29T17:14:55.000Z","dependencies_parsed_at":"2024-12-21T01:20:13.293Z","dependency_job_id":"21f52ddc-9a0e-441b-a60a-1013413196d7","html_url":"https://github.com/alienator88/AlinFoundation","commit_stats":null,"previous_names":["alienator88/alinfoundation"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienator88%2FAlinFoundation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienator88%2FAlinFoundation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienator88%2FAlinFoundation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienator88%2FAlinFoundation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alienator88","download_url":"https://codeload.github.com/alienator88/AlinFoundation/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252940932,"owners_count":21828769,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["foundation","swift","swiftui","utilities","utility"],"created_at":"2024-11-30T10:15:22.338Z","updated_at":"2025-05-07T19:09:37.046Z","avatar_url":"https://github.com/alienator88.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AlinFoundation\n\n`AlinFoundation` is a Swift package that houses my most commonly used classes, functions, and utilities, optimized for macOS projects. It simplifies the setup of new projects by providing foundational components, including a custom ColorPicker, Updater and PermissionsManager.\n\n## Features\n\n- **Updater**: Allows seamless updates by checking the latest available versions from a specified public or private GitHub repository. Works with the TokenManager below as well to load private GitHub API token from KeyChain app\n- **TokenManager**: Save passwords, keys and more to Keychain Access with encryption\n- **ColorPicker**: Minimalistic color picker that follows macOS interface guidelines\n- **ThemeManager**: Choose appearance modes like Auto, Light, Dark. Or choose custom to set a theme color using the color picker above\n- **PermissionsManager**: Check for permissions and show a view to manage these (Currently supports FDA, Accessibility, Automation)\n- **Authorization**: Execute a sudo shell command, asking for permission from end-user\n- **Utilities**: A multitude of functions and extensions\n- **Styles**: Some custom views, buttonStyles, etc.\n\n\n\n## Screenshots\n![Screenshot 2024-07-18 at 2 00 57 PM](https://github.com/user-attachments/assets/5c68da88-166b-4eb1-acc8-5f2f0497544c)\n![Screenshot 2024-07-18 at 2 01 02 PM](https://github.com/user-attachments/assets/82f204b3-ca81-4189-bb02-f493f94ac998)\n![Screenshot 2024-07-18 at 2 01 07 PM](https://github.com/user-attachments/assets/539f961e-5781-49d1-9cc4-280a2d2b28ad)\n![Screenshot 2024-07-18 at 2 01 18 PM](https://github.com/user-attachments/assets/f4545da8-1f2f-4c34-857d-78a86df57904)\n\n\n\n\n## Installation\n\nTo integrate `AlinFoundation` into your Swift project, configure your `Package.swift` to include the following dependency:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/alienator88/AlinFoundation.git\", from: \"1.0.0\")\n]\n```\nThen, import AlinFoundation in your project files where you need to use its functionalities.\n\n## Usage\n\n### Importing the Package\n\nTo use AlinFoundation in your Swift project, you need to import it along with other necessary frameworks:\n```swift\nimport SwiftUI\nimport AppKit\nimport AlinFoundation\n```\n\n## Example\n\n### App.swift\n```swift\nimport SwiftUI\nimport AppKit\nimport AlinFoundation\n\n@main\nstruct FoundationTestingApp: App {\n    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate\n    @StateObject private var updater = Updater(owner: \"USER\", repo: \"REPO\")\n    @StateObject private var themeManager = ThemeManager.shared\n    @StateObject private var permissionManager = PermissionManager.shared\n\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n                .environmentObject(themeManager)\n                .environmentObject(updater)\n                .environmentObject(permissionManager)\n                .frame(maxWidth: .infinity, maxHeight: .infinity)\n                .background(\n                    themeManager.pickerColor\n                )\n                .onAppear{\n                    themeManager.setupAppearance()\n                }\n                .preferredColorScheme(themeManager.displayMode.colorScheme)\n        }\n        .windowStyle(.hiddenTitleBar)\n\n    }\n}\n```\n\n### ContentView.swift\n```swift\nimport SwiftUI\nimport AlinFoundation\n\nstruct ContentView: View {\n    @EnvironmentObject var updater: Updater\n    @EnvironmentObject var themeManager: ThemeManager\n    @EnvironmentObject var permissions: ThemeManager\n\n    @Environment(\\.colorScheme) var colorScheme\n    @State private var token: String = \"\"\n    @State private var tokenStatus: String = \"\"\n    @State var show = false\n    let tokenManager = TokenManager(service: Bundle.main.bundleId, account: \"API-Token\")\n\n    var body: some View {\n\n        HStack(spacing: 0) {\n            ZStack {\n                \n                VStack {\n                    Spacer()\n                }\n                .materialColor(themeManager: themeManager, brightness: 5, opacity: 1)\n\n                VStack(alignment: .leading, spacing: 15) {\n\n                    Text(\"Permissions Badge\").font(.title2)\n                    /// This shows a permission notification view if permissions are missing\n                    PermissionsBadge()\n                        .backgroundAF(opacity: 1)\n\n                    Divider()\n\n                    Text(\"Updater Badge\").font(.title2)\n                    /// This will check for an update on appear of the button and show if there's one available or not in the label\n                    UpdateBadge(updater: updater)\n                        .backgroundAF(opacity: 1)\n\n\n                    Divider()\n\n                    Text(\"Token Badge\").font(.title2)\n                    /// This will check if the token is valid\n                    if tokenManager.tokenValid {\n                        TokenBadge(buttonAction: {\n                            print(\"Show a token view\")\n                        })\n                        .backgroundAF(opacity: 1)\n                    }\n\n\n                    Text(\"Frequency\").font(.title2)\n                    /// This will allow the user to set how often to check for updates\n                    FrequencyView(updater: updater)\n                        .backgroundAF(opacity: 1)\n\n                    Divider()\n\n                    Text(\"Appearance\").font(.title2)\n                    /// Show appearance/theme mode changer\n                    ThemeSettingsView(opacity: 1)\n                        .backgroundAF(opacity: 1)\n\n                    Text(\"ColorPicker\").font(.title2)\n                    /// Show a color picker\n                    ColorButtonView(themeManager: themeManager)\n                        .backgroundAF(opacity: 1)\n\n                    Spacer()\n                }\n                .padding()\n                .padding(.top, 40)\n            }\n            .frame(width: 350)\n\n            Divider()\n\n\n            VStack(alignment: .leading, spacing: 20) {\n\n                Text(\"Updater Releases\").font(.title2)\n                /// This will show the last 3 versions release notes\n                ReleasesView(updater: updater)\n                    .frame(height: 300)\n                    .backgroundAF(opacity: 0.5)\n\n                Divider()\n\n\n                /// Create and store an encrypted token in Keychain Access\n                Text(\"Token Manager\").font(.title2)\n\n                HStack {\n                    TextField(\" Enter Token\", text: $token)\n                        .textFieldStyle(.plain)\n                        .backgroundAF(opacity: 0.7)\n                    Button(\"Create\") {\n                        // Save token\n                        tokenManager.saveToken(token) { success in\n                            if success {\n                                tokenStatus = \"Token saved:\\n\\(token)\"\n                            } else {\n                                tokenStatus = token.isEmpty ? \"Token cannot be empty\" : \"Failed to save token:\\n\\(token)\"\n                            }\n                        }\n                    }\n                    .buttonStyle(AFButtonStyle(image: \"plus\"))\n\n                    Button(\"Load\") {\n                        // Load a token\n                        var loadedToken = \"\"\n                        loadedToken = tokenManager.loadToken { success in\n                            if success {\n                                DispatchQueue.main.async {\n                                    token = loadedToken\n                                    tokenStatus = \"Token loaded:\\n\\(token)\"\n\n                                    tokenManager.checkTokenValidity(token: token) { success in\n                                        if success {\n                                            print(\"Token is good\")\n                                        } else {\n                                            print(\"Token is bad\")\n                                        }\n                                    }\n                                }\n                            } else {\n                                DispatchQueue.main.async {\n                                    tokenStatus = \"No token found:\\n\\(token)\"\n                                }\n                            }\n                        }\n\n                    }\n                    .buttonStyle(AFButtonStyle(image: \"externaldrive\"))\n\n                    Button(\"Delete\") {\n                        // Delete a token\n                        tokenManager.deleteToken() { success in\n                            if success {\n                                tokenStatus = \"Token deleted:\\n\\(token)\"\n                                token = \"\"\n                            } else {\n                                tokenStatus = token.isEmpty ? \"Unable to delete empty token\" : \"Error deleting token:\\n\\(token)\"\n                            }\n                        }\n                    }\n                    .buttonStyle(AFButtonStyle(image: \"minus\"))\n\n                }\n                Text(tokenStatus)\n\n                Spacer()\n\n            }\n            .padding()\n            .onAppear {\n                /// This will check for updates on load based on the update frequency\n                updater.checkAndUpdateIfNeeded()\n            }\n            .sheet(isPresented: $updater.showSheet, content: {\n                /// This will show the update sheet based on the frequency check function only\n                updater.getUpdateView()\n            })\n        }\n        .edgesIgnoringSafeArea(.all)\n\n\n    }\n}\n```\n\n## License\n\nDistributed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falienator88%2Falinfoundation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falienator88%2Falinfoundation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falienator88%2Falinfoundation/lists"}