Files
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

93 lines
2.3 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
'use strict';
import type {PackagerAsset} from './registry.js';
const androidScaleSuffix = {
'0.75': 'ldpi',
'1': 'mdpi',
'1.5': 'hdpi',
'2': 'xhdpi',
'3': 'xxhdpi',
'4': 'xxxhdpi',
};
const ANDROID_BASE_DENSITY = 160;
/**
* FIXME: using number to represent discrete scale numbers is fragile in essence because of
* floating point numbers imprecision.
*/
function getAndroidAssetSuffix(scale: number): string {
if (scale.toString() in androidScaleSuffix) {
return androidScaleSuffix[scale.toString()];
}
// NOTE: Android Gradle Plugin does not fully support the nnndpi format.
// See https://issuetracker.google.com/issues/72884435
if (Number.isFinite(scale) && scale > 0) {
return Math.round(scale * ANDROID_BASE_DENSITY) + 'dpi';
}
throw new Error('no such scale ' + scale.toString());
}
// See https://developer.android.com/guide/topics/resources/drawable-resource.html
const drawableFileTypes = new Set([
'gif',
'jpeg',
'jpg',
'ktx',
'png',
'svg',
'webp',
'xml',
]);
function getAndroidResourceFolderName(
asset: PackagerAsset,
scale: number,
): string | $TEMPORARY$string<'raw'> {
if (!drawableFileTypes.has(asset.type)) {
return 'raw';
}
const suffix = getAndroidAssetSuffix(scale);
if (!suffix) {
throw new Error(
"Don't know which android drawable suffix to use for scale: " +
scale +
'\nAsset: ' +
JSON.stringify(asset, null, '\t') +
'\nPossible scales are:' +
JSON.stringify(androidScaleSuffix, null, '\t'),
);
}
return 'drawable-' + suffix;
}
function getAndroidResourceIdentifier(asset: PackagerAsset): string {
return (getBasePath(asset) + '/' + asset.name)
.toLowerCase()
.replace(/\//g, '_') // Encode folder structure in file name
.replace(/([^a-z0-9_])/g, '') // Remove illegal chars
.replace(/^assets_/, ''); // Remove "assets_" prefix
}
function getBasePath(asset: PackagerAsset): string {
const basePath = asset.httpServerLocation;
return basePath.startsWith('/') ? basePath.slice(1) : basePath;
}
module.exports = {
getAndroidResourceFolderName,
getAndroidResourceIdentifier,
getBasePath,
};