Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2a5706e
Added support for dark mode for timer template
May 16, 2025
c595498
Added support for dark mode for Rating template
May 16, 2025
3bcdde0
Added dark mode support for Carousel template
May 16, 2025
d9d7c0f
Add dark mode support for Product Catalog, Single media template
May 16, 2025
ff43da2
Updated traitCollectionDidChange method to get the status of device's…
May 16, 2025
4d6f768
Resolved bugs for dark mode
May 18, 2025
ff06313
Fixed the bug for timer colour
May 18, 2025
574dd7d
- Updated Changelog
May 18, 2025
f1c6f2b
Added support for dark mode in Zero Bezel template
Jun 3, 2025
f2bbb3a
Fixed deeplink issue for product display vertical
Jun 3, 2025
fdc2fcf
Updated SDWebImage project
Jun 9, 2025
a4503dc
Fixed the vertical product display button bug
Jun 9, 2025
3c04097
Resolved dark mode bug for product display linear view template
Jun 9, 2025
f4e7b4d
Updated xcframework
Jun 9, 2025
603393f
Updated changelog
Jun 9, 2025
b3e2814
Updated dark mode support for product display button text
Jun 9, 2025
73ab072
Updated changelog and xcframework
Jun 9, 2025
ba54bd0
Update README.md
kushCT Jun 9, 2025
3085493
Removed device and simulator xcarchive file
Jun 9, 2025
d1bb4a0
Handled the traitCollectionDidChange deprecation — using registerForT…
Jun 10, 2025
58d3cf1
- Fixes attributed string text in product display template.
nishant-clevertap Jun 17, 2025
2f2e907
Updated release date in changelog
nishant-clevertap Jun 20, 2025
a7c1f38
Updated xcframework
nishant-clevertap Jun 20, 2025
2d10e3d
Merge pull request #45 from CleverTap/task/add-dark-mode-support
nishant-clevertap Jun 20, 2025
615def0
Fixes pod lint error for cocoapods compiler error.
nishant-clevertap Jun 20, 2025
cb7a28c
Updated xcframework
nishant-clevertap Jun 20, 2025
338cd6f
Updated changelog and version
nishant-clevertap Jun 20, 2025
20e57b3
Merge pull request #47 from CleverTap/fix/pod_lint_fix
nishant-clevertap Jun 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
Change Log
==========
Version 1.0.0 (20 June, 2025)
-----------------------------------------------

- Implemented new color attributes with _dark suffix for theming:

`pt_title_clr_dark` - For title text in dark mode
`pt_msg_clr_dark` - For message text in dark mode
`pt_bg_dark` - For background in dark mode
`pt_chrono_title_clr_dark` - For timer text in dark mode
`pt_product_display_action_clr_dark` - For action buttons in product display templates
`pt_product_display_action_text_clr_dark` - For action button text in product display templates

- Implemented a dynamic color selection system that adapts to the device's UI mode. If no colours are passed in the payload then the default colours will be picked for iOS 13+

Version 0.3.0 (10 April, 2025)
-----------------------------------------------
- Added support for bold, italic, underline, and strikethrough HTML tags in title and message for rich push notifications.
Expand Down
2 changes: 1 addition & 1 deletion CTNotificationContent.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CTNotificationContent"
s.version = "0.3.0"
s.version = "1.0.0"
s.summary = "A Notification Content Extension class to display custom content interfaces for iOS 10 push notifications"
s.homepage = "https://github.com/CleverTap/CTNotificationContent"
s.license = "MIT"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@ import UserNotificationsUI
@objc public var templateSubcaption: String = ""
@objc public var deeplinkURL: String = ""
@objc public var isFromProductDisplay: Bool = false

var bgColor: String = ConstantKeys.kDefaultColor
var captionColor: String = ConstantKeys.kHexBlackColor
var subcaptionColor: String = ConstantKeys.kHexLightGrayColor

// Dark mode colors
var bgColorDark: String = ConstantKeys.kDefaultColorDark
var captionColorDark: String = ConstantKeys.kHexWhiteColor
var subcaptionColorDark: String = ConstantKeys.kHexDarkGrayColor

var jsonContent: CarouselProperties? = nil
var nextButtonImage: UIImage = UIImage()
var previousButtonImage: UIImage = UIImage()
Expand All @@ -34,6 +41,15 @@ import UserNotificationsUI

jsonContent = CTUtiltiy.loadContentData(data: data)
createView()

// Register for trait changes on iOS 17+
if #available(iOS 17.0, *) {
registerForTraitChanges([UITraitUserInterfaceStyle.self]) { (self: Self, previousTraitCollection: UITraitCollection) in
if self.traitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle {
self.updateContentViewBackground()
}
}
}
}

