diff --git a/Extension App/ContentExtension/Info.plist b/Extension App/ContentExtension/Info.plist
index 671bd94..337085a 100644
--- a/Extension App/ContentExtension/Info.plist
+++ b/Extension App/ContentExtension/Info.plist
@@ -1,26 +1,26 @@
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- ContentExtension
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- XPC!
- CFBundleShortVersionString
- 1.0
- CFBundleVersion
- 1
- NSExtension
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ ContentExtension
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ NSExtension
NSExtensionAttributes
@@ -30,19 +30,27 @@
WEG_CAROUSEL_V1
WEG_RATING_V1
+ WEG_RICH_V1
+ WEG_RICH_V2
+ WEG_RICH_V3
+ WEG_RICH_V4
+ WEG_RICH_V5
+ WEG_RICH_V6
+ WEG_RICH_V7
+ WEG_RICH_V8
UNNotificationExtensionInitialContentSizeRatio
- 1
+ 1
NSExtensionMainStoryboard
MainInterface
NSExtensionPointIdentifier
com.apple.usernotifications.content-extension
- NSAppTransportSecurity
-
- NSAllowsArbitraryLoads
-
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
-
diff --git a/Extension App/WEGExtensionApp.xcodeproj/project.pbxproj b/Extension App/WEGExtensionApp.xcodeproj/project.pbxproj
index a7e32a4..36a5f29 100644
--- a/Extension App/WEGExtensionApp.xcodeproj/project.pbxproj
+++ b/Extension App/WEGExtensionApp.xcodeproj/project.pbxproj
@@ -62,6 +62,14 @@
56A49FB8EB9E003121E4C723 /* Pods-WEGExtensionApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WEGExtensionApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WEGExtensionApp/Pods-WEGExtensionApp.debug.xcconfig"; sourceTree = ""; };
8167C6E259A361F9B2183151 /* libPods-WEGExtensionApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WEGExtensionApp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
8288374F4CC9F6A69DC1929F /* Pods-ContentExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ContentExtension/Pods-ContentExtension.debug.xcconfig"; sourceTree = ""; };
+ A67089DF27A019E200DF27AC /* UIColor+DarkMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIColor+DarkMode.h"; sourceTree = ""; };
+ A67089E027A019EF00DF27AC /* UIColor+DarkMode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIColor+DarkMode.m"; sourceTree = ""; };
+ A693721927C0134F00045C60 /* WEXTextPushNotificationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WEXTextPushNotificationViewController.h; sourceTree = ""; };
+ A693721A27C0135D00045C60 /* WEXTextPushNotificationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WEXTextPushNotificationViewController.m; sourceTree = ""; };
+ A6DDEE99279A7A8D007FADE1 /* NSMutableAttributedString+Additions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSMutableAttributedString+Additions.h"; sourceTree = ""; };
+ A6DDEE9A279A7B22007FADE1 /* NSMutableAttributedString+Additions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSMutableAttributedString+Additions.m"; sourceTree = ""; };
+ A6F5D066278D6EA1005A96AA /* WEXBannerPushNotificationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WEXBannerPushNotificationViewController.h; sourceTree = ""; };
+ A6F5D067278D6EAE005A96AA /* WEXBannerPushNotificationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WEXBannerPushNotificationViewController.m; sourceTree = ""; };
B554331A99838E3647290F86 /* Pods-ServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ServiceExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ServiceExtension/Pods-ServiceExtension.debug.xcconfig"; sourceTree = ""; };
BF5C12043F19FA4C36D82355 /* Pods-WEGExtensionApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WEGExtensionApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-WEGExtensionApp/Pods-WEGExtensionApp.release.xcconfig"; sourceTree = ""; };
CF34E9CCD03C284D4C70479B /* Pods-ContentExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ContentExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-ContentExtension/Pods-ContentExtension.release.xcconfig"; sourceTree = ""; };
@@ -265,6 +273,14 @@
EC9A3DBA21B6B15300C63B7D /* WEXRichPushNotificationViewController.h */,
EC9A3DB721B6B15300C63B7D /* WEXRichPushNotificationViewController.m */,
EC9A3DB521B6B15300C63B7D /* WEXRichPushNotificationViewController+Private.h */,
+ A6F5D066278D6EA1005A96AA /* WEXBannerPushNotificationViewController.h */,
+ A6F5D067278D6EAE005A96AA /* WEXBannerPushNotificationViewController.m */,
+ A6DDEE99279A7A8D007FADE1 /* NSMutableAttributedString+Additions.h */,
+ A6DDEE9A279A7B22007FADE1 /* NSMutableAttributedString+Additions.m */,
+ A67089DF27A019E200DF27AC /* UIColor+DarkMode.h */,
+ A67089E027A019EF00DF27AC /* UIColor+DarkMode.m */,
+ A693721927C0134F00045C60 /* WEXTextPushNotificationViewController.h */,
+ A693721A27C0135D00045C60 /* WEXTextPushNotificationViewController.m */,
);
path = ContentExtension;
sourceTree = "";
diff --git a/Extension App/WEGExtensionApp/AppDelegate.swift b/Extension App/WEGExtensionApp/AppDelegate.swift
index e900faf..0c3a085 100644
--- a/Extension App/WEGExtensionApp/AppDelegate.swift
+++ b/Extension App/WEGExtensionApp/AppDelegate.swift
@@ -8,6 +8,7 @@
import UIKit
import WebEngage
+import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -15,12 +16,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
-
WebEngage.sharedInstance()?.application(application, didFinishLaunchingWithOptions: launchOptions, autoRegister: true)
-
- NSLog("Extension Demo app launched " + #function)
-
+ WebEngage.sharedInstance().user.login("ExtensionQWE1")
return true
}
}
-
diff --git a/Extension App/WEGExtensionApp/Info.plist b/Extension App/WEGExtensionApp/Info.plist
index 50aabe6..d08776d 100644
--- a/Extension App/WEGExtensionApp/Info.plist
+++ b/Extension App/WEGExtensionApp/Info.plist
@@ -53,7 +53,7 @@
WEGEnableLocationAuthorizationRequest
IN_USE
WEGLicenseCode
- 311c5607
+ d3a4a436
WEGLogLevel
VERBOSE
NSAppTransportSecurity
diff --git a/WebEngageAppEx.podspec b/WebEngageAppEx.podspec
index 527c4e2..46bf928 100644
--- a/WebEngageAppEx.podspec
+++ b/WebEngageAppEx.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |spec|
spec.name = 'WebEngageAppEx'
- spec.version = '0.12.0'
+ spec.version = '1.0.0'
spec.summary = 'App Extension Target SDK for WebEngage for Rich Push Notifications support.'
@@ -10,7 +10,7 @@ Pod::Spec.new do |spec|
DESC
spec.license = 'MIT'
- spec.author = 'Saumitra Bhave', 'Uzma Sayyed', 'Unmesh Rathod'
+ spec.author = 'Saumitra Bhave', 'Uzma Sayyed', 'Unmesh Rathod', 'Bhavesh Sarwar'
spec.homepage = 'https://webengage.com'
spec.social_media_url = 'http://twitter.com/webengage'
spec.documentation_url = 'https://docs.webengage.com/docs/ios-getting-started'
diff --git a/WebEngageAppEx/Classes/ContentExtension/NSMutableAttributedString+Additions.h b/WebEngageAppEx/Classes/ContentExtension/NSMutableAttributedString+Additions.h
new file mode 100644
index 0000000..76b791d
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/NSMutableAttributedString+Additions.h
@@ -0,0 +1,18 @@
+//
+// NSMutableAttributedString+Additions.h
+// WebEngage
+//
+// Copyright (c) 2017 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import
+
+@interface NSMutableAttributedString (Additions)
+
+- (void)updateDefaultTextColor;
+
+- (void)setFontFaceWithFont:(UIFont *)font;
+
+- (void)trimWhiteSpace;
+
+@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/NSMutableAttributedString+Additions.m b/WebEngageAppEx/Classes/ContentExtension/NSMutableAttributedString+Additions.m
new file mode 100644
index 0000000..531bb60
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/NSMutableAttributedString+Additions.m
@@ -0,0 +1,82 @@
+//
+// NSMutableAttributedString+Additions.m
+// WebEngage
+//
+// Copyright (c) 2017 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import
+#import "NSMutableAttributedString+Additions.h"
+#import "UIColor+DarkMode.h"
+
+@implementation NSMutableAttributedString (Additions)
+
+- (void)updateDefaultTextColor {
+ if (@available(iOS 13.0, *)) {
+ [self beginEditing];
+ [self enumerateAttribute:NSForegroundColorAttributeName
+ inRange:NSMakeRange(0, self.length)
+ options:0
+ usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
+
+ UIColor *color = (UIColor *)value;
+ UIColor *labelColor = [UIColor WEXLabelColor];
+ NSString *colorHex = [self hexStringFromColor:color];
+
+ if ([colorHex isEqualToString:@"000000"]) {
+ [self removeAttribute:NSForegroundColorAttributeName range:range];
+ [self addAttribute:NSForegroundColorAttributeName value:labelColor range:range];
+ }
+ }];
+ [self endEditing];
+ }
+}
+
+- (NSString *)hexStringFromColor:(UIColor *)color {
+ const CGFloat *components = CGColorGetComponents(color.CGColor);
+
+ CGFloat r = components[0];
+ CGFloat g = components[1];
+ CGFloat b = components[2];
+
+ return [NSString stringWithFormat:@"%02lX%02lX%02lX",
+ lroundf(r * 255),
+ lroundf(g * 255),
+ lroundf(b * 255)];
+}
+
+- (void)setFontFaceWithFont:(UIFont *)font {
+ [self beginEditing];
+ [self enumerateAttribute:NSFontAttributeName
+ inRange:NSMakeRange(0, self.length)
+ options:0
+ usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
+
+ UIFont *oldFont = (UIFont *)value;
+ UIFontDescriptor *newFontDescriptor = [[oldFont.fontDescriptor fontDescriptorWithFamily:font.familyName] fontDescriptorWithSymbolicTraits:oldFont.fontDescriptor.symbolicTraits];
+ UIFont *newFont = [UIFont fontWithDescriptor:newFontDescriptor size:font.pointSize];
+
+ if (newFont) {
+ [self removeAttribute:NSFontAttributeName range:range];
+ [self addAttribute:NSFontAttributeName value:newFont range:range];
+ }
+ }];
+ [self endEditing];
+}
+
+- (void)trimWhiteSpace {
+ NSCharacterSet *legalChars = [[NSCharacterSet whitespaceAndNewlineCharacterSet] invertedSet];
+ NSRange startRange = [self.string rangeOfCharacterFromSet: legalChars];
+ NSRange endRange = [self.string rangeOfCharacterFromSet: legalChars options:NSBackwardsSearch];
+ if (startRange.location == NSNotFound || endRange.location == NSNotFound) {
+ // there are no legal characters in self --- it is ALL whitespace, and so we 'trim' everything leaving an empty string
+ [self setAttributedString:[NSAttributedString new]];
+ }
+ else {
+ NSUInteger startLocation = NSMaxRange(startRange), endLocation = endRange.location;
+ NSRange range = NSMakeRange(startLocation - 1, endLocation - startLocation + 2);
+ [self setAttributedString:[self attributedSubstringFromRange:range]];
+ }
+}
+
+@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/UIColor+DarkMode.h b/WebEngageAppEx/Classes/ContentExtension/UIColor+DarkMode.h
new file mode 100644
index 0000000..551427d
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/UIColor+DarkMode.h
@@ -0,0 +1,22 @@
+//
+// UIColor+DarkMode.h
+// WebEngage
+//
+// Copyright (c) 2017 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import
+
+@interface UIColor (DarkMode)
+
++ (UIColor *)WEXWhiteColor;
+
++ (UIColor *)WEXGreyColor;
+
++ (UIColor *)WEXLabelColor;
+
++ (UIColor *)WEXLightTextColor;
+
++ (UIColor *)colorFromHexString:(NSString *)hexString defaultColor:(UIColor *)defaultColor;
+
+@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/UIColor+DarkMode.m b/WebEngageAppEx/Classes/ContentExtension/UIColor+DarkMode.m
new file mode 100644
index 0000000..2859dec
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/UIColor+DarkMode.m
@@ -0,0 +1,63 @@
+//
+// UIColor+DarkMode.m
+// WebEngage
+//
+// Copyright (c) 2017 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import
+#import "UIColor+DarkMode.h"
+
+@implementation UIColor (DarkMode)
+
++ (UIColor *)WEXWhiteColor {
+ if (@available(iOS 13.0, *)) {
+ return UIColor.systemBackgroundColor;
+ } else {
+ return UIColor.whiteColor;
+ }
+}
+
++ (UIColor *)WEXGreyColor {
+ if (@available(iOS 13.0, *)) {
+ return UIColor.systemGrayColor;
+ } else {
+ return UIColor.lightGrayColor;
+ }
+}
+
++ (UIColor *)WEXLabelColor {
+ if (@available(iOS 13.0, *)) {
+ return UIColor.labelColor;
+ } else {
+ return UIColor.blackColor;
+ }
+}
+
++ (UIColor *)WEXLightTextColor {
+ if (@available(iOS 13.0, *)) {
+ return UIColor.systemGray4Color;
+ } else {
+ return UIColor.lightTextColor;
+ }
+}
+
++ (UIColor *)colorFromHexString:(NSString *)hexString defaultColor:(UIColor *)defaultColor {
+ if (hexString == (id)[NSNull null] || hexString.length == 0) {
+ return defaultColor;
+ }
+
+ unsigned rgbValue = 0;
+ NSScanner *scanner = [NSScanner scannerWithString:hexString];
+
+ if ([hexString hasPrefix:@"#"]) {
+ [scanner setScanLocation:1]; // bypass '#' character
+ } else {
+ [scanner setScanLocation:0];
+ }
+
+ [scanner scanHexInt:&rgbValue];
+ return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
+}
+
+@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.h b/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.h
new file mode 100644
index 0000000..b82e6a3
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.h
@@ -0,0 +1,24 @@
+//
+// WEXBannerPushNotificationViewController.h
+// WebEngage
+//
+// Copyright (c) 2022 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+#import
+#import
+#import "WEXRichPushNotificationViewController+Private.h"
+#import "WEXRichPushLayout.h"
+#endif
+
+@interface WEXBannerPushNotificationViewController
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+: WEXRichPushLayout
+#else
+: NSObject
+#endif
+
+@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.m
new file mode 100644
index 0000000..030bb01
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXBannerPushNotificationViewController.m
@@ -0,0 +1,241 @@
+//
+// WEXBannerPushNotificationViewController.m
+// WebEngage
+//
+// Copyright (c) 2022 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import "WEXBannerPushNotificationViewController.h"
+#import "WEXRichPushNotificationViewController+Private.h"
+#import "UIColor+DarkMode.h"
+
+#define CONTENT_PADDING 10
+#define TITLE_BODY_SPACE 5
+#define LANDSCAPE_ASPECT 0.5
+
+API_AVAILABLE(ios(10.0))
+@interface WEXBannerPushNotificationViewController ()
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+
+@property (nonatomic) UNNotification *notification;
+
+#endif
+
+@end
+
+@implementation WEXBannerPushNotificationViewController
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+
+- (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios(10.0)) {
+ self.notification = notification;
+ [self initialiseViewHierarchy];
+}
+
+- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion{
+ completion(UNNotificationContentExtensionResponseOptionDismissAndForwardAction);
+}
+
+- (void)initialiseViewHierarchy {
+ self.view.backgroundColor = [UIColor WEXWhiteColor];
+
+ UIView *superViewWrapper = [[UIView alloc] init];
+ [self.view addSubview:superViewWrapper];
+
+ UIView *mainContentView = [[UIView alloc] init];
+ [superViewWrapper addSubview:mainContentView];
+
+ [self setupBannerImageView];
+}
+
+- (void)setupBannerImageView {
+ UIView *superViewWrapper = self.view.subviews[0];
+ UIView *mainContentView = superViewWrapper.subviews[0];
+
+ NSDictionary *expandableDetails = self.notification.request.content.userInfo[@"expandableDetails"];
+
+ UIImageView *imageView = [[UIImageView alloc] init];
+ if (expandableDetails[@"image"]) {
+ if (self.notification.request.content.attachments
+ && self.notification.request.content.attachments.count > 0) {
+
+ if (@available(iOS 10.0, *)) {
+ UNNotificationAttachment *attachment = self.notification.request.content.attachments.firstObject;
+
+ if ([attachment.URL startAccessingSecurityScopedResource]) {
+ NSData *imageData = [NSData dataWithContentsOfFile:attachment.URL.path];
+ UIImage *image = [UIImage imageWithData:imageData];
+
+ [attachment.URL stopAccessingSecurityScopedResource];
+
+ if (image) {
+ imageView.image = image;
+ } else {
+ NSLog(@"Image not present in cache!");
+ }
+ }
+ } else {
+ NSLog(@"Expected to be running iOS version 10 or above");
+ }
+ } else {
+ NSLog(@"Attachment not present for: %@", expandableDetails[@"image"]);
+ }
+ } else {
+ NSLog(@"Image not present in payload: %@", expandableDetails[@"image"]);
+ }
+
+ imageView.contentMode = UIViewContentModeScaleAspectFill;
+ [mainContentView addSubview:imageView];
+ [self setupLabelsContainer];
+}
+
+- (void)setupLabelsContainer {
+ UIView *superViewWrapper = self.view.subviews[0];
+ NSString *colorHex = self.notification.request.content.userInfo[@"expandableDetails"][@"bckColor"];
+
+ UIView *richContentView = [[UIView alloc] init];
+ richContentView.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXWhiteColor];
+
+ NSDictionary *expandedDetails = self.notification.request.content.userInfo[@"expandableDetails"];
+ NSString *title = expandedDetails[@"rt"];
+ NSString *subtitle = expandedDetails[@"rst"];
+ NSString *message = expandedDetails[@"rm"];
+
+ BOOL titlePresent = title && ![title isEqualToString:@""];
+ BOOL subTitlePresent = subtitle && ![subtitle isEqualToString:@""];
+ BOOL messagePresent = message && ![message isEqualToString:@""];
+
+ if (!titlePresent) {
+ title = self.notification.request.content.title;
+ }
+ if (!subTitlePresent) {
+ subtitle = self.notification.request.content.subtitle;
+ }
+ if (!messagePresent) {
+ message = self.notification.request.content.body;
+ }
+
+ UILabel *richTitleLabel = [[UILabel alloc] init];
+ richTitleLabel.attributedText = [self.viewController getHtmlParsedString:title isTitle:YES bckColor:colorHex];
+ richTitleLabel.textAlignment = [self.viewController naturalTextAligmentForText:richTitleLabel.text];
+
+ UILabel *richSubLabel = [[UILabel alloc] init];
+ richSubLabel.attributedText = [self.viewController getHtmlParsedString:subtitle isTitle:YES bckColor:colorHex];
+ richSubLabel.textAlignment = [self.viewController naturalTextAligmentForText:richSubLabel.text];
+
+ UILabel *richBodyLabel = [[UILabel alloc] init];
+ richBodyLabel.attributedText = [self.viewController getHtmlParsedString:message isTitle:NO bckColor:colorHex];
+ richBodyLabel.textAlignment = [self.viewController naturalTextAligmentForText:richBodyLabel.text];
+ richBodyLabel.numberOfLines = 0;
+
+ [richContentView addSubview:richTitleLabel];
+ [richContentView addSubview:richSubLabel];
+ [richContentView addSubview:richBodyLabel];
+
+ [superViewWrapper addSubview:richContentView];
+
+ [self setupConstraints];
+}
+
+- (void)setupConstraints {
+ UIView *superViewWrapper = self.view.subviews[0];
+ UIView *mainContentView = superViewWrapper.subviews[0];
+ UIView *richContentView = superViewWrapper.subviews[1];
+
+ if (@available(iOS 10.0, *)) {
+ superViewWrapper.translatesAutoresizingMaskIntoConstraints = NO;
+ [superViewWrapper.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
+ [superViewWrapper.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
+ [superViewWrapper.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
+ [superViewWrapper.bottomAnchor constraintEqualToAnchor:richContentView.bottomAnchor].active = YES;
+
+ //Top level view constraints
+ mainContentView.translatesAutoresizingMaskIntoConstraints = NO;
+ [mainContentView.leadingAnchor constraintEqualToAnchor:mainContentView.superview.leadingAnchor].active = YES;
+ [mainContentView.trailingAnchor constraintEqualToAnchor:mainContentView.superview.trailingAnchor].active = YES;
+ [mainContentView.topAnchor constraintEqualToAnchor:mainContentView.superview.topAnchor].active = YES;
+
+ richContentView.translatesAutoresizingMaskIntoConstraints = NO;
+ [richContentView.leadingAnchor constraintEqualToAnchor:richContentView.superview.leadingAnchor].active = YES;
+ [richContentView.trailingAnchor constraintEqualToAnchor:richContentView.superview.trailingAnchor].active = YES;
+ [richContentView.topAnchor constraintEqualToAnchor:mainContentView.bottomAnchor].active = YES;
+
+ [self.viewController.bottomLayoutGuide.topAnchor constraintEqualToAnchor:superViewWrapper.bottomAnchor].active = YES;
+
+ //Main Content View ImageView constraints
+ UIImageView *imageView = mainContentView.subviews[0];
+ imageView.translatesAutoresizingMaskIntoConstraints = NO;
+
+ UIImage *bannerImage = imageView.image;
+ CGFloat imageAspect = LANDSCAPE_ASPECT;
+ if (bannerImage && bannerImage.size.height != 0) {
+ imageAspect = bannerImage.size.height/bannerImage.size.width;
+ } else {
+ imageAspect = 0;
+ }
+
+ [imageView.topAnchor constraintEqualToAnchor:mainContentView.topAnchor].active = YES;
+ [imageView.leadingAnchor constraintEqualToAnchor:mainContentView.leadingAnchor].active = YES;
+ [imageView.trailingAnchor constraintEqualToAnchor:mainContentView.trailingAnchor].active = YES;
+ [imageView.heightAnchor constraintEqualToAnchor:imageView.widthAnchor multiplier:imageAspect].active = YES;
+ [mainContentView.bottomAnchor constraintEqualToAnchor:imageView.bottomAnchor].active = YES;
+
+ //Rich View labels
+ UIView *richTitleLabel = richContentView.subviews[0];
+ UIView *richSubTitleLabel = richContentView.subviews[1];
+ UIView *richBodyLabel = richContentView.subviews[2];
+
+ richTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richTitleLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richTitleLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richTitleLabel.topAnchor
+ constraintEqualToAnchor:richContentView.topAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+
+ richSubTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richSubTitleLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richSubTitleLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richSubTitleLabel.topAnchor
+ constraintEqualToAnchor:richTitleLabel.bottomAnchor
+ constant:0]
+ .active = YES;
+
+ richBodyLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richBodyLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richBodyLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richBodyLabel.topAnchor constraintEqualToAnchor:richSubTitleLabel.bottomAnchor
+ constant:0]
+ .active = YES;
+ [richBodyLabel.bottomAnchor
+ constraintEqualToAnchor:richContentView.bottomAnchor
+ constant:-CONTENT_PADDING]
+ .active = YES;
+ } else {
+ NSLog(@"Expected to be running iOS version 10 or above");
+ }
+}
+
+#endif
+
+@end
+
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m
index a86442f..8d1de2a 100644
--- a/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXCarouselPushNotificationViewController.m
@@ -8,6 +8,7 @@
#import "WEXCarouselPushNotificationViewController.h"
#import "WEXRichPushNotificationViewController+Private.h"
+#import "UIColor+DarkMode.h"
#define CONTENT_PADDING 10
#define TITLE_BODY_SPACE 5
@@ -38,6 +39,9 @@ @interface WEXCarouselPushNotificationViewController ()
@property (atomic) NSInteger nextViewIndexToReturn;
@property (atomic) BOOL isRendering;
+@property (nonatomic, readwrite) NSTimer *scrollTimer;
+@property (nonatomic, readwrite) BOOL shouldScroll;
+
#endif
@end
@@ -153,6 +157,8 @@ - (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios(
[self initialiseCarouselForNotification:notification];
+ [self setupAutoScroll:notification];
+
if (downloadedCount < self.carouselItems.count) {
[self downloadRemaining:downloadedCount];
@@ -182,6 +188,46 @@ - (void)downloadRemaining:(NSUInteger)downloadFromIndex {
}
}
+- (void)setupAutoScroll:(UNNotification *)notification API_AVAILABLE(ios(10.0)) {
+ NSString *scrollTime = notification.request.content.userInfo[@"expandableDetails"][@"ast"];
+
+ if (scrollTime == (id)[NSNull null] || scrollTime.length == 0) {
+ return;
+ }
+
+ [self.scrollTimer invalidate];
+ self.scrollTimer = nil;
+
+ float intervalInMili = [scrollTime floatValue];
+ float intervalSeconds = intervalInMili/1000.0;
+
+ // Scroll if interval is more than 0
+ if (intervalSeconds > 0) {
+ _shouldScroll = YES;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ self.scrollTimer = [NSTimer scheduledTimerWithTimeInterval:intervalSeconds
+ target:self
+ selector:@selector(scrollContent:)
+ userInfo:notification repeats:YES];
+ });
+ }
+}
+
+- (void)scrollContent:(NSTimer *)scrollTimer {
+ if (_shouldScroll) {
+ [self renderAnimated:(UNNotification *)[scrollTimer userInfo]];
+ } else {
+ [self stopScrollTimer];
+ }
+}
+
+- (void)stopScrollTimer {
+ if (self.scrollTimer) {
+ [self.scrollTimer invalidate];
+ self.scrollTimer = nil;
+ }
+}
+
- (void)initialiseCarouselForNotification:(UNNotification *)notification API_AVAILABLE(ios(10.0)) {
[self initialiseViewContainers];
@@ -197,6 +243,10 @@ - (void)initialiseCarouselForNotification:(UNNotification *)notification API_AVA
// for portrait
float superViewHeight = viewHeight + 2 * verticalMargins;
+ NSString *colorHex = notification.request.content.userInfo[@"expandableDetails"][@"bckColor"];
+ self.view.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXWhiteColor];
+ self.viewController.view.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXWhiteColor];
+
NSString *mode = notification.request.content.userInfo[@"expandableDetails"][@"mode"];
BOOL isPortrait = mode && [mode isEqualToString:@"portrait"];
@@ -240,10 +290,10 @@ - (void)initialiseCarouselForNotification:(UNNotification *)notification API_AVA
}
UIView *topSeparator = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, superViewWidth, 0.5)];
- topSeparator.backgroundColor = [UIColor lightGrayColor];
+ topSeparator.backgroundColor = [UIColor WEXGreyColor];
UIView *bottomSeparator = [[UIView alloc] initWithFrame:CGRectMake(0.0, superViewHeight - 0.5, superViewWidth, 0.5)];
- bottomSeparator.backgroundColor = [UIColor lightGrayColor];
+ bottomSeparator.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXGreyColor];
NSDictionary *extensionAttributes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSExtension"][@"NSExtensionAttributes"];
@@ -254,23 +304,43 @@ - (void)initialiseCarouselForNotification:(UNNotification *)notification API_AVA
if (defaultContentHidden) {
+ NSString *title = notification.request.content.userInfo[@"expandableDetails"][@"rt"];
+ NSString *subtitle = notification.request.content.userInfo[@"expandableDetails"][@"rst"];
+ NSString *message = notification.request.content.userInfo[@"expandableDetails"][@"rm"];
+
+ BOOL isRichTitle = title && ![title isEqualToString:@""];
+ BOOL isRichSubtitle = subtitle && ![subtitle isEqualToString:@""];
+ BOOL isRichMessage = message && ![message isEqualToString:@""];
+
+ if (!isRichTitle) {
+ title = self.notification.request.content.title;
+ }
+ if (!isRichSubtitle) {
+ subtitle = self.notification.request.content.subtitle;
+ }
+ if (!isRichMessage) {
+ message = self.notification.request.content.body;
+ }
+
// Add a notification content view for displaying title and body.
UIView *notificationContentView = [[UIView alloc] init];
- notificationContentView.backgroundColor = [UIColor whiteColor];
+ notificationContentView.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXWhiteColor];
UILabel *titleLabel = [[UILabel alloc] init];
- titleLabel.text = notification.request.content.title;
- titleLabel.textColor = [UIColor blackColor];
- titleLabel.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
+ titleLabel.attributedText = [self.viewController getHtmlParsedString:title isTitle:YES bckColor:colorHex];
titleLabel.textAlignment = [self.viewController naturalTextAligmentForText:titleLabel.text];
+ UILabel *subTitleLabel = [[UILabel alloc] init];
+ subTitleLabel.attributedText = [self.viewController getHtmlParsedString:subtitle isTitle:YES bckColor:colorHex];
+ subTitleLabel.textAlignment = [self.viewController naturalTextAligmentForText:titleLabel.text];
+
UILabel *bodyLabel = [[UILabel alloc] init];
- bodyLabel.text = notification.request.content.body;
- bodyLabel.textColor = [UIColor blackColor];
+ bodyLabel.attributedText = [self.viewController getHtmlParsedString:message isTitle:NO bckColor:colorHex];
bodyLabel.textAlignment = [self.viewController naturalTextAligmentForText:bodyLabel.text];
bodyLabel.numberOfLines = 0;
[notificationContentView addSubview:titleLabel];
+ [notificationContentView addSubview:subTitleLabel];
[notificationContentView addSubview:bodyLabel];
[self.view addSubview:notificationContentView];
@@ -306,6 +376,20 @@ - (void)initialiseCarouselForNotification:(UNNotification *)notification API_AVA
constant:CONTENT_PADDING]
.active = YES;
+ subTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [subTitleLabel.leadingAnchor
+ constraintEqualToAnchor:notificationContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [subTitleLabel.trailingAnchor
+ constraintEqualToAnchor:notificationContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [subTitleLabel.topAnchor
+ constraintEqualToAnchor:titleLabel.bottomAnchor
+ constant:0]
+ .active = YES;
+
bodyLabel.translatesAutoresizingMaskIntoConstraints = NO;
[bodyLabel.leadingAnchor
constraintEqualToAnchor:notificationContentView.leadingAnchor
@@ -315,8 +399,8 @@ - (void)initialiseCarouselForNotification:(UNNotification *)notification API_AVA
constraintEqualToAnchor:notificationContentView.trailingAnchor
constant:0 - CONTENT_PADDING]
.active = YES;
- [bodyLabel.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor
- constant:TITLE_BODY_SPACE]
+ [bodyLabel.topAnchor constraintEqualToAnchor:subTitleLabel.bottomAnchor
+ constant:0]
.active = YES;
[bodyLabel.bottomAnchor
constraintEqualToAnchor:notificationContentView.bottomAnchor
@@ -497,7 +581,7 @@ - (void)slideLeft:(UIView *)view By:(CGFloat)slide {
- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response
completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion API_AVAILABLE(ios(10.0)) {
-
+ NSLog(@"PUSHDEBUG: ResponseClicked: %@", response.actionIdentifier);
BOOL dismissed = NO;
if (self.isRendering) {
@@ -505,7 +589,7 @@ - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response
}
if ([response.actionIdentifier isEqualToString:@"WEG_NEXT"]) {
-
+ _shouldScroll = NO;
[self renderAnimated:response.notification];
} else if ([response.actionIdentifier isEqualToString:@"WEG_PREV"]) {
@@ -564,6 +648,8 @@ - (UIView *)viewAtPosition:(NSInteger)index {
self.notification.request.content.userInfo[@"expandableDetails"][@"mode"];
BOOL isPortrait = mode && [mode isEqualToString:@"portrait"];
+ NSString *colorHex = self.notification.request.content.userInfo[@"expandableDetails"][@"bckColor"];
+
if (!isPortrait) {
viewWidth = superViewWidth;
viewHeight = viewWidth * LANDSCAPE_ASPECT;
@@ -574,7 +660,7 @@ - (UIView *)viewAtPosition:(NSInteger)index {
UIView *viewContainer = viewToReturn;
UIImage *image = self.images[index];
- viewContainer.backgroundColor = [UIColor lightGrayColor];
+ viewContainer.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXGreyColor];
UIImageView *imageView = self.imageViews[cachedViewIndex];
imageView.frame = CGRectMake(0.0, 0.0, viewWidth, viewHeight);
@@ -592,7 +678,7 @@ - (UIView *)viewAtPosition:(NSInteger)index {
viewWidth, descriptionViewHeight);
descriptionView.alpha = DESCRIPTION_VIEW_ALPHA;
- descriptionView.backgroundColor = [UIColor whiteColor];
+ descriptionView.backgroundColor = [UIColor WEXWhiteColor];
UILabel *descriptionLabel = self.descriptionLabels[cachedViewIndex];
descriptionLabel.frame =
@@ -601,7 +687,7 @@ - (UIView *)viewAtPosition:(NSInteger)index {
descriptionLabel.text = carouselItem[@"actionText"];
descriptionLabel.textAlignment = NSTextAlignmentCenter;
- descriptionLabel.textColor = [UIColor blackColor];
+ descriptionLabel.textColor = [UIColor WEXLabelColor];
[descriptionView addSubview:descriptionLabel];
@@ -616,7 +702,7 @@ - (UIView *)viewAtPosition:(NSInteger)index {
UIView *alphaView = self.alphaViews[cachedViewIndex];
alphaView.frame = CGRectMake(0.0, 0.0, viewWidth, viewHeight);
alphaView.alpha = 0.0;
- alphaView.backgroundColor = [UIColor whiteColor];
+ alphaView.backgroundColor = [UIColor WEXWhiteColor];
[viewContainer addSubview:alphaView];
}
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.h b/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.h
index 4e25ec9..4e93d3e 100644
--- a/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.h
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.h
@@ -14,6 +14,8 @@
#import "WEXRichPushLayout.h"
#endif
+#define CONTENT_PADDING 10
+#define TITLE_BODY_SPACE 5
@interface WEXRatingPushNotificationViewController
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m
index 89b918f..0e315f8 100644
--- a/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXRatingPushNotificationViewController.m
@@ -7,6 +7,7 @@
#import "WEXRatingPushNotificationViewController.h"
+#import "UIColor+DarkMode.h"
//#define NO_OF_STARS 5
#define STAR_BAR_HEIGHT 50
@@ -120,7 +121,7 @@ @implementation WEXRatingPushNotificationViewController
- (void)initialiseViewHierarchy {
- self.view.backgroundColor = [UIColor yellowColor];
+ self.view.backgroundColor = [UIColor WEXWhiteColor];
UIView *superViewWrapper = [[UIView alloc] init];
@@ -179,13 +180,11 @@ - (void)initialiseViewHierarchy {
textDisplayView.opaque = NO;
textDisplayView.backgroundColor = [UIColor clearColor];
} else {
-
if (bckColor) {
- textDisplayView.backgroundColor = [self colorWithHexString:bckColor];
+ textDisplayView.backgroundColor = [UIColor colorFromHexString:bckColor defaultColor:UIColor.WEXLightTextColor];
} else {
- textDisplayView.backgroundColor = [UIColor lightTextColor];
+ textDisplayView.backgroundColor = UIColor.WEXLightTextColor;
}
-
}
UILabel *titleLabel;
@@ -206,9 +205,9 @@ - (void)initialiseViewHierarchy {
titleLabel.text = title;
titleLabel.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
if (textColor) {
- titleLabel.textColor = [self colorWithHexString:textColor];
+ titleLabel.textColor = [UIColor colorFromHexString:textColor defaultColor:UIColor.WEXLabelColor];
} else {
- titleLabel.textColor = [UIColor blackColor];
+ titleLabel.textColor = UIColor.WEXLabelColor;
}
[textDisplayView addSubview:titleLabel];
@@ -220,9 +219,9 @@ - (void)initialiseViewHierarchy {
messageLabel.text = message;
if (textColor) {
- messageLabel.textColor = [self colorWithHexString:textColor];
+ messageLabel.textColor = [UIColor colorFromHexString:textColor defaultColor:UIColor.WEXLabelColor];
} else {
- messageLabel.textColor = [UIColor blackColor];
+ messageLabel.textColor = UIColor.WEXLabelColor;
}
messageLabel.numberOfLines = 3;
@@ -232,14 +231,63 @@ - (void)initialiseViewHierarchy {
[mainContentView addSubview:textDisplayView];
+ //TODO: Add conditions for lack of rich texts
+
+ UIView *contentSeparator = [[UIView alloc] init];
+ contentSeparator.backgroundColor = UIColor.WEXGreyColor;
+
+ [superViewWrapper addSubview:contentSeparator];
+
+ NSString *richTitle = self.notification.request.content.userInfo[@"expandableDetails"][@"rt"];
+ NSString *richSub = self.notification.request.content.userInfo[@"expandableDetails"][@"rst"];
+ NSString *richMessage = self.notification.request.content.userInfo[@"expandableDetails"][@"rm"];
+
+ BOOL isRichTitle = richTitle && ![richTitle isEqualToString:@""];
+ BOOL isRichSubtitle = richSub && ![richSub isEqualToString:@""];
+ BOOL isRichMessage = richMessage && ![richMessage isEqualToString:@""];
+
+ if (!isRichTitle) {
+ richTitle = self.notification.request.content.title;
+ }
+ if (!isRichSubtitle) {
+ richSub = self.notification.request.content.subtitle;
+ }
+ if (!isRichMessage) {
+ richMessage = self.notification.request.content.body;
+ }
+
+ NSString *colorHex = self.notification.request.content.userInfo[@"expandableDetails"][@"bckColor"];
+
+ // Add a notification content view for displaying title and body.
+ UIView *richContentView = [[UIView alloc] init];
+ richContentView.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXWhiteColor];
+
+ UILabel *richTitleLabel = [[UILabel alloc] init];
+ richTitleLabel.attributedText = [self.viewController getHtmlParsedString:richTitle isTitle:YES bckColor:colorHex];
+ richTitleLabel.textAlignment = [self.viewController naturalTextAligmentForText:richTitleLabel.text];
+
+ UILabel *richSubLabel = [[UILabel alloc] init];
+ richSubLabel.attributedText = [self.viewController getHtmlParsedString:richSub isTitle:YES bckColor:colorHex];
+ richSubLabel.textAlignment = [self.viewController naturalTextAligmentForText:richSubLabel.text];
+
+ UILabel *richBodyLabel = [[UILabel alloc] init];
+ richBodyLabel.attributedText = [self.viewController getHtmlParsedString:richMessage isTitle:NO bckColor:colorHex];
+ richBodyLabel.textAlignment = [self.viewController naturalTextAligmentForText:richBodyLabel.text];
+ richBodyLabel.numberOfLines = 0;
+
+ [richContentView addSubview:richTitleLabel];
+ [richContentView addSubview:richSubLabel];
+ [richContentView addSubview:richBodyLabel];
+
+ [superViewWrapper addSubview:richContentView];
+
UIView *separator = [[UIView alloc] init];
- separator.backgroundColor = [UIColor lightGrayColor];
+ separator.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXGreyColor];
[superViewWrapper addSubview:separator];
UIView *starRatingView = [[UIView alloc] init];
- starRatingView.backgroundColor = [UIColor whiteColor];
-
+ starRatingView.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXWhiteColor];
self.labelsWrapper = [[UIView alloc] init];
self.unselectedLabel = [[UILabel alloc] init];
@@ -305,7 +353,7 @@ - (void)renderStarControl {
self.unselectedLabel.text = starStringUnselected;
- self.unselectedLabel.textColor = [UIColor lightGrayColor];
+ self.unselectedLabel.textColor = UIColor.WEXGreyColor;
self.unselectedLabel.font = [self.unselectedLabel.font fontWithSize:STAR_FONT_SIZE];
}
@@ -315,9 +363,11 @@ - (void)setUpConstraintsWithImageView:(BOOL)imageViewIncluded
UIView *superViewWrapper = self.view.subviews[0];
UIView *mainContentView = superViewWrapper.subviews[0];
- UIView *separator = superViewWrapper.subviews[1];
- UIView *starRatingWrapper = superViewWrapper.subviews[2];
-
+ UIView *contentSeparator = superViewWrapper.subviews[1];
+ UIView *richContentView = superViewWrapper.subviews[2];
+ UIView *separator = superViewWrapper.subviews[3];
+ UIView *starRatingWrapper = superViewWrapper.subviews[4];
+
if (@available(iOS 10.0, *)) {
superViewWrapper.translatesAutoresizingMaskIntoConstraints = NO;
@@ -332,10 +382,21 @@ - (void)setUpConstraintsWithImageView:(BOOL)imageViewIncluded
[mainContentView.trailingAnchor constraintEqualToAnchor:mainContentView.superview.trailingAnchor].active = YES;
[mainContentView.topAnchor constraintEqualToAnchor:mainContentView.superview.topAnchor].active = YES;
+ contentSeparator.translatesAutoresizingMaskIntoConstraints = NO;
+ [contentSeparator.leadingAnchor constraintEqualToAnchor:contentSeparator.superview.leadingAnchor].active = YES;
+ [contentSeparator.trailingAnchor constraintEqualToAnchor:contentSeparator.superview.trailingAnchor].active = YES;
+ [contentSeparator.topAnchor constraintEqualToAnchor:mainContentView.bottomAnchor].active = YES;
+ [contentSeparator.heightAnchor constraintEqualToConstant:0.5].active = YES;
+
+ richContentView.translatesAutoresizingMaskIntoConstraints = NO;
+ [richContentView.leadingAnchor constraintEqualToAnchor:richContentView.superview.leadingAnchor].active = YES;
+ [richContentView.trailingAnchor constraintEqualToAnchor:richContentView.superview.trailingAnchor].active = YES;
+ [richContentView.topAnchor constraintEqualToAnchor:contentSeparator.bottomAnchor].active = YES;
+
separator.translatesAutoresizingMaskIntoConstraints = NO;
[separator.leadingAnchor constraintEqualToAnchor:separator.superview.leadingAnchor].active = YES;
[separator.trailingAnchor constraintEqualToAnchor:separator.superview.trailingAnchor].active = YES;
- [separator.topAnchor constraintEqualToAnchor:mainContentView.bottomAnchor].active = YES;
+ [separator.topAnchor constraintEqualToAnchor:richContentView.bottomAnchor].active = YES;
[separator.heightAnchor constraintEqualToConstant:0.5].active = YES;
starRatingWrapper.translatesAutoresizingMaskIntoConstraints = NO;
@@ -405,6 +466,57 @@ - (void)setUpConstraintsWithImageView:(BOOL)imageViewIncluded
[messageLabel.bottomAnchor constraintEqualToAnchor:textDisplayView.bottomAnchor constant:0-TEXT_PADDING].active = YES;
}
+ // Rich View labels
+
+ UIView *richTitleLabel = richContentView.subviews[0];
+ UIView *richSubTitleLabel = richContentView.subviews[1];
+ UIView *richBodyLabel = richContentView.subviews[2];
+
+ richTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richTitleLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richTitleLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richTitleLabel.topAnchor
+ constraintEqualToAnchor:richContentView.topAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+
+ richSubTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richSubTitleLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richSubTitleLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richSubTitleLabel.topAnchor
+ constraintEqualToAnchor:richTitleLabel.bottomAnchor
+ constant:0]
+ .active = YES;
+
+ richBodyLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richBodyLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richBodyLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richBodyLabel.topAnchor constraintEqualToAnchor:richSubTitleLabel.bottomAnchor
+ constant:0]
+ .active = YES;
+ [richBodyLabel.bottomAnchor
+ constraintEqualToAnchor:richContentView.bottomAnchor
+ constant:-CONTENT_PADDING]
+ .active = YES;
+
//Star rating view internal constraints
self.labelsWrapper.translatesAutoresizingMaskIntoConstraints = NO;
[self.labelsWrapper.topAnchor constraintEqualToAnchor:self.labelsWrapper.superview.topAnchor].active = YES;
@@ -438,7 +550,7 @@ - (UIView *)inputAccessoryView {
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, 50);
UIView *inputAccessoryView = [[UIView alloc] initWithFrame:frame];
- inputAccessoryView.backgroundColor = [UIColor lightTextColor];
+ inputAccessoryView.backgroundColor = UIColor.WEXLightTextColor;
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem];
NSAttributedString *attrTitle = [[NSAttributedString alloc] initWithString:@"Done"
@@ -446,7 +558,7 @@ - (UIView *)inputAccessoryView {
NSUnderlineStyleAttributeName:
[NSNumber numberWithInt:NSUnderlineStyleNone],
NSFontAttributeName: [UIFont boldSystemFontOfSize:20],
- NSForegroundColorAttributeName: [self colorWithHexString:@"0077cc"]
+ NSForegroundColorAttributeName: [UIColor colorFromHexString:@"0077cc" defaultColor:UIColor.blueColor]
}];
[doneButton setAttributedTitle:attrTitle forState:UIControlStateNormal];
@@ -563,19 +675,6 @@ - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response comple
}
}
-- (UIColor *)colorWithHexString:(NSString *)hexString {
-
- unsigned rgbValue = 0;
- NSScanner *scanner = [NSScanner scannerWithString:hexString];
- [scanner setScanLocation:1]; // bypass '#' character
- [scanner scanHexInt:&rgbValue];
-
- return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
- green:((rgbValue & 0xFF00) >> 8)/255.0
- blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
-}
-
-
#endif
@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h
index 8d2d3b4..655063d 100644
--- a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController+Private.h
@@ -26,6 +26,8 @@
- (NSTextAlignment)naturalTextAligmentForText:(NSString*) text;
+- (NSAttributedString *)getHtmlParsedString:(NSString *)textString isTitle:(BOOL)isTitle bckColor:(NSString *)bckColor;
+
#endif
@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m
index a0a963c..3712cad 100644
--- a/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXRichPushNotificationViewController.m
@@ -9,10 +9,12 @@
#import "WEXRichPushNotificationViewController+Private.h"
#import "WEXCarouselPushNotificationViewController.h"
#import "WEXRatingPushNotificationViewController.h"
+#import "WEXBannerPushNotificationViewController.h"
+#import "WEXTextPushNotificationViewController.h"
#import "WEXRichPushLayout.h"
#import
#import
-
+#import "NSMutableAttributedString+Additions.h"
API_AVAILABLE(ios(10.0))
@interface WEXRichPushNotificationViewController ()
@@ -25,6 +27,7 @@ @interface WEXRichPushNotificationViewController ()
@property (nonatomic) NSUserDefaults *richPushDefaults;
@property (atomic) BOOL isRendering;
+@property (atomic) BOOL isDarkMode;
#endif
@@ -85,6 +88,7 @@ - (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios
self.notification = notification;
self.isRendering = YES;
+ [self updateDarkModeStatus];
NSString *appGroup = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"WEX_APP_GROUP"];
@@ -126,8 +130,11 @@ - (WEXRichPushLayout *)layoutForStyle:(NSString *)style {
return [[WEXCarouselPushNotificationViewController alloc] initWithNotificationViewController:self];
} else if (style && [style isEqualToString:@"RATING_V1"]) {
return [[WEXRatingPushNotificationViewController alloc] initWithNotificationViewController:self];
+ } else if (style && [style isEqualToString:@"BIG_PICTURE"]) {
+ return [[WEXBannerPushNotificationViewController alloc] initWithNotificationViewController:self];
+ } else if (style && [style isEqualToString:@"BIG_TEXT"]) {
+ return [[WEXTextPushNotificationViewController alloc] initWithNotificationViewController:self];
}
-
return nil;
}
@@ -136,6 +143,10 @@ - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response comple
[self.currentLayout didReceiveNotificationResponse:response completionHandler:completion];
}
+- (void)traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {
+ [super traitCollectionDidChange: previousTraitCollection];
+ [self updateDarkModeStatus];
+}
- (NSMutableDictionary *) getActivityDictionaryForCurrentNotification {
@@ -215,9 +226,9 @@ - (void)addEventWithName:(NSString *)eventName
if ([category isEqualToString:@"system"]) {
[WEXAnalytics trackEventWithName:[@"we_" stringByAppendingString:eventName]
andValue:@{
- @"system_data_overrides": systemData ? systemData : @{},
- @"event_data_overrides": customDataDictionary
- }];
+ @"system_data_overrides": systemData ? systemData : @{},
+ @"event_data_overrides": customDataDictionary
+ }];
} else {
[WEXAnalytics trackEventWithName:eventName andValue:customDataDictionary];
}
@@ -230,7 +241,11 @@ - (void)setCTAWithId:(NSString *)ctaId andLink:(NSString *)actionLink {
[self updateActivityWithObject:cta forKey:@"cta"];
}
-- (NSTextAlignment)naturalTextAligmentForText:(NSString*) text{
+- (NSTextAlignment)naturalTextAligmentForText:(NSString*)text {
+ if (text == (id)[NSNull null] || text.length == 0 ) {
+ return NSTextAlignmentLeft;
+ }
+
NSArray *tagschemes = [NSArray arrayWithObjects:NSLinguisticTagSchemeLanguage, nil];
NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:tagschemes options:0];
[tagger setString:text];
@@ -242,6 +257,76 @@ - (NSTextAlignment)naturalTextAligmentForText:(NSString*) text{
}
}
+- (NSAttributedString *)getHtmlParsedString:(NSString *)textString isTitle:(BOOL)isTitle bckColor:(NSString *)bckColor {
+ BOOL containsHTML = [self containsHTML:textString];
+ NSString *inputString = textString;
+
+ // Updating font attributes overrides Italic characteristic
+ // Adding extra tags makes more sense
+ if (containsHTML && isTitle) {
+ inputString = [NSString stringWithFormat: @"%@", textString];
+ }
+
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
+ initWithData: [inputString dataUsingEncoding:NSUnicodeStringEncoding]
+ options: @{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
+ documentAttributes: nil
+ error: nil
+ ];
+
+ BOOL hasBckColor = bckColor && ![bckColor isEqualToString:@""];
+ if (!hasBckColor && _isDarkMode) {
+ [attributedString updateDefaultTextColor];
+ }
+
+ BOOL containsFontSize = [inputString rangeOfString:@"font-size"].location != NSNotFound;
+
+ UIFont *defaultFont = [UIFont systemFontOfSize:[UIFont labelFontSize]];
+ UIFont *boldFont = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
+
+ /*
+ If html string doesn't contain font-size,
+ then setting default based on title position
+ */
+
+ if (containsHTML && containsFontSize == NO) {
+ if (isTitle) {
+ [attributedString setFontFaceWithFont:boldFont];
+ } else {
+ [attributedString setFontFaceWithFont:defaultFont];
+ }
+ [attributedString trimWhiteSpace];
+
+ } else if (containsHTML == NO) {
+ if (isTitle) {
+ [attributedString addAttribute:NSFontAttributeName value:boldFont range:NSMakeRange(0, attributedString.length)];
+ } else {
+ [attributedString addAttribute:NSFontAttributeName value:defaultFont range:NSMakeRange(0, attributedString.length)];
+ }
+
+ } else {
+ [attributedString trimWhiteSpace];
+ }
+
+ return attributedString;
+}
+
+- (BOOL)containsHTML:(NSString *)value {
+ NSString *htmlRegex = @"<[a-z][\\s\\S]*>";
+ NSPredicate *htmlText = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", htmlRegex];
+ return [htmlText evaluateWithObject:value];
+}
+
+- (void)updateDarkModeStatus {
+ if (@available(iOS 12.0, *)) {
+ if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
+ self.isDarkMode = YES;
+ return;
+ }
+ }
+ self.isDarkMode = NO;
+}
+
#endif
@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXTextPushNotificationViewController.h b/WebEngageAppEx/Classes/ContentExtension/WEXTextPushNotificationViewController.h
new file mode 100644
index 0000000..00c2247
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXTextPushNotificationViewController.h
@@ -0,0 +1,24 @@
+//
+// WEXTextPushNotificationViewController.h
+// WebEngage
+//
+// Copyright (c) 2022 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+#import
+#import
+#import "WEXRichPushNotificationViewController+Private.h"
+#import "WEXRichPushLayout.h"
+#endif
+
+@interface WEXTextPushNotificationViewController
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+: WEXRichPushLayout
+#else
+: NSObject
+#endif
+
+@end
diff --git a/WebEngageAppEx/Classes/ContentExtension/WEXTextPushNotificationViewController.m b/WebEngageAppEx/Classes/ContentExtension/WEXTextPushNotificationViewController.m
new file mode 100644
index 0000000..fd519f4
--- /dev/null
+++ b/WebEngageAppEx/Classes/ContentExtension/WEXTextPushNotificationViewController.m
@@ -0,0 +1,172 @@
+//
+// WEXTextPushNotificationViewController.m
+// WebEngage
+//
+// Copyright (c) 2022 Webklipper Technologies Pvt Ltd. All rights reserved.
+//
+
+#import "WEXTextPushNotificationViewController.h"
+#import "WEXRichPushNotificationViewController+Private.h"
+#import "UIColor+DarkMode.h"
+
+#define CONTENT_PADDING 10
+#define TITLE_BODY_SPACE 5
+#define LANDSCAPE_ASPECT 0.5
+
+API_AVAILABLE(ios(10.0))
+@interface WEXTextPushNotificationViewController ()
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+
+@property (nonatomic) UNNotification *notification;
+
+#endif
+
+@end
+
+@implementation WEXTextPushNotificationViewController
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
+
+- (void)didReceiveNotification:(UNNotification *)notification API_AVAILABLE(ios(10.0)) {
+ self.notification = notification;
+ [self initialiseViewHierarchy];
+}
+
+- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion{
+ completion(UNNotificationContentExtensionResponseOptionDismissAndForwardAction);
+}
+
+- (void)initialiseViewHierarchy {
+ self.view.backgroundColor = [UIColor WEXWhiteColor];
+
+ UIView *superViewWrapper = [[UIView alloc] init];
+ [self.view addSubview:superViewWrapper];
+
+ [self setupLabelsContainer];
+}
+
+- (void)setupLabelsContainer {
+ UIView *superViewWrapper = self.view.subviews[0];
+ NSString *colorHex = self.notification.request.content.userInfo[@"expandableDetails"][@"bckColor"];
+
+ UIView *richContentView = [[UIView alloc] init];
+ richContentView.backgroundColor = [UIColor colorFromHexString:colorHex defaultColor:UIColor.WEXWhiteColor];
+
+ NSDictionary *expandedDetails = self.notification.request.content.userInfo[@"expandableDetails"];
+ NSString *title = expandedDetails[@"rt"];
+ NSString *subtitle = expandedDetails[@"rst"];
+ NSString *message = expandedDetails[@"rm"];
+
+ BOOL titlePresent = title && ![title isEqualToString:@""];
+ BOOL subTitlePresent = subtitle && ![subtitle isEqualToString:@""];
+ BOOL messagePresent = message && ![message isEqualToString:@""];
+
+ if (!titlePresent) {
+ title = self.notification.request.content.title;
+ }
+ if (!subTitlePresent) {
+ subtitle = self.notification.request.content.subtitle;
+ }
+ if (!messagePresent) {
+ message = self.notification.request.content.body;
+ }
+
+ UILabel *richTitleLabel = [[UILabel alloc] init];
+ richTitleLabel.attributedText = [self.viewController getHtmlParsedString:title isTitle:YES bckColor:colorHex];
+ richTitleLabel.textAlignment = [self.viewController naturalTextAligmentForText:richTitleLabel.text];
+
+ UILabel *richSubLabel = [[UILabel alloc] init];
+ richSubLabel.attributedText = [self.viewController getHtmlParsedString:subtitle isTitle:YES bckColor:colorHex];
+ richSubLabel.textAlignment = [self.viewController naturalTextAligmentForText:richSubLabel.text];
+
+ UILabel *richBodyLabel = [[UILabel alloc] init];
+ richBodyLabel.attributedText = [self.viewController getHtmlParsedString:message isTitle:NO bckColor:colorHex];
+ richBodyLabel.textAlignment = [self.viewController naturalTextAligmentForText:richBodyLabel.text];
+ richBodyLabel.numberOfLines = 0;
+
+ [richContentView addSubview:richTitleLabel];
+ [richContentView addSubview:richSubLabel];
+ [richContentView addSubview:richBodyLabel];
+
+ [superViewWrapper addSubview:richContentView];
+
+ [self setupConstraints];
+}
+
+- (void)setupConstraints {
+ UIView *superViewWrapper = self.view.subviews[0];
+ UIView *richContentView = superViewWrapper.subviews[0];
+
+ if (@available(iOS 10.0, *)) {
+ superViewWrapper.translatesAutoresizingMaskIntoConstraints = NO;
+ [superViewWrapper.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
+ [superViewWrapper.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;
+ [superViewWrapper.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
+ [superViewWrapper.bottomAnchor constraintEqualToAnchor:richContentView.bottomAnchor].active = YES;
+
+ richContentView.translatesAutoresizingMaskIntoConstraints = NO;
+ [richContentView.leadingAnchor constraintEqualToAnchor:superViewWrapper.leadingAnchor].active = YES;
+ [richContentView.trailingAnchor constraintEqualToAnchor:superViewWrapper.trailingAnchor].active = YES;
+ [richContentView.topAnchor constraintEqualToAnchor:superViewWrapper.topAnchor].active = YES;
+
+ [self.viewController.bottomLayoutGuide.topAnchor constraintEqualToAnchor:superViewWrapper.bottomAnchor].active = YES;
+
+ //Rich View labels
+ UIView *richTitleLabel = richContentView.subviews[0];
+ UIView *richSubTitleLabel = richContentView.subviews[1];
+ UIView *richBodyLabel = richContentView.subviews[2];
+
+ richTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richTitleLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richTitleLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richTitleLabel.topAnchor
+ constraintEqualToAnchor:richContentView.topAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+
+ richSubTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richSubTitleLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richSubTitleLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richSubTitleLabel.topAnchor
+ constraintEqualToAnchor:richTitleLabel.bottomAnchor
+ constant:0]
+ .active = YES;
+
+ richBodyLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [richBodyLabel.leadingAnchor
+ constraintEqualToAnchor:richContentView.leadingAnchor
+ constant:CONTENT_PADDING]
+ .active = YES;
+ [richBodyLabel.trailingAnchor
+ constraintEqualToAnchor:richContentView.trailingAnchor
+ constant:0 - CONTENT_PADDING]
+ .active = YES;
+ [richBodyLabel.topAnchor constraintEqualToAnchor:richSubTitleLabel.bottomAnchor
+ constant:0]
+ .active = YES;
+ [richBodyLabel.bottomAnchor
+ constraintEqualToAnchor:richContentView.bottomAnchor
+ constant:-CONTENT_PADDING]
+ .active = YES;
+ } else {
+ NSLog(@"Expected to be running iOS version 10 or above");
+ }
+}
+
+#endif
+
+@end
+
diff --git a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m
index f9ef554..d908442 100644
--- a/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m
+++ b/WebEngageAppEx/Classes/NotificationService/WEXPushNotificationService.m
@@ -7,6 +7,7 @@
#import "WEXPushNotificationService.h"
+#import
@interface WEXPushNotificationService ()
@@ -16,6 +17,7 @@ @interface WEXPushNotificationService ()
@property (nonatomic) UNMutableNotificationContent *bestAttemptContent;
@property (nonatomic) NSString *enviroment;
@property NSDictionary *sharedUserDefaults;
+@property NSArray *customCategories;
#endif
@end
@@ -33,38 +35,89 @@ - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
-
[self setExtensionDefaults];
NSLog(@"Push Notification content: %@", request.content.userInfo);
NSDictionary *expandableDetails = request.content.userInfo[@"expandableDetails"];
-
NSString *style = expandableDetails[@"style"];
if (expandableDetails && style && [style isEqualToString:@"CAROUSEL_V1"]) {
-
[self drawCarouselViewWith:expandableDetails[@"items"]];
- }
- else if (expandableDetails && style &&
- ([style isEqualToString:@"RATING_V1"] || [style isEqualToString:@"BIG_PICTURE"])) {
- [self drawBannerViewWith:expandableDetails[@"image"]];
- }
- else {
- [self trackEventWithCompletion:^{
- self.contentHandler(self.bestAttemptContent);
+ } else if (expandableDetails && style && [style isEqualToString:@"RATING_V1"]) {
+ [self handleContentFor:style image:expandableDetails[@"image"]];
+
+ } else if (expandableDetails && style && ([style isEqualToString:@"BIG_PICTURE"] || [style isEqualToString:@"BIG_TEXT"])) {
+ self.customCategories = @[@"WEG_RICH_V1", @"WEG_RICH_V2", @"WEG_RICH_V3", @"WEG_RICH_V4", @"WEG_RICH_V5", @"WEG_RICH_V6", @"WEG_RICH_V7", @"WEG_RICH_V8"];
+
+ NSString *customCategory = [self getCategoryFor:self.customCategories currentCategory:self.bestAttemptContent.categoryIdentifier];
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+
+ [center getNotificationCategoriesWithCompletionHandler:^(NSSet *existingCategories) {
+ UNNotificationCategory *currentCategory;
+ BOOL isCategoryRegistered = NO;
+ BOOL isCurrentCatCustom = NO;
+ NSMutableSet *existingMutablecat = [[NSMutableSet alloc] init];
+
+ for(UNNotificationCategory *dict in existingCategories) {
+ if([dict.identifier isEqual: self.bestAttemptContent.categoryIdentifier]) {
+ currentCategory = dict;
+ isCategoryRegistered = [dict.identifier isEqualToString:customCategory];
+ isCurrentCatCustom = [self.customCategories containsObject:dict.identifier];
+ } else {
+ [existingMutablecat addObject:dict];
+ }
+ }
+
+ if (isCategoryRegistered) {
+ if (!isCurrentCatCustom) {
+ [self.bestAttemptContent setCategoryIdentifier:customCategory];
+ }
+ [self handleContentFor:style image:expandableDetails[@"image"]];
+ return;
+ }
+
+ // Register banner layout here.
+ NSMutableArray *actions = [NSMutableArray arrayWithCapacity:currentCategory.actions.count];
+
+ for (UNNotificationAction *action in currentCategory.actions) {
+ UNNotificationAction *actionObject = [UNNotificationAction actionWithIdentifier:action.identifier
+ title:action.title
+ options:action.options];
+ [actions addObject:actionObject];
+ }
+
+ UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:customCategory
+ actions:actions
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionCustomDismissAction];
+ [existingMutablecat addObject:category];
+ [center setNotificationCategories:existingMutablecat];
+ [self.bestAttemptContent setCategoryIdentifier:customCategory];
+ /*
+ Dispatching on Main thread after 2 sec delay to make sure our category is registered with NotificationCenter
+ Registering will make sure, contentHandler will invoke ContentExtension with this custom category
+
+ NOTE: Use this workaround till we receive banner category in network response.
+ */
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+ [self handleContentFor:style image:expandableDetails[@"image"]];
+ });
}];
+
+ } else {
+ [self handleContentFor:style image:@""];
}
}
-- (void)setExtensionDefaults {
- NSUserDefaults *sharedDefaults = [self getSharedUserDefaults];
- // Write operation only if key is not present in the UserDefaults
-
- if ([sharedDefaults valueForKey:@"WEG_ServiceToApp"] == nil) {
- [sharedDefaults setValue:@"WEG" forKey:@"WEG_ServiceToApp"];
- [sharedDefaults synchronize];
+- (void)handleContentFor:(NSString *)style image:(NSString *)image {
+ if ([style isEqualToString:@"BIG_PICTURE"] || [style isEqualToString:@"RATING_V1"]) {
+ [self drawBannerViewWith:image];
+ } else {
+ [self trackEventWithCompletion:^{
+ self.contentHandler(self.bestAttemptContent);
+ }];
}
}
@@ -73,6 +126,28 @@ - (void)serviceExtensionTimeWillExpire {
self.contentHandler(self.bestAttemptContent);
}
+// NOTE: This mapping is a temporary workaround, Will be removed in future releases
+
+- (NSString *)getCategoryFor:(NSArray *)categories currentCategory:(NSString *)currentCategory {
+ NSDictionary *categoryMapping = @{
+ @"default" : categories[0], // Default, No buttons
+ @"19db52de": categories[0], // Default, No buttons
+ @"18dfbbcc": categories[1], // Yes/No - Open App/Dismiss
+ @"16589g0g": categories[2], // Yes/No - Dismiss both
+ @"15ead296": categories[3], // Accept/Decline - Open/Dismiss
+ @"17543720": categories[4], // Accept/Decline - Dismiss both
+ @"16e66ba8": categories[5], // Shop Now
+ @"1c406g7a": categories[6], // Buy Now
+ @"1bd2a2g0": categories[7] // Download Now
+ };
+
+ NSString *category = categoryMapping[currentCategory];
+ if (category) {
+ return category;
+ } else {
+ return currentCategory;
+ }
+}
#pragma mark - Rich Push View Helpers
@@ -80,37 +155,37 @@ - (void)drawCarouselViewWith:(NSArray *)items {
NSMutableArray *attachmentsArray = [[NSMutableArray alloc] initWithCapacity:items.count];
- if (items.count >= 3) {
+ if (items.count <= 0) {
+ return;
+ }
+
+ NSUInteger itemCounter = 0;
+ NSUInteger __block imageDownloadAttemptCounter = 0;
+
+ for (NSDictionary *carouselItem in items) {
- NSUInteger itemCounter = 0;
- NSUInteger __block imageDownloadAttemptCounter = 0;
+ NSString *imageURL = carouselItem[@"image"];
- for (NSDictionary *carouselItem in items) {
+ [self fetchAttachmentFor:imageURL
+ at:itemCounter
+ completionHandler:^(UNNotificationAttachment *attachment, NSUInteger index) {
- NSString *imageURL = carouselItem[@"image"];
+ imageDownloadAttemptCounter++;
- [self fetchAttachmentFor:imageURL
- at:itemCounter
- completionHandler:^(UNNotificationAttachment *attachment, NSUInteger index) {
-
- imageDownloadAttemptCounter++;
-
- if (attachment) {
- NSLog(@"Downloaded Attachment No. %ld", (unsigned long)index);
- [attachmentsArray addObject:attachment];
- self.bestAttemptContent.attachments = attachmentsArray;
- }
-
- if (imageDownloadAttemptCounter == items.count) {
-
- [self trackEventWithCompletion:^{
- NSLog(@"Ending WebEngage Rich Push Service");
- self.contentHandler(self.bestAttemptContent);
- }];
- }
- }];
- itemCounter++;
- }
+ if (attachment) {
+ NSLog(@"Downloaded Attachment No. %ld", (unsigned long)index);
+ [attachmentsArray addObject:attachment];
+ self.bestAttemptContent.attachments = attachmentsArray;
+ }
+
+ if (imageDownloadAttemptCounter == items.count) {
+ [self trackEventWithCompletion:^{
+ NSLog(@"Ending WebEngage Rich Push Service");
+ self.contentHandler(self.bestAttemptContent);
+ }];
+ }
+ }];
+ itemCounter++;
}
}
@@ -119,16 +194,16 @@ - (void)drawBannerViewWith:(NSString *)urlStr {
[self fetchAttachmentFor:urlStr
at:0
completionHandler:^(UNNotificationAttachment *attachment, NSUInteger index) {
-
- if (attachment) {
- NSLog(@"WebEngage Downloaded Image for Rating Layout");
- self.bestAttemptContent.attachments = @[ attachment ];
- }
-
- [self trackEventWithCompletion:^{
- self.contentHandler(self.bestAttemptContent);
- }];
- }];
+
+ if (attachment) {
+ NSLog(@"WebEngage Downloaded Image for Rating Layout");
+ self.bestAttemptContent.attachments = @[ attachment ];
+ }
+
+ [self trackEventWithCompletion:^{
+ self.contentHandler(self.bestAttemptContent);
+ }];
+ }];
}
- (void)fetchAttachmentFor:(NSString *)urlString
@@ -200,19 +275,29 @@ - (void)trackEventWithCompletion:(void(^)(void))completion {
else {
NSLog(@"Push Tracker URLResponse: %@", response);
}
-
+
if (completion) {
completion();
}
}] resume];
}
+- (void)setExtensionDefaults {
+ NSUserDefaults *sharedDefaults = [self getSharedUserDefaults];
+ // Write operation only if key is not present in the UserDefaults
+
+ if ([sharedDefaults valueForKey:@"WEG_ServiceToApp"] == nil) {
+ [sharedDefaults setValue:@"WEG" forKey:@"WEG_ServiceToApp"];
+ [sharedDefaults synchronize];
+ }
+}
+
- (NSString *) getBaseURL{
NSString *baseURL = @"https://c.webengage.com/tracker";
[self setDataFromSharedUserDefaults];
- NSLog(@"Setting Enviroment to : %@",self.enviroment);
+ NSLog(@"Setting Enviroment to: %@",self.enviroment);
if ([self.enviroment.uppercaseString isEqualToString:@"IN"]) {
baseURL = @"https://c.in.webengage.com/tracker";
@@ -262,21 +347,20 @@ - (NSData *)getTrackerRequestBody {
// Passing custom data into event tracking
id customData = self.bestAttemptContent.userInfo[@"customData"];
-
+
if (customData && [customData isKindOfClass:[NSArray class]]) {
-
- NSArray *customDataArray = (NSArray *)customData;
-
- NSMutableDictionary *customDataDictionary = [[NSMutableDictionary alloc]
- initWithCapacity:customDataArray.count];
-
- for (NSDictionary *customDataItem in customDataArray) {
- if (customDataItem[@"key"] && [customDataItem[@"key"] isKindOfClass:[NSString class]]) {
- customDataDictionary[customDataItem[@"key"]] =
- customDataItem[@"value"];
- }
- }
-
+ NSArray *customDataArray = (NSArray *)customData;
+
+ NSMutableDictionary *customDataDictionary = [[NSMutableDictionary alloc]
+ initWithCapacity:customDataArray.count];
+
+ for (NSDictionary *customDataItem in customDataArray) {
+ if (customDataItem[@"key"] && [customDataItem[@"key"] isKindOfClass:[NSString class]]) {
+ customDataDictionary[customDataItem[@"key"]] =
+ customDataItem[@"value"];
+ }
+ }
+
body[@"event_data"] = customDataDictionary;
} else {
body[@"event_data"] = @{};
diff --git a/WebEngageBannerPush.podspec b/WebEngageBannerPush.podspec
index 812a8c5..d9d22c1 100644
--- a/WebEngageBannerPush.podspec
+++ b/WebEngageBannerPush.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |spec|
spec.name = 'WebEngageBannerPush'
- spec.version = '0.12.0'
+ spec.version = '1.0.0'
spec.summary = 'Extension Target SDK for adding WebEngage Rich Push Notifications support'
spec.description = <<-DESC
@@ -9,7 +9,7 @@ Pod::Spec.new do |spec|
DESC
spec.license = 'MIT'
- spec.author = 'Saumitra Bhave', 'Uzma Sayyed', 'Unmesh Rathod'
+ spec.author = 'Saumitra Bhave', 'Uzma Sayyed', 'Unmesh Rathod', 'Bhavesh Sarwar'
spec.homepage = 'https://webengage.com'
spec.social_media_url = 'http://twitter.com/webengage'
spec.documentation_url = 'https://docs.webengage.com/docs/ios-getting-started'