A SwiftUI-based todo list library for debugging and development purposes with optional GitHub integration.
import SwiftUI
import DebugTodo
struct ContentView: View {
var body: some View {
NavigationStack {
TodoListView(storage: UserDefaultsStorage())
}
}
}import SwiftUI
import DebugTodo
struct ContentView: View {
@State private var service = GitHubService()
var body: some View {
NavigationStack {
TodoListView(
storage: UserDefaultsStorage(),
service: service
)
}
}
}Setup: Tap the settings icon (gear) in the toolbar, then enter:
- Personal Access Token (required scope:
repofor private repos,public_repofor public repos only) - Owner and Repo name
Note: TodoListView uses SwiftUI's NavigationLink internally. Wrap it in NavigationStack if presenting as a root view or in a sheet
InMemory Storage (data lost on app termination):
TodoListView(storage: InMemoryStorage())File Storage (JSON file persistence):
let fileURL = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)[0]
.appendingPathComponent("todos.json")
TodoListView(storage: FileStorage(fileURL: fileURL))UserDefaults Storage:
TodoListView(storage: UserDefaultsStorage())
// Custom key
TodoListView(storage: UserDefaultsStorage(
userDefaults: .standard,
key: "myCustomTodos"
))- Swift: 6.2+
- Xcode: 26.0+
- Platforms:
- iOS 17.0+
- macOS 14.0+
- visionOS 1.0+
- Mac Catalyst 17.0+
Add the following to your Package.swift:
dependencies: [
.package(url: "https://github.com/yourusername/swift-debug-todo.git", from: "0.1.0")
]Or add it through Xcode:
- File → Add Package Dependencies
- Enter the repository URL
- Select the version you want to use
See the Example/ directory for a complete sample app demonstrating all storage implementations and GitHub integration.
struct ContentView: View {
@State private var service: GitHubService = {
let tokenStorage = KeychainTokenStorage(
service: "com.myapp.github",
key: "myAccessToken"
)
let repositorySettingsStorage = KeychainRepositorySettingsStorage(
service: "com.myapp.github",
ownerKey: "myOwner",
repoKey: "myRepo",
showConfirmationAlertKey: "myShowConfirmation"
)
return GitHubService(
tokenStorage: tokenStorage,
repositorySettingsStorage: repositorySettingsStorage
)
}()
var body: some View {
NavigationStack {
TodoListView(
storage: UserDefaultsStorage(),
service: service
)
}
}
}TodoListView(
storage: UserDefaultsStorage(),
service: service,
logLevel: .debug // Available: .trace, .debug, .info, .notice, .warning, .error, .critical
)Implement these protocols for custom backends:
Storage Protocol:
public protocol Storage: Sendable {
func save(_ items: [TodoItem]) async throws
func load() async throws -> [TodoItem]
func delete() async throws
}GitHub Token Storage:
public protocol GitHubTokenStorage: Sendable {
func saveToken(_ token: String) async throws
func loadToken() async throws -> String?
func deleteToken() async throws
}GitHub Issue Creator:
public protocol GitHubIssueCreatorProtocol: Sendable {
func createIssue(for item: TodoItem) async throws -> GitHubIssue?
func updateIssueState(
owner: String,
repo: String,
issueNumber: Int,
state: String,
stateReason: String?
) async throws -> GitHubIssue?
func updateIssueContent(
owner: String,
repo: String,
issueNumber: Int,
title: String,
body: String?
) async throws -> GitHubIssue?
}