func createView() {
Expand Down Expand Up @@ -61,11 +77,23 @@ import UserNotificationsUI
if let msgColor = jsonContent.pt_msg_clr, !msgColor.isEmpty {
subcaptionColor = msgColor
}

// Handle dark mode colors
if let bgDark = jsonContent.pt_bg_dark, !bgDark.isEmpty {
bgColorDark = bgDark
}
if let titleColorDark = jsonContent.pt_title_clr_dark, !titleColorDark.isEmpty {
captionColorDark = titleColorDark
}
if let msgColorDark = jsonContent.pt_msg_clr_dark, !msgColorDark.isEmpty {
subcaptionColorDark = msgColorDark
}
var actionUrl = deeplinkURL
if let deeplink = jsonContent.pt_dl1, !deeplink.isEmpty {
actionUrl = deeplink
}
deeplinkURL = actionUrl
updateContentViewBackground()

if templateType == TemplateConstants.kTemplateBasic {
var basicImageUrl = ""
Expand All @@ -85,7 +113,7 @@ import UserNotificationsUI
CTUtiltiy.checkImageUrlValid(imageUrl: basicImageUrl) { [weak self] (imageData) in
DispatchQueue.main.async {
if imageData != nil {
let itemComponents = CaptionedImageViewComponents(caption: self!.templateCaption, subcaption: self!.templateSubcaption, imageUrl: basicImageUrl, actionUrl: actionUrl, bgColor: self!.bgColor, captionColor: self!.captionColor, subcaptionColor: self!.subcaptionColor)
let itemComponents = CaptionedImageViewComponents(caption: self!.templateCaption, subcaption: self!.templateSubcaption, imageUrl: basicImageUrl, actionUrl: actionUrl, bgColor: self!.bgColor, captionColor: self!.captionColor, subcaptionColor: self!.subcaptionColor, bgColorDark: self!.bgColorDark, captionColorDark: self!.captionColorDark, subcaptionColorDark: self!.subcaptionColorDark)
let itemView = CTCaptionedImageView(components: itemComponents)
self?.itemViews.append(itemView)
}
Expand All @@ -111,7 +139,7 @@ import UserNotificationsUI
CTUtiltiy.checkImageUrlValid(imageUrl: url) { [weak self] (imageData) in
DispatchQueue.main.async {
if imageData != nil {
let itemComponents = CaptionedImageViewComponents(caption: self!.templateCaption, subcaption: self!.templateSubcaption, imageUrl: url, actionUrl: actionUrl, bgColor: self!.bgColor, captionColor: self!.captionColor, subcaptionColor: self!.subcaptionColor)
let itemComponents = CaptionedImageViewComponents(caption: self!.templateCaption, subcaption: self!.templateSubcaption, imageUrl: url, actionUrl: actionUrl, bgColor: self!.bgColor, captionColor: self!.captionColor, subcaptionColor: self!.subcaptionColor, bgColorDark: self!.bgColorDark, captionColorDark: self!.captionColorDark, subcaptionColorDark: self!.subcaptionColorDark)
let itemView = CTCaptionedImageView(components: itemComponents)
self?.itemViews.append(itemView)
}
Expand All @@ -125,6 +153,31 @@ import UserNotificationsUI
}
}

@objc public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)

// Handle trait changes, for iOS 17+ it is handled by registerForTraitChanges.
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
updateContentViewBackground()
}
}
}

func updateContentViewBackground() {
// Check if device is in dark mode (iOS 12+)
let isDarkMode: Bool

if #available(iOS 12.0, *) {
isDarkMode = traitCollection.userInterfaceStyle == .dark
} else {
// For iOS versions before 12.0,using light mode colors since dark mode wasn't officially supported
isDarkMode = false
}

contentView.backgroundColor = UIColor(hex: isDarkMode ? bgColorDark : bgColor)
}

