// CxLLM Studio — iOS GitView.swift // Gitea repository dashboard adapted for iOS import SwiftUI import CxGit struct GitView: View { @Environment(GitService.self) private var git enum Section: String, CaseIterable { case repos = "Repos" case pulls = "PRs" case issues = "Issues" } @State private var section: Section = .repos @State private var selectedRepo: GitRepository? var body: some View { VStack(spacing: 0) { // Connection bar HStack(spacing: 8) { Circle().fill(git.isConnected ? .green : .red).frame(width: 8, height: 8) Text(git.isConnected ? "Connected" : "Disconnected").font(.caption) Spacer() if let user = git.currentUser { Label(user.login, systemImage: "person.circle").font(.caption).foregroundStyle(.secondary) } Button { Task { await git.refreshAll() } } label: { Image(systemName: "arrow.clockwise").font(.caption) } } .padding(.horizontal).padding(.vertical, 8) .background(.ultraThinMaterial) // Section picker Picker("Section", selection: $section) { ForEach(Section.allCases, id: \.self) { s in Text(s.rawValue).tag(s) } } .pickerStyle(.segmented) .padding(.horizontal).padding(.vertical, 8) // Content switch section { case .repos: reposList case .pulls: pullsList case .issues: issuesList } } .task { await git.refreshAll() } } // MARK: - Repos private var reposList: some View { Group { if git.repositories.isEmpty { ContentUnavailableView("No Repositories", systemImage: "folder", description: Text("Check your Gitea connection")) } else { List(git.repositories) { repo in NavigationLink { repoDetail(repo) } label: { HStack(spacing: 8) { Image(systemName: repo.private ? "lock.fill" : "globe") .foregroundStyle(repo.private ? .orange : .green) .font(.caption) VStack(alignment: .leading, spacing: 2) { Text(repo.name).font(.subheadline.weight(.medium)) if let desc = repo.description, !desc.isEmpty { Text(desc).font(.caption).foregroundStyle(.secondary).lineLimit(1) } } Spacer() HStack(spacing: 6) { Label("\(repo.starsCount)", systemImage: "star").font(.caption2) Label("\(repo.openIssuesCount)", systemImage: "exclamationmark.circle").font(.caption2) }.foregroundStyle(.secondary) } } } } } } private func repoDetail(_ repo: GitRepository) -> some View { List { SwiftUI.Section("Info") { LabeledContent("Name", value: repo.name) LabeledContent("Default Branch", value: repo.defaultBranch) LabeledContent("Stars", value: "\(repo.starsCount)") LabeledContent("Forks", value: "\(repo.forksCount)") LabeledContent("Open Issues", value: "\(repo.openIssuesCount)") if let desc = repo.description { LabeledContent("Description", value: desc) } } SwiftUI.Section { Button("Load PRs") { let parts = repo.fullName.components(separatedBy: "/") if parts.count == 2 { Task { await git.loadPullRequests(owner: parts[0], repo: parts[1]); section = .pulls } } } Button("Load Issues") { let parts = repo.fullName.components(separatedBy: "/") if parts.count == 2 { Task { await git.loadIssues(owner: parts[0], repo: parts[1]); section = .issues } } } Button("Load Branches") { let parts = repo.fullName.components(separatedBy: "/") if parts.count == 2 { Task { await git.loadBranches(owner: parts[0], repo: parts[1]) } } } } } .navigationTitle(repo.name) } // MARK: - Pull Requests private var pullsList: some View { Group { if git.pullRequests.isEmpty { ContentUnavailableView("No Pull Requests", systemImage: "arrow.triangle.pull", description: Text("Select a repo to load PRs")) } else { List(git.pullRequests) { pr in HStack(spacing: 8) { Image(systemName: pr.state == "open" ? "arrow.triangle.pull" : "checkmark.circle.fill") .foregroundStyle(pr.state == "open" ? .green : .purple) VStack(alignment: .leading, spacing: 2) { Text("#\(pr.number) \(pr.title)").font(.subheadline.weight(.medium)) HStack(spacing: 6) { if let user = pr.user { Text(user.login).font(.caption2) } if let head = pr.head, let base = pr.base { Text("\(head.ref) → \(base.ref)").font(.caption2).foregroundStyle(.secondary) } } } Spacer() Text(pr.state).font(.caption2) .padding(.horizontal, 6).padding(.vertical, 2) .background(pr.state == "open" ? Color.green.opacity(0.1) : Color.purple.opacity(0.1)) .clipShape(Capsule()) } } } } } // MARK: - Issues private var issuesList: some View { Group { if git.issues.isEmpty { ContentUnavailableView("No Issues", systemImage: "exclamationmark.circle", description: Text("Select a repo to load issues")) } else { List(git.issues) { issue in HStack(spacing: 8) { Image(systemName: issue.state == "open" ? "circle" : "checkmark.circle.fill") .foregroundStyle(issue.state == "open" ? .green : .secondary) VStack(alignment: .leading, spacing: 2) { Text("#\(issue.number) \(issue.title)").font(.subheadline.weight(.medium)) HStack(spacing: 4) { if let user = issue.user { Text(user.login).font(.caption2).foregroundStyle(.secondary) } if let labels = issue.labels { ForEach(labels.prefix(3)) { label in Text(label.name).font(.system(size: 9)) .padding(.horizontal, 4).padding(.vertical, 1) .background(Color.secondary.opacity(0.1)).clipShape(Capsule()) } } } } Spacer() } } } } } }