- App.tsx: full navigation (Auth stack + Main tabs with 5 screens) - Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen - HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors - MapScreen: interactive map with layer toggles (6 layers) - MarketplaceScreen: categories (6), products (5), search - ChatScreen: AI chat with quick prompts (4), bot responses - ProfileScreen: user info, stats, menu (9 items), logout - AlertsScreen: alert list with severity, acknowledge - SensorsScreen: sensor list with type filters (6 types), search - ZonesScreen: zone cards with stats - SettingsScreen: language picker (FR/EN/ES/DE), privacy, about - Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n - Hooks: useSensors, useAlerts, useNotifications, useLocation - Components: Card, Button, LoadingSpinner, ErrorBoundary, Header - Services: iotService, notificationService (with axios API client) - Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN) - Theme: colors.ts with full design system (Blue Ocean palette) - Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
155 lines
4.2 KiB
Objective-C
155 lines
4.2 KiB
Objective-C
// Copyright 2018-present 650 Industries. All rights reserved.
|
|
|
|
#import <EXNotifications/EXPushTokenModule.h>
|
|
#import <EXNotifications/EXPushTokenManager.h>
|
|
|
|
#import <ExpoModulesCore/EXEventEmitterService.h>
|
|
|
|
static NSString * const onDevicePushTokenEventName = @"onDevicePushToken";
|
|
|
|
@interface EXPushTokenModule ()
|
|
|
|
@property (nonatomic, weak) id<EXPushTokenManager> pushTokenManager;
|
|
|
|
@property (nonatomic, assign) BOOL isListening;
|
|
@property (nonatomic, assign) BOOL isBeingObserved;
|
|
@property (nonatomic, assign) BOOL isSettlingPromise;
|
|
|
|
@property (nonatomic, weak) id<EXEventEmitterService> eventEmitter;
|
|
|
|
@property (nonatomic, strong) EXPromiseResolveBlock getDevicePushTokenResolver;
|
|
@property (nonatomic, strong) EXPromiseRejectBlock getDevicePushTokenRejecter;
|
|
|
|
@end
|
|
|
|
@implementation EXPushTokenModule
|
|
|
|
EX_EXPORT_MODULE(ExpoPushTokenManager);
|
|
|
|
# pragma mark - Exported methods
|
|
|
|
EX_EXPORT_METHOD_AS(getDevicePushTokenAsync,
|
|
getDevicePushTokenResolving:(EXPromiseResolveBlock)resolve rejecting:(EXPromiseRejectBlock)reject)
|
|
{
|
|
if (_getDevicePushTokenRejecter) {
|
|
reject(@"E_AWAIT_PROMISE", @"Another async call to this method is in progress. Await the first Promise.", nil);
|
|
return;
|
|
}
|
|
|
|
_getDevicePushTokenResolver = resolve;
|
|
_getDevicePushTokenRejecter = reject;
|
|
[self setIsSettlingPromise:YES];
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
|
});
|
|
}
|
|
|
|
EX_EXPORT_METHOD_AS(unregisterForNotificationsAsync,
|
|
unregisterForNotificationsAsync:(EXPromiseResolveBlock)resolve reject:(EXPromiseRejectBlock)reject)
|
|
{
|
|
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
|
|
resolve(nil);
|
|
}
|
|
|
|
# pragma mark - EXModuleRegistryConsumer
|
|
|
|
- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry
|
|
{
|
|
_eventEmitter = [moduleRegistry getModuleImplementingProtocol:@protocol(EXEventEmitterService)];
|
|
_pushTokenManager = [moduleRegistry getSingletonModuleForName:@"PushTokenManager"];
|
|
}
|
|
|
|
# pragma mark - EXEventEmitter
|
|
|
|
- (NSArray<NSString *> *)supportedEvents
|
|
{
|
|
return @[onDevicePushTokenEventName];
|
|
}
|
|
|
|
- (void)startObserving
|
|
{
|
|
[self setIsBeingObserved:YES];
|
|
}
|
|
|
|
- (void)stopObserving
|
|
{
|
|
[self setIsBeingObserved:NO];
|
|
}
|
|
|
|
- (BOOL)shouldListen
|
|
{
|
|
return _isBeingObserved || _isSettlingPromise;
|
|
}
|
|
|
|
- (void)updateListeningState
|
|
{
|
|
if ([self shouldListen] && !_isListening) {
|
|
[_pushTokenManager addListener:self];
|
|
_isListening = YES;
|
|
} else if (![self shouldListen] && _isListening) {
|
|
[_pushTokenManager removeListener:self];
|
|
_isListening = NO;
|
|
}
|
|
}
|
|
|
|
# pragma mark - EXPushTokenListener
|
|
|
|
- (void)onDidRegisterWithDeviceToken:(NSData *)devicePushToken
|
|
{
|
|
NSMutableString *stringToken = [NSMutableString string];
|
|
const char *bytes = [devicePushToken bytes];
|
|
for (int i = 0; i < [devicePushToken length]; i++) {
|
|
[stringToken appendFormat:@"%02.2hhx", bytes[i]];
|
|
}
|
|
|
|
if (_getDevicePushTokenResolver) {
|
|
_getDevicePushTokenResolver(stringToken);
|
|
[self onGetDevicePushTokenPromiseSettled];
|
|
}
|
|
|
|
if (_isBeingObserved) {
|
|
[_eventEmitter sendEventWithName:onDevicePushTokenEventName
|
|
body:@{ @"devicePushToken": stringToken }];
|
|
}
|
|
}
|
|
|
|
- (void)onDidFailToRegisterWithError:(NSError *)error
|
|
{
|
|
if (_getDevicePushTokenRejecter) {
|
|
NSString *message = @"Notification registration failed: ";
|
|
|
|
// A common error, localizedDescription may not be helpful.
|
|
if (error.code == 3000 && [NSCocoaErrorDomain isEqualToString:error.domain]) {
|
|
message = [message stringByAppendingString:@"\"Push Notifications\" capability hasn't been added to the app in current environment: "];
|
|
}
|
|
|
|
message = [message stringByAppendingFormat:@"%@", error.localizedDescription];
|
|
_getDevicePushTokenRejecter(@"E_REGISTRATION_FAILED", message, error);
|
|
[self onGetDevicePushTokenPromiseSettled];
|
|
}
|
|
}
|
|
|
|
- (void)onGetDevicePushTokenPromiseSettled
|
|
{
|
|
_getDevicePushTokenResolver = nil;
|
|
_getDevicePushTokenRejecter = nil;
|
|
[self setIsSettlingPromise:NO];
|
|
}
|
|
|
|
# pragma mark - Internal state
|
|
|
|
- (void)setIsBeingObserved:(BOOL)isBeingObserved
|
|
{
|
|
_isBeingObserved = isBeingObserved;
|
|
[self updateListeningState];
|
|
}
|
|
|
|
- (void)setIsSettlingPromise:(BOOL)isSettlingPromise
|
|
{
|
|
_isSettlingPromise = isSettlingPromise;
|
|
[self updateListeningState];
|
|
}
|
|
|
|
@end
|