Files
smart-city-digital-twin-mar…/smart-app-city/frontend/node_modules/expo-file-system/ios/EXFileSystemAssetLibraryHandler.m
Eric FELIXINE e30ae8ed09 feat(smart-app): implement complete mobile app MVP
- 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
2026-06-01 18:00:35 -04:00

146 lines
5.6 KiB
Objective-C

#import <ExpoFileSystem/EXFileSystemAssetLibraryHandler.h>
#import <ExpoFileSystem/NSData+EXFileSystem.h>
#import <Photos/Photos.h>
@implementation EXFileSystemAssetLibraryHandler
+ (void)getInfoForFile:(NSURL *)fileUri
withOptions:(NSDictionary *)options
resolver:(EXPromiseResolveBlock)resolve
rejecter:(EXPromiseRejectBlock)reject
{
NSError *error;
PHFetchResult<PHAsset *> *fetchResult = [self fetchResultForUri:fileUri error:&error];
if (error) {
reject(@"E_UNSUPPORTED_ARG", error.description, error);
return;
}
if (fetchResult.count > 0) {
PHAsset *asset = fetchResult[0];
NSMutableDictionary *result = [NSMutableDictionary dictionary];
result[@"exists"] = @(YES);
result[@"isDirectory"] = @(NO);
result[@"uri"] = fileUri;
// Uses required reason API based on the following reason: 3B52.1
result[@"modificationTime"] = @(asset.modificationDate.timeIntervalSince1970);
if (options[@"md5"] || options[@"size"]) {
[[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, CGImagePropertyOrientation orientation, NSDictionary * _Nullable info) {
result[@"size"] = @(imageData.length);
if (options[@"md5"]) {
result[@"md5"] = [imageData md5String];
}
resolve(result);
}];
} else {
resolve(result);
}
} else {
resolve(@{@"exists": @(NO), @"isDirectory": @(NO)});
}
}
+ (void)copyFrom:(NSURL *)from
to:(NSURL *)to
resolver:(EXPromiseResolveBlock)resolve
rejecter:(EXPromiseRejectBlock)reject
{
NSString *toPath = [to.path stringByStandardizingPath];
// NOTE: The destination-delete and the copy should happen atomically, but we hope for the best for now
NSError *error;
if ([[NSFileManager defaultManager] fileExistsAtPath:toPath]) {
if (![[NSFileManager defaultManager] removeItemAtPath:toPath error:&error]) {
reject(@"E_FILE_NOT_COPIED",
[NSString stringWithFormat:@"File '%@' could not be copied to '%@' because a file already exists at "
"the destination and could not be deleted.", from, to],
error);
return;
}
}
PHFetchResult<PHAsset *> *fetchResult = [self fetchResultForUri:from error:&error];
if (error) {
reject(@"E_UNSUPPORTED_ARG", error.description, error);
return;
}
if (fetchResult.count > 0) {
PHAsset *asset = fetchResult[0];
if (asset.mediaType == PHAssetMediaTypeVideo) {
[[PHImageManager defaultManager] requestAVAssetForVideo:asset options:nil resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
if (![asset isKindOfClass:[AVURLAsset class]]) {
reject(@"ERR_INCORRECT_ASSET_TYPE",
[NSString stringWithFormat:@"File '%@' has incorrect asset type.", from],
nil);
return;
}
AVURLAsset* urlAsset = (AVURLAsset*)asset;
NSNumber *size;
[urlAsset.URL getResourceValue:&size forKey:NSURLFileSizeKey error:nil];
NSData *data = [NSData dataWithContentsOfURL:urlAsset.URL];
[EXFileSystemAssetLibraryHandler copyData:data toPath:toPath resolver:resolve rejecter:reject];
}];
} else {
[[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, CGImagePropertyOrientation orientation, NSDictionary * _Nullable info) {
[EXFileSystemAssetLibraryHandler copyData:imageData toPath:toPath resolver:resolve rejecter:reject];
}];
}
} else {
reject(@"E_FILE_NOT_COPIED",
[NSString stringWithFormat:@"File '%@' could not be found.", from],
error);
}
}
// adapted from RCTImageLoader.m
+ (PHFetchResult<PHAsset *> *)fetchResultForUri:(NSURL *)url error:(NSError **)error
{
if ([url.scheme caseInsensitiveCompare:@"ph"] == NSOrderedSame) {
// Fetch assets using PHAsset localIdentifier (recommended)
NSString *const localIdentifier = [url.absoluteString substringFromIndex:@"ph://".length];
return [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil];
} else if ([url.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame) {
#if TARGET_OS_MACCATALYST
static BOOL hasWarned = NO;
if (!hasWarned) {
NSLog(@"assets-library:// URLs have been deprecated and cannot be accessed in macOS Catalyst. Returning nil (future warnings will be suppressed).");
hasWarned = YES;
}
return nil;
#elif TARGET_OS_IOS || TARGET_OS_TV
// This is the older, deprecated way of fetching assets from assets-library
// using the "assets-library://" protocol
return [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
#elif TARGET_OS_OSX
return nil;
#endif
}
NSString *description = [NSString stringWithFormat:@"Invalid URL provided, expected scheme to be either 'ph' or 'assets-library', was '%@'.", url.scheme];
*error = [[NSError alloc] initWithDomain:NSURLErrorDomain
code:NSURLErrorUnsupportedURL
userInfo:@{NSLocalizedDescriptionKey: description}];
return nil;
}
+ (void)copyData:(NSData *)data
toPath:(NSString *)path
resolver:(EXPromiseResolveBlock)resolve
rejecter:(EXPromiseRejectBlock)reject
{
if ([data writeToFile:path atomically:YES]) {
resolve(nil);
} else {
reject(@"E_FILE_NOT_COPIED",
[NSString stringWithFormat:@"File could not be copied to '%@'.", path],
nil);
}
}
@end