diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m index b5997339cd..d165ddff02 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m @@ -74,9 +74,14 @@ - (BOOL)application:(UIApplication *)application uiForm.submitButtonLabel = @"Report that jank"; uiForm.messagePlaceholder = @"Describe the nature of the jank. Its essence, if you will."; + uiForm.useSentryUser = YES; }; config.configureTheme = ^(SentryUserFeedbackThemeConfiguration *_Nonnull theme) { theme.font = [UIFont fontWithName:@"ChalkboardSE-Regular" size:25]; + theme.outlineStyle = + [[SentryFormElementOutlineStyle alloc] initWithColor:UIColor.purpleColor + cornerRadius:10 + outlineWidth:4]; }; config.onSubmitSuccess = ^(NSDictionary *_Nonnull info) { NSString *name = info[@"name"] ?: @"$shakespearean_insult_name"; diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m index c048ac9b91..c6632756f6 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/ViewController.m @@ -71,11 +71,14 @@ - (IBAction)captureUserFeedback:(id)sender captureError:error withScopeBlock:^(SentryScope *_Nonnull scope) { [scope setLevel:kSentryLevelFatal]; }]; - SentryUserFeedback *userFeedback = [[SentryUserFeedback alloc] initWithEventId:eventId]; - userFeedback.comments = @"It broke on iOS-ObjectiveC. I don't know why, but this happens."; - userFeedback.email = @"john@me.com"; - userFeedback.name = @"John Me"; - [SentrySDK captureUserFeedback:userFeedback]; + SentryFeedback *feedback = [[SentryFeedback alloc] + initWithMessage:@"It broke on iOS-ObjectiveC. I don't know why, but this happens." + name:@"John Me" + email:@"john@me.com" + source:SentryFeedbackSourceCustom + associatedEventId:nil + screenshot:nil]; + [SentrySDK captureUserFeedback:feedback]; } - (IBAction)captureError:(id)sender diff --git a/Samples/iOS-Swift/iOS-Swift/ExtraViewController.swift b/Samples/iOS-Swift/iOS-Swift/ExtraViewController.swift index b222ff56ea..abd62874ca 100644 --- a/Samples/iOS-Swift/iOS-Swift/ExtraViewController.swift +++ b/Samples/iOS-Swift/iOS-Swift/ExtraViewController.swift @@ -143,17 +143,8 @@ class ExtraViewController: UIViewController { @IBAction func captureUserFeedback(_ sender: UIButton) { highlightButton(sender) - let error = NSError(domain: "UserFeedbackErrorDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "This never happens."]) - - let eventId = SentrySDK.capture(error: error) { scope in - scope.setLevel(.fatal) - } - - let userFeedback = UserFeedback(eventId: eventId) - userFeedback.comments = "It broke on iOS-Swift. I don't know why, but this happens." - userFeedback.email = "john@me.com" - userFeedback.name = "John Me" - SentrySDK.capture(userFeedback: userFeedback) + let feedback = SentryFeedback(message: "It broke on iOS-Swift. I don't know why, but this happens.", name: "John Me", email: "john@me.com", source: .custom, associatedEventId: nil, screenshot: nil) + SentrySDK.capture(userFeedback: feedback) } @IBAction func permissions(_ sender: UIButton) { diff --git a/Samples/iOS-Swift/iOS-Swift/SentrySDKWrapper.swift b/Samples/iOS-Swift/iOS-Swift/SentrySDKWrapper.swift index 2b7daac915..6e6d2e2972 100644 --- a/Samples/iOS-Swift/iOS-Swift/SentrySDKWrapper.swift +++ b/Samples/iOS-Swift/iOS-Swift/SentrySDKWrapper.swift @@ -153,6 +153,7 @@ extension SentrySDKWrapper { } func configureFeedbackForm(config: SentryUserFeedbackFormConfiguration) { + config.useSentryUser = !args.contains("--io.sentry.feedback.dont-use-sentry-user") config.formTitle = "Jank Report" config.isEmailRequired = args.contains("--io.sentry.feedback.require-email") config.isNameRequired = args.contains("--io.sentry.feedback.require-name") @@ -181,7 +182,7 @@ extension SentrySDKWrapper { fontFamily = "ChalkboardSE-Regular" } config.fontFamily = fontFamily - config.outlineStyle = .init(outlineColor: .purple) + config.outlineStyle = .init(color: .purple) config.foreground = .purple config.background = .init(red: 0.95, green: 0.9, blue: 0.95, alpha: 1) config.submitBackground = .orange @@ -199,7 +200,6 @@ extension SentrySDKWrapper { return } - config.useSentryUser = !args.contains("--io.sentry.feedback.dont-use-sentry-user") config.animations = !args.contains("--io.sentry.feedback.no-animations") config.useShakeGesture = true config.showFormForScreenshots = true diff --git a/Sources/Sentry/Public/SentrySDK.h b/Sources/Sentry/Public/SentrySDK.h index b93a824334..3f53c721eb 100644 --- a/Sources/Sentry/Public/SentrySDK.h +++ b/Sources/Sentry/Public/SentrySDK.h @@ -254,8 +254,7 @@ SENTRY_NO_INIT * Captures user feedback that was manually gathered and sends it to Sentry. * @param userFeedback The user feedback to send to Sentry. */ -+ (void)captureUserFeedback:(SentryUserFeedback *)userFeedback - NS_SWIFT_NAME(capture(userFeedback:)); ++ (void)captureUserFeedback:(SentryFeedback *)userFeedback NS_SWIFT_NAME(capture(userFeedback:)); /** * Adds a Breadcrumb to the current Scope of the current Hub. If the total number of breadcrumbs diff --git a/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackConfiguration.swift b/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackConfiguration.swift index 28d0d5c1bc..c67d14b437 100644 --- a/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackConfiguration.swift +++ b/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackConfiguration.swift @@ -53,12 +53,6 @@ public class SentryUserFeedbackConfiguration: NSObject { */ public var tags: [String: Any]? - /** - * Sets the email and name field text content to `SentryUser.email` and `SentryUser.name`. - * - note: Default: `true` - */ - public var useSentryUser: Bool = true - /** * Called when the managed feedback form is opened. * - note: Default: `nil` diff --git a/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackFormConfiguration.swift b/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackFormConfiguration.swift index 74d5c94337..4344b982ab 100644 --- a/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackFormConfiguration.swift +++ b/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackFormConfiguration.swift @@ -11,6 +11,12 @@ import UIKit public class SentryUserFeedbackFormConfiguration: NSObject { // MARK: General settings + /** + * Sets the email and name field text content to `SentryUser.email` and `SentryUser.name`. + * - note: Default: `true` + */ + public var useSentryUser: Bool = true + /** * Displays the Sentry logo inside of the form. * - note: Default: `true` @@ -41,16 +47,10 @@ public class SentryUserFeedbackFormConfiguration: NSObject { /** * The label shown next to an input field that is required. - * - note: Default: `"(required)"` + * - note: Default: `"(Required)"` */ public var isRequiredLabel: String = "(Required)" - /** - * The message displayed after a successful feedback submission. - * - note: Default: `"Thank you for your report!"` - */ - public var successMessageText: String = "Thank you for your report!" - // MARK: Screenshots /** @@ -124,7 +124,7 @@ public class SentryUserFeedbackFormConfiguration: NSObject { */ public var emailPlaceholder: String = "your.email@example.org" - public lazy var emailTextFieldAccessibilityLabel = emailPlaceholder + public lazy var emailTextFieldAccessibilityLabel = "Your email address" // MARK: Buttons diff --git a/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackThemeConfiguration.swift b/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackThemeConfiguration.swift index 5607ed0118..02b4f0a27f 100644 --- a/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackThemeConfiguration.swift +++ b/Sources/Swift/Integrations/UserFeedback/Configuration/SentryUserFeedbackThemeConfiguration.swift @@ -16,13 +16,13 @@ public class SentryUserFeedbackThemeConfiguration: NSObject { public lazy var fontFamily: String? = nil /** - * Font for form input elements. + * Font for form input elements and the widget button label. * - note: Defaults to `UIFont.TextStyle.callout`. */ lazy var font = scaledFont(style: .callout) /** - * Font for main header title of the feedback form. + * Font for the main header title of the feedback form. * - note: Defaults to `UIFont.TextStyle.title1`. */ lazy var headerFont = scaledFont(style: .title1) @@ -88,24 +88,18 @@ public class SentryUserFeedbackThemeConfiguration: NSObject { */ public var buttonBackground: UIColor = UIColor.clear - /** - * Color used for success-related components (such as text color when feedback is submitted successfully). - * - note: Default light mode: `rgb(38, 141, 117)`; dark mode: `rgb(45, 169, 140)` - */ - public var successColor = UIScreen.main.traitCollection.userInterfaceStyle == .dark ? UIColor(red: 45 / 255, green: 169 / 255, blue: 140 / 255, alpha: 1) : UIColor(red: 38 / 255, green: 141 / 255, blue: 117 / 255, alpha: 1) - /** * Color used for error-related components (such as text color when there's an error submitting feedback). * - note: Default light mode: `rgb(223, 51, 56)`; dark mode: `rgb(245, 84, 89)` */ public var errorColor = UIScreen.main.traitCollection.userInterfaceStyle == .dark ? UIColor(red: 245 / 255, green: 84 / 255, blue: 89 / 255, alpha: 1) : UIColor(red: 223 / 255, green: 51 / 255, blue: 56 / 255, alpha: 1) - public struct OutlineStyle: Equatable { + @objc public class SentryFormElementOutlineStyle: NSObject { /** * Outline color for form inputs. * - note: Default: The system default of a UITextField outline with borderStyle of .roundedRect. */ - public var outlineColor = UIColor(white: 204 / 255, alpha: 1) + public var color = UIColor(white: 204 / 255, alpha: 1) /** * Outline corner radius for form input elements. @@ -119,8 +113,8 @@ public class SentryUserFeedbackThemeConfiguration: NSObject { */ public var outlineWidth: CGFloat = 0.5 - public init(outlineColor: UIColor = UIColor(white: 204 / 255, alpha: 1), cornerRadius: CGFloat = 5, outlineWidth: CGFloat = 0.5) { - self.outlineColor = outlineColor + @objc public init(color: UIColor = UIColor(white: 204 / 255, alpha: 1), cornerRadius: CGFloat = 5, outlineWidth: CGFloat = 0.5) { + self.color = color self.cornerRadius = cornerRadius self.outlineWidth = outlineWidth } @@ -129,17 +123,22 @@ public class SentryUserFeedbackThemeConfiguration: NSObject { /** * - note: We need to keep a reference to a default instance of this for comparison purposes later. We don't use the default to give UITextFields a default style, instead, we use `UITextField.BorderStyle.roundedRect` if `SentryUserFeedbackThemeConfiguration.outlineStyle == defaultOutlineStyle`. */ - let defaultOutlineStyle = OutlineStyle() + let defaultOutlineStyle = SentryFormElementOutlineStyle() /** * Options for styling the outline of input elements and buttons in the feedback form. */ - public lazy var outlineStyle: OutlineStyle = defaultOutlineStyle + public lazy var outlineStyle: SentryFormElementOutlineStyle = defaultOutlineStyle /** * Background color to use for text inputs in the feedback form. */ public var inputBackground: UIColor = UIColor.secondarySystemBackground + + /** + * Background color to use for text inputs in the feedback form. + */ + public var inputForeground: UIColor = UIScreen.main.traitCollection.userInterfaceStyle == .dark ? UIColor.lightText : UIColor.darkText } #endif // os(iOS) && !SENTRY_NO_UIKIT diff --git a/Sources/Swift/Integrations/UserFeedback/SentryFeedback.swift b/Sources/Swift/Integrations/UserFeedback/SentryFeedback.swift index f3f4890100..102ea99225 100644 --- a/Sources/Swift/Integrations/UserFeedback/SentryFeedback.swift +++ b/Sources/Swift/Integrations/UserFeedback/SentryFeedback.swift @@ -3,7 +3,14 @@ import Foundation @objcMembers class SentryFeedback: NSObject { - enum Source: String { + @objc enum SentryFeedbackSource: Int, CustomStringConvertible { + public var description: String { + switch self { + case .widget: return "widget" + case .custom: return "custom" + } + } + case widget case custom } @@ -11,7 +18,7 @@ class SentryFeedback: NSObject { var name: String? var email: String? var message: String - var source: Source + var source: SentryFeedbackSource let eventId: SentryId /// PNG data for the screenshot image @@ -21,7 +28,7 @@ class SentryFeedback: NSObject { var associatedEventId: String? /// - parameter screenshot Image encoded as PNG data. - init(message: String, name: String?, email: String?, source: Source = .widget, associatedEventId: String? = nil, screenshot: Data? = nil) { + @objc init(message: String, name: String?, email: String?, source: SentryFeedbackSource = .widget, associatedEventId: String? = nil, screenshot: Data? = nil) { self.eventId = SentryId() self.name = name self.email = email diff --git a/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackFormViewModel.swift b/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackFormViewModel.swift index cae3058b5c..ae50a4ece4 100644 --- a/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackFormViewModel.swift +++ b/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackFormViewModel.swift @@ -70,7 +70,7 @@ class SentryUserFeedbackFormViewModel: NSObject { field.delegate = controller field.autocapitalizationType = .words field.returnKeyType = .done - if config.useSentryUser { + if config.formConfig.useSentryUser { field.text = sentry_getCurrentUser()?.name } return field @@ -91,7 +91,7 @@ class SentryUserFeedbackFormViewModel: NSObject { field.keyboardType = .emailAddress field.autocapitalizationType = .none field.returnKeyType = .done - if config.useSentryUser { + if config.formConfig.useSentryUser { field.text = sentry_getCurrentUser()?.email } return field @@ -336,12 +336,13 @@ extension SentryUserFeedbackFormViewModel { [fullNameTextField, emailTextField].forEach { $0.font = config.theme.font $0.adjustsFontForContentSizeCategory = true + $0.textColor = config.theme.inputForeground if config.theme.outlineStyle == config.theme.defaultOutlineStyle { $0.borderStyle = .roundedRect } else { $0.layer.cornerRadius = config.theme.outlineStyle.cornerRadius $0.layer.borderWidth = config.theme.outlineStyle.outlineWidth - $0.layer.borderColor = config.theme.outlineStyle.outlineColor.cgColor + $0.layer.borderColor = config.theme.outlineStyle.color.cgColor } } @@ -349,6 +350,8 @@ extension SentryUserFeedbackFormViewModel { $0.backgroundColor = config.theme.inputBackground } + messageTextView.textColor = config.theme.inputForeground + [fullNameLabel, emailLabel, messageLabel].forEach { $0.font = config.theme.titleFont $0.adjustsFontForContentSizeCategory = true @@ -362,7 +365,7 @@ extension SentryUserFeedbackFormViewModel { [submitButton, removeScreenshotButton, cancelButton, messageTextView].forEach { $0.layer.cornerRadius = config.theme.outlineStyle.cornerRadius $0.layer.borderWidth = config.theme.outlineStyle.outlineWidth - $0.layer.borderColor = config.theme.outlineStyle.outlineColor.cgColor + $0.layer.borderColor = config.theme.outlineStyle.color.cgColor } [removeScreenshotButton, cancelButton].forEach { diff --git a/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackWidgetButtonView.swift b/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackWidgetButtonView.swift index a9a3f952a1..b7e088ff58 100644 --- a/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackWidgetButtonView.swift +++ b/Sources/Swift/Integrations/UserFeedback/SentryUserFeedbackWidgetButtonView.swift @@ -167,10 +167,10 @@ class SentryUserFeedbackWidgetButtonView: UIView { if UIScreen.main.traitCollection.userInterfaceStyle == .dark { lozengeLayer.fillColor = config.darkTheme.background.cgColor - lozengeLayer.strokeColor = config.darkTheme.outlineStyle.outlineColor.cgColor + lozengeLayer.strokeColor = config.darkTheme.outlineStyle.color.cgColor } else { lozengeLayer.fillColor = config.theme.background.cgColor - lozengeLayer.strokeColor = config.theme.outlineStyle.outlineColor.cgColor + lozengeLayer.strokeColor = config.theme.outlineStyle.color.cgColor } let iconSizeDifference = (scaledIconSize - svgSize) / 2