@convep_mobilogy/react-native-qms-plugin 0.10.4 → 0.10.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +1 -1
- package/ios/QmsPlugin/QmsDashboardViewManager.mm +408 -2
- package/ios/QmsPlugin/QmsModule.mm +221 -0
- package/ios/QmsPlugin/UIViewController+QmsAnalytics.m +292 -19
- package/ios/QmsPluginFramework.xcframework/Info.plist +5 -5
- package/ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/Assets.car +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/Info.plist +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/Montserrat-Bold.ttf +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/Montserrat-Medium.ttf +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/Montserrat-Regular.ttf +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/QmsPluginFramework +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64/QmsPluginFramework.framework/_CodeSignature/CodeResources +36 -3
- package/ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/Assets.car +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/Info.plist +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/Montserrat-Bold.ttf +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/Montserrat-Medium.ttf +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/Montserrat-Regular.ttf +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/QmsPluginFramework +0 -0
- package/ios/QmsPluginFramework.xcframework/ios-arm64_x86_64-simulator/QmsPluginFramework.framework/_CodeSignature/CodeResources +36 -3
- package/lib/module/QmsDashboardView.android.js +16 -16
- package/lib/module/QmsDashboardView.android.js.map +1 -1
- package/lib/module/QmsDashboardView.ios.js +38 -12
- package/lib/module/QmsDashboardView.ios.js.map +1 -1
- package/lib/typescript/src/QmsDashboardView.ios.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/QmsDashboardView.android.tsx +16 -16
- package/src/QmsDashboardView.ios.tsx +64 -25
package/android/build.gradle
CHANGED
|
@@ -75,7 +75,7 @@ dependencies {
|
|
|
75
75
|
implementation "com.facebook.react:react-android"
|
|
76
76
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
77
77
|
implementation 'com.facebook.react:react-native:+'
|
|
78
|
-
implementation "com.convep.qms:qms-plugin:1.
|
|
78
|
+
implementation "com.convep.qms:qms-plugin:1.13.37"
|
|
79
79
|
|
|
80
80
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
81
81
|
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
#import <QmsPluginFramework/QmsPluginFramework.h>
|
|
4
4
|
#import <QmsPluginFramework/QmsPlugin.h>
|
|
5
5
|
|
|
6
|
+
static NSString * const kQmsThemePrimaryColorKey = @"QmsThemePrimaryColor";
|
|
7
|
+
static NSString * const kQmsThemeHeaderTextColorKey = @"QmsThemeHeaderTextColor";
|
|
8
|
+
static NSString * const kQmsThemeAccentColorKey = @"QmsThemeAccentColor";
|
|
9
|
+
static NSString * const kQmsThemeFontFamilyKey = @"QmsThemeFontFamily";
|
|
10
|
+
static NSString * const kQmsRoutePayloadNotification = @"QmsRoutePayloadNotification";
|
|
11
|
+
|
|
6
12
|
@interface QmsDashboardView : UIView
|
|
7
13
|
@property (nonatomic, strong) UIViewController *dashboardVC;
|
|
8
14
|
@property (nonatomic, assign) BOOL didSetupVC;
|
|
@@ -10,18 +16,51 @@
|
|
|
10
16
|
@property (nonatomic, copy) NSString *ClientID;
|
|
11
17
|
@property (nonatomic, copy) NSString *ClientCode;
|
|
12
18
|
@property (nonatomic, copy) NSString *user_token;
|
|
19
|
+
@property (nonatomic, copy) NSString *themeColor;
|
|
13
20
|
@property (nonatomic, copy) NSString *headerTextColor;
|
|
14
21
|
@property (nonatomic, copy) NSString *headerIconColor;
|
|
15
22
|
@property (nonatomic, copy) NSString *accentColor;
|
|
16
23
|
@property (nonatomic, copy) NSString *fontFamily;
|
|
24
|
+
@property (nonatomic, assign) BOOL isOrigin;
|
|
25
|
+
@property (nonatomic, copy) NSDictionary *payload;
|
|
26
|
+
@property (nonatomic, assign) BOOL didRouteInitialPayload;
|
|
17
27
|
|
|
18
28
|
@property (nonatomic, copy) RCTDirectEventBlock onClose;
|
|
29
|
+
@property (nonatomic, copy) RCTDirectEventBlock onLogout;
|
|
19
30
|
@property (nonatomic, copy) RCTDirectEventBlock onAnalyticsScreen;
|
|
20
31
|
@property (nonatomic, copy) RCTDirectEventBlock onAnalyticsEvent;
|
|
21
32
|
@end
|
|
22
33
|
|
|
23
34
|
@implementation QmsDashboardView
|
|
24
35
|
|
|
36
|
+
- (void)persistThemeDefaults {
|
|
37
|
+
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
38
|
+
if (_themeColor.length > 0) [defaults setObject:_themeColor forKey:kQmsThemePrimaryColorKey];
|
|
39
|
+
else [defaults removeObjectForKey:kQmsThemePrimaryColorKey];
|
|
40
|
+
|
|
41
|
+
if (_headerTextColor.length > 0) [defaults setObject:_headerTextColor forKey:kQmsThemeHeaderTextColorKey];
|
|
42
|
+
else [defaults removeObjectForKey:kQmsThemeHeaderTextColorKey];
|
|
43
|
+
|
|
44
|
+
if (_accentColor.length > 0) [defaults setObject:_accentColor forKey:kQmsThemeAccentColorKey];
|
|
45
|
+
else [defaults removeObjectForKey:kQmsThemeAccentColorKey];
|
|
46
|
+
|
|
47
|
+
if (_fontFamily.length > 0) [defaults setObject:_fontFamily forKey:kQmsThemeFontFamilyKey];
|
|
48
|
+
else [defaults removeObjectForKey:kQmsThemeFontFamilyKey];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (void)applyAllThemeImmediatelyIfNeeded {
|
|
52
|
+
if (!_dashboardVC || !_dashboardVC.view) return;
|
|
53
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
54
|
+
[self persistThemeDefaults];
|
|
55
|
+
[self applyThemeColorIfNeeded];
|
|
56
|
+
[self applyHeaderThemeIfNeeded];
|
|
57
|
+
[self applyAccentColorIfNeeded];
|
|
58
|
+
[self applyFontFamilyIfNeeded];
|
|
59
|
+
[_dashboardVC.view setNeedsLayout];
|
|
60
|
+
[_dashboardVC.view layoutIfNeeded];
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
25
64
|
- (instancetype)initWithFrame:(CGRect)frame {
|
|
26
65
|
if (self = [super initWithFrame:frame]) {
|
|
27
66
|
_dashboardVC = [QmsPluginUI makeViewController];
|
|
@@ -41,6 +80,14 @@
|
|
|
41
80
|
selector:@selector(handleAnalyticsEvent:)
|
|
42
81
|
name:@"QmsAnalyticsEventNotification"
|
|
43
82
|
object:nil];
|
|
83
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
84
|
+
selector:@selector(handleDashboardLogout:)
|
|
85
|
+
name:@"QmsDashboardDidLogoutNotification"
|
|
86
|
+
object:nil];
|
|
87
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
88
|
+
selector:@selector(handleRoutePayloadNotification:)
|
|
89
|
+
name:kQmsRoutePayloadNotification
|
|
90
|
+
object:nil];
|
|
44
91
|
}
|
|
45
92
|
return self;
|
|
46
93
|
}
|
|
@@ -50,6 +97,7 @@
|
|
|
50
97
|
if (self.window && !_didSetupVC) {
|
|
51
98
|
UIViewController *parentVC = [UIApplication sharedApplication].keyWindow.rootViewController;
|
|
52
99
|
if (parentVC) {
|
|
100
|
+
[self persistThemeDefaults];
|
|
53
101
|
|
|
54
102
|
// 1️⃣ create VC with props
|
|
55
103
|
_dashboardVC = [QmsPluginUI makeViewController];
|
|
@@ -63,6 +111,8 @@
|
|
|
63
111
|
|
|
64
112
|
// 2️⃣ forward props again if needed
|
|
65
113
|
[self forwardPropsToVC];
|
|
114
|
+
[self routePayloadIfNeeded:self.payload force:NO];
|
|
115
|
+
[self applyAllThemeImmediatelyIfNeeded];
|
|
66
116
|
}
|
|
67
117
|
}
|
|
68
118
|
}
|
|
@@ -89,6 +139,12 @@
|
|
|
89
139
|
}
|
|
90
140
|
}
|
|
91
141
|
|
|
142
|
+
- (void)handleDashboardLogout:(NSNotification *)note {
|
|
143
|
+
if (self.onLogout) {
|
|
144
|
+
self.onLogout(note.userInfo ?: @{});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
92
148
|
- (void)cleanupDashboard {
|
|
93
149
|
if (!_dashboardVC) return;
|
|
94
150
|
|
|
@@ -116,27 +172,51 @@
|
|
|
116
172
|
[self forwardProp:@"user_token" value:_user_token];
|
|
117
173
|
}
|
|
118
174
|
|
|
175
|
+
- (void)setThemeColor:(NSString *)themeColor {
|
|
176
|
+
_themeColor = [themeColor copy];
|
|
177
|
+
[self persistThemeDefaults];
|
|
178
|
+
[self forwardProp:@"themeColor" value:_themeColor];
|
|
179
|
+
[self applyAllThemeImmediatelyIfNeeded];
|
|
180
|
+
}
|
|
181
|
+
|
|
119
182
|
- (void)setHeaderTextColor:(NSString *)headerTextColor {
|
|
120
183
|
_headerTextColor = [headerTextColor copy];
|
|
184
|
+
[self persistThemeDefaults];
|
|
121
185
|
[self forwardProp:@"headerTextColor" value:_headerTextColor];
|
|
186
|
+
[self applyAllThemeImmediatelyIfNeeded];
|
|
122
187
|
}
|
|
123
188
|
|
|
124
189
|
- (void)setHeaderIconColor:(NSString *)headerIconColor {
|
|
125
190
|
_headerIconColor = [headerIconColor copy];
|
|
126
191
|
[self forwardProp:@"headerIconColor" value:_headerIconColor];
|
|
192
|
+
[self applyAllThemeImmediatelyIfNeeded];
|
|
127
193
|
}
|
|
128
194
|
|
|
129
195
|
- (void)setAccentColor:(NSString *)accentColor {
|
|
130
196
|
_accentColor = [accentColor copy];
|
|
197
|
+
[self persistThemeDefaults];
|
|
131
198
|
[self forwardProp:@"accentColor" value:_accentColor];
|
|
199
|
+
[self applyAllThemeImmediatelyIfNeeded];
|
|
132
200
|
}
|
|
133
201
|
|
|
134
202
|
- (void)setFontFamily:(NSString *)fontFamily {
|
|
135
203
|
_fontFamily = [fontFamily copy];
|
|
204
|
+
[self persistThemeDefaults];
|
|
136
205
|
[self forwardProp:@"fontFamily" value:_fontFamily];
|
|
206
|
+
[self applyAllThemeImmediatelyIfNeeded];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
- (void)setIsOrigin:(BOOL)isOrigin {
|
|
210
|
+
_isOrigin = isOrigin;
|
|
211
|
+
[self forwardProp:@"isOrigin" value:@(isOrigin)];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
- (void)setPayload:(NSDictionary *)payload {
|
|
215
|
+
_payload = [payload copy];
|
|
216
|
+
[self routePayloadIfNeeded:_payload force:NO];
|
|
137
217
|
}
|
|
138
218
|
#pragma mark - Forward Props via KVC
|
|
139
|
-
- (void)forwardProp:(NSString *)key value:(
|
|
219
|
+
- (void)forwardProp:(NSString *)key value:(id)value {
|
|
140
220
|
if (_dashboardVC && [_dashboardVC respondsToSelector:NSSelectorFromString(key)]) {
|
|
141
221
|
@try {
|
|
142
222
|
[_dashboardVC setValue:value forKey:key];
|
|
@@ -150,10 +230,315 @@
|
|
|
150
230
|
[self forwardProp:@"ClientID" value:_ClientID];
|
|
151
231
|
[self forwardProp:@"ClientCode" value:_ClientCode];
|
|
152
232
|
[self forwardProp:@"user_token" value:_user_token];
|
|
233
|
+
[self forwardProp:@"themeColor" value:_themeColor];
|
|
153
234
|
[self forwardProp:@"headerTextColor" value:_headerTextColor];
|
|
154
235
|
[self forwardProp:@"headerIconColor" value:_headerIconColor];
|
|
155
236
|
[self forwardProp:@"accentColor" value:_accentColor];
|
|
156
237
|
[self forwardProp:@"fontFamily" value:_fontFamily];
|
|
238
|
+
[self forwardProp:@"isOrigin" value:@(_isOrigin)];
|
|
239
|
+
[self applyAllThemeImmediatelyIfNeeded];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
- (NSString *)stringFromPayload:(NSDictionary *)payload key:(NSString *)key {
|
|
243
|
+
id value = payload[key];
|
|
244
|
+
if ((!value || value == [NSNull null]) && [payload[@"data"] isKindOfClass:[NSDictionary class]]) {
|
|
245
|
+
value = payload[@"data"][key];
|
|
246
|
+
}
|
|
247
|
+
if (!value || value == [NSNull null]) return nil;
|
|
248
|
+
return [value description];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
- (BOOL)isIssueType:(NSString *)type {
|
|
252
|
+
static NSSet<NSString *> *types;
|
|
253
|
+
static dispatch_once_t onceToken;
|
|
254
|
+
dispatch_once(&onceToken, ^{
|
|
255
|
+
types = [NSSet setWithArray:@[
|
|
256
|
+
@"new_issue", @"new_info", @"accept_issue", @"reject_issue", @"decline_issue",
|
|
257
|
+
@"start_fix", @"redo", @"completed", @"close_internal", @"close_external",
|
|
258
|
+
@"pending_owner_acceptance", @"assign_issue", @"reassign_issue", @"poa_reminder",
|
|
259
|
+
@"auto_close_reminder", @"pending_access_reminder", @"overdue_reminder",
|
|
260
|
+
@"issue_summary_reminder", @"lodge_summary_reminder", @"overdue_summary_reminder"
|
|
261
|
+
]];
|
|
262
|
+
});
|
|
263
|
+
return type.length > 0 && [types containsObject:type];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
- (BOOL)isAppointmentType:(NSString *)type {
|
|
267
|
+
return [type isEqualToString:@"appointment_reminder"] ||
|
|
268
|
+
[type isEqualToString:@"unattend_appt_reminder"];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
- (void)applyPayloadContext:(NSDictionary *)payload {
|
|
272
|
+
Class apiConfig = NSClassFromString(@"APIConfig");
|
|
273
|
+
if (!apiConfig) return;
|
|
274
|
+
|
|
275
|
+
NSString *projectId = [self stringFromPayload:payload key:@"project_id"];
|
|
276
|
+
NSString *planId = [self stringFromPayload:payload key:@"plan_id"];
|
|
277
|
+
|
|
278
|
+
if (projectId.length > 0 && [apiConfig respondsToSelector:NSSelectorFromString(@"setProjectId:")]) {
|
|
279
|
+
[apiConfig performSelector:NSSelectorFromString(@"setProjectId:") withObject:projectId];
|
|
280
|
+
}
|
|
281
|
+
if (planId.length > 0 && [apiConfig respondsToSelector:NSSelectorFromString(@"setDrawingPlanId:")]) {
|
|
282
|
+
[apiConfig performSelector:NSSelectorFromString(@"setDrawingPlanId:") withObject:planId];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
- (UINavigationController *)mainNavigationController {
|
|
287
|
+
id mainVC = nil;
|
|
288
|
+
@try {
|
|
289
|
+
mainVC = [self.dashboardVC valueForKey:@"mainViewController"];
|
|
290
|
+
} @catch (__unused NSException *exception) {}
|
|
291
|
+
|
|
292
|
+
if ([mainVC isKindOfClass:[UINavigationController class]]) {
|
|
293
|
+
return (UINavigationController *)mainVC;
|
|
294
|
+
}
|
|
295
|
+
if ([self.dashboardVC isKindOfClass:[UINavigationController class]]) {
|
|
296
|
+
return (UINavigationController *)self.dashboardVC;
|
|
297
|
+
}
|
|
298
|
+
return self.dashboardVC.navigationController;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
- (void)pushViewControllerNamed:(NSString *)className {
|
|
302
|
+
Class cls = NSClassFromString(className);
|
|
303
|
+
if (!cls) return;
|
|
304
|
+
UIViewController *vc = [[cls alloc] init];
|
|
305
|
+
if (!vc) return;
|
|
306
|
+
UINavigationController *nav = [self mainNavigationController];
|
|
307
|
+
if (nav) {
|
|
308
|
+
[nav pushViewController:vc animated:YES];
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
- (void)pushIssuesViewControllerWithPayload:(NSDictionary *)payload {
|
|
313
|
+
Class cls = NSClassFromString(@"IssuesViewController");
|
|
314
|
+
if (!cls) return;
|
|
315
|
+
UIViewController *vc = [[cls alloc] init];
|
|
316
|
+
if (!vc) return;
|
|
317
|
+
NSString *issueId = [self stringFromPayload:payload key:@"issue_id"];
|
|
318
|
+
if (issueId.length > 0 && [vc respondsToSelector:NSSelectorFromString(@"setDeepLinkIssueId:")]) {
|
|
319
|
+
@try {
|
|
320
|
+
[vc setValue:issueId forKey:@"deepLinkIssueId"];
|
|
321
|
+
} @catch (__unused NSException *exception) {}
|
|
322
|
+
}
|
|
323
|
+
UINavigationController *nav = [self mainNavigationController];
|
|
324
|
+
if (nav) {
|
|
325
|
+
[nav pushViewController:vc animated:YES];
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
- (void)routePayloadIfNeeded:(NSDictionary *)payload force:(BOOL)force {
|
|
330
|
+
if (![payload isKindOfClass:[NSDictionary class]] || payload.count == 0) return;
|
|
331
|
+
if (!_didSetupVC || !self.dashboardVC) return;
|
|
332
|
+
if (_didRouteInitialPayload && !force) return;
|
|
333
|
+
|
|
334
|
+
_didRouteInitialPayload = YES;
|
|
335
|
+
[self applyPayloadContext:payload];
|
|
336
|
+
|
|
337
|
+
NSString *type = [self stringFromPayload:payload key:@"type"];
|
|
338
|
+
NSLog(@"🧭 routePayloadIfNeeded type=%@ issue_id=%@ plan_id=%@ project_id=%@",
|
|
339
|
+
type ?: @"", [self stringFromPayload:payload key:@"issue_id"] ?: @"",
|
|
340
|
+
[self stringFromPayload:payload key:@"plan_id"] ?: @"",
|
|
341
|
+
[self stringFromPayload:payload key:@"project_id"] ?: @"");
|
|
342
|
+
if ([self isIssueType:type]) {
|
|
343
|
+
NSString *issueId = [self stringFromPayload:payload key:@"issue_id"];
|
|
344
|
+
if (issueId.length > 0) {
|
|
345
|
+
NSLog(@"🧭 routing issue deep link to IssuesViewController issue_id=%@", issueId);
|
|
346
|
+
[self pushIssuesViewControllerWithPayload:payload];
|
|
347
|
+
} else {
|
|
348
|
+
NSLog(@"🧭 routing issue type without issue_id to IssuesViewController");
|
|
349
|
+
[self pushViewControllerNamed:@"IssuesViewController"];
|
|
350
|
+
}
|
|
351
|
+
} else if ([self isAppointmentType:type]) {
|
|
352
|
+
NSLog(@"🧭 routing appointment type to AppointmentViewController");
|
|
353
|
+
[self pushViewControllerNamed:@"AppointmentViewController"];
|
|
354
|
+
} else if ([type isEqualToString:@"clearance_letter"]) {
|
|
355
|
+
NSLog(@"🧭 routing clearance_letter to GeneralInfoViewController");
|
|
356
|
+
[self pushViewControllerNamed:@"GeneralInfoViewController"];
|
|
357
|
+
} else {
|
|
358
|
+
NSLog(@"🧭 no route matched for type=%@", type ?: @"");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
- (void)handleRoutePayloadNotification:(NSNotification *)note {
|
|
363
|
+
NSDictionary *payload = [note.userInfo isKindOfClass:[NSDictionary class]] ? note.userInfo : nil;
|
|
364
|
+
[self routePayloadIfNeeded:payload force:YES];
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
- (UIColor *)qms_colorFromHexString:(NSString *)hexString {
|
|
368
|
+
if (hexString.length == 0) return nil;
|
|
369
|
+
NSString *value = [[hexString stringByTrimmingCharactersInSet:
|
|
370
|
+
[NSCharacterSet whitespaceAndNewlineCharacterSet]]
|
|
371
|
+
uppercaseString];
|
|
372
|
+
if ([value hasPrefix:@"#"]) value = [value substringFromIndex:1];
|
|
373
|
+
if (value.length == 3) {
|
|
374
|
+
unichar c0 = [value characterAtIndex:0];
|
|
375
|
+
unichar c1 = [value characterAtIndex:1];
|
|
376
|
+
unichar c2 = [value characterAtIndex:2];
|
|
377
|
+
value = [NSString stringWithFormat:@"%C%C%C%C%C%C", c0, c0, c1, c1, c2, c2];
|
|
378
|
+
}
|
|
379
|
+
if (value.length != 6 && value.length != 8) return nil;
|
|
380
|
+
|
|
381
|
+
unsigned int hex = 0;
|
|
382
|
+
[[NSScanner scannerWithString:value] scanHexInt:&hex];
|
|
383
|
+
|
|
384
|
+
CGFloat a = 1.0;
|
|
385
|
+
CGFloat r = 0, g = 0, b = 0;
|
|
386
|
+
if (value.length == 8) {
|
|
387
|
+
a = ((hex >> 24) & 0xFF) / 255.0;
|
|
388
|
+
r = ((hex >> 16) & 0xFF) / 255.0;
|
|
389
|
+
g = ((hex >> 8) & 0xFF) / 255.0;
|
|
390
|
+
b = (hex & 0xFF) / 255.0;
|
|
391
|
+
} else {
|
|
392
|
+
r = ((hex >> 16) & 0xFF) / 255.0;
|
|
393
|
+
g = ((hex >> 8) & 0xFF) / 255.0;
|
|
394
|
+
b = (hex & 0xFF) / 255.0;
|
|
395
|
+
}
|
|
396
|
+
return [UIColor colorWithRed:r green:g blue:b alpha:a];
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
- (void)applyHeaderThemeRecursivelyOnView:(UIView *)view textColor:(UIColor *)textColor iconColor:(UIColor *)iconColor {
|
|
400
|
+
if (!view) return;
|
|
401
|
+
|
|
402
|
+
if (textColor && [view isKindOfClass:[UILabel class]]) {
|
|
403
|
+
UILabel *label = (UILabel *)view;
|
|
404
|
+
CGPoint originInRoot = [label.superview convertPoint:label.frame.origin toView:_dashboardVC.view];
|
|
405
|
+
if (originInRoot.y <= 120) {
|
|
406
|
+
label.textColor = textColor;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (iconColor && [view isKindOfClass:[UIButton class]]) {
|
|
411
|
+
UIButton *button = (UIButton *)view;
|
|
412
|
+
CGPoint originInRoot = [button.superview convertPoint:button.frame.origin toView:_dashboardVC.view];
|
|
413
|
+
if (originInRoot.y <= 120) {
|
|
414
|
+
button.tintColor = iconColor;
|
|
415
|
+
[button setTitleColor:iconColor forState:UIControlStateNormal];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
for (UIView *subview in view.subviews) {
|
|
420
|
+
[self applyHeaderThemeRecursivelyOnView:subview textColor:textColor iconColor:iconColor];
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
- (void)applyHeaderThemeIfNeeded {
|
|
425
|
+
if (!_dashboardVC || !_dashboardVC.view) return;
|
|
426
|
+
UIColor *text = [self qms_colorFromHexString:_headerTextColor];
|
|
427
|
+
UIColor *icon = [self qms_colorFromHexString:_headerIconColor];
|
|
428
|
+
if (!text && !icon) return;
|
|
429
|
+
[self applyHeaderThemeRecursivelyOnView:_dashboardVC.view textColor:text iconColor:icon];
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
- (BOOL)isDefaultQmsBlueColor:(UIColor *)color {
|
|
433
|
+
if (!color) return NO;
|
|
434
|
+
CGFloat r = 0, g = 0, b = 0, a = 0;
|
|
435
|
+
if (![color getRed:&r green:&g blue:&b alpha:&a]) return NO;
|
|
436
|
+
if (a < 0.01) return NO;
|
|
437
|
+
|
|
438
|
+
BOOL closeToBlueA = (fabs(r - 0.0) < 0.12 && fabs(g - 0.50) < 0.16 && fabs(b - 0.60) < 0.16);
|
|
439
|
+
BOOL closeToBlueB = (fabs(r - 0.0) < 0.12 && fabs(g - 0.43) < 0.16 && fabs(b - 0.55) < 0.16);
|
|
440
|
+
return closeToBlueA || closeToBlueB;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
- (void)applyThemeRecursivelyOnView:(UIView *)view color:(UIColor *)themeColor {
|
|
444
|
+
if (!view || !themeColor) return;
|
|
445
|
+
|
|
446
|
+
CGPoint originInRoot = [view.superview convertPoint:view.frame.origin toView:_dashboardVC.view];
|
|
447
|
+
BOOL nearHeader = originInRoot.y <= 140.0 && view.bounds.size.height <= 120.0;
|
|
448
|
+
if (nearHeader && [self isDefaultQmsBlueColor:view.backgroundColor]) {
|
|
449
|
+
view.backgroundColor = themeColor;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if ([view isKindOfClass:[UIButton class]]) {
|
|
453
|
+
UIButton *button = (UIButton *)view;
|
|
454
|
+
if ([self isDefaultQmsBlueColor:button.backgroundColor]) {
|
|
455
|
+
button.backgroundColor = themeColor;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
for (UIView *subview in view.subviews) {
|
|
460
|
+
[self applyThemeRecursivelyOnView:subview color:themeColor];
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
- (void)applyThemeColorIfNeeded {
|
|
465
|
+
if (!_dashboardVC || !_dashboardVC.view) return;
|
|
466
|
+
UIColor *theme = [self qms_colorFromHexString:_themeColor];
|
|
467
|
+
if (!theme) return;
|
|
468
|
+
[self applyThemeRecursivelyOnView:_dashboardVC.view color:theme];
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
- (void)applyAccentRecursivelyOnView:(UIView *)view color:(UIColor *)color {
|
|
472
|
+
if (!view || !color) return;
|
|
473
|
+
|
|
474
|
+
if ([view isKindOfClass:[UIButton class]]) {
|
|
475
|
+
UIButton *button = (UIButton *)view;
|
|
476
|
+
button.tintColor = color;
|
|
477
|
+
} else if ([view isKindOfClass:[UITextField class]]) {
|
|
478
|
+
((UITextField *)view).tintColor = color;
|
|
479
|
+
} else if ([view isKindOfClass:[UITextView class]]) {
|
|
480
|
+
((UITextView *)view).tintColor = color;
|
|
481
|
+
} else if ([view isKindOfClass:[UISwitch class]]) {
|
|
482
|
+
((UISwitch *)view).onTintColor = color;
|
|
483
|
+
} else if ([view isKindOfClass:[UISlider class]]) {
|
|
484
|
+
((UISlider *)view).minimumTrackTintColor = color;
|
|
485
|
+
} else if ([view isKindOfClass:[UIPageControl class]]) {
|
|
486
|
+
((UIPageControl *)view).currentPageIndicatorTintColor = color;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
for (UIView *subview in view.subviews) {
|
|
490
|
+
[self applyAccentRecursivelyOnView:subview color:color];
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
- (void)applyAccentColorIfNeeded {
|
|
495
|
+
if (!_dashboardVC || !_dashboardVC.view) return;
|
|
496
|
+
UIColor *accent = [self qms_colorFromHexString:_accentColor];
|
|
497
|
+
if (!accent) return;
|
|
498
|
+
[self applyAccentRecursivelyOnView:_dashboardVC.view color:accent];
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
- (UIFont *)fontByPreservingStyleFromFont:(UIFont *)sourceFont {
|
|
502
|
+
if (sourceFont == nil || _fontFamily.length == 0) return sourceFont;
|
|
503
|
+
|
|
504
|
+
UIFont *base = [UIFont fontWithName:_fontFamily size:sourceFont.pointSize];
|
|
505
|
+
if (!base) return sourceFont;
|
|
506
|
+
|
|
507
|
+
UIFontDescriptorSymbolicTraits traits = sourceFont.fontDescriptor.symbolicTraits;
|
|
508
|
+
UIFontDescriptor *descriptor = [base.fontDescriptor fontDescriptorWithSymbolicTraits:traits];
|
|
509
|
+
if (descriptor) {
|
|
510
|
+
return [UIFont fontWithDescriptor:descriptor size:sourceFont.pointSize];
|
|
511
|
+
}
|
|
512
|
+
return base;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
- (void)applyFontFamilyRecursivelyOnView:(UIView *)view {
|
|
516
|
+
if (!view) return;
|
|
517
|
+
|
|
518
|
+
if ([view isKindOfClass:[UILabel class]]) {
|
|
519
|
+
UILabel *label = (UILabel *)view;
|
|
520
|
+
label.font = [self fontByPreservingStyleFromFont:label.font];
|
|
521
|
+
} else if ([view isKindOfClass:[UIButton class]]) {
|
|
522
|
+
UIButton *button = (UIButton *)view;
|
|
523
|
+
if (button.titleLabel) {
|
|
524
|
+
button.titleLabel.font = [self fontByPreservingStyleFromFont:button.titleLabel.font];
|
|
525
|
+
}
|
|
526
|
+
} else if ([view isKindOfClass:[UITextField class]]) {
|
|
527
|
+
UITextField *textField = (UITextField *)view;
|
|
528
|
+
textField.font = [self fontByPreservingStyleFromFont:textField.font];
|
|
529
|
+
} else if ([view isKindOfClass:[UITextView class]]) {
|
|
530
|
+
UITextView *textView = (UITextView *)view;
|
|
531
|
+
textView.font = [self fontByPreservingStyleFromFont:textView.font];
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
for (UIView *subview in view.subviews) {
|
|
535
|
+
[self applyFontFamilyRecursivelyOnView:subview];
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
- (void)applyFontFamilyIfNeeded {
|
|
540
|
+
if (_fontFamily.length == 0 || !_dashboardVC || !_dashboardVC.view) return;
|
|
541
|
+
[self applyFontFamilyRecursivelyOnView:_dashboardVC.view];
|
|
157
542
|
}
|
|
158
543
|
|
|
159
544
|
- (void)removeFromSuperview {
|
|
@@ -178,10 +563,14 @@ RCT_EXPORT_MODULE(QmsDashboardView)
|
|
|
178
563
|
RCT_EXPORT_VIEW_PROPERTY(ClientID, NSString)
|
|
179
564
|
RCT_EXPORT_VIEW_PROPERTY(ClientCode, NSString)
|
|
180
565
|
RCT_EXPORT_VIEW_PROPERTY(user_token, NSString)
|
|
566
|
+
RCT_EXPORT_VIEW_PROPERTY(themeColor, NSString)
|
|
181
567
|
RCT_EXPORT_VIEW_PROPERTY(headerTextColor, NSString)
|
|
182
568
|
RCT_EXPORT_VIEW_PROPERTY(headerIconColor, NSString)
|
|
183
569
|
RCT_EXPORT_VIEW_PROPERTY(accentColor, NSString)
|
|
184
570
|
RCT_EXPORT_VIEW_PROPERTY(fontFamily, NSString)
|
|
571
|
+
RCT_EXPORT_VIEW_PROPERTY(isOrigin, BOOL)
|
|
572
|
+
RCT_EXPORT_VIEW_PROPERTY(payload, NSDictionary)
|
|
573
|
+
RCT_EXPORT_VIEW_PROPERTY(onLogout, RCTDirectEventBlock)
|
|
185
574
|
RCT_EXPORT_VIEW_PROPERTY(onAnalyticsScreen, RCTDirectEventBlock)
|
|
186
575
|
RCT_EXPORT_VIEW_PROPERTY(onAnalyticsEvent, RCTDirectEventBlock)
|
|
187
576
|
|
|
@@ -221,12 +610,23 @@ RCT_EXPORT_MODULE();
|
|
|
221
610
|
selector:@selector(handleAnalyticsEvent:)
|
|
222
611
|
name:@"QmsAnalyticsEventNotification"
|
|
223
612
|
object:nil];
|
|
613
|
+
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
614
|
+
selector:@selector(handleDashboardLogout:)
|
|
615
|
+
name:@"QmsDashboardDidLogoutNotification"
|
|
616
|
+
object:nil];
|
|
224
617
|
}
|
|
225
618
|
return self;
|
|
226
619
|
}
|
|
227
620
|
|
|
228
621
|
- (NSArray<NSString *> *)supportedEvents {
|
|
229
|
-
return @[
|
|
622
|
+
return @[
|
|
623
|
+
@"onClose",
|
|
624
|
+
@"onLogout",
|
|
625
|
+
@"onAnalyticsScreen",
|
|
626
|
+
@"onAnalyticsEvent",
|
|
627
|
+
@"QmsSdkOnAnalyticsScreen",
|
|
628
|
+
@"QmsSdkOnAnalyticsEvent"
|
|
629
|
+
];
|
|
230
630
|
}
|
|
231
631
|
|
|
232
632
|
- (void)handleDashboardClose:(NSNotification *)note {
|
|
@@ -236,10 +636,16 @@ RCT_EXPORT_MODULE();
|
|
|
236
636
|
|
|
237
637
|
- (void)handleAnalyticsScreen:(NSNotification *)note {
|
|
238
638
|
[self sendEventWithName:@"onAnalyticsScreen" body:note.userInfo];
|
|
639
|
+
[self sendEventWithName:@"QmsSdkOnAnalyticsScreen" body:note.userInfo];
|
|
239
640
|
}
|
|
240
641
|
|
|
241
642
|
- (void)handleAnalyticsEvent:(NSNotification *)note {
|
|
242
643
|
[self sendEventWithName:@"onAnalyticsEvent" body:note.userInfo];
|
|
644
|
+
[self sendEventWithName:@"QmsSdkOnAnalyticsEvent" body:note.userInfo];
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
- (void)handleDashboardLogout:(NSNotification *)note {
|
|
648
|
+
[self sendEventWithName:@"onLogout" body:note.userInfo];
|
|
243
649
|
}
|
|
244
650
|
|
|
245
651
|
- (void)dealloc {
|