Skip to content

Commit fdf1c2f

Browse files
committed
ios app attention
1 parent b4c76e8 commit fdf1c2f

File tree

9 files changed

+245
-6
lines changed

9 files changed

+245
-6
lines changed

example/ios/PamReactNativeExample.xcodeproj/project.pbxproj

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,10 @@
588588
"-DFOLLY_CFG_NO_COROUTINES=1",
589589
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
590590
);
591-
OTHER_LDFLAGS = "$(inherited) ";
591+
OTHER_LDFLAGS = (
592+
"$(inherited)",
593+
" ",
594+
);
592595
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
593596
SDKROOT = iphoneos;
594597
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
@@ -657,7 +660,10 @@
657660
"-DFOLLY_CFG_NO_COROUTINES=1",
658661
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
659662
);
660-
OTHER_LDFLAGS = "$(inherited) ";
663+
OTHER_LDFLAGS = (
664+
"$(inherited)",
665+
" ",
666+
);
661667
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
662668
SDKROOT = iphoneos;
663669
USE_HERMES = true;

example/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,7 @@ SPEC CHECKSUMS:
17671767
fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be
17681768
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
17691769
hermes-engine: 1949ca944b195a8bde7cbf6316b9068e19cf53c6
1770-
pam-react-native: 5fd247e9915c62966e7aa383042f17f624d04d69
1770+
pam-react-native: 7dad01e9b173c7ba546ce0d135aada61baafdb2b
17711771
RCT-Folly: bf5c0376ffe4dd2cf438dcf86db385df9fdce648
17721772
RCTDeprecation: 063fc281b30b7dc944c98fe53a7e266dab1a8706
17731773
RCTRequired: 8eda2a5a745f6081157a4f34baac40b65fe02b31
@@ -1830,4 +1830,4 @@ SPEC CHECKSUMS:
18301830

18311831
PODFILE CHECKSUM: 0b23fa334f7dc47bad5ff245a36b4ae07016c9d8
18321832

1833-
COCOAPODS: 1.15.2
1833+
COCOAPODS: 1.16.2

example/src/App.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { View, StyleSheet, Button } from 'react-native';
2-
import { Pam } from 'pam-react-native';
2+
import { Pam, displayPopup } from 'pam-react-native';
33

44
Pam.initialize({
55
baseApi: 'https://stgx.pams.ai',
@@ -31,6 +31,12 @@ export default function App() {
3131
}
3232
}}
3333
/>
34+
<Button
35+
title="Open Popup"
36+
onPress={async () => {
37+
displayPopup();
38+
}}
39+
/>
3440
</View>
3541
);
3642
}

ios/PamReactNative.mm

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#import "PamReactNative.h"
2+
#import "PopupViewController.h"
23

34
@implementation PamReactNative
45
RCT_EXPORT_MODULE()
@@ -9,6 +10,27 @@ - (NSNumber *)multiply:(double)a b:(double)b {
910
return result;
1011
}
1112

