diff options
| author | Christian Cleberg <[email protected]> | 2026-03-17 23:19:22 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-03-17 23:19:22 -0500 |
| commit | 8f2057c53e9009c2529c9c4849c914666c0e4b40 (patch) | |
| tree | 77b5a93625fe9ea98baf4ab0d137055524705dad /Hutch/Extensions | |
| parent | d27726d8755a5631fbd2105f735811a95379c4ab (diff) | |
| download | hutch-8f2057c53e9009c2529c9c4849c914666c0e4b40.tar.gz hutch-8f2057c53e9009c2529c9c4849c914666c0e4b40.tar.bz2 hutch-8f2057c53e9009c2529c9c4849c914666c0e4b40.zip | |
create privacy policy
Diffstat (limited to 'Hutch/Extensions')
| -rw-r--r-- | Hutch/Extensions/SRHTShareUI.swift | 57 | ||||
| -rw-r--r-- | Hutch/Extensions/SRHTWebURL.swift | 84 |
2 files changed, 141 insertions, 0 deletions
diff --git a/Hutch/Extensions/SRHTShareUI.swift b/Hutch/Extensions/SRHTShareUI.swift new file mode 100644 index 0000000..9d949c9 --- /dev/null +++ b/Hutch/Extensions/SRHTShareUI.swift @@ -0,0 +1,57 @@ +import SwiftUI +import UIKit + +enum SRHTShareTarget: String { + case repository = "repository" + case commit = "commit" + case file = "file" + case build = "build" + case tracker = "tracker" + case ticket = "ticket" + case profile = "profile" + + var fallbackMessage: String { + "This \(rawValue) does not have a valid web URL to share." + } +} + +struct SRHTShareButton<Label: View>: View { + let url: URL? + let target: SRHTShareTarget + @ViewBuilder let label: () -> Label + + @State private var isShowingShareSheet = false + @State private var isShowingFallbackAlert = false + + var body: some View { + Button { + if url != nil { + isShowingShareSheet = true + } else { + isShowingFallbackAlert = true + } + } label: { + label() + } + .sheet(isPresented: $isShowingShareSheet) { + if let url { + ShareSheet(activityItems: [url]) + } + } + .alert("Share Unavailable", isPresented: $isShowingFallbackAlert) { + Button("OK", role: .cancel) {} + } message: { + Text(target.fallbackMessage) + } + } +} + +private struct ShareSheet: UIViewControllerRepresentable { + let activityItems: [Any] + + func makeUIViewController(context: Context) -> UIActivityViewController { + UIActivityViewController(activityItems: activityItems, applicationActivities: nil) + } + + func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {} +} diff --git a/Hutch/Extensions/SRHTWebURL.swift b/Hutch/Extensions/SRHTWebURL.swift new file mode 100644 index 0000000..53556de --- /dev/null +++ b/Hutch/Extensions/SRHTWebURL.swift @@ -0,0 +1,84 @@ +import Foundation + +enum SRHTWebURL { + static func repository(_ repository: RepositorySummary) -> URL? { + userScopedURL( + host: "\(repository.service.rawValue).sr.ht", + ownerCanonicalName: repository.owner.canonicalName, + pathComponents: [repository.name] + ) + } + + static func build(jobId: Int, ownerCanonicalName: String) -> URL? { + userScopedURL( + host: "builds.sr.ht", + ownerCanonicalName: ownerCanonicalName, + pathComponents: ["job", String(jobId)] + ) + } + + static func tracker(ownerUsername: String, trackerName: String) -> URL? { + userScopedURL( + host: "todo.sr.ht", + ownerUsername: ownerUsername, + pathComponents: [trackerName] + ) + } + + static func ticket(ownerUsername: String, trackerName: String, ticketId: Int) -> URL? { + userScopedURL( + host: "todo.sr.ht", + ownerUsername: ownerUsername, + pathComponents: [trackerName, String(ticketId)] + ) + } + + static func profile(canonicalName: String) -> URL? { + userScopedURL( + host: "meta.sr.ht", + ownerCanonicalName: canonicalName, + pathComponents: [] + ) + } + + private static func userScopedURL( + host: String, + ownerCanonicalName: String, + pathComponents: [String] + ) -> URL? { + userScopedURL( + host: host, + ownerUsername: username(from: ownerCanonicalName), + pathComponents: pathComponents + ) + } + + private static func userScopedURL( + host: String, + ownerUsername: String, + pathComponents: [String] + ) -> URL? { + var components = URLComponents() + components.scheme = "https" + components.host = host + + let encodedComponents = (["~\(ownerUsername)"] + pathComponents).map { pathComponent in + pathComponent.addingPercentEncoding(withAllowedCharacters: pathComponentCharacterSet) ?? pathComponent + } + components.percentEncodedPath = "/" + encodedComponents.joined(separator: "/") + return components.url + } + + private static func username(from canonicalName: String) -> String { + if canonicalName.hasPrefix("~") { + return String(canonicalName.dropFirst()) + } + return canonicalName + } + + private static let pathComponentCharacterSet: CharacterSet = { + var characterSet = CharacterSet.urlPathAllowed + characterSet.remove(charactersIn: "/") + return characterSet + }() +} |
