From a0ddebfc665428a1223270e3e953154ec9d10d0f Mon Sep 17 00:00:00 2001 From: Philip Niedertscheider Date: Thu, 18 Sep 2025 13:49:57 +0200 Subject: [PATCH 1/2] feat: Add toolbar button to display user feedback UI --- Targets/App/Sources/Generated/L10n.swift | 10 ++++++ .../Sources/Resources/Localizable.xcstrings | 36 +++++++++++++++++++ .../CreateLinkEditorRenderView.swift | 13 +++++++ .../CreateLinkListEditorRenderView.swift | 13 +++++++ .../UI/LinkDetail/LinkDetailRenderView.swift | 11 ++++++ .../UI/LinkInfo/LinkInfoRenderView.swift | 12 ++++++- .../LinkListDetailRenderView.swift | 12 +++++++ .../UI/LinkLists/LinkListsContainerView.swift | 5 --- .../UI/LinkLists/LinkListsRenderView.swift | 12 +++++++ 9 files changed, 118 insertions(+), 6 deletions(-) diff --git a/Targets/App/Sources/Generated/L10n.swift b/Targets/App/Sources/Generated/L10n.swift index 4259079..fa05fbf 100644 --- a/Targets/App/Sources/Generated/L10n.swift +++ b/Targets/App/Sources/Generated/L10n.swift @@ -281,6 +281,16 @@ internal enum L10n { internal static let label = L10n.tr("shared.button.edit.accessibility.label", fallback: "Edit") } } + internal enum Feedback { + /// Send Feedback + internal static let label = L10n.tr("shared.button.feedback.label", fallback: "Send Feedback") + internal enum Accessibility { + /// Send feedback to help improve the app + internal static let hint = L10n.tr("shared.button.feedback.accessibility.hint", fallback: "Send feedback to help improve the app") + /// Send Feedback + internal static let label = L10n.tr("shared.button.feedback.accessibility.label", fallback: "Send Feedback") + } + } internal enum NewLink { internal enum Accessibility { /// Create a new link in this list diff --git a/Targets/App/Sources/Resources/Localizable.xcstrings b/Targets/App/Sources/Resources/Localizable.xcstrings index 8f086bc..0666494 100644 --- a/Targets/App/Sources/Resources/Localizable.xcstrings +++ b/Targets/App/Sources/Resources/Localizable.xcstrings @@ -1026,6 +1026,42 @@ } } }, + "shared.button.feedback.accessibility.hint": { + "comment": "Feedback button accessibility hint", + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Send feedback to help improve the app" + } + } + } + }, + "shared.button.feedback.accessibility.label": { + "comment": "Feedback button accessibility label", + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Send Feedback" + } + } + } + }, + "shared.button.feedback.label": { + "comment": "Feedback button text", + "extractionState": "manual", + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Send Feedback" + } + } + } + }, "shared.color-picker.accessibility.label": { "comment": "Color picker accessibility label", "extractionState": "manual", diff --git a/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift b/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift index 91acb29..5b47e20 100644 --- a/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift +++ b/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift @@ -1,4 +1,6 @@ import SwiftUI +import SFSafeSymbols +import Sentry struct CreateLinkEditorRenderView: View { private enum CreateField { @@ -49,6 +51,17 @@ struct CreateLinkEditorRenderView: View { .accessibilityHint(L10n.Shared.Button.Cancel.Accessibility.hint) .accessibilityIdentifier("create-link.cancel.button") } + ToolbarItem(placement: .topBarTrailing) { + Button(action: { + // TODO: Display the feedback UI when available + // SentrySDK.feedback.presentUI() + }, label: { + Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) + }) + .accessibilityLabel(L10n.Shared.Button.Feedback.Accessibility.label) + .accessibilityHint(L10n.Shared.Button.Feedback.Accessibility.hint) + .accessibilityIdentifier("create-link.feedback.button") + } ToolbarItem(placement: .confirmationAction) { Button(L10n.Shared.Button.Save.label) { submit() diff --git a/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift b/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift index bafa132..e7c75af 100644 --- a/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift +++ b/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift @@ -1,3 +1,5 @@ +import SFSafeSymbols +import Sentry import SwiftUI struct CreateLinkListEditorRenderView: View { @@ -27,6 +29,17 @@ struct CreateLinkListEditorRenderView: View { .navigationTitle(L10n.CreateList.title) .accessibilityIdentifier("create-link-list.container") .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button(action: { + // TODO: Display the feedback UI when available + // SentrySDK.feedback.presentUI() + }, label: { + Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) + }) + .accessibilityLabel(L10n.Shared.Button.Feedback.Accessibility.label) + .accessibilityHint(L10n.Shared.Button.Feedback.Accessibility.hint) + .accessibilityIdentifier("create-link-list.feedback.button") + } ToolbarItem(placement: .cancellationAction) { Button(L10n.Shared.Button.Cancel.label) { dismiss() diff --git a/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift b/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift index c245cb3..285b1b8 100644 --- a/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift +++ b/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift @@ -32,6 +32,17 @@ struct LinkDetailRenderView: View { } .background(Color(UIColor.systemGroupedBackground)) .toolbar { + ToolbarItemGroup(placement: .topBarLeading) { + Button(action: { + // TODO: Display the feedback UI when available + // SentrySDK.feedback.presentUI() + }, label: { + Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) + }) + .accessibilityLabel(L10n.Shared.Button.Feedback.Accessibility.label) + .accessibilityHint(L10n.Shared.Button.Feedback.Accessibility.hint) + .accessibilityIdentifier("link-detail.feedback.button") + } ToolbarItemGroup(placement: .topBarLeading) { Menu { Button { diff --git a/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift b/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift index 008138a..9c1f04b 100644 --- a/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift +++ b/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift @@ -1,5 +1,6 @@ import FlinkyCore import SFSafeSymbols +import Sentry import SwiftUI struct LinkInfoRenderView: View { @@ -30,7 +31,16 @@ struct LinkInfoRenderView: View { .accessibilityHint(L10n.Shared.Button.Cancel.Accessibility.hint) .accessibilityIdentifier("link-info.cancel.button") } - ToolbarItem(placement: .topBarTrailing) { + ToolbarItemGroup(placement: .topBarTrailing) { + Button(action: { + // TODO: Display the feedback UI when available + // SentrySDK.feedback.presentUI() + }, label: { + Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) + }) + .accessibilityLabel(L10n.Shared.Button.Feedback.Accessibility.label) + .accessibilityHint(L10n.Shared.Button.Feedback.Accessibility.hint) + .accessibilityIdentifier("link-info.feedback.button") Button { saveAction() } label: { diff --git a/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift b/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift index 2f55652..d9dcbe0 100644 --- a/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift +++ b/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift @@ -1,4 +1,5 @@ import SFSafeSymbols +import Sentry import SwiftUI struct LinkListDetailRenderView: View { @@ -55,6 +56,17 @@ struct LinkListDetailRenderView: View { @ToolbarContentBuilder private var toolbarContent: some ToolbarContent { + ToolbarItem(placement: .topBarTrailing) { + Button(action: { + // TODO: Display the feedback UI when available + // SentrySDK.feedback.presentUI() + }, label: { + Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) + }) + .accessibilityLabel(L10n.Shared.Button.Feedback.Accessibility.label) + .accessibilityHint(L10n.Shared.Button.Feedback.Accessibility.hint) + .accessibilityIdentifier("link-list-detail.feedback.button") + } ToolbarItem(placement: .navigationBarTrailing) { moreMenu } diff --git a/Targets/App/Sources/UI/LinkLists/LinkListsContainerView.swift b/Targets/App/Sources/UI/LinkLists/LinkListsContainerView.swift index 75e7adc..94b9a8e 100644 --- a/Targets/App/Sources/UI/LinkLists/LinkListsContainerView.swift +++ b/Targets/App/Sources/UI/LinkLists/LinkListsContainerView.swift @@ -188,11 +188,6 @@ struct LinkListsContainerView: View { } } .sentryTrace("LINK_LISTS_VIEW") - .onAppear { - // Auto-injecting Sentry feedback widget is currently not supported in SwiftUI. - // Therefore we manually trigger it when the view appears. - SentrySDK.feedback.showWidget() - } } var pinnedListDisplayItems: [LinkListsDisplayItem] { diff --git a/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift b/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift index 6ccd248..009745a 100644 --- a/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift +++ b/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift @@ -1,4 +1,5 @@ import SFSafeSymbols +import Sentry import SwiftUI struct LinkListsRenderView: View { @@ -70,6 +71,17 @@ struct LinkListsRenderView: View { } } .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button(action: { + // TODO: Display the feedback UI when available + // SentrySDK.feedback.presentUI() + }, label: { + Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) + }) + .accessibilityLabel(L10n.Shared.Button.Feedback.Accessibility.label) + .accessibilityHint(L10n.Shared.Button.Feedback.Accessibility.hint) + .accessibilityIdentifier("link-lists.feedback.button") + } if !pinnedLists.isEmpty || !unpinnedLists.isEmpty { ToolbarItem(placement: .navigationBarTrailing) { EditButton() From addf073a167ab84de61e8a3248f8d8550b081177 Mon Sep 17 00:00:00 2001 From: Philip Niedertscheider Date: Mon, 24 Nov 2025 14:55:59 +0100 Subject: [PATCH 2/2] WIP --- Flinky.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- .../CreateLinkEditorRenderView.swift | 3 +-- .../CreateLinkListEditorRenderView.swift | 3 +-- .../UI/LinkDetail/LinkDetailRenderView.swift | 3 +-- .../Sources/UI/LinkInfo/LinkInfoRenderView.swift | 16 ++++++---------- .../LinkListDetailRenderView.swift | 3 +-- .../UI/LinkLists/LinkListsRenderView.swift | 3 +-- 8 files changed, 14 insertions(+), 23 deletions(-) diff --git a/Flinky.xcodeproj/project.pbxproj b/Flinky.xcodeproj/project.pbxproj index daa23ab..4a78979 100644 --- a/Flinky.xcodeproj/project.pbxproj +++ b/Flinky.xcodeproj/project.pbxproj @@ -1884,7 +1884,7 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/getsentry/sentry-cocoa"; requirement = { - branch = main; + branch = "philprime/feedback-show-form-button"; kind = branch; }; }; diff --git a/Flinky.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Flinky.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1b1d4a7..7431653 100644 --- a/Flinky.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Flinky.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/getsentry/sentry-cocoa", "state" : { - "branch" : "main", - "revision" : "5d81ddcd2a3df4f6825797d8d5c39a589da195ba" + "branch" : "philprime/feedback-show-form-button", + "revision" : "5c6740d29d13c13e7990906a0e72bae22573479b" } }, { diff --git a/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift b/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift index 8b0609b..aae8313 100644 --- a/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift +++ b/Targets/App/Sources/UI/CreateLinkEditor/CreateLinkEditorRenderView.swift @@ -59,8 +59,7 @@ struct CreateLinkEditorRenderView: View { } ToolbarItem(placement: .topBarTrailing) { Button(action: { - // TODO: Display the feedback UI when available - // SentrySDK.feedback.presentUI() + SentrySDK.feedback.showForm() }, label: { Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) }) diff --git a/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift b/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift index 41af154..7e7bb40 100644 --- a/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift +++ b/Targets/App/Sources/UI/CreateListEditor/CreateLinkListEditorRenderView.swift @@ -31,8 +31,7 @@ struct CreateLinkListEditorRenderView: View { .toolbar { ToolbarItem(placement: .topBarTrailing) { Button(action: { - // TODO: Display the feedback UI when available - // SentrySDK.feedback.presentUI() + SentrySDK.feedback.showForm() }, label: { Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) }) diff --git a/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift b/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift index 048a174..14c7e7f 100644 --- a/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift +++ b/Targets/App/Sources/UI/LinkDetail/LinkDetailRenderView.swift @@ -34,8 +34,7 @@ struct LinkDetailRenderView: View { .toolbar { ToolbarItemGroup(placement: .topBarLeading) { Button(action: { - // TODO: Display the feedback UI when available - // SentrySDK.feedback.presentUI() + SentrySDK.feedback.showForm() }, label: { Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) }) diff --git a/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift b/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift index 0886772..6dc1a90 100644 --- a/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift +++ b/Targets/App/Sources/UI/LinkInfo/LinkInfoRenderView.swift @@ -35,20 +35,16 @@ struct LinkInfoRenderView: View { .accessibilityHint(L10n.Shared.Button.Cancel.Accessibility.hint) .accessibilityIdentifier("link-info.cancel.button") } - ToolbarItemGroup(placement: .topBarTrailing) { + ToolbarItem(placement: .topBarTrailing) { Button(action: { - // TODO: Display the feedback UI when available - // SentrySDK.feedback.presentUI() + SentrySDK.feedback.showForm() }, label: { Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) }) .accessibilityLabel(L10n.Shared.Button.Feedback.Accessibility.label) .accessibilityHint(L10n.Shared.Button.Feedback.Accessibility.hint) .accessibilityIdentifier("link-info.feedback.button") - Button { - saveAction() - } label: { - Text(L10n.Shared.Button.Done.label) + } if #available(iOS 26, *) { ToolbarItem(placement: .confirmationAction) { Button(role: .confirm) { @@ -186,8 +182,8 @@ extension LinkInfoRenderView { .font(.system(size: 22, weight: .medium)) .foregroundStyle( symbol.isEmoji - ? Color.blue - : (colorScheme == .light ? Color.gray.mix(with: Color.black, by: 0.3) : Color.gray) + ? Color.blue + : (colorScheme == .light ? Color.gray.mix(with: Color.black, by: 0.3) : Color.gray) ) .frame(maxWidth: .infinity, maxHeight: .infinity) .padding(6) @@ -195,7 +191,7 @@ extension LinkInfoRenderView { .frame(maxWidth: .infinity, maxHeight: .infinity) .background( symbol.isEmoji - ? Color.blue.opacity(0.15) : Color.gray.opacity(colorScheme == .light ? 0.1 : 0.2) + ? Color.blue.opacity(0.15) : Color.gray.opacity(colorScheme == .light ? 0.1 : 0.2) ) .clipShape(Circle()) .contentShape(Circle()) diff --git a/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift b/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift index d695a9f..041a975 100644 --- a/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift +++ b/Targets/App/Sources/UI/LinkListDetail/LinkListDetailRenderView.swift @@ -32,8 +32,7 @@ struct LinkListDetailRenderView: View { } ToolbarItem(placement: .topBarTrailing) { Button(action: { - // TODO: Display the feedback UI when available - // SentrySDK.feedback.presentUI() + SentrySDK.feedback.presentUI() }, label: { Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) }) diff --git a/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift b/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift index 63a294c..3f274f8 100644 --- a/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift +++ b/Targets/App/Sources/UI/LinkLists/LinkListsRenderView.swift @@ -98,8 +98,7 @@ struct LinkListsRenderView: View { } ToolbarItem(placement: .topBarTrailing) { Button(action: { - // TODO: Display the feedback UI when available - // SentrySDK.feedback.presentUI() + SentrySDK.feedback.presentUI() }, label: { Label(L10n.Shared.Button.Feedback.label, systemSymbol: .megaphone) })