Commit 77df444b20
Unsigned
Layout: unified · split
Hutch.xcodeproj/project.pbxproj +4 −4
| @@ -359,7 +359,7 @@ | |||
| 359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | 359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
| 360 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; | 360 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; |
| 361 | CODE_SIGN_STYLE = Automatic; | 361 | CODE_SIGN_STYLE = Automatic; |
| 362 | CURRENT_PROJECT_VERSION = 5; | 362 | CURRENT_PROJECT_VERSION = 6; |
| 363 | DEVELOPMENT_TEAM = ZCNAX3VL9D; | 363 | DEVELOPMENT_TEAM = ZCNAX3VL9D; |
| 364 | ENABLE_PREVIEWS = YES; | 364 | ENABLE_PREVIEWS = YES; |
| 365 | GENERATE_INFOPLIST_FILE = YES; | 365 | GENERATE_INFOPLIST_FILE = YES; |
| @@ -376,7 +376,7 @@ | |||
| 376 | "$(inherited)", | 376 | "$(inherited)", |
| 377 | "@executable_path/Frameworks", | 377 | "@executable_path/Frameworks", |
| 378 | ); | 378 | ); |
| 379 | MARKETING_VERSION = 2.0; | 379 | MARKETING_VERSION = 2.1; |
| 380 | PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; | 380 | PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; |
| 381 | PRODUCT_NAME = "$(TARGET_NAME)"; | 381 | PRODUCT_NAME = "$(TARGET_NAME)"; |
| 382 | STRING_CATALOG_GENERATE_SYMBOLS = YES; | 382 | STRING_CATALOG_GENERATE_SYMBOLS = YES; |
| @@ -395,7 +395,7 @@ | |||
| 395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | 395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
| 396 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; | 396 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; |
| 397 | CODE_SIGN_STYLE = Automatic; | 397 | CODE_SIGN_STYLE = Automatic; |
| 398 | CURRENT_PROJECT_VERSION = 5; | 398 | CURRENT_PROJECT_VERSION = 6; |
| 399 | DEVELOPMENT_TEAM = ZCNAX3VL9D; | 399 | DEVELOPMENT_TEAM = ZCNAX3VL9D; |
| 400 | ENABLE_PREVIEWS = YES; | 400 | ENABLE_PREVIEWS = YES; |
| 401 | GENERATE_INFOPLIST_FILE = YES; | 401 | GENERATE_INFOPLIST_FILE = YES; |
| @@ -412,7 +412,7 @@ | |||
| 412 | "$(inherited)", | 412 | "$(inherited)", |
| 413 | "@executable_path/Frameworks", | 413 | "@executable_path/Frameworks", |
| 414 | ); | 414 | ); |
| 415 | MARKETING_VERSION = 2.0; | 415 | MARKETING_VERSION = 2.1; |
| 416 | PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; | 416 | PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; |
| 417 | PRODUCT_NAME = "$(TARGET_NAME)"; | 417 | PRODUCT_NAME = "$(TARGET_NAME)"; |
| 418 | STRING_CATALOG_GENERATE_SYMBOLS = YES; | 418 | STRING_CATALOG_GENERATE_SYMBOLS = YES; |
Hutch/Views/Repositories/HgRepositorySettingsView.swift +29 −2
| @@ -9,6 +9,7 @@ struct HgRepositorySettingsView: View { | |||
| 9 | @State private var viewModel: HgRepositorySettingsViewModel? | 9 | @State private var viewModel: HgRepositorySettingsViewModel? |
| 10 | @State private var showDeleteConfirmation = false | 10 | @State private var showDeleteConfirmation = false |
| 11 | @State private var pendingACLDeletion: HgACLEntry? | 11 | @State private var pendingACLDeletion: HgACLEntry? |
| 12 | @State private var saveResultAlert: SaveResultAlert? | ||
| 12 | 13 | ||
| 13 | var body: some View { | 14 | var body: some View { |
| 14 | NavigationStack { | 15 | NavigationStack { |
| @@ -88,6 +89,13 @@ struct HgRepositorySettingsView: View { | |||
| 88 | Text("\(entry.entity.canonicalName) will lose \(entry.mode) access to this repository.") | 89 | Text("\(entry.entity.canonicalName) will lose \(entry.mode) access to this repository.") |
| 89 | } | 90 | } |
| 90 | } | 91 | } |
| 92 | .alert(item: $saveResultAlert) { alert in | ||
| 93 | Alert( | ||
| 94 | title: Text(alert.title), | ||
| 95 | message: Text(alert.message), | ||
| 96 | dismissButton: .default(Text("OK")) | ||
| 97 | ) | ||
| 98 | } | ||
| 91 | } | 99 | } |
| 92 | 100 | ||
| 93 | @ViewBuilder | 101 | @ViewBuilder |
| @@ -108,7 +116,13 @@ struct HgRepositorySettingsView: View { | |||
| 108 | } | 116 | } |
| 109 | 117 | ||
| 110 | Button { | 118 | Button { |
| 111 | Task { await viewModel.saveInfo() } | 119 | Task { |
| 120 | let didSave = await viewModel.saveInfo() | ||
| 121 | saveResultAlert = SaveResultAlert( | ||
| 122 | title: didSave ? "Settings Updated" : "Couldn't Update Settings", | ||
| 123 | message: didSave ? "Repository settings were saved." : (viewModel.error ?? "Please try again.") | ||
| 124 | ) | ||
| 125 | } | ||
| 112 | } label: { | 126 | } label: { |
| 113 | if viewModel.isSavingInfo { | 127 | if viewModel.isSavingInfo { |
| 114 | ProgressView() | 128 | ProgressView() |
| @@ -188,7 +202,13 @@ struct HgRepositorySettingsView: View { | |||
| 188 | Toggle("Hide this repository from public listings", isOn: Bindable(viewModel).editedNonPublishing) | 202 | Toggle("Hide this repository from public listings", isOn: Bindable(viewModel).editedNonPublishing) |
| 189 | 203 | ||
| 190 | Button { | 204 | Button { |
| 191 | Task { await viewModel.saveInfo() } | 205 | Task { |
| 206 | let didSave = await viewModel.saveInfo() | ||
| 207 | saveResultAlert = SaveResultAlert( | ||
| 208 | title: didSave ? "Settings Updated" : "Couldn't Update Settings", | ||
| 209 | message: didSave ? "Repository settings were saved." : (viewModel.error ?? "Please try again.") | ||
| 210 | ) | ||
| 211 | } | ||
| 192 | } label: { | 212 | } label: { |
| 193 | if viewModel.isSavingInfo { | 213 | if viewModel.isSavingInfo { |
| 194 | ProgressView() | 214 | ProgressView() |
| @@ -236,4 +256,11 @@ struct HgRepositorySettingsView: View { | |||
| 236 | .disabled(viewModel.isDeleting) | 256 | .disabled(viewModel.isDeleting) |
| 237 | } | 257 | } |
| 238 | } | 258 | } |
| 259 | |||
| 260 | private struct SaveResultAlert: Identifiable { | ||
| 261 | let title: String | ||
| 262 | let message: String | ||
| 263 | |||
| 264 | var id: String { "\(title)-\(message)" } | ||
| 265 | } | ||
| 239 | } | 266 | } |
Hutch/Views/Repositories/HgRepositorySettingsViewModel.swift +3 −1
| @@ -168,7 +168,7 @@ final class HgRepositorySettingsViewModel { | |||
| 168 | } | 168 | } |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | func saveInfo() async { | 171 | func saveInfo() async -> Bool { |
| 172 | isSavingInfo = true | 172 | isSavingInfo = true |
| 173 | defer { isSavingInfo = false } | 173 | defer { isSavingInfo = false } |
| 174 | error = nil | 174 | error = nil |
| @@ -185,8 +185,10 @@ final class HgRepositorySettingsViewModel { | |||
| 185 | variables: ["id": repositoryId, "input": input], | 185 | variables: ["id": repositoryId, "input": input], |
| 186 | responseType: HgUpdateRepositoryResponse.self | 186 | responseType: HgUpdateRepositoryResponse.self |
| 187 | ) | 187 | ) |
| 188 | return true | ||
| 188 | } catch { | 189 | } catch { |
| 189 | self.error = error.userFacingMessage | 190 | self.error = error.userFacingMessage |
| 191 | return false | ||
| 190 | } | 192 | } |
| 191 | } | 193 | } |
| 192 | 194 | ||
Hutch/Views/Repositories/ReadmeView.swift +5 −1
| @@ -1108,7 +1108,11 @@ private struct HTMLWebViewRepresentable: UIViewRepresentable { | |||
| 1108 | if let cachedHeight = HTMLWebViewCoordinator.heightCache.object(forKey: wrapped as NSString)?.doubleValue { | 1108 | if let cachedHeight = HTMLWebViewCoordinator.heightCache.object(forKey: wrapped as NSString)?.doubleValue { |
| 1109 | let height = CGFloat(cachedHeight) | 1109 | let height = CGFloat(cachedHeight) |
| 1110 | if abs(dynamicHeight - height) > 0.5 { | 1110 | if abs(dynamicHeight - height) > 0.5 { |
| 1111 | dynamicHeight = height | 1111 | DispatchQueue.main.async { |
| 1112 | if abs(self.dynamicHeight - height) > 0.5 { | ||
| 1113 | self.dynamicHeight = height | ||
| 1114 | } | ||
| 1115 | } | ||
| 1112 | } | 1116 | } |
| 1113 | } | 1117 | } |
| 1114 | 1118 | ||
Hutch/Views/Repositories/RepositorySettingsView.swift +22 −1
| @@ -11,6 +11,7 @@ struct RepositorySettingsView: View { | |||
| 11 | @State private var viewModel: RepositorySettingsViewModel? | 11 | @State private var viewModel: RepositorySettingsViewModel? |
| 12 | @State private var showDeleteConfirmation = false | 12 | @State private var showDeleteConfirmation = false |
| 13 | @State private var pendingACLDeletion: ACLEntry? | 13 | @State private var pendingACLDeletion: ACLEntry? |
| 14 | @State private var saveResultAlert: SaveResultAlert? | ||
| 14 | 15 | ||
| 15 | var body: some View { | 16 | var body: some View { |
| 16 | NavigationStack { | 17 | NavigationStack { |
| @@ -91,6 +92,13 @@ struct RepositorySettingsView: View { | |||
| 91 | Text("\(entry.entity.canonicalName) will lose \(entry.mode) access to this repository.") | 92 | Text("\(entry.entity.canonicalName) will lose \(entry.mode) access to this repository.") |
| 92 | } | 93 | } |
| 93 | } | 94 | } |
| 95 | .alert(item: $saveResultAlert) { alert in | ||
| 96 | Alert( | ||
| 97 | title: Text(alert.title), | ||
| 98 | message: Text(alert.message), | ||
| 99 | dismissButton: .default(Text("OK")) | ||
| 100 | ) | ||
| 101 | } | ||
| 94 | } | 102 | } |
| 95 | 103 | ||
| 96 | // MARK: - Info Section | 104 | // MARK: - Info Section |
| @@ -122,7 +130,13 @@ struct RepositorySettingsView: View { | |||
| 122 | } | 130 | } |
| 123 | 131 | ||
| 124 | Button { | 132 | Button { |
| 125 | Task { await viewModel.saveInfo() } | 133 | Task { |
| 134 | let didSave = await viewModel.saveInfo() | ||
| 135 | saveResultAlert = SaveResultAlert( | ||
| 136 | title: didSave ? "Settings Updated" : "Couldn't Update Settings", | ||
| 137 | message: didSave ? "Repository settings were saved." : (viewModel.error ?? "Please try again.") | ||
| 138 | ) | ||
| 139 | } | ||
| 126 | } label: { | 140 | } label: { |
| 127 | if viewModel.isSavingInfo { | 141 | if viewModel.isSavingInfo { |
| 128 | ProgressView() | 142 | ProgressView() |
| @@ -256,4 +270,11 @@ struct RepositorySettingsView: View { | |||
| 256 | .disabled(viewModel.isDeleting) | 270 | .disabled(viewModel.isDeleting) |
| 257 | } | 271 | } |
| 258 | } | 272 | } |
| 273 | |||
| 274 | private struct SaveResultAlert: Identifiable { | ||
| 275 | let title: String | ||
| 276 | let message: String | ||
| 277 | |||
| 278 | var id: String { "\(title)-\(message)" } | ||
| 279 | } | ||
| 259 | } | 280 | } |
Hutch/Views/Repositories/RepositorySettingsViewModel.swift +3 −1
| @@ -153,7 +153,7 @@ final class RepositorySettingsViewModel { | |||
| 153 | } | 153 | } |
| 154 | """ | 154 | """ |
| 155 | 155 | ||
| 156 | func saveInfo() async { | 156 | func saveInfo() async -> Bool { |
| 157 | isSavingInfo = true | 157 | isSavingInfo = true |
| 158 | defer { isSavingInfo = false } | 158 | defer { isSavingInfo = false } |
| 159 | error = nil | 159 | error = nil |
| @@ -172,8 +172,10 @@ final class RepositorySettingsViewModel { | |||
| 172 | variables: ["id": repositoryId, "input": input], | 172 | variables: ["id": repositoryId, "input": input], |
| 173 | responseType: UpdateRepoInfoResponse.self | 173 | responseType: UpdateRepoInfoResponse.self |
| 174 | ) | 174 | ) |
| 175 | return true | ||
| 175 | } catch { | 176 | } catch { |
| 176 | self.error = error.userFacingMessage | 177 | self.error = error.userFacingMessage |
| 178 | return false | ||
| 177 | } | 179 | } |
| 178 | } | 180 | } |
| 179 | 181 | ||