diff --git a/CHANGELOG.md b/CHANGELOG.md index 2044a24a9..6fa8aeabd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Destructive queries (DROP, TRUNCATE, DELETE without WHERE) now always ask for confirmation, even with Safe Mode off. (#1481) - Table structure changes, table creation, maintenance, column reorder, and saved data-grid edits now follow the connection's Safe Mode and read-only setting. (#1481) - AI assistant and MCP queries now follow the same Safe Mode confirmation, read-only, and authentication rules as the editor. (#1481) +- iOS: sheet close, cancel, and confirm buttons use the native iOS 26 button roles, matching system apps like Mail. iOS 18 keeps titled buttons. (#1524) ### Removed diff --git a/TableProMobile/TableProMobile/Views/Components/FKPreviewView.swift b/TableProMobile/TableProMobile/Views/Components/FKPreviewView.swift index c6fe8aea1..975c4d513 100644 --- a/TableProMobile/TableProMobile/Views/Components/FKPreviewView.swift +++ b/TableProMobile/TableProMobile/Views/Components/FKPreviewView.swift @@ -53,7 +53,7 @@ struct FKPreviewView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .confirmationAction) { - Button("Done") { dismiss() } + CloseButton { dismiss() } } } .task { await loadReferencedRow() } diff --git a/TableProMobile/TableProMobile/Views/Components/FilterSheetView.swift b/TableProMobile/TableProMobile/Views/Components/FilterSheetView.swift index 29bb6cec5..c5693e3c4 100644 --- a/TableProMobile/TableProMobile/Views/Components/FilterSheetView.swift +++ b/TableProMobile/TableProMobile/Views/Components/FilterSheetView.swift @@ -88,10 +88,10 @@ struct FilterSheetView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { dismiss() } + CancelButton { dismiss() } } ToolbarItem(placement: .confirmationAction) { - Button("Apply") { + ConfirmButton(title: "Apply") { filters = draft logicMode = draftLogicMode onApply() diff --git a/TableProMobile/TableProMobile/Views/Components/GroupFormSheet.swift b/TableProMobile/TableProMobile/Views/Components/GroupFormSheet.swift index 82f65d0ab..15758a8d4 100644 --- a/TableProMobile/TableProMobile/Views/Components/GroupFormSheet.swift +++ b/TableProMobile/TableProMobile/Views/Components/GroupFormSheet.swift @@ -32,10 +32,10 @@ struct GroupFormSheet: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { dismiss() } + CancelButton { dismiss() } } ToolbarItem(placement: .confirmationAction) { - Button("Save") { + ConfirmButton(title: "Save") { var group = existingGroup ?? ConnectionGroup() group.name = name group.color = color diff --git a/TableProMobile/TableProMobile/Views/Components/SemanticButtons.swift b/TableProMobile/TableProMobile/Views/Components/SemanticButtons.swift new file mode 100644 index 000000000..ae6735f44 --- /dev/null +++ b/TableProMobile/TableProMobile/Views/Components/SemanticButtons.swift @@ -0,0 +1,42 @@ +import SwiftUI + +struct CloseButton: View { + let action: () -> Void + + var body: some View { + if #available(iOS 26.0, *) { + Button(role: .close, action: action) + } else { + Button(String(localized: "Done"), action: action) + } + } +} + +struct CancelButton: View { + let action: () -> Void + + var body: some View { + if #available(iOS 26.0, *) { + Button(role: .cancel, action: action) + } else { + Button("Cancel", role: .cancel, action: action) + } + } +} + +struct ConfirmButton: View { + let title: LocalizedStringKey + var isInProgress = false + let action: () -> Void + + var body: some View { + if isInProgress { + ProgressView() + .controlSize(.small) + } else if #available(iOS 26.0, *) { + Button(role: .confirm, action: action) + } else { + Button(title, action: action) + } + } +} diff --git a/TableProMobile/TableProMobile/Views/Components/TagFormSheet.swift b/TableProMobile/TableProMobile/Views/Components/TagFormSheet.swift index 183a92b95..202ae722a 100644 --- a/TableProMobile/TableProMobile/Views/Components/TagFormSheet.swift +++ b/TableProMobile/TableProMobile/Views/Components/TagFormSheet.swift @@ -32,10 +32,10 @@ struct TagFormSheet: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { dismiss() } + CancelButton { dismiss() } } ToolbarItem(placement: .confirmationAction) { - Button("Save") { + ConfirmButton(title: "Save") { var tag = existingTag ?? ConnectionTag() tag.name = name tag.color = color diff --git a/TableProMobile/TableProMobile/Views/ConnectedView.swift b/TableProMobile/TableProMobile/Views/ConnectedView.swift index 51adad9ea..884516866 100644 --- a/TableProMobile/TableProMobile/Views/ConnectedView.swift +++ b/TableProMobile/TableProMobile/Views/ConnectedView.swift @@ -82,7 +82,7 @@ struct ConnectedView: View { Text(String(format: String(localized: "Connecting to %@..."), connection.name.isEmpty ? connection.host : connection.name)) } - Button(String(localized: "Cancel")) { + Button(String(localized: "Cancel"), role: .cancel) { dismiss() } .buttonStyle(.bordered) diff --git a/TableProMobile/TableProMobile/Views/ConnectionFormView.swift b/TableProMobile/TableProMobile/Views/ConnectionFormView.swift index 94052dc63..484202960 100644 --- a/TableProMobile/TableProMobile/Views/ConnectionFormView.swift +++ b/TableProMobile/TableProMobile/Views/ConnectionFormView.swift @@ -81,10 +81,10 @@ struct ConnectionFormView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { dismiss() } + CancelButton { dismiss() } } ToolbarItem(placement: .confirmationAction) { - Button("Save", action: handleSave) + ConfirmButton(title: "Save", action: handleSave) .disabled(!viewModel.canSave) } } diff --git a/TableProMobile/TableProMobile/Views/ConnectionListView.swift b/TableProMobile/TableProMobile/Views/ConnectionListView.swift index ac0b1faa4..861ac63e9 100644 --- a/TableProMobile/TableProMobile/Views/ConnectionListView.swift +++ b/TableProMobile/TableProMobile/Views/ConnectionListView.swift @@ -160,7 +160,7 @@ struct ConnectionListView: View { SettingsView() .toolbar { ToolbarItem(placement: .confirmationAction) { - Button(String(localized: "Done")) { + CloseButton { showingSettings = false } } diff --git a/TableProMobile/TableProMobile/Views/GroupManagementView.swift b/TableProMobile/TableProMobile/Views/GroupManagementView.swift index c058713f1..be90e82cc 100644 --- a/TableProMobile/TableProMobile/Views/GroupManagementView.swift +++ b/TableProMobile/TableProMobile/Views/GroupManagementView.swift @@ -96,7 +96,7 @@ struct GroupManagementView: View { } label: { Image(systemName: "plus") } - Button("Done") { dismiss() } + CloseButton { dismiss() } } } .sheet(isPresented: $showingAddGroup) { diff --git a/TableProMobile/TableProMobile/Views/InsertRowView.swift b/TableProMobile/TableProMobile/Views/InsertRowView.swift index c1baf56ab..0b3465260 100644 --- a/TableProMobile/TableProMobile/Views/InsertRowView.swift +++ b/TableProMobile/TableProMobile/Views/InsertRowView.swift @@ -113,19 +113,12 @@ struct InsertRowView: View { .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { dismiss() } + CancelButton { dismiss() } .disabled(isSaving) } ToolbarItem(placement: .confirmationAction) { - Button { + ConfirmButton(title: "Save", isInProgress: isSaving) { Task { await insertRow() } - } label: { - if isSaving { - ProgressView() - .controlSize(.small) - } else { - Text("Save") - } } .disabled(isSaving) } diff --git a/TableProMobile/TableProMobile/Views/RowDetailView.swift b/TableProMobile/TableProMobile/Views/RowDetailView.swift index 742cf7826..250965931 100644 --- a/TableProMobile/TableProMobile/Views/RowDetailView.swift +++ b/TableProMobile/TableProMobile/Views/RowDetailView.swift @@ -124,15 +124,8 @@ struct RowDetailView: View { ToolbarItem(placement: .primaryAction) { if viewModel.canEdit { if viewModel.isEditing { - Button { + ConfirmButton(title: "Save", isInProgress: viewModel.isSaving) { Task { await handleSave() } - } label: { - if viewModel.isSaving { - ProgressView() - .controlSize(.small) - } else { - Text("Save") - } } .disabled(viewModel.isSaving) } else { @@ -143,7 +136,7 @@ struct RowDetailView: View { if viewModel.isEditing { ToolbarItem(placement: .cancellationAction) { - Button("Cancel") { viewModel.cancelEditing() } + CancelButton { viewModel.cancelEditing() } .disabled(viewModel.isSaving) } } diff --git a/TableProMobile/TableProMobile/Views/TagManagementView.swift b/TableProMobile/TableProMobile/Views/TagManagementView.swift index 7fd3ce153..51ec3b696 100644 --- a/TableProMobile/TableProMobile/Views/TagManagementView.swift +++ b/TableProMobile/TableProMobile/Views/TagManagementView.swift @@ -74,7 +74,7 @@ struct TagManagementView: View { } label: { Image(systemName: "plus") } - Button("Done") { dismiss() } + CloseButton { dismiss() } } } .sheet(isPresented: $showingAddTag) {