summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-13 20:07:53 -0500
committerChristian Cleberg <[email protected]>2026-04-13 20:07:53 -0500
commit312e535f400f31714b3750de5222a1f6a8e5bcda (patch)
treedfa0d9dfcfd08187befa79cf5d8afc4da9fef860
parentfe1ccc69661603d419a642a450e4ac9e1258adb0 (diff)
downloadhutch-312e535f400f31714b3750de5222a1f6a8e5bcda.tar.gz
hutch-312e535f400f31714b3750de5222a1f6a8e5bcda.tar.bz2
hutch-312e535f400f31714b3750de5222a1f6a8e5bcda.zip
fix: sonarqube code smell fixesv3.1.4
-rw-r--r--Hutch.xcodeproj/project.pbxproj16
-rw-r--r--Hutch/Models/Git.swift4
-rw-r--r--Hutch/Models/Project.swift4
-rw-r--r--Hutch/Models/RepositorySummary.swift63
-rw-r--r--Hutch/Networking/ProjectService.swift10
-rw-r--r--Hutch/Networking/SRHTClient.swift48
-rw-r--r--Hutch/Views/Builds/BuildDetailView.swift6
-rw-r--r--Hutch/Views/Builds/BuildListView.swift6
-rw-r--r--Hutch/Views/Lookup/LookupView.swift20
-rw-r--r--Hutch/Views/Lookup/UserProfileViewModel.swift20
-rw-r--r--Hutch/Views/Pastes/PasteDetailView.swift10
-rw-r--r--Hutch/Views/Pastes/PasteListView.swift16
-rw-r--r--Hutch/Views/Pastes/PasteListViewModel.swift8
-rw-r--r--Hutch/Views/Repositories/FileTreeViewModel.swift5
-rw-r--r--Hutch/Views/Repositories/HgRepositorySettingsView.swift4
-rw-r--r--Hutch/Views/Repositories/ReadmeView.swift2
-rw-r--r--Hutch/Views/Repositories/RepositoryListView.swift6
-rw-r--r--Hutch/Views/Repositories/RepositoryListViewModel.swift95
-rw-r--r--Hutch/Views/Repositories/RepositoryRowView.swift8
-rw-r--r--Hutch/Views/Repositories/RepositorySettingsView.swift8
-rw-r--r--Hutch/Views/Repositories/RepositorySettingsViewModel.swift20
-rw-r--r--Hutch/Views/Repositories/RepositorySummarySupport.swift4
-rw-r--r--Hutch/Views/Settings/SettingsViewModel.swift10
-rw-r--r--Hutch/Views/Tickets/TicketListView.swift2
-rw-r--r--Hutch/Views/Tickets/TrackerListView.swift2
-rw-r--r--Hutch/Views/Tickets/TrackerManagementView.swift4
-rw-r--r--HutchTests/AppStateTests.swift22
-rw-r--r--HutchTests/ProjectTests.swift12
-rw-r--r--HutchTests/RepositoryACLViewModelTests.swift20
-rw-r--r--HutchTests/RepositoryListViewModelTests.swift20
-rw-r--r--HutchTests/RepositorySettingsViewModelTests.swift20
-rw-r--r--HutchTests/SRHTWebURLTests.swift22
-rw-r--r--HutchTests/TrackerListViewModelTests.swift2
33 files changed, 257 insertions, 262 deletions
diff --git a/Hutch.xcodeproj/project.pbxproj b/Hutch.xcodeproj/project.pbxproj
index bbdb9e3..3162b32 100644
--- a/Hutch.xcodeproj/project.pbxproj
+++ b/Hutch.xcodeproj/project.pbxproj
@@ -515,7 +515,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 71;
+ CURRENT_PROJECT_VERSION = 72;
DEVELOPMENT_TEAM = ZCNAX3VL9D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -532,7 +532,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 3.1.3;
+ MARKETING_VERSION = 3.1.4;
PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -552,7 +552,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 71;
+ CURRENT_PROJECT_VERSION = 72;
DEVELOPMENT_TEAM = ZCNAX3VL9D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -569,7 +569,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 3.1.3;
+ MARKETING_VERSION = 3.1.4;
PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -632,7 +632,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 71;
+ CURRENT_PROJECT_VERSION = 72;
DEVELOPMENT_TEAM = ZCNAX3VL9D;
GENERATE_INFOPLIST_FILE = NO;
INFOPLIST_FILE = HutchWidgetExtension/Info.plist;
@@ -642,7 +642,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 3.1.3;
+ MARKETING_VERSION = 3.1.4;
PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -661,7 +661,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 71;
+ CURRENT_PROJECT_VERSION = 72;
DEVELOPMENT_TEAM = ZCNAX3VL9D;
GENERATE_INFOPLIST_FILE = NO;
INFOPLIST_FILE = HutchWidgetExtension/Info.plist;
@@ -671,7 +671,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 3.1.3;
+ MARKETING_VERSION = 3.1.4;
PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
diff --git a/Hutch/Models/Git.swift b/Hutch/Models/Git.swift
index 3629ce4..26a5e2d 100644
--- a/Hutch/Models/Git.swift
+++ b/Hutch/Models/Git.swift
@@ -4,9 +4,9 @@ import Foundation
/// Repository visibility level.
enum Visibility: String, Codable, Sendable {
- case `public` = "PUBLIC"
+ case publicVisibility = "PUBLIC"
case unlisted = "UNLISTED"
- case `private` = "PRIVATE"
+ case privateVisibility = "PRIVATE"
}
/// Repository access mode.
diff --git a/Hutch/Models/Project.swift b/Hutch/Models/Project.swift
index bbca7d6..8f5aa68 100644
--- a/Hutch/Models/Project.swift
+++ b/Hutch/Models/Project.swift
@@ -230,11 +230,11 @@ extension String {
extension Visibility {
var displayName: String {
switch self {
- case .public:
+ case .publicVisibility:
"Public"
case .unlisted:
"Unlisted"
- case .private:
+ case .privateVisibility:
"Private"
}
}
diff --git a/Hutch/Models/RepositorySummary.swift b/Hutch/Models/RepositorySummary.swift
index 3821aa2..b41589b 100644
--- a/Hutch/Models/RepositorySummary.swift
+++ b/Hutch/Models/RepositorySummary.swift
@@ -20,26 +20,29 @@ struct RepositorySummary: Codable, Sendable, Identifiable, Hashable {
case head = "HEAD"
}
- init(
- id: Int,
- rid: String,
- service: SRHTService,
- name: String,
- description: String?,
- visibility: Visibility,
- updated: Date,
- owner: Entity,
- head: Reference?
- ) {
- self.id = id
- self.rid = rid
- self.service = service
- self.name = name
- self.description = description
- self.visibility = visibility
- self.updated = updated
- self.owner = owner
- self.head = head
+ /// Grouped initializer fields (single parameter keeps APIs explicit without exceeding parameter-count limits).
+ struct Fields: Sendable, Hashable {
+ let id: Int
+ let rid: String
+ let service: SRHTService
+ let name: String
+ let description: String?
+ let visibility: Visibility
+ let updated: Date
+ let owner: Entity
+ let head: Reference?
+ }
+
+ init(fields: Fields) {
+ id = fields.id
+ rid = fields.rid
+ service = fields.service
+ name = fields.name
+ description = fields.description
+ visibility = fields.visibility
+ updated = fields.updated
+ owner = fields.owner
+ head = fields.head
}
init(from decoder: any Decoder) throws {
@@ -69,15 +72,17 @@ extension RepositorySummary {
head: Reference? = nil
) -> RepositorySummary {
RepositorySummary(
- id: id,
- rid: rid,
- service: service,
- name: name ?? self.name,
- description: description ?? self.description,
- visibility: visibility ?? self.visibility,
- updated: updated ?? self.updated,
- owner: owner,
- head: head ?? self.head
+ fields: .init(
+ id: id,
+ rid: rid,
+ service: service,
+ name: name ?? self.name,
+ description: description ?? self.description,
+ visibility: visibility ?? self.visibility,
+ updated: updated ?? self.updated,
+ owner: owner,
+ head: head ?? self.head
+ )
)
}
diff --git a/Hutch/Networking/ProjectService.swift b/Hutch/Networking/ProjectService.swift
index bd8ccdc..5e0e061 100644
--- a/Hutch/Networking/ProjectService.swift
+++ b/Hutch/Networking/ProjectService.swift
@@ -49,7 +49,7 @@ private struct ProjectSummaryPayload: Decodable, Sendable {
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
description = try container.decodeIfPresent(String.self, forKey: .description)
website = try container.decodeIfPresent(String.self, forKey: .website)
- visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public
+ visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? []
updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast
}
@@ -90,7 +90,7 @@ private struct ProjectDetailPayload: Decodable, Sendable {
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
description = try container.decodeIfPresent(String.self, forKey: .description)
website = try container.decodeIfPresent(String.self, forKey: .website)
- visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public
+ visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? []
updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast
mailingLists = try container.decodeIfPresent(ProjectMailingListPage.self, forKey: .mailingLists) ?? .empty
@@ -126,7 +126,7 @@ private struct ProjectMailingListPayload: Decodable, Sendable {
rid = try container.decode(String.self, forKey: .rid)
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
description = try container.decodeIfPresent(String.self, forKey: .description)
- visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public
+ visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown")
}
}
@@ -160,7 +160,7 @@ private struct ProjectSourcePayload: Decodable, Sendable {
rid = try container.decode(String.self, forKey: .rid)
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
description = try container.decodeIfPresent(String.self, forKey: .description)
- visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public
+ visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown")
repoType = try container.decodeIfPresent(Project.SourceRepo.RepoType.self, forKey: .repoType) ?? .git
}
@@ -193,7 +193,7 @@ private struct ProjectTrackerPayload: Decodable, Sendable {
rid = try container.decode(String.self, forKey: .rid)
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
description = try container.decodeIfPresent(String.self, forKey: .description)
- visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public
+ visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown")
}
}
diff --git a/Hutch/Networking/SRHTClient.swift b/Hutch/Networking/SRHTClient.swift
index 7e1f619..fa7b26b 100644
--- a/Hutch/Networking/SRHTClient.swift
+++ b/Hutch/Networking/SRHTClient.swift
@@ -57,7 +57,7 @@ final class SRHTClient: Sendable {
service: SRHTService,
query: String,
variables: [String: any Sendable]? = nil,
- responseType: T.Type
+ responseType _: T.Type
) async throws -> T {
guard let token = _token.withLock({ $0 }), !token.isEmpty else {
throw SRHTError.unauthorized
@@ -164,20 +164,14 @@ final class SRHTClient: Sendable {
/// - service: The target SourceHut service.
/// - query: The GraphQL mutation string.
/// - variables: Variables dict; the file variable should be set to `nil`.
- /// - fileVariablePath: The dot-separated path to the file variable (e.g. "input.avatar").
- /// - fileData: The raw file data (e.g. JPEG).
- /// - fileName: The file name to send (e.g. "avatar.jpg").
- /// - mimeType: The MIME type (e.g. "image/jpeg").
+ /// - file: Multipart file payload (`variablePath` is the dot-separated GraphQL variable, e.g. `input.avatar`).
/// - responseType: The expected `Decodable` type nested under `data`.
func executeMultipart<T: Decodable>(
service: SRHTService,
query: String,
variables: [String: any Sendable],
- fileVariablePath: String,
- fileData: Data,
- fileName: String,
- mimeType: String,
- responseType: T.Type
+ file: MultipartUploadFile,
+ responseType _: T.Type
) async throws -> T {
guard let token = _token.withLock({ $0 }), !token.isEmpty else {
throw SRHTError.unauthorized
@@ -197,8 +191,8 @@ final class SRHTClient: Sendable {
)
let operationsData = try encoder.encode(operationsBody)
- // Build the map JSON: { "0": ["variables.<fileVariablePath>"] }
- let mapDict = ["0": ["variables.\(fileVariablePath)"]]
+ // Build the map JSON: { "0": ["variables.<variablePath>"] }
+ let mapDict = ["0": ["variables.\(file.variablePath)"]]
let mapData = try encoder.encode(mapDict)
// Assemble multipart body
@@ -220,9 +214,9 @@ final class SRHTClient: Sendable {
// Part: file
body.append("--\(boundary)\r\n")
- body.append("Content-Disposition: form-data; name=\"0\"; filename=\"\(fileName)\"\r\n")
- body.append("Content-Type: \(mimeType)\r\n\r\n")
- body.append(fileData)
+ body.append("Content-Disposition: form-data; name=\"0\"; filename=\"\(file.fileName)\"\r\n")
+ body.append("Content-Type: \(file.mimeType)\r\n\r\n")
+ body.append(file.fileData)
body.append("\r\n")
// Closing boundary
@@ -311,7 +305,7 @@ final class SRHTClient: Sendable {
query: String,
variables: [String: any Sendable],
files: [MultipartUploadFile],
- responseType: T.Type
+ responseType _: T.Type
) async throws -> T {
guard let token = _token.withLock({ $0 }), !token.isEmpty else {
throw SRHTError.unauthorized
@@ -408,15 +402,14 @@ final class SRHTClient: Sendable {
service: SRHTService,
query: String,
variables: [String: any Sendable]? = nil,
- responseType: T.Type,
+ responseType _: T.Type,
cacheKey: String
) async throws -> T {
// Try cache first
- if let cachedData = responseCache.get(forKey: cacheKey) {
- if let cached = try? decoder.decode(GraphQLResponse<T>.self, from: cachedData),
- let data = cached.data {
- return data
- }
+ if let cachedData = responseCache.get(forKey: cacheKey),
+ let cached = try? decoder.decode(GraphQLResponse<T>.self, from: cachedData),
+ let data = cached.data {
+ return data
}
// No cache hit — fetch normally
@@ -434,7 +427,7 @@ final class SRHTClient: Sendable {
service: SRHTService,
query: String,
variables: [String: any Sendable]? = nil,
- responseType: T.Type,
+ responseType _: T.Type,
cacheKey: String
) async throws -> T {
guard let token = _token.withLock({ $0 }), !token.isEmpty else {
@@ -580,8 +573,7 @@ final class SRHTClient: Sendable {
service: SRHTService,
query: String,
variables: [String: any Sendable]? = nil,
- resultKeyPath: String,
- type: T.Type
+ resultKeyPath: String
) -> SRHTPaginatedSequence<T> {
SRHTPaginatedSequence(
client: self,
@@ -598,16 +590,14 @@ final class SRHTClient: Sendable {
service: SRHTService,
query: String,
variables: [String: any Sendable]? = nil,
- resultKeyPath: String,
- type: T.Type
+ resultKeyPath: String
) async throws -> [T] {
var all: [T] = []
for try await element in paginated(
service: service,
query: query,
variables: variables,
- resultKeyPath: resultKeyPath,
- type: type
+ resultKeyPath: resultKeyPath
) {
all.append(element)
}
diff --git a/Hutch/Views/Builds/BuildDetailView.swift b/Hutch/Views/Builds/BuildDetailView.swift
index 46fb42d..334dff7 100644
--- a/Hutch/Views/Builds/BuildDetailView.swift
+++ b/Hutch/Views/Builds/BuildDetailView.swift
@@ -468,7 +468,7 @@ private struct EditResubmitBuildSheet: View {
_manifest = State(initialValue: job.manifest ?? "")
_tagsText = State(initialValue: job.tags.joined(separator: ", "))
_note = State(initialValue: job.note ?? "")
- _visibility = State(initialValue: job.visibility ?? .public)
+ _visibility = State(initialValue: job.visibility ?? .publicVisibility)
}
var body: some View {
@@ -491,9 +491,9 @@ private struct EditResubmitBuildSheet: View {
.autocorrectionDisabled()
.themedRow()
Picker("Visibility", selection: $visibility) {
- Text("Public").tag(Visibility.public)
+ Text("Public").tag(Visibility.publicVisibility)
Text("Unlisted").tag(Visibility.unlisted)
- Text("Private").tag(Visibility.private)
+ Text("Private").tag(Visibility.privateVisibility)
}
.themedRow()
Toggle("Start build now", isOn: $execute)
diff --git a/Hutch/Views/Builds/BuildListView.swift b/Hutch/Views/Builds/BuildListView.swift
index fc91ea1..8de2220 100644
--- a/Hutch/Views/Builds/BuildListView.swift
+++ b/Hutch/Views/Builds/BuildListView.swift
@@ -265,7 +265,7 @@ private struct SubmitBuildSheet: View {
@State private var note = ""
@State private var secrets = false
@State private var execute = true
- @State private var visibility: Visibility = .public
+ @State private var visibility: Visibility = .publicVisibility
init(viewModel: BuildListViewModel, onSubmitted: @escaping (Int) -> Void) {
self.viewModel = viewModel
@@ -293,9 +293,9 @@ private struct SubmitBuildSheet: View {
.autocorrectionDisabled()
.themedRow()
Picker("Visibility", selection: $visibility) {
- Text("Public").tag(Visibility.public)
+ Text("Public").tag(Visibility.publicVisibility)
Text("Unlisted").tag(Visibility.unlisted)
- Text("Private").tag(Visibility.private)
+ Text("Private").tag(Visibility.privateVisibility)
}
.themedRow()
Toggle("Start build now", isOn: $execute)
diff --git a/Hutch/Views/Lookup/LookupView.swift b/Hutch/Views/Lookup/LookupView.swift
index f45082d..64ca39d 100644
--- a/Hutch/Views/Lookup/LookupView.swift
+++ b/Hutch/Views/Lookup/LookupView.swift
@@ -233,15 +233,17 @@ final class LookupViewModel {
let repository = try await appState.resolveRepository(owner: owner, name: name, service: service)
let resolvedRepository = RepositorySummary(
- id: repository.id,
- rid: repository.rid,
- service: service,
- name: repository.name,
- description: repository.description,
- visibility: repository.visibility,
- updated: repository.updated,
- owner: repository.owner,
- head: repository.head
+ fields: .init(
+ id: repository.id,
+ rid: repository.rid,
+ service: service,
+ name: repository.name,
+ description: repository.description,
+ visibility: repository.visibility,
+ updated: repository.updated,
+ owner: repository.owner,
+ head: repository.head
+ )
)
return .repository(resolvedRepository)
diff --git a/Hutch/Views/Lookup/UserProfileViewModel.swift b/Hutch/Views/Lookup/UserProfileViewModel.swift
index b88d36a..0e503ce 100644
--- a/Hutch/Views/Lookup/UserProfileViewModel.swift
+++ b/Hutch/Views/Lookup/UserProfileViewModel.swift
@@ -179,15 +179,17 @@ final class UserProfileViewModel {
func repositorySummary(service: SRHTService) -> RepositorySummary {
RepositorySummary(
- id: id,
- rid: rid,
- service: service,
- name: name,
- description: description,
- visibility: visibility,
- updated: updated,
- owner: owner,
- head: head
+ fields: .init(
+ id: id,
+ rid: rid,
+ service: service,
+ name: name,
+ description: description,
+ visibility: visibility,
+ updated: updated,
+ owner: owner,
+ head: head
+ )
)
}
}
diff --git a/Hutch/Views/Pastes/PasteDetailView.swift b/Hutch/Views/Pastes/PasteDetailView.swift
index c6fe11a..49d4fa6 100644
--- a/Hutch/Views/Pastes/PasteDetailView.swift
+++ b/Hutch/Views/Pastes/PasteDetailView.swift
@@ -442,27 +442,27 @@ private struct PasteVisibilitySheet: View {
}
private var visibilityOptions: [Visibility] {
- [.public, .unlisted, .private]
+ [.publicVisibility, .unlisted, .privateVisibility]
}
private func title(for visibility: Visibility) -> String {
switch visibility {
- case .public:
+ case .publicVisibility:
"Public"
case .unlisted:
"Unlisted"
- case .private:
+ case .privateVisibility:
"Private"
}
}
private func description(for visibility: Visibility) -> String {
switch visibility {
- case .public:
+ case .publicVisibility:
"Visible to everyone and listed on your profile."
case .unlisted:
"Visible to anyone with the URL, but not listed on your profile."
- case .private:
+ case .privateVisibility:
"Visible only to explicitly allowed viewers."
}
}
diff --git a/Hutch/Views/Pastes/PasteListView.swift b/Hutch/Views/Pastes/PasteListView.swift
index dfd472b..17bb8ac 100644
--- a/Hutch/Views/Pastes/PasteListView.swift
+++ b/Hutch/Views/Pastes/PasteListView.swift
@@ -179,33 +179,33 @@ struct PasteListView: View {
private func nextVisibilityLabel(for visibility: Visibility) -> String {
switch visibility {
- case .public:
+ case .publicVisibility:
return "Make Unlisted"
case .unlisted:
return "Make Private"
- case .private:
+ case .privateVisibility:
return "Make Public"
}
}
private func nextVisibilityIcon(for visibility: Visibility) -> String {
switch visibility {
- case .public:
+ case .publicVisibility:
return "eye.slash"
case .unlisted:
return "lock"
- case .private:
+ case .privateVisibility:
return "globe"
}
}
private func nextVisibilityColor(for visibility: Visibility) -> Color {
switch visibility {
- case .public:
+ case .publicVisibility:
return .orange
case .unlisted:
return .red
- case .private:
+ case .privateVisibility:
return .green
}
}
@@ -316,9 +316,9 @@ private struct CreatePasteSheet: View {
Section("Visibility") {
Picker("Visibility", selection: $visibility) {
- Text("Public").tag(Visibility.public)
+ Text("Public").tag(Visibility.publicVisibility)
Text("Unlisted").tag(Visibility.unlisted)
- Text("Private").tag(Visibility.private)
+ Text("Private").tag(Visibility.privateVisibility)
}
.themedRow()
}
diff --git a/Hutch/Views/Pastes/PasteListViewModel.swift b/Hutch/Views/Pastes/PasteListViewModel.swift
index 75f2f4b..640e31b 100644
--- a/Hutch/Views/Pastes/PasteListViewModel.swift
+++ b/Hutch/Views/Pastes/PasteListViewModel.swift
@@ -131,12 +131,12 @@ final class PasteListViewModel {
func cycleVisibility(for paste: Paste) async {
let next: Visibility
switch paste.visibility {
- case .public:
+ case .publicVisibility:
next = .unlisted
case .unlisted:
- next = .private
- case .private:
- next = .public
+ next = .privateVisibility
+ case .privateVisibility:
+ next = .publicVisibility
}
let original = pastes
diff --git a/Hutch/Views/Repositories/FileTreeViewModel.swift b/Hutch/Views/Repositories/FileTreeViewModel.swift
index c6fecbe..98211bf 100644
--- a/Hutch/Views/Repositories/FileTreeViewModel.swift
+++ b/Hutch/Views/Repositories/FileTreeViewModel.swift
@@ -327,14 +327,11 @@ final class FileTreeViewModel {
}
case .binaryBlob(let blob):
- if blob.content != nil {
+ if blob.content != nil || blob.id == nil {
viewingEntry = entry
viewingObject = object
} else if let blobId = blob.id {
await loadBlob(entry: entry, blobId: blobId)
- } else {
- viewingEntry = entry
- viewingObject = object
}
case .unknown:
diff --git a/Hutch/Views/Repositories/HgRepositorySettingsView.swift b/Hutch/Views/Repositories/HgRepositorySettingsView.swift
index e3c97e0..7b57505 100644
--- a/Hutch/Views/Repositories/HgRepositorySettingsView.swift
+++ b/Hutch/Views/Repositories/HgRepositorySettingsView.swift
@@ -121,9 +121,9 @@ struct HgRepositorySettingsView: View {
.themedRow()
Picker("Visibility", selection: Bindable(viewModel).editedVisibility) {
- Text("Public").tag(Visibility.public)
+ Text("Public").tag(Visibility.publicVisibility)
Text("Unlisted").tag(Visibility.unlisted)
- Text("Private").tag(Visibility.private)
+ Text("Private").tag(Visibility.privateVisibility)
}
.themedRow()
diff --git a/Hutch/Views/Repositories/ReadmeView.swift b/Hutch/Views/Repositories/ReadmeView.swift
index 21d7a74..1a72b70 100644
--- a/Hutch/Views/Repositories/ReadmeView.swift
+++ b/Hutch/Views/Repositories/ReadmeView.swift
@@ -1828,7 +1828,7 @@ private final class HTMLWebViewCoordinator: NSObject, WKNavigationDelegate, @unc
}
func webView(
- _ webView: WKWebView,
+ _: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void
) {
diff --git a/Hutch/Views/Repositories/RepositoryListView.swift b/Hutch/Views/Repositories/RepositoryListView.swift
index 08ebb5c..04a7084 100644
--- a/Hutch/Views/Repositories/RepositoryListView.swift
+++ b/Hutch/Views/Repositories/RepositoryListView.swift
@@ -214,7 +214,7 @@ private struct CreateRepositorySheet: View {
@State private var name = ""
@State private var description = ""
@State private var cloneURL = ""
- @State private var visibility: Visibility = .public
+ @State private var visibility: Visibility = .publicVisibility
@State private var service: RepositoryCreationService = .git
var body: some View {
@@ -235,9 +235,9 @@ private struct CreateRepositorySheet: View {
.lineLimit(2...4)
.themedRow()
Picker("Visibility", selection: $visibility) {
- Text("Public").tag(Visibility.public)
+ Text("Public").tag(Visibility.publicVisibility)
Text("Unlisted").tag(Visibility.unlisted)
- Text("Private").tag(Visibility.private)
+ Text("Private").tag(Visibility.privateVisibility)
}
.themedRow()
}
diff --git a/Hutch/Views/Repositories/RepositoryListViewModel.swift b/Hutch/Views/Repositories/RepositoryListViewModel.swift
index 1e830bb..61053a0 100644
--- a/Hutch/Views/Repositories/RepositoryListViewModel.swift
+++ b/Hutch/Views/Repositories/RepositoryListViewModel.swift
@@ -397,15 +397,17 @@ final class RepositoryListViewModel {
func repositorySummary(service: SRHTService) -> RepositorySummary {
RepositorySummary(
- id: id,
- rid: rid,
- service: service,
- name: name,
- description: description,
- visibility: visibility,
- updated: updated,
- owner: owner,
- head: head
+ fields: .init(
+ id: id,
+ rid: rid,
+ service: service,
+ name: name,
+ description: description,
+ visibility: visibility,
+ updated: updated,
+ owner: owner,
+ head: head
+ )
)
}
}
@@ -422,15 +424,17 @@ final class RepositoryListViewModel {
func repositorySummary(service: SRHTService) -> RepositorySummary {
RepositorySummary(
- id: id,
- rid: rid,
- service: service,
- name: name,
- description: description,
- visibility: visibility,
- updated: updated,
- owner: owner,
- head: tip.map { Reference(name: $0.branch, target: nil) }
+ fields: .init(
+ id: id,
+ rid: rid,
+ service: service,
+ name: name,
+ description: description,
+ visibility: visibility,
+ updated: updated,
+ owner: owner,
+ head: tip.map { Reference(name: $0.branch, target: nil) }
+ )
)
}
}
@@ -463,17 +467,7 @@ final class RepositoryListViewModel {
}
if useCache && cursor == nil {
- switch service {
- case .git:
- let result = try await client.executeAndCache(
- service: service,
- query: Self.gitQuery,
- variables: variables.isEmpty ? nil : variables,
- responseType: RepositoriesResponse.self,
- cacheKey: cacheKey(for: service)
- )
- return result.repositories ?? Self.emptyPage
- case .hg:
+ if service == .hg {
let hgVariables = cursor.map { ["cursor": $0 as any Sendable] }
let result = try await client.executeAndCache(
service: service,
@@ -497,27 +491,17 @@ final class RepositoryListViewModel {
} ?? [],
cursor: result.repositories?.cursor
)
- default:
- let result = try await client.executeAndCache(
- service: service,
- query: Self.gitQuery,
- variables: variables.isEmpty ? nil : variables,
- responseType: RepositoriesResponse.self,
- cacheKey: cacheKey(for: service)
- )
- return result.repositories ?? Self.emptyPage
}
+ let result = try await client.executeAndCache(
+ service: service,
+ query: Self.gitQuery,
+ variables: variables.isEmpty ? nil : variables,
+ responseType: RepositoriesResponse.self,
+ cacheKey: cacheKey(for: service)
+ )
+ return result.repositories ?? Self.emptyPage
} else {
- switch service {
- case .git:
- let result = try await client.execute(
- service: service,
- query: Self.gitQuery,
- variables: variables.isEmpty ? nil : variables,
- responseType: RepositoriesResponse.self
- )
- return result.repositories ?? Self.emptyPage
- case .hg:
+ if service == .hg {
let hgVariables = cursor.map { ["cursor": $0 as any Sendable] }
let result = try await client.execute(
service: service,
@@ -540,15 +524,14 @@ final class RepositoryListViewModel {
} ?? [],
cursor: result.repositories?.cursor
)
- default:
- let result = try await client.execute(
- service: service,
- query: Self.gitQuery,
- variables: variables.isEmpty ? nil : variables,
- responseType: RepositoriesResponse.self
- )
- return result.repositories ?? Self.emptyPage
}
+ let result = try await client.execute(
+ service: service,
+ query: Self.gitQuery,
+ variables: variables.isEmpty ? nil : variables,
+ responseType: RepositoriesResponse.self
+ )
+ return result.repositories ?? Self.emptyPage
}
}
diff --git a/Hutch/Views/Repositories/RepositoryRowView.swift b/Hutch/Views/Repositories/RepositoryRowView.swift
index a2d120b..86c8889 100644
--- a/Hutch/Views/Repositories/RepositoryRowView.swift
+++ b/Hutch/Views/Repositories/RepositoryRowView.swift
@@ -154,17 +154,17 @@ struct VisibilityBadge: View {
private var label: String {
switch visibility {
- case .public: "PUBLIC"
+ case .publicVisibility: "PUBLIC"
case .unlisted: "UNLISTED"
- case .private: "PRIVATE"
+ case .privateVisibility: "PRIVATE"
}
}
private var color: Color {
switch visibility {
- case .public: .green
+ case .publicVisibility: .green
case .unlisted: .orange
- case .private: .red
+ case .privateVisibility: .red
}
}
}
diff --git a/Hutch/Views/Repositories/RepositorySettingsView.swift b/Hutch/Views/Repositories/RepositorySettingsView.swift
index 44b50ae..9f172a8 100644
--- a/Hutch/Views/Repositories/RepositorySettingsView.swift
+++ b/Hutch/Views/Repositories/RepositorySettingsView.swift
@@ -227,9 +227,9 @@ struct RepositorySettingsView: View {
private func visibilitySection(_ viewModel: RepositorySettingsViewModel) -> some View {
Section {
Picker("Visibility", selection: Bindable(viewModel).editedVisibility) {
- Text("Public").tag(Visibility.public)
+ Text("Public").tag(Visibility.publicVisibility)
Text("Unlisted").tag(Visibility.unlisted)
- Text("Private").tag(Visibility.private)
+ Text("Private").tag(Visibility.privateVisibility)
}
.themedRow()
@@ -283,11 +283,11 @@ struct RepositorySettingsView: View {
private func visibilityConfirmationMessage(for viewModel: RepositorySettingsViewModel) -> String {
switch viewModel.editedVisibility {
- case .public:
+ case .publicVisibility:
"Anyone will be able to find and view this repository."
case .unlisted:
"People with the link can view this repository, but it won't appear in public listings."
- case .private:
+ case .privateVisibility:
"Only people with explicit access will be able to view this repository."
}
}
diff --git a/Hutch/Views/Repositories/RepositorySettingsViewModel.swift b/Hutch/Views/Repositories/RepositorySettingsViewModel.swift
index 8bd80a1..6233bec 100644
--- a/Hutch/Views/Repositories/RepositorySettingsViewModel.swift
+++ b/Hutch/Views/Repositories/RepositorySettingsViewModel.swift
@@ -20,15 +20,17 @@ private struct UpdatedRepositoryPayload: Decodable, Sendable {
func repositorySummary(using owner: Entity, service: SRHTService) -> RepositorySummary {
RepositorySummary(
- id: id,
- rid: rid,
- service: service,
- name: name,
- description: description,
- visibility: visibility,
- updated: updated,
- owner: owner,
- head: head
+ fields: .init(
+ id: id,
+ rid: rid,
+ service: service,
+ name: name,
+ description: description,
+ visibility: visibility,
+ updated: updated,
+ owner: owner,
+ head: head
+ )
)
}
}
diff --git a/Hutch/Views/Repositories/RepositorySummarySupport.swift b/Hutch/Views/Repositories/RepositorySummarySupport.swift
index 741ff39..393e3ff 100644
--- a/Hutch/Views/Repositories/RepositorySummarySupport.swift
+++ b/Hutch/Views/Repositories/RepositorySummarySupport.swift
@@ -37,11 +37,11 @@ func repositoryCloneURLs(for repository: RepositorySummary) -> RepositoryCloneUR
func repositoryVisibilityLabel(_ visibility: Visibility) -> String {
switch visibility {
- case .public:
+ case .publicVisibility:
return "Public"
case .unlisted:
return "Unlisted"
- case .private:
+ case .privateVisibility:
return "Private"
}
}
diff --git a/Hutch/Views/Settings/SettingsViewModel.swift b/Hutch/Views/Settings/SettingsViewModel.swift
index 29103f6..0b55e6a 100644
--- a/Hutch/Views/Settings/SettingsViewModel.swift
+++ b/Hutch/Views/Settings/SettingsViewModel.swift
@@ -228,10 +228,12 @@ final class SettingsViewModel {
service: .meta,
query: Self.updateUserMutation,
variables: ["input": input],
- fileVariablePath: "input.avatar",
- fileData: jpegData,
- fileName: "avatar.jpg",
- mimeType: "image/jpeg",
+ file: MultipartUploadFile(
+ variablePath: "input.avatar",
+ fileData: jpegData,
+ fileName: "avatar.jpg",
+ mimeType: "image/jpeg"
+ ),
responseType: UpdateUserResponse.self
)
let updated = result.updateUser
diff --git a/Hutch/Views/Tickets/TicketListView.swift b/Hutch/Views/Tickets/TicketListView.swift
index 940a282..afee96d 100644
--- a/Hutch/Views/Tickets/TicketListView.swift
+++ b/Hutch/Views/Tickets/TicketListView.swift
@@ -1400,11 +1400,13 @@ struct FlowLayout: Layout {
var spacing: CGFloat = 4
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
+ _ = cache
let result = layoutSubviews(proposal: proposal, subviews: subviews)
return result.size
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
+ _ = cache
let result = layoutSubviews(proposal: proposal, subviews: subviews)
for (index, position) in result.positions.enumerated() {
subviews[index].place(
diff --git a/Hutch/Views/Tickets/TrackerListView.swift b/Hutch/Views/Tickets/TrackerListView.swift
index 9ca3340..5deb513 100644
--- a/Hutch/Views/Tickets/TrackerListView.swift
+++ b/Hutch/Views/Tickets/TrackerListView.swift
@@ -37,7 +37,7 @@ struct TrackerListView: View {
error: viewModel.error,
initialName: "",
initialDescription: "",
- initialVisibility: .public
+ initialVisibility: .publicVisibility
) { name, description, visibility in
if let tracker = await viewModel.createTracker(
name: name,
diff --git a/Hutch/Views/Tickets/TrackerManagementView.swift b/Hutch/Views/Tickets/TrackerManagementView.swift
index 4e04bbd..fad1ae8 100644
--- a/Hutch/Views/Tickets/TrackerManagementView.swift
+++ b/Hutch/Views/Tickets/TrackerManagementView.swift
@@ -659,9 +659,9 @@ struct TrackerEditorSheet: View {
.lineLimit(2...4)
.themedRow()
Picker("Visibility", selection: $visibility) {
- Text("Public").tag(Visibility.public)
+ Text("Public").tag(Visibility.publicVisibility)
Text("Unlisted").tag(Visibility.unlisted)
- Text("Private").tag(Visibility.private)
+ Text("Private").tag(Visibility.privateVisibility)
}
.themedRow()
}
diff --git a/HutchTests/AppStateTests.swift b/HutchTests/AppStateTests.swift
index fe357cb..a5661ef 100644
--- a/HutchTests/AppStateTests.swift
+++ b/HutchTests/AppStateTests.swift
@@ -39,22 +39,24 @@ struct AppStateTests {
func navigationHelpersQueueExpectedTargets() {
let appState = AppState()
let repository = RepositorySummary(
- id: 1,
- rid: "repo",
- service: .git,
- name: "hutch",
- description: nil,
- visibility: .public,
- updated: .distantPast,
- owner: Entity(canonicalName: "~owner"),
- head: nil
+ fields: .init(
+ id: 1,
+ rid: "repo",
+ service: .git,
+ name: "hutch",
+ description: nil,
+ visibility: .publicVisibility,
+ updated: .distantPast,
+ owner: Entity(canonicalName: "~owner"),
+ head: nil
+ )
)
let tracker = TrackerSummary(
id: 2,
rid: "tracker",
name: "todo",
description: nil,
- visibility: .public,
+ visibility: .publicVisibility,
updated: .distantPast,
owner: Entity(canonicalName: "~owner")
)
diff --git a/HutchTests/ProjectTests.swift b/HutchTests/ProjectTests.swift
index 0323f25..23faa0d 100644
--- a/HutchTests/ProjectTests.swift
+++ b/HutchTests/ProjectTests.swift
@@ -15,7 +15,7 @@ struct ProjectTests {
name: "Hutch",
description: nil,
website: nil,
- visibility: .public,
+ visibility: .publicVisibility,
tags: [],
updated: Date(timeIntervalSince1970: 0)
),
@@ -25,7 +25,7 @@ struct ProjectTests {
id: "list-1",
name: "hutch-devel",
description: nil,
- visibility: .public,
+ visibility: .publicVisibility,
owner: Entity(canonicalName: "~owner")
)
],
@@ -34,7 +34,7 @@ struct ProjectTests {
id: "repo-1",
name: "hutch",
description: nil,
- visibility: .public,
+ visibility: .publicVisibility,
owner: Entity(canonicalName: "~owner"),
repoType: .git
),
@@ -42,7 +42,7 @@ struct ProjectTests {
id: "repo-2",
name: "hutch-web",
description: nil,
- visibility: .public,
+ visibility: .publicVisibility,
owner: Entity(canonicalName: "~owner"),
repoType: .git
)
@@ -52,7 +52,7 @@ struct ProjectTests {
id: "tracker-1",
name: "bugs",
description: nil,
- visibility: .public,
+ visibility: .publicVisibility,
owner: Entity(canonicalName: "~owner")
)
],
@@ -71,7 +71,7 @@ struct ProjectTests {
name: "Docs",
description: nil,
website: Fixture.exampleWebsite,
- visibility: .public,
+ visibility: .publicVisibility,
tags: [],
updated: Date(timeIntervalSince1970: 0)
),
diff --git a/HutchTests/RepositoryACLViewModelTests.swift b/HutchTests/RepositoryACLViewModelTests.swift
index 9c3f929..9640b93 100644
--- a/HutchTests/RepositoryACLViewModelTests.swift
+++ b/HutchTests/RepositoryACLViewModelTests.swift
@@ -110,15 +110,17 @@ struct RepositoryACLViewModelTests {
@MainActor
private func makeRepository() -> RepositorySummary {
RepositorySummary(
- id: 1,
- rid: "rid-1",
- service: .git,
- name: "repo",
- description: nil,
- visibility: .public,
- updated: .now,
- owner: Entity(canonicalName: "~owner"),
- head: nil
+ fields: .init(
+ id: 1,
+ rid: "rid-1",
+ service: .git,
+ name: "repo",
+ description: nil,
+ visibility: .publicVisibility,
+ updated: .now,
+ owner: Entity(canonicalName: "~owner"),
+ head: nil
+ )
)
}
}
diff --git a/HutchTests/RepositoryListViewModelTests.swift b/HutchTests/RepositoryListViewModelTests.swift
index 07f66aa..5fe3974 100644
--- a/HutchTests/RepositoryListViewModelTests.swift
+++ b/HutchTests/RepositoryListViewModelTests.swift
@@ -79,15 +79,17 @@ struct RepositoryListViewModelTests {
branch: String = "main"
) -> RepositorySummary {
RepositorySummary(
- id: id,
- rid: "rid-\(id)",
- service: service,
- name: name,
- description: description,
- visibility: .public,
- updated: Date(timeIntervalSince1970: TimeInterval(id)),
- owner: Entity(canonicalName: owner),
- head: Reference(name: branch, target: nil)
+ fields: .init(
+ id: id,
+ rid: "rid-\(id)",
+ service: service,
+ name: name,
+ description: description,
+ visibility: .publicVisibility,
+ updated: Date(timeIntervalSince1970: TimeInterval(id)),
+ owner: Entity(canonicalName: owner),
+ head: Reference(name: branch, target: nil)
+ )
)
}
}
diff --git a/HutchTests/RepositorySettingsViewModelTests.swift b/HutchTests/RepositorySettingsViewModelTests.swift
index 3b76da1..e64e08f 100644
--- a/HutchTests/RepositorySettingsViewModelTests.swift
+++ b/HutchTests/RepositorySettingsViewModelTests.swift
@@ -118,15 +118,17 @@ struct RepositorySettingsViewModelTests {
@MainActor
private func makeRepository(headName: String?) -> RepositorySummary {
RepositorySummary(
- id: 1,
- rid: "rid-1",
- service: .git,
- name: "repo",
- description: "desc",
- visibility: .public,
- updated: .now,
- owner: Entity(canonicalName: "~owner"),
- head: headName.map { Reference(name: $0, target: nil) }
+ fields: .init(
+ id: 1,
+ rid: "rid-1",
+ service: .git,
+ name: "repo",
+ description: "desc",
+ visibility: .publicVisibility,
+ updated: .now,
+ owner: Entity(canonicalName: "~owner"),
+ head: headName.map { Reference(name: $0, target: nil) }
+ )
)
}
}
diff --git a/HutchTests/SRHTWebURLTests.swift b/HutchTests/SRHTWebURLTests.swift
index c1f0dc0..d1053e6 100644
--- a/HutchTests/SRHTWebURLTests.swift
+++ b/HutchTests/SRHTWebURLTests.swift
@@ -14,22 +14,24 @@ struct SRHTWebURLTests {
}
private let repository = RepositorySummary(
- id: 1,
- rid: "repo-1",
- service: .git,
- name: "hutch",
- description: nil,
- visibility: .public,
- updated: .distantPast,
- owner: Entity(canonicalName: "~ccleberg"),
- head: nil
+ fields: .init(
+ id: 1,
+ rid: "repo-1",
+ service: .git,
+ name: "hutch",
+ description: nil,
+ visibility: .publicVisibility,
+ updated: .distantPast,
+ owner: Entity(canonicalName: "~ccleberg"),
+ head: nil
+ )
)
private let tracker = TrackerSummary(
id: 2,
rid: "tracker-1",
name: "todo",
description: nil,
- visibility: .public,
+ visibility: .publicVisibility,
updated: .distantPast,
owner: Entity(canonicalName: "~ccleberg")
)
diff --git a/HutchTests/TrackerListViewModelTests.swift b/HutchTests/TrackerListViewModelTests.swift
index 7e927af..5c57e04 100644
--- a/HutchTests/TrackerListViewModelTests.swift
+++ b/HutchTests/TrackerListViewModelTests.swift
@@ -66,7 +66,7 @@ struct TrackerListViewModelTests {
rid: "rid-\(id)",
name: name,
description: description,
- visibility: .public,
+ visibility: .publicVisibility,
updated: Date(),
owner: Entity(canonicalName: owner)
)