openclaw/apps/ios-github-mobile/Sources/Models/AppState.swift
Claude cffaf0b904
feat: add SwiftUI GitHub mobile app inspired by Claude Code
- Create new iOS app at apps/ios-github-mobile
- Session list view with repository info and status
- Chat view with collapsible tool executions (Write, Bash, Read)
- Message input with model/repo/branch selection chips
- PR creation flow simulation
- Dark theme matching Claude Code aesthetic
- Mock data for repos, sessions, and tool calls
- Modern SwiftUI with @Observable, NavigationStack

https://claude.ai/code/session_018qmTB96S8xvNRQFrhcvzJp
2026-01-23 08:22:15 +00:00

93 lines
2.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
import Observation
import SwiftUI
@Observable
@MainActor
final class AppState {
var sessions: [Session] = Session.mockList
var repositories: [Repository] = Repository.mockList
var selectedModel: AIModel = .sonnet
var currentSession: Session?
var navigationPath = NavigationPath()
// Current input state
var messageInput: String = ""
var selectedRepository: Repository?
var selectedBranch: String = "main"
init() {
self.selectedRepository = repositories.first
}
func createNewSession(title: String, repository: Repository) -> Session {
let session = Session(
id: UUID().uuidString,
title: title,
repository: repository,
createdAt: Date(),
status: .idle,
messages: []
)
sessions.insert(session, at: 0)
return session
}
func sendMessage(_ content: String, to session: Session) {
guard let index = sessions.firstIndex(where: { $0.id == session.id }) else { return }
let message = Message(
id: UUID().uuidString,
role: .user,
content: content,
timestamp: Date(),
toolCalls: []
)
sessions[index].messages.append(message)
sessions[index].status = .running
// Simulate assistant response after a delay
simulateResponse(for: sessions[index])
}
private func simulateResponse(for session: Session) {
guard let index = sessions.firstIndex(where: { $0.id == session.id }) else { return }
// Create a simulated assistant response
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [weak self] in
guard let self else { return }
let assistantMessage = Message(
id: UUID().uuidString,
role: .assistant,
content: "Anladım! Şimdi bu değişiklikleri yapmaya başlıyorum...",
timestamp: Date(),
toolCalls: [
ToolCall(
id: UUID().uuidString,
type: .read,
name: "Read",
input: "/home/user/\(session.repository.name)/README.md",
output: "# \(session.repository.name)\n\nProject description...",
status: .completed
)
]
)
self.sessions[index].messages.append(assistantMessage)
self.sessions[index].status = .idle
}
}
func openSession(_ session: Session) {
currentSession = session
navigationPath.append(session)
}
func selectRepository(_ repository: Repository) {
selectedRepository = repository
selectedBranch = repository.defaultBranch
}
}