func setUpConstraints() {
if itemViews.count == 0 {
// Add default alert view if no image is downloaded.
Expand Down Expand Up @@ -221,7 +274,7 @@ import UserNotificationsUI
}

func createDefaultAlertView() {
let itemComponents = CaptionedImageViewComponents(caption: templateCaption, subcaption: templateSubcaption, imageUrl: "", actionUrl: deeplinkURL, bgColor: bgColor, captionColor: captionColor, subcaptionColor: subcaptionColor)
let itemComponents = CaptionedImageViewComponents(caption: templateCaption, subcaption: templateSubcaption, imageUrl: "", actionUrl: deeplinkURL, bgColor: bgColor, captionColor: captionColor, subcaptionColor: subcaptionColor, bgColorDark: bgColorDark, captionColorDark: captionColorDark, subcaptionColorDark: subcaptionColorDark)
let itemView = CTCaptionedImageView(components: itemComponents)
itemViews.append(itemView)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ struct CarouselProperties: Decodable {
let pt_bg: String?
let pt_title_clr: String?
let pt_msg_clr: String?
let pt_bg_dark: String?
let pt_title_clr_dark: String?
let pt_msg_clr_dark: String?
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fileprivate enum Constants {
action = self!.deeplinkURL
}

let itemComponents = CaptionedImageViewComponents(caption: title, subcaption: subTiltle, imageUrl: item.imageUrl, actionUrl: action, bgColor: ConstantKeys.kDefaultColor, captionColor: ConstantKeys.kHexBlackColor, subcaptionColor: ConstantKeys.kHexLightGrayColor)
let itemComponents = CaptionedImageViewComponents(caption: title, subcaption: subTiltle, imageUrl: item.imageUrl, actionUrl: action, bgColor: ConstantKeys.kDefaultColor, captionColor: ConstantKeys.kHexBlackColor, subcaptionColor: ConstantKeys.kHexLightGrayColor, bgColorDark: ConstantKeys.kDefaultColorDark, captionColorDark: ConstantKeys.kHexWhiteColor, subcaptionColorDark: ConstantKeys.kHexDarkGrayColor)
let itemView = CTCaptionedImageView(components: itemComponents)
self?.itemViews.append(itemView)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,32 @@ import UserNotificationsUI
@IBOutlet weak var smallImageBtn2: UIImageView!
@IBOutlet weak var smallImageBtn3: UIImageView!

// Light mode colors
var bgColor: String = ConstantKeys.kDefaultColor
var titleColor: String = ConstantKeys.kHexBlackColor
var productDisplayActionColor: String = ConstantKeys.kHexLightGrayColor
var productDisplayActionTextColor: String = ConstantKeys.kHexBlackColor

// Dark mode colors
var bgColorDark: String = ConstantKeys.kHexBlackColor
var titleColorDark: String = ConstantKeys.kDefaultColor
var productDisplayActionColorDark: String = ConstantKeys.kHexBlackColor
var productDisplayActionTextColorDark: String = ConstantKeys.kDefaultColor

public override func viewDidLoad() {
super.viewDidLoad()

self.addGestureReconizerToImageView()
createView()
// Do any additional setup after loading the view.

// Register for trait changes on iOS 17+
if #available(iOS 17.0, *) {
registerForTraitChanges([UITraitUserInterfaceStyle.self]) { (self: Self, previousTraitCollection: UITraitCollection) in
if self.traitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle {
self.updateInterfaceColors()
}
}
}
}

func addGestureReconizerToImageView(){
Expand Down Expand Up @@ -120,10 +140,63 @@ import UserNotificationsUI
self.priceLabel.text = jsonContent.pt_bt1
self.buyBtnOutlet.setTitle(jsonContent.pt_product_display_action, for: .normal)

view.backgroundColor = UIColor(hex: jsonContent.pt_bg ?? "")
// Set light mode colors
if let bg = jsonContent.pt_bg, !bg.isEmpty {
bgColor = bg
}
if let titleClr = jsonContent.pt_title_clr, !titleClr.isEmpty {
titleColor = titleClr
}
if let actionColor = jsonContent.pt_product_display_action_clr, !actionColor.isEmpty {
productDisplayActionColor = actionColor
}
if let actionTextColor = jsonContent.pt_product_display_action_text_clr, !actionTextColor.isEmpty {
productDisplayActionTextColor = actionTextColor
}

// Handle dark mode colors
if let bgDark = jsonContent.pt_bg_dark, !bgDark.isEmpty {
bgColorDark = bgDark
}
if let titleClrDark = jsonContent.pt_title_clr_dark, !titleClrDark.isEmpty {
titleColorDark = titleClrDark
}
if let actionColorDark = jsonContent.pt_product_display_action_clr_dark, !actionColorDark.isEmpty {
productDisplayActionColorDark = actionColorDark
}
if let actionTextColorDark = jsonContent.pt_product_display_action_text_clr_dark, !actionTextColorDark.isEmpty {
productDisplayActionTextColorDark = actionTextColorDark
}

updateInterfaceColors()
}

@objc public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)

// Handle trait changes, for iOS 17+ it is handled by registerForTraitChanges.
if #available(iOS 12.0, *) {
if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
updateInterfaceColors()
}
}
}

buyBtnOutlet.backgroundColor = UIColor(hex: jsonContent.pt_product_display_action_clr ?? "")

func updateInterfaceColors() {
// Check if device is in dark mode (iOS 12+)
let isDarkMode: Bool

if #available(iOS 12.0, *) {
isDarkMode = traitCollection.userInterfaceStyle == .dark
} else {
// For iOS versions before 12.0, using light mode colors since dark mode wasn't officially supported
isDarkMode = false
}

view.backgroundColor = UIColor(hex: isDarkMode ? bgColorDark : bgColor)
priceLabel.textColor = UIColor(hex: isDarkMode ? titleColorDark : titleColor)
buyBtnOutlet.backgroundColor = UIColor(hex: isDarkMode ? productDisplayActionColorDark : productDisplayActionColor)
buyBtnOutlet.setTitleColor(UIColor(hex: isDarkMode ? productDisplayActionTextColorDark : productDisplayActionTextColor), for: .normal)
}

@objc public override func handleAction(_ action: String) -> UNNotificationContentExtensionResponseOption {
Expand Down
Loading