|
1 | 1 | #import "ViewController.h" |
| 2 | +@import mParticle_Apple_SDK_ObjC; |
| 3 | +@import RoktContracts; |
2 | 4 |
|
3 | 5 | @interface ViewController () |
4 | 6 |
|
| 7 | +@property (nonatomic, strong) UIScrollView *scrollView; |
| 8 | +@property (nonatomic, strong) UIStackView *stackView; |
| 9 | +@property (nonatomic, strong) UIButton *overlayButton; |
| 10 | +@property (nonatomic, strong) UIButton *bottomsheetButton; |
| 11 | +@property (nonatomic, strong) UIStackView *eventLogStack; |
| 12 | +@property (nonatomic, strong) UILabel *eventLogHeader; |
| 13 | +@property (nonatomic, strong) NSMutableArray<NSString *> *eventLog; |
| 14 | +@property (nonatomic, assign) BOOL overlayTriggered; |
| 15 | +@property (nonatomic, assign) BOOL bottomsheetTriggered; |
| 16 | + |
5 | 17 | @end |
6 | 18 |
|
7 | 19 | @implementation ViewController |
8 | 20 |
|
9 | 21 | - (void)viewDidLoad { |
10 | 22 | [super viewDidLoad]; |
| 23 | + |
| 24 | + self.eventLog = [NSMutableArray array]; |
| 25 | + self.view.backgroundColor = UIColor.systemBackgroundColor; |
| 26 | + |
| 27 | + [self setupUI]; |
| 28 | +} |
| 29 | + |
| 30 | +- (void)setupUI { |
| 31 | + // Checkmark icon |
| 32 | + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:56]; |
| 33 | + UIImageView *checkmark = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"checkmark.circle.fill" withConfiguration:config]]; |
| 34 | + checkmark.tintColor = [self colorFromHex:@"#C20075"]; |
| 35 | + checkmark.contentMode = UIViewContentModeCenter; |
| 36 | + |
| 37 | + // Title |
| 38 | + UILabel *titleLabel = [[UILabel alloc] init]; |
| 39 | + titleLabel.text = @"Order Confirmed"; |
| 40 | + titleLabel.font = [UIFont boldSystemFontOfSize:28]; |
| 41 | + titleLabel.textAlignment = NSTextAlignmentCenter; |
| 42 | + |
| 43 | + // Subtitle |
| 44 | + UILabel *subtitleLabel = [[UILabel alloc] init]; |
| 45 | + subtitleLabel.text = @"Reference: ORDER-12345"; |
| 46 | + subtitleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; |
| 47 | + subtitleLabel.textColor = UIColor.secondaryLabelColor; |
| 48 | + subtitleLabel.textAlignment = NSTextAlignmentCenter; |
| 49 | + |
| 50 | + // Overlay button |
| 51 | + self.overlayButton = [UIButton buttonWithType:UIButtonTypeSystem]; |
| 52 | + [self.overlayButton setTitle:@"Load Rokt Placement" forState:UIControlStateNormal]; |
| 53 | + [self.overlayButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; |
| 54 | + self.overlayButton.backgroundColor = [self colorFromHex:@"#C20075"]; |
| 55 | + self.overlayButton.layer.cornerRadius = 8; |
| 56 | + self.overlayButton.contentEdgeInsets = UIEdgeInsetsMake(12, 24, 12, 24); |
| 57 | + [self.overlayButton addTarget:self action:@selector(loadOverlayPlacement) forControlEvents:UIControlEventTouchUpInside]; |
| 58 | + |
| 59 | + // Bottomsheet button |
| 60 | + self.bottomsheetButton = [UIButton buttonWithType:UIButtonTypeSystem]; |
| 61 | + [self.bottomsheetButton setTitle:@"Load Bottomsheet Placement" forState:UIControlStateNormal]; |
| 62 | + [self.bottomsheetButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; |
| 63 | + self.bottomsheetButton.backgroundColor = [self colorFromHex:@"#5A2D82"]; |
| 64 | + self.bottomsheetButton.layer.cornerRadius = 8; |
| 65 | + self.bottomsheetButton.contentEdgeInsets = UIEdgeInsetsMake(12, 24, 12, 24); |
| 66 | + [self.bottomsheetButton addTarget:self action:@selector(loadBottomsheetPlacement) forControlEvents:UIControlEventTouchUpInside]; |
| 67 | + |
| 68 | + // Event log header (initially hidden) |
| 69 | + self.eventLogHeader = [[UILabel alloc] init]; |
| 70 | + self.eventLogHeader.text = @"Event Log"; |
| 71 | + self.eventLogHeader.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; |
| 72 | + self.eventLogHeader.hidden = YES; |
| 73 | + |
| 74 | + // Event log stack |
| 75 | + self.eventLogStack = [[UIStackView alloc] init]; |
| 76 | + self.eventLogStack.axis = UILayoutConstraintAxisVertical; |
| 77 | + self.eventLogStack.spacing = 4; |
| 78 | + self.eventLogStack.alignment = UIStackViewAlignmentLeading; |
| 79 | + |
| 80 | + // Event log container |
| 81 | + UIView *eventLogContainer = [[UIView alloc] init]; |
| 82 | + eventLogContainer.backgroundColor = UIColor.secondarySystemGroupedBackgroundColor; |
| 83 | + eventLogContainer.layer.cornerRadius = 10; |
| 84 | + eventLogContainer.clipsToBounds = YES; |
| 85 | + eventLogContainer.hidden = YES; |
| 86 | + eventLogContainer.tag = 100; |
| 87 | + |
| 88 | + [eventLogContainer addSubview:self.eventLogHeader]; |
| 89 | + [eventLogContainer addSubview:self.eventLogStack]; |
| 90 | + |
| 91 | + self.eventLogHeader.translatesAutoresizingMaskIntoConstraints = NO; |
| 92 | + self.eventLogStack.translatesAutoresizingMaskIntoConstraints = NO; |
| 93 | + |
| 94 | + [NSLayoutConstraint activateConstraints:@[ |
| 95 | + [self.eventLogHeader.topAnchor constraintEqualToAnchor:eventLogContainer.topAnchor constant:12], |
| 96 | + [self.eventLogHeader.leadingAnchor constraintEqualToAnchor:eventLogContainer.leadingAnchor constant:12], |
| 97 | + [self.eventLogHeader.trailingAnchor constraintEqualToAnchor:eventLogContainer.trailingAnchor constant:-12], |
| 98 | + [self.eventLogStack.topAnchor constraintEqualToAnchor:self.eventLogHeader.bottomAnchor constant:8], |
| 99 | + [self.eventLogStack.leadingAnchor constraintEqualToAnchor:eventLogContainer.leadingAnchor constant:12], |
| 100 | + [self.eventLogStack.trailingAnchor constraintEqualToAnchor:eventLogContainer.trailingAnchor constant:-12], |
| 101 | + [self.eventLogStack.bottomAnchor constraintEqualToAnchor:eventLogContainer.bottomAnchor constant:-12], |
| 102 | + ]]; |
| 103 | + |
| 104 | + // Main stack |
| 105 | + self.stackView = [[UIStackView alloc] initWithArrangedSubviews:@[ |
| 106 | + checkmark, titleLabel, subtitleLabel, |
| 107 | + self.overlayButton, self.bottomsheetButton, |
| 108 | + eventLogContainer |
| 109 | + ]]; |
| 110 | + self.stackView.axis = UILayoutConstraintAxisVertical; |
| 111 | + self.stackView.spacing = 24; |
| 112 | + self.stackView.alignment = UIStackViewAlignmentCenter; |
| 113 | + self.stackView.translatesAutoresizingMaskIntoConstraints = NO; |
| 114 | + |
| 115 | + // Scroll view |
| 116 | + self.scrollView = [[UIScrollView alloc] init]; |
| 117 | + self.scrollView.translatesAutoresizingMaskIntoConstraints = NO; |
| 118 | + [self.scrollView addSubview:self.stackView]; |
| 119 | + [self.view addSubview:self.scrollView]; |
| 120 | + |
| 121 | + [NSLayoutConstraint activateConstraints:@[ |
| 122 | + [self.scrollView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], |
| 123 | + [self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
| 124 | + [self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], |
| 125 | + [self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], |
| 126 | + [self.stackView.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor constant:40], |
| 127 | + [self.stackView.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor constant:16], |
| 128 | + [self.stackView.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor constant:-16], |
| 129 | + [self.stackView.bottomAnchor constraintEqualToAnchor:self.scrollView.bottomAnchor constant:-16], |
| 130 | + [self.stackView.widthAnchor constraintEqualToAnchor:self.scrollView.widthAnchor constant:-32], |
| 131 | + [eventLogContainer.widthAnchor constraintEqualToAnchor:self.stackView.widthAnchor], |
| 132 | + ]]; |
11 | 133 | } |
12 | 134 |
|
| 135 | +- (NSDictionary<NSString *, NSString *> *)attributes { |
| 136 | + return @{ |
| 137 | + @"email": @"jenny.smith@rokt.com", |
| 138 | + @"firstname": @"Jenny", |
| 139 | + @"lastname": @"Smith", |
| 140 | + @"confirmationref": @"ORDER-12345", |
| 141 | + @"billingzipcode": @"10014", |
| 142 | + @"sandbox": @"true" |
| 143 | + }; |
| 144 | +} |
| 145 | + |
| 146 | +- (void)loadOverlayPlacement { |
| 147 | + self.overlayTriggered = YES; |
| 148 | + self.overlayButton.enabled = NO; |
| 149 | + self.overlayButton.alpha = 0.5; |
| 150 | + |
| 151 | + [[MParticle sharedInstance].rokt selectPlacements:@"MSDKOverlayLayout" |
| 152 | + attributes:[self attributes] |
| 153 | + embeddedViews:nil |
| 154 | + config:nil |
| 155 | + onEvent:nil]; |
| 156 | +} |
| 157 | + |
| 158 | +- (void)loadBottomsheetPlacement { |
| 159 | + self.bottomsheetTriggered = YES; |
| 160 | + self.bottomsheetButton.enabled = NO; |
| 161 | + self.bottomsheetButton.alpha = 0.5; |
| 162 | + |
| 163 | + __weak typeof(self) weakSelf = self; |
| 164 | + |
| 165 | + [[MParticle sharedInstance].rokt events:@"MSDKBottomsheetLayout" onEvent:^(RoktEvent * _Nonnull event) { |
| 166 | + NSString *description = [weakSelf describeEvent:event]; |
| 167 | + NSLog(@"RoktEvent: %@", description); |
| 168 | + dispatch_async(dispatch_get_main_queue(), ^{ |
| 169 | + [weakSelf appendEventLog:description]; |
| 170 | + }); |
| 171 | + }]; |
| 172 | + |
| 173 | + [[MParticle sharedInstance].rokt selectPlacements:@"MSDKBottomsheetLayout" |
| 174 | + attributes:[self attributes] |
| 175 | + embeddedViews:nil |
| 176 | + config:nil |
| 177 | + onEvent:nil]; |
| 178 | +} |
| 179 | + |
| 180 | +- (void)appendEventLog:(NSString *)entry { |
| 181 | + [self.eventLog addObject:entry]; |
| 182 | + |
| 183 | + UIView *eventLogContainer = [self.view viewWithTag:100]; |
| 184 | + eventLogContainer.hidden = NO; |
| 185 | + self.eventLogHeader.hidden = NO; |
| 186 | + |
| 187 | + // Insert at top (reversed order like Swift example) |
| 188 | + UILabel *label = [[UILabel alloc] init]; |
| 189 | + label.text = entry; |
| 190 | + label.font = [UIFont monospacedSystemFontOfSize:11 weight:UIFontWeightRegular]; |
| 191 | + label.numberOfLines = 0; |
| 192 | + [self.eventLogStack insertArrangedSubview:label atIndex:0]; |
| 193 | +} |
| 194 | + |
| 195 | +- (NSString *)describeEvent:(RoktEvent *)event { |
| 196 | + if ([event isKindOfClass:[RoktShowLoadingIndicator class]]) { |
| 197 | + return @"ShowLoadingIndicator"; |
| 198 | + } else if ([event isKindOfClass:[RoktHideLoadingIndicator class]]) { |
| 199 | + return @"HideLoadingIndicator"; |
| 200 | + } else if ([event isKindOfClass:[RoktPlacementReady class]]) { |
| 201 | + RoktPlacementReady *e = (RoktPlacementReady *)event; |
| 202 | + return [NSString stringWithFormat:@"PlacementReady - %@", e.identifier ?: @""]; |
| 203 | + } else if ([event isKindOfClass:[RoktPlacementInteractive class]]) { |
| 204 | + RoktPlacementInteractive *e = (RoktPlacementInteractive *)event; |
| 205 | + return [NSString stringWithFormat:@"PlacementInteractive - %@", e.identifier ?: @""]; |
| 206 | + } else if ([event isKindOfClass:[RoktOfferEngagement class]]) { |
| 207 | + RoktOfferEngagement *e = (RoktOfferEngagement *)event; |
| 208 | + return [NSString stringWithFormat:@"OfferEngagement - %@", e.identifier ?: @""]; |
| 209 | + } else if ([event isKindOfClass:[RoktPositiveEngagement class]]) { |
| 210 | + RoktPositiveEngagement *e = (RoktPositiveEngagement *)event; |
| 211 | + return [NSString stringWithFormat:@"PositiveEngagement - %@", e.identifier ?: @""]; |
| 212 | + } else if ([event isKindOfClass:[RoktFirstPositiveEngagement class]]) { |
| 213 | + RoktFirstPositiveEngagement *e = (RoktFirstPositiveEngagement *)event; |
| 214 | + return [NSString stringWithFormat:@"FirstPositiveEngagement - %@", e.identifier ?: @""]; |
| 215 | + } else if ([event isKindOfClass:[RoktOpenUrl class]]) { |
| 216 | + RoktOpenUrl *e = (RoktOpenUrl *)event; |
| 217 | + return [NSString stringWithFormat:@"OpenUrl - %@", e.url]; |
| 218 | + } else if ([event isKindOfClass:[RoktPlacementClosed class]]) { |
| 219 | + RoktPlacementClosed *e = (RoktPlacementClosed *)event; |
| 220 | + return [NSString stringWithFormat:@"PlacementClosed - %@", e.identifier ?: @""]; |
| 221 | + } else if ([event isKindOfClass:[RoktPlacementCompleted class]]) { |
| 222 | + RoktPlacementCompleted *e = (RoktPlacementCompleted *)event; |
| 223 | + return [NSString stringWithFormat:@"PlacementCompleted - %@", e.identifier ?: @""]; |
| 224 | + } else if ([event isKindOfClass:[RoktPlacementFailure class]]) { |
| 225 | + RoktPlacementFailure *e = (RoktPlacementFailure *)event; |
| 226 | + return [NSString stringWithFormat:@"PlacementFailure - %@", e.identifier ?: @""]; |
| 227 | + } |
| 228 | + return NSStringFromClass([event class]); |
| 229 | +} |
| 230 | + |
| 231 | +- (UIColor *)colorFromHex:(NSString *)hex { |
| 232 | + NSString *cleaned = [[hex stringByTrimmingCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]] uppercaseString]; |
| 233 | + unsigned int rgbValue = 0; |
| 234 | + [[NSScanner scannerWithString:cleaned] scanHexInt:&rgbValue]; |
| 235 | + return [UIColor colorWithRed:((rgbValue >> 16) & 0xFF) / 255.0 |
| 236 | + green:((rgbValue >> 8) & 0xFF) / 255.0 |
| 237 | + blue:(rgbValue & 0xFF) / 255.0 |
| 238 | + alpha:1.0]; |
| 239 | +} |
13 | 240 |
|
14 | 241 | @end |
0 commit comments