13+
- (void) displayPopup {
14+
dispatch_async(dispatch_get_main_queue(), ^{
15+
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
16+
UIViewController *rootViewController = keyWindow.rootViewController;
17+
18+
if (rootViewController) {
19+
PopupViewController *viewController = [[PopupViewController alloc] init];
20+
viewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
21+
22+
viewController.popupData = @{
23+
@"title": @"Hello World",
24+
@"description": @"This is a popup",
25+
@"size": @"large",
26+
@"image": @"https://placehold.co/720x1280/5596CA/000000"
27+
};
28+
29+
[rootViewController presentViewController:viewController animated:NO completion:nil];
30+
}
31+
});
32+
}
33+
1234
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
1335
(const facebook::react::ObjCTurboModule::InitParams &)params
1436
{

ios/PopupViewController.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#import <UIKit/UIKit.h>
2+
#import <AVFoundation/AVFoundation.h>
3+
4+
NS_ASSUME_NONNULL_BEGIN
5+
6+
@interface PopupViewController : UIViewController
7+
8+
@property (nonatomic, strong) NSDictionary *popupData;
9+
@property (nonatomic, strong) AVPlayerLayer *playerLayer;
10+
@property (nonatomic, strong) UIView *containerView;
11+
@property (nonatomic, strong) AVPlayer *videoPlayer;
12+
13+
14+
@end
15+
16+
NS_ASSUME_NONNULL_END

ios/PopupViewController.mm

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#import "PopupViewController.h"
2+
3+
@implementation PopupViewController
4+
5+
- (void)viewDidLoad {
6+
[super viewDidLoad];
7+
[self setupUI];
8+
}
9+
10+
- (void)setupUI {
11+
NSDictionary *popup = self.popupData;
12+
if (!popup) return;
13+
14+
NSString *title = popup[@"title"];
15+
NSString *description = popup[@"description"];
16+
NSString *image = popup[@"image"];
17+
NSString *video = popup[@"video"];
18+
NSString *size = popup[@"size"];
19+
NSString *trackingPixelUrl = popup[@"tracking_pixel_url"];
20+
21+
// Send tracking pixel
22+
if (trackingPixelUrl) {
23+
NSURL *url = [NSURL URLWithString:trackingPixelUrl];
24+
if (url) {
25+
[[[NSURLSession sharedSession] dataTaskWithURL:url] resume];
26+
}
27+
}
28+
29+
self.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
30+
31+
// Container view
32+
self.containerView = [[UIView alloc] init];
33+
self.containerView.backgroundColor = [UIColor clearColor];
34+
self.containerView.layer.cornerRadius = 15;
35+
self.containerView.clipsToBounds = YES;
36+
self.containerView.translatesAutoresizingMaskIntoConstraints = NO;
37+
[self.view addSubview:self.containerView];
38+
39+
if ([size isEqualToString:@"large"]) {
40+
[NSLayoutConstraint activateConstraints:@[
41+
[self.containerView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:0.8],
42+
[self.containerView.heightAnchor constraintEqualToAnchor:self.view.heightAnchor multiplier:0.6],
43+
[self.containerView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
44+
[self.containerView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:-10]
45+
]];
46+
} else {
47+
[NSLayoutConstraint activateConstraints:@[
48+
[self.containerView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
49+
[self.containerView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
50+
[self.containerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
51+
[self.containerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]
52+
]];
53+
}
54+
55+
// Description label
56+
UILabel *descriptionLabel = [[UILabel alloc] init];
57+
descriptionLabel.text = description;
58+
descriptionLabel.textColor = [UIColor whiteColor];
59+
descriptionLabel.font = [UIFont systemFontOfSize:16];
60+
descriptionLabel.numberOfLines = 0;
61+
descriptionLabel.translatesAutoresizingMaskIntoConstraints = NO;
62+
[self.view addSubview:descriptionLabel];
63+
64+
if ([size isEqualToString:@"large"]) {
65+
[NSLayoutConstraint activateConstraints:@[
66+
[descriptionLabel.topAnchor constraintEqualToAnchor:self.containerView.bottomAnchor constant:10],
67+
[descriptionLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
68+
[descriptionLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20]
69+
]];
70+
} else {
71+
[NSLayoutConstraint activateConstraints:@[
72+
[descriptionLabel.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:-70],
73+
[descriptionLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
74+
[descriptionLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20]
75+
]];
76+
}
77+
78+
// Title label
79+
UILabel *titleLabel = [[UILabel alloc] init];
80+
titleLabel.text = title;
81+
titleLabel.textColor = [UIColor whiteColor];
82+
titleLabel.font = [UIFont boldSystemFontOfSize:20];
83+
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
84+
[self.view addSubview:titleLabel];
85+
86+
if ([size isEqualToString:@"large"]) {
87+
[NSLayoutConstraint activateConstraints:@[
88+
[titleLabel.bottomAnchor constraintEqualToAnchor:self.containerView.topAnchor constant:-10],
89+
[titleLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
90+
[titleLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20]
91+
]];
92+
} else {
93+
[NSLayoutConstraint activateConstraints:@[
94+
[titleLabel.bottomAnchor constraintEqualToAnchor:descriptionLabel.topAnchor constant:-10],
95+
[titleLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
96+
[titleLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20]
97+
]];
98+
}
99+
100+
// Image or Video
101+
if (image != nil && ![image isKindOfClass:[NSNull class]] && ![image isEqualToString:@""]) {
102+
NSURL *imageUrl = [NSURL URLWithString:image];
103+
if (imageUrl && imageUrl.scheme && imageUrl.host) {
104+
UIImageView *imageView = [[UIImageView alloc] init];
105+
imageView.contentMode = UIViewContentModeScaleAspectFit;
106+
imageView.translatesAutoresizingMaskIntoConstraints = NO;
107+
108+
109+
[self.containerView addSubview:imageView];
110+
[NSLayoutConstraint activateConstraints:@[
111+
[imageView.widthAnchor constraintEqualToAnchor:self.containerView.widthAnchor],
112+
[imageView.heightAnchor constraintEqualToAnchor:self.containerView.heightAnchor],
113+
[imageView.centerXAnchor constraintEqualToAnchor:self.containerView.centerXAnchor],
114+
[imageView.centerYAnchor constraintEqualToAnchor:self.containerView.centerYAnchor]
115+
]];
116+
117+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
118+
NSData *data = [NSData dataWithContentsOfURL:imageUrl];
119+
UIImage *image = [UIImage imageWithData:data];
120+
121+
NSLog(@"Image data length: %lu", (unsigned long)data.length);
122+
dispatch_async(dispatch_get_main_queue(), ^{
123+
imageView.image = image;
124+
CGSize size = imageView.frame.size;
125+
NSLog(@"Image size: %f x %f", size.width, size.height);
126+
});
127+
});
128+
}
129+
}
130+
131+
if (video != nil && ![video isKindOfClass:[NSNull class]] && ![video isEqualToString:@""]) {
132+
NSURL *videoUrl = [NSURL URLWithString:video];
133+
if (videoUrl) {
134+
self.videoPlayer = [AVPlayer playerWithURL:videoUrl];
135+
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.videoPlayer];
136+
self.playerLayer.frame = CGRectZero;
137+
[self.containerView.layer addSublayer:self.playerLayer];
138+
[self.videoPlayer play];
139+
}
140+
}
141+
142+
// Close button
143+
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
144+
closeButton.backgroundColor = [UIColor whiteColor];
145+
closeButton.layer.cornerRadius = 20;
146+
UIImage *icon = nil;
147+
148+
if (@available(iOS 13.0, *)) {
149+
icon = [UIImage systemImageNamed:@"xmark"];
150+
} else {
151+
icon = [UIImage imageNamed:@"ic_close"];
152+
}
153+
154+
[closeButton setImage:icon forState:UIControlStateNormal];
155+
closeButton.tintColor = [UIColor blackColor];
156+
closeButton.translatesAutoresizingMaskIntoConstraints = NO;
157+
[closeButton addTarget:self action:@selector(closePopup) forControlEvents:UIControlEventTouchUpInside];
158+
[self.view addSubview:closeButton];
159+
160+
[NSLayoutConstraint activateConstraints:@[
161+
[closeButton.heightAnchor constraintEqualToConstant:40],
162+
[closeButton.widthAnchor constraintEqualToConstant:40],
163+
[closeButton.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:20],
164+
[closeButton.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor constant:-20]
165+
]];
166+
}
167+
168+
- (void)viewDidLayoutSubviews {
169+
[super viewDidLayoutSubviews];
170+
self.playerLayer.frame = self.containerView.bounds;
171+
}
172+
173+
- (void)closePopup {
174+
[UIView animateWithDuration:0.3 animations:^{
175+
self.view.alpha = 0;
176+
} completion:^(BOOL finished) {
177+
// if (self.result) {
178+
// self.result(nil);
179+
// }
180+
[self dismissViewControllerAnimated:NO completion:nil];
181+
}];
182+
}
183+
184+
@end

pam-react-native.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Pod::Spec.new do |s|
1414
s.platforms = { :ios => min_ios_version_supported }
1515
s.source = { :git => "https://github.com/3dsinteractive/pam-react-native.git", :tag => "#{s.version}" }
1616

17-
s.source_files = "ios/**/*.{h,m,mm,cpp}"
17+
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
1818

1919
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
2020
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.

src/NativePamReactNative.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { TurboModuleRegistry } from 'react-native';
33

44
export interface Spec extends TurboModule {
55
multiply(a: number, b: number): number;
6+
displayPopup(): void;
67
}
78

89
export default TurboModuleRegistry.getEnforcing<Spec>('PamReactNative');

src/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,7 @@ export class Pam {
125125
export function multiply(a: number, b: number): number {
126126
return PamReactNative.multiply(a, b);
127127
}
128+
129+
export function displayPopup(): void {
130+
PamReactNative.displayPopup();
131+
}

0 commit comments

Comments
 (0)