diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/CloseButton.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/CloseButton.swift index 4cb93a660..fe0780290 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/CloseButton.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/CloseButton.swift @@ -3,66 +3,63 @@ import SwiftUI struct CloseButton: View { - internal init(dismissIconColor: Color, dismissIconResource:String, circleColor: Color? = nil, onTap: @escaping () -> ()) { + internal init( + dismissIconImage: Image, + dismissIconColor: Color, + width: CGFloat? = nil, + height: CGFloat? = nil, + onTap: @escaping () -> () + ) { self.dismissIconColor = dismissIconColor - self.circleColor = circleColor ?? Color.gray.opacity(opacity) - self.dismissIconResource = dismissIconResource + self.dismissIconImage = dismissIconImage + self.width = width ?? 12 + self.height = height ?? 12 self.onTap = onTap } let dismissIconColor: Color - let dismissIconResource: String - - let circleColor: Color + let dismissIconImage: Image let onTap: () -> () private let opacity: CGFloat = 0.25 private let defaultPadding: CGFloat = 24 - private let height: CGFloat = 24 - private let width: CGFloat = 24 - - private let tappableHeight: CGFloat = 48 - private let tappableWidth: CGFloat = 48 + private let height: CGFloat + private let width: CGFloat - private func imageExistsInBundle(name: String) -> Bool { - return UIImage(named: name) != nil - } + private let tappableHeight: CGFloat = 44 + private let tappableWidth: CGFloat = 44 /// Check bundle and system for resource name /// If system image assume it's an icon and add a circular background @ViewBuilder private var dismissButtonImage: some View { - imageExistsInBundle(name: dismissIconResource) ? - AnyView(Image(dismissIconResource) - .resizable() - .frame(width: width/2, height: height/2)) : - AnyView(Image(systemName: dismissIconResource) - .resizable() - .frame(width: width/2, height: height/2) + dismissIconImage .foregroundColor(dismissIconColor) + .frame(width: width, height: height) .padding(8) - .background(circleColor) - .clipShape(Circle())) } var body: some View { Button(action: onTap) { - VStack(alignment:.center, spacing:0) { + VStack(alignment: .center, spacing: 0) { Spacer() dismissButtonImage Spacer() } - }.frame(width: tappableWidth, height: tappableHeight) + } + .frame( + width: max(tappableWidth, width), + height: max(tappableHeight, height) + ) .accessibilityLabel("Dismiss") } } #Preview { - CloseButton(dismissIconColor: .white, - dismissIconResource: "xmark", - circleColor: .red, + CloseButton(dismissIconImage: Image(systemName: "xmark"), + dismissIconColor: .white, onTap: {}) .background(Color.green) } diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/FullscreenView.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/FullscreenView.swift index 85a2d4d18..ed9179826 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/FullscreenView.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/FullscreenView.swift @@ -78,8 +78,10 @@ struct FullscreenView: View, Sendable { .background(Color.airshipTappableClear) } .addCloseButton( - dismissButtonColor: displayContent.dismissButtonColor?.color ?? Color.white, dismissIconResource: theme.dismissIconResource, + dismissButtonColor: displayContent.dismissButtonColor?.color, + width: theme.dismissIconWidth, + height: theme.dismissIconHeight, onUserDismissed: { environment.onUserDismissed() } diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/HTMLView.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/HTMLView.swift index e2e28a90f..ffd1f4eb7 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/HTMLView.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/HTMLView.swift @@ -38,9 +38,10 @@ struct HTMLView: View { InAppMessageWebView(displayContent: displayContent, accessibilityLabel: "In-app web view") .applyIf(!theme.hideDismissIcon){ $0.addCloseButton( - dismissButtonColor: displayContent.dismissButtonColor?.color ?? Color.white, dismissIconResource: theme.dismissIconResource, - circleColor: .airshipTappableClear, /// Probably should just do this everywhere and remove circleColor entirely + dismissButtonColor: displayContent.dismissButtonColor?.color, + width: theme.dismissIconWidth, + height: theme.dismissIconHeight, onUserDismissed: { environment.onUserDismissed() } diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageModalView.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageModalView.swift index 6ae5b0285..6df57a6cc 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageModalView.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageModalView.swift @@ -128,10 +128,13 @@ struct InAppMessageModalView: View { var body: some View { content .addCloseButton( - dismissButtonColor: displayContent.dismissButtonColor?.color ?? Color.white, dismissIconResource: theme.dismissIconResource, - circleColor: .airshipTappableClear, /// Probably should just do this everywhere and remove circleColor entirely - onUserDismissed: { environment.onUserDismissed() } + dismissButtonColor: displayContent.dismissButtonColor?.color, + width: theme.dismissIconWidth, + height: theme.dismissIconHeight, + onUserDismissed: { + environment.onUserDismissed() + } ) .background(displayContent.backgroundColor?.color ?? Color.black) .applyIf(isModal) { diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageViewUtils.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageViewUtils.swift index 89bbc58b8..7037bf2a0 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageViewUtils.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/InAppMessageViewUtils.swift @@ -157,17 +157,22 @@ extension View { @ViewBuilder func addCloseButton( - dismissButtonColor: Color, dismissIconResource: String, - circleColor:Color? = nil, + dismissButtonColor: Color?, + width: CGFloat? = nil, + height: CGFloat? = nil, onUserDismissed: @escaping () -> Void ) -> some View { + let dismissIconImage = InAppMessageTheme.dismissIcon(dismissIconResource) + let defaultDismissColor = Color.white + ZStack(alignment: .topTrailing) { // Align close button to the top trailing corner self.zIndex(0) CloseButton( - dismissIconColor: dismissButtonColor, - dismissIconResource: dismissIconResource, - circleColor: circleColor, + dismissIconImage: dismissIconImage, + dismissIconColor: dismissButtonColor ?? defaultDismissColor, + width: width, + height: height, onTap: onUserDismissed ) .zIndex(1) diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeButton.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeButton.swift index c7a9d4561..dbb1d381f 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeButton.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeButton.swift @@ -3,18 +3,27 @@ import Foundation import SwiftUI - public extension InAppMessageTheme { + static func dismissIcon(_ dismissIconResource: String?) -> Image { + /// Try custom image, then fallback to system image, finally fallback to xmark + if let name = dismissIconResource, let customImage = UIImage(named: name) { + return Image(uiImage: customImage) + } else if let name = dismissIconResource, let systemImage = UIImage(systemName: name) { + return Image(uiImage: systemImage) + } else { + return Image(systemName: "xmark") + } + } /// Button in-app message theme struct Button: Equatable { /// Button height public var height: Double - /// Button spacing when stackeds + /// Button spacing when stacked public var stackedSpacing: Double - /// Button spacing when seperated + /// Button spacing when separated public var separatedSpacing: Double /// Padding diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeFullscreen.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeFullscreen.swift index c2ad26feb..a2b4c696d 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeFullscreen.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeFullscreen.swift @@ -25,10 +25,16 @@ public extension InAppMessageTheme { public var media: InAppMessageTheme.Media /// Button theme - public var buttons: InAppMessageTheme.Button + public var buttons: InAppMessageTheme.Button /// Dismiss icon resource name - public var dismissIconResource: String + public var dismissIconResource: String + + /// Dismiss icon width + public var dismissIconWidth: CGFloat + + /// Dismiss icon height + public var dismissIconHeight: CGFloat /// Applies a style from a plist to the theme. /// - Parameters: @@ -60,6 +66,8 @@ public extension InAppMessageTheme { self.media.applyOverrides(overrides.mediaTheme) self.buttons.applyOverrides(overrides.buttonTheme) self.dismissIconResource = overrides.dismissIconResource ?? self.dismissIconResource + self.dismissIconWidth = overrides.dismissIconWidth ?? self.dismissIconWidth + self.dismissIconHeight = overrides.dismissIconHeight ?? self.dismissIconHeight } struct Overrides: Decodable { @@ -69,6 +77,8 @@ public extension InAppMessageTheme { var mediaTheme: InAppMessageTheme.Media.Overrides? var buttonTheme: InAppMessageTheme.Button.Overrides? var dismissIconResource: String? + var dismissIconWidth: CGFloat? + var dismissIconHeight: CGFloat? enum CodingKeys: String, CodingKey { case additionalPadding = "additionalPadding" @@ -77,6 +87,8 @@ public extension InAppMessageTheme { case mediaTheme = "mediaStyle" case buttonTheme = "buttonStyle" case dismissIconResource = "dismissIconResource" + case dismissIconWidth = "dismissIconWidth" + case dismissIconHeight = "dismissIconHeight" } } @@ -103,7 +115,9 @@ public extension InAppMessageTheme { separatedSpacing: 16, padding: EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) ), - dismissIconResource: "xmark" + dismissIconResource: "ua_airship_dismiss", + dismissIconWidth: 12, + dismissIconHeight: 12 ) /// Overrides diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeHTML.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeHTML.swift index 723df54b2..a8f5cbc95 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeHTML.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeHTML.swift @@ -16,7 +16,7 @@ public extension InAppMessageTheme { /// Max width in points public var maxWidth: CGFloat - /// Max height in pointts + /// Max height in points public var maxHeight: CGFloat /// If the dismiss icon should be hidden or not. Defaults to `false` @@ -28,6 +28,12 @@ public extension InAppMessageTheme { /// Dismiss icon resource name public var dismissIconResource: String + /// Dismiss icon width + public var dismissIconWidth: CGFloat + + /// Dismiss icon height + public var dismissIconHeight: CGFloat + /// Applies a style from a plist to the theme. /// - Parameters: /// - plistName: The name of the plist @@ -55,6 +61,8 @@ public extension InAppMessageTheme { self.hideDismissIcon = overrides.hideDismissIcon ?? self.hideDismissIcon self.padding.add(overrides.additionalPadding) self.dismissIconResource = overrides.dismissIconResource ?? self.dismissIconResource + self.dismissIconWidth = overrides.dismissIconWidth ?? self.dismissIconWidth + self.dismissIconHeight = overrides.dismissIconHeight ?? self.dismissIconHeight self.maxWidth = overrides.maxWidth ?? self.maxWidth self.maxHeight = overrides.maxHeight ?? self.maxHeight } @@ -63,6 +71,8 @@ public extension InAppMessageTheme { var hideDismissIcon: Bool? var additionalPadding: InAppMessageTheme.AdditionalPadding? var dismissIconResource: String? + var dismissIconWidth: CGFloat? + var dismissIconHeight: CGFloat? var maxWidth: CGFloat? var maxHeight: CGFloat? } @@ -73,7 +83,9 @@ public extension InAppMessageTheme { maxWidth: 420, maxHeight: 720, padding: EdgeInsets(top: 48, leading: 24, bottom: 48, trailing: 24), - dismissIconResource: "xmark" + dismissIconResource: "ua_airship_dismiss", + dismissIconWidth: 12, + dismissIconHeight: 12 ) /// Overrides diff --git a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeModal.swift b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeModal.swift index a6cf56a9d..89340df23 100644 --- a/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeModal.swift +++ b/Airship/AirshipAutomation/Source/InAppMessage/View/Theme/InAppMessageThemeModal.swift @@ -36,6 +36,11 @@ public extension InAppMessageTheme { /// Dismiss icon resource name public var dismissIconResource: String + /// Dismiss icon width + public var dismissIconWidth: CGFloat + + /// Dismiss icon height + public var dismissIconHeight: CGFloat /// Applies a style from a plist to the theme. /// - Parameters: @@ -69,6 +74,8 @@ public extension InAppMessageTheme { self.media.applyOverrides(overrides.mediaTheme) self.buttons.applyOverrides(overrides.buttonTheme) self.dismissIconResource = overrides.dismissIconResource ?? self.dismissIconResource + self.dismissIconWidth = overrides.dismissIconWidth ?? self.dismissIconWidth + self.dismissIconHeight = overrides.dismissIconHeight ?? self.dismissIconHeight } struct Overrides: Decodable { @@ -78,6 +85,8 @@ public extension InAppMessageTheme { var mediaTheme: InAppMessageTheme.Media.Overrides? var buttonTheme: InAppMessageTheme.Button.Overrides? var dismissIconResource: String? + var dismissIconWidth: CGFloat? + var dismissIconHeight: CGFloat? var maxWidth: CGFloat? var maxHeight: CGFloat? @@ -88,6 +97,8 @@ public extension InAppMessageTheme { case mediaTheme = "mediaStyle" case buttonTheme = "buttonStyle" case dismissIconResource = "dismissIconResource" + case dismissIconWidth = "dismissIconWidth" + case dismissIconHeight = "dismissIconHeight" case maxWidth = "maxWidth" case maxHeight = "maxHeight" } @@ -118,7 +129,9 @@ public extension InAppMessageTheme { separatedSpacing: 16, padding: EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) ), - dismissIconResource: "xmark" + dismissIconResource: "ua_airship_dismiss", + dismissIconWidth: 12, + dismissIconHeight: 12 ) /// Overrides diff --git a/Airship/AirshipPreferenceCenter/Source/view/Contact management/Component Views/PreferenceCloseButton.swift b/Airship/AirshipPreferenceCenter/Source/view/Contact management/Component Views/PreferenceCloseButton.swift index 39016d325..225c6fae7 100644 --- a/Airship/AirshipPreferenceCenter/Source/view/Contact management/Component Views/PreferenceCloseButton.swift +++ b/Airship/AirshipPreferenceCenter/Source/view/Contact management/Component Views/PreferenceCloseButton.swift @@ -79,7 +79,6 @@ extension View { dismissButtonColor: Color, dismissIconResource: String, contentDescription: String?, - circleColor:Color? = nil, onUserDismissed: @escaping () -> Void ) -> some View { ZStack(alignment: .topTrailing) { // Align close button to the top trailing corner