Files
ios-gitea-prs/GiteaPR/Detail/Sheets.swift
T
Hermes 1025634978
Build iOS App / Build .ipa and publish source (push) Failing after 35s
GiteaPR: native iOS app to manage Gitea pull requests
Multi-repo PR inbox, review (approve/request changes/comment), merge with
gating toggle, read-only diff viewer, and Gitea Actions check status with
one-tap re-run. Ships unsigned via the iMac runner to the SideStore source.
2026-08-12 17:07:58 +00:00

136 lines
5.0 KiB
Swift

import SwiftUI
/// Composes a comment. `mode` picks whether it posts a plain comment or a
/// review with a state (Approve / Request changes / Comment).
struct CommentSheet: View {
@ObservedObject var vm: PRDetailViewModel
@Environment(\.dismiss) private var dismiss
@State private var text = ""
var mode: CommentMode = .comment
enum CommentMode { case comment, approve, requestChanges }
var body: some View {
NavigationStack {
VStack(alignment: .leading, spacing: 12) {
Text(title).font(.headline)
TextEditor(text: $text)
.frame(minHeight: 150)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color(.separator)))
Text("\(text.count) characters")
.font(.caption2)
.foregroundColor(.secondary)
Spacer()
}
.padding()
.navigationTitle(title)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button("Submit") { submit() }
.disabled(text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
}
}
}
}
private var title: String {
switch mode {
case .approve: return "Approve"
case .requestChanges: return "Request changes"
case .comment: return "Comment"
}
}
private func submit() {
let body = text.trimmingCharacters(in: .whitespacesAndNewlines)
switch mode {
case .approve:
Task { await vm.submitReview(state: "approved", comment: body) }
case .requestChanges:
Task { await vm.submitReview(state: "changes", comment: body) }
case .comment:
Task { await vm.postComment(body) }
}
dismiss()
}
}
struct MergeSheet: View {
@ObservedObject var vm: PRDetailViewModel
@Environment(\.dismiss) private var dismiss
@State private var method = "merge"
private let methods = [("merge", "Create merge commit"),
("rebase", "Rebase and merge"),
("squash", "Squash and merge")]
var body: some View {
NavigationStack {
Form {
Section("Merge method") {
Picker("Method", selection: $method) {
ForEach(methods, id: \.0) { m in
Text(m.1).tag(m.0)
}
}
.pickerStyle(.inline)
}
Section {
HStack {
Text("CI")
Spacer()
switch vm.ciStatus {
case .success: Label("Passing", systemImage: "checkmark.circle.fill")
.foregroundColor(.green)
case .failure: Label("Failing", systemImage: "xmark.circle.fill")
.foregroundColor(.red)
case .running: Label("Running", systemImage: "hourglass")
.foregroundColor(.orange)
case .cancelled, .unknown: Label("Unknown", systemImage: "questionmark.circle")
.foregroundColor(.secondary)
}
}
if vm.ciStatus == .failure {
if SettingsStore.shared.mergeGateMode == .block {
Label("Merging is blocked while CI is red (Settings).",
systemImage: "lock")
.font(.caption)
.foregroundColor(.secondary)
} else {
Label("CI is red — you can still merge (Settings allows it).",
systemImage: "exclamationmark.triangle")
.font(.caption)
.foregroundColor(.orange)
}
}
}
}
.navigationTitle("Merge")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button("Merge") { performMerge() }
.disabled(SettingsStore.shared.mergeGateMode == .block
&& vm.ciStatus == .failure)
}
}
}
}
private func performMerge() {
Task {
let success = await vm.merge(method: method)
if success { dismiss() }
}
}
}