summaryrefslogtreecommitdiff
path: root/Hutch/Views/Repositories
diff options
context:
space:
mode:
Diffstat (limited to 'Hutch/Views/Repositories')
-rw-r--r--Hutch/Views/Repositories/CommitDetailView.swift36
-rw-r--r--Hutch/Views/Repositories/CommitLogView.swift2
-rw-r--r--Hutch/Views/Repositories/CommitRowView.swift17
-rw-r--r--Hutch/Views/Repositories/ReadmeView.swift23
-rw-r--r--Hutch/Views/Repositories/RepositoryDetailView.swift75
-rw-r--r--Hutch/Views/Repositories/RepositoryRowView.swift45
6 files changed, 162 insertions, 36 deletions
diff --git a/Hutch/Views/Repositories/CommitDetailView.swift b/Hutch/Views/Repositories/CommitDetailView.swift
index d303542..1dcbf68 100644
--- a/Hutch/Views/Repositories/CommitDetailView.swift
+++ b/Hutch/Views/Repositories/CommitDetailView.swift
@@ -5,6 +5,7 @@ struct CommitDetailView: View {
let repository: RepositorySummary
@Environment(AppState.self) private var appState
+ @Environment(\.openURL) private var openURL
@State private var viewModel: CommitDetailViewModel?
var body: some View {
@@ -18,7 +19,38 @@ struct CommitDetailView: View {
.navigationTitle(commitSummary.shortId)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
- ToolbarItem(placement: .topBarTrailing) {
+ ToolbarItemGroup(placement: .topBarTrailing) {
+ Menu {
+ if let commitURL = SRHTWebURL.commit(repository: repository, commitId: commitSummary.id) {
+ Button {
+ openURL(commitURL)
+ } label: {
+ Label("Open in Browser", systemImage: "safari")
+ }
+
+ Button {
+ appState.copyToPasteboard(commitURL.absoluteString, label: "commit URL")
+ } label: {
+ Label("Copy URL", systemImage: "doc.on.doc")
+ }
+ }
+
+ Button {
+ appState.copyToPasteboard(commitSummary.id, label: "commit SHA")
+ } label: {
+ Label("Copy Full SHA", systemImage: "doc.on.doc")
+ }
+
+ Button {
+ appState.copyToPasteboard(commitSummary.shortId, label: "short commit SHA")
+ } label: {
+ Label("Copy Short SHA", systemImage: "number")
+ }
+ } label: {
+ Image(systemName: "ellipsis.circle")
+ }
+ .accessibilityLabel("Commit actions")
+
SRHTShareButton(url: SRHTWebURL.commit(repository: repository, commitId: commitSummary.id), target: .commit) {
Image(systemName: "square.and.arrow.up")
}
@@ -109,7 +141,7 @@ struct CommitDetailView: View {
VStack(alignment: .leading, spacing: 8) {
// Full hash — tappable to copy
Button {
- UIPasteboard.general.string = commit.id
+ appState.copyToPasteboard(commit.id, label: "commit SHA")
} label: {
HStack(spacing: 4) {
Text(commit.id)
diff --git a/Hutch/Views/Repositories/CommitLogView.swift b/Hutch/Views/Repositories/CommitLogView.swift
index d63c5eb..bc8ccc9 100644
--- a/Hutch/Views/Repositories/CommitLogView.swift
+++ b/Hutch/Views/Repositories/CommitLogView.swift
@@ -7,7 +7,7 @@ struct CommitLogView: View {
List {
ForEach(viewModel.commits) { commit in
NavigationLink(value: commit) {
- CommitRowView(commit: commit)
+ CommitRowView(commit: commit, repository: viewModel.repository)
}
.task {
await viewModel.loadMoreCommitsIfNeeded(currentItem: commit)
diff --git a/Hutch/Views/Repositories/CommitRowView.swift b/Hutch/Views/Repositories/CommitRowView.swift
index 362ab4d..6f40b57 100644
--- a/Hutch/Views/Repositories/CommitRowView.swift
+++ b/Hutch/Views/Repositories/CommitRowView.swift
@@ -1,8 +1,11 @@
import SwiftUI
-import UIKit
struct CommitRowView: View {
+ @Environment(AppState.self) private var appState
+ @Environment(\.openURL) private var openURL
+
let commit: CommitSummary
+ let repository: RepositorySummary
var body: some View {
VStack(alignment: .leading, spacing: 4) {
@@ -28,14 +31,22 @@ struct CommitRowView: View {
}
.padding(.vertical, 2)
.contextMenu {
+ if let url = SRHTWebURL.commit(repository: repository, commitId: commit.id) {
+ Button {
+ openURL(url)
+ } label: {
+ Label("Open in Browser", systemImage: "safari")
+ }
+ }
+
Button {
- UIPasteboard.general.string = commit.id
+ appState.copyToPasteboard(commit.id, label: "commit SHA")
} label: {
Label("Copy Full SHA", systemImage: "doc.on.doc")
}
Button {
- UIPasteboard.general.string = commit.shortId
+ appState.copyToPasteboard(commit.shortId, label: "short commit SHA")
} label: {
Label("Copy Short SHA", systemImage: "doc.on.doc.fill")
}
diff --git a/Hutch/Views/Repositories/ReadmeView.swift b/Hutch/Views/Repositories/ReadmeView.swift
index 5742811..f5c0c9f 100644
--- a/Hutch/Views/Repositories/ReadmeView.swift
+++ b/Hutch/Views/Repositories/ReadmeView.swift
@@ -2,6 +2,7 @@ import SwiftUI
import WebKit
struct ReadmeView: View {
+ @Environment(AppState.self) private var appState
let viewModel: RepositoryDetailViewModel
@Environment(\.colorScheme) private var colorScheme
@@ -15,6 +16,9 @@ struct ReadmeView: View {
repositoryDetailsSection
latestChangeSection
readmeSection
+ if appState.isDebugModeEnabled {
+ debugSection
+ }
}
.padding()
}
@@ -150,6 +154,25 @@ struct ReadmeView: View {
.plainText(text)
}
}
+
+ private var debugSection: some View {
+ DebugTextBlock(
+ title: "Debug",
+ content: """
+ repositoryId: \(viewModel.repository.id)
+ rid: \(viewModel.repository.rid)
+ service: \(viewModel.repository.service.rawValue)
+ defaultBranch: \(viewModel.repository.defaultBranchName ?? "none")
+ webURL: \(SRHTWebURL.repository(viewModel.repository)?.absoluteString ?? "unavailable")
+ httpsClone: \(SRHTWebURL.httpsCloneURL(viewModel.repository) ?? "unavailable")
+ sshClone: \(SRHTWebURL.sshCloneURL(viewModel.repository))
+ readmePath: \(viewModel.readmePath ?? "none")
+ commitsLoaded: \(viewModel.commits.count)
+ branchesLoaded: \(viewModel.branches.count)
+ tagsLoaded: \(viewModel.tags.count)
+ """
+ )
+ }
}
enum RenderedMarkupContent: Sendable {
diff --git a/Hutch/Views/Repositories/RepositoryDetailView.swift b/Hutch/Views/Repositories/RepositoryDetailView.swift
index 0031e47..2715134 100644
--- a/Hutch/Views/Repositories/RepositoryDetailView.swift
+++ b/Hutch/Views/Repositories/RepositoryDetailView.swift
@@ -1,6 +1,8 @@
import SwiftUI
struct RepositoryDetailView: View {
+ @Environment(\.openURL) private var openURL
+
let onRepositoryUpdated: ((RepositorySummary) -> Void)?
var onDeleted: (() -> Void)?
@@ -42,23 +44,11 @@ struct RepositoryDetailView: View {
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
+ repositoryActionsMenu
+
SRHTShareButton(url: SRHTWebURL.repository(currentRepository), target: .repository) {
Image(systemName: "square.and.arrow.up")
}
-
- if canManageRepository {
- Button {
- showACLs = true
- } label: {
- Image(systemName: "person.2")
- }
-
- Button {
- showSettings = true
- } label: {
- Image(systemName: "gear")
- }
- }
}
}
.sheet(isPresented: $showSettings) {
@@ -137,4 +127,61 @@ struct RepositoryDetailView: View {
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
return trimmed.hasPrefix("~") ? String(trimmed.dropFirst()) : trimmed
}
+
+ private var repositoryActionsMenu: some View {
+ Menu {
+ if let repositoryURL = SRHTWebURL.repository(currentRepository) {
+ Button {
+ openURL(repositoryURL)
+ } label: {
+ Label("Open in Browser", systemImage: "safari")
+ }
+
+ Button {
+ appState.copyToPasteboard(repositoryURL.absoluteString, label: "repository URL")
+ } label: {
+ Label("Copy URL", systemImage: "doc.on.doc")
+ }
+ }
+
+ if let httpsURL = SRHTWebURL.httpsCloneURL(currentRepository) {
+ Button {
+ appState.copyToPasteboard(httpsURL, label: "HTTPS clone URL")
+ } label: {
+ Label("Copy HTTPS URL", systemImage: "doc.on.doc")
+ }
+ }
+
+ Button {
+ appState.copyToPasteboard(SRHTWebURL.sshCloneURL(currentRepository), label: "SSH clone URL")
+ } label: {
+ Label("Copy SSH URL", systemImage: "terminal")
+ }
+
+ Button {
+ appState.copyToPasteboard(currentRepository.rid, label: "repository RID")
+ } label: {
+ Label("Copy RID", systemImage: "number")
+ }
+
+ if canManageRepository {
+ Divider()
+
+ Button {
+ showACLs = true
+ } label: {
+ Label("Manage ACLs", systemImage: "person.2")
+ }
+
+ Button {
+ showSettings = true
+ } label: {
+ Label("Repository Settings", systemImage: "gear")
+ }
+ }
+ } label: {
+ Image(systemName: "ellipsis.circle")
+ }
+ .accessibilityLabel("Repository actions")
+ }
}
diff --git a/Hutch/Views/Repositories/RepositoryRowView.swift b/Hutch/Views/Repositories/RepositoryRowView.swift
index 814ea76..0da6cbc 100644
--- a/Hutch/Views/Repositories/RepositoryRowView.swift
+++ b/Hutch/Views/Repositories/RepositoryRowView.swift
@@ -1,7 +1,9 @@
import SwiftUI
-import UIKit
struct RepositoryRowView: View {
+ @Environment(AppState.self) private var appState
+ @Environment(\.openURL) private var openURL
+
let repository: RepositorySummary
let buildStatus: RepositoryBuildStatus
@@ -56,34 +58,45 @@ struct RepositoryRowView: View {
}
.padding(.vertical, 2)
.contextMenu {
+ if let url = SRHTWebURL.repository(repository) {
+ Button {
+ openURL(url)
+ } label: {
+ Label("Open in Browser", systemImage: "safari")
+ }
+ }
+
+ Button {
+ if let url = SRHTWebURL.repository(repository)?.absoluteString {
+ appState.copyToPasteboard(url, label: "repository URL")
+ }
+ } label: {
+ Label("Copy URL", systemImage: "doc.on.doc")
+ }
+
Button {
- UIPasteboard.general.string = httpsCloneURL(for: repository)
+ if let url = SRHTWebURL.httpsCloneURL(repository) {
+ appState.copyToPasteboard(url, label: "HTTPS clone URL")
+ }
} label: {
Label("Copy HTTPS URL", systemImage: "doc.on.doc")
}
Button {
- UIPasteboard.general.string = sshCloneURL(for: repository)
+ appState.copyToPasteboard(SRHTWebURL.sshCloneURL(repository), label: "SSH clone URL")
} label: {
Label("Copy SSH URL", systemImage: "terminal")
}
+
+ Button {
+ appState.copyToPasteboard(repository.rid, label: "repository RID")
+ } label: {
+ Label("Copy RID", systemImage: "number")
+ }
}
}
}
-private func httpsCloneURL(for repository: RepositorySummary) -> String {
- let host = "\(repository.service.rawValue).sr.ht"
- let owner = repository.owner.canonicalName
- return "https://\(host)/\(owner)/\(repository.name)"
-}
-
-private func sshCloneURL(for repository: RepositorySummary) -> String {
- let host = "\(repository.service.rawValue).sr.ht"
- let user = repository.service == .hg ? "hg" : "git"
- let owner = repository.owner.canonicalName
- return "\(user)@\(host):\(owner)/\(repository.name)"
-}
-
private struct RepositoryBuildStatusIndicator: View {
let status: RepositoryBuildStatus