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
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,148 @@
# Changelog
## Unpublished
### 🛠 Breaking changes
### 🎉 New features
### 🐛 Bug fixes
### 💡 Others
## 4.7.0 — 2024-04-18
### 💡 Others
- Removed deprecated backward compatible Gradle settings. ([#28083](https://github.com/expo/expo/pull/28083) by [@kudo](https://github.com/kudo))
## 4.6.0 — 2023-11-14
### 🛠 Breaking changes
- Bumped iOS deployment target to 13.4. ([#25063](https://github.com/expo/expo/pull/25063) by [@gabrieldonadel](https://github.com/gabrieldonadel))
- On `Android` bump `compileSdkVersion` and `targetSdkVersion` to `34`. ([#24708](https://github.com/expo/expo/pull/24708) by [@alanjhughes](https://github.com/alanjhughes))
### 💡 Others
- Renamed `unimodule.json` to `expo-module.config.json`. ([#25100](https://github.com/expo/expo/pull/25100) by [@reichhartd](https://github.com/reichhartd))
## 4.5.0 — 2023-10-17
### 🛠 Breaking changes
- Dropped support for Android SDK 21 and 22. ([#24201](https://github.com/expo/expo/pull/24201) by [@behenate](https://github.com/behenate))
## 4.4.0 — 2023-09-04
### 🎉 New features
- Added support for React Native 0.73. ([#24018](https://github.com/expo/expo/pull/24018) by [@kudo](https://github.com/kudo))
### 🐛 Bug fixes
- Bump `Glide` version to resolve `SecurityException` on Android 13. ([#24196](https://github.com/expo/expo/pull/24196) by [@alanjhughes](https://github.com/alanjhughes))
## 4.3.0 — 2023-06-13
- Removed `com.facebook.fresco:fresco` dependency ([#22542](https://github.com/expo/expo/pull/22542) by [@josephyanks](https://github.com/josephyanks))
### 📚 3rd party library updates
- Updated `com.github.bumptech.glide:glide` to `4.13.2` and added customizable `glideVersion` variable on ext. ([#22542](https://github.com/expo/expo/pull/22542) by [@josephyanks](https://github.com/josephyanks))
### 🐛 Bug fixes
- Fixed Android build warnings for Gradle version 8. ([#22537](https://github.com/expo/expo/pull/22537), [#22609](https://github.com/expo/expo/pull/22609) by [@kudo](https://github.com/kudo))
## 4.2.0 — 2023-05-08
_This version does not introduce any user-facing changes._
## 4.1.1 — 2023-02-09
_This version does not introduce any user-facing changes._
## 4.1.0 — 2023-02-03
### 💡 Others
- On Android bump `compileSdkVersion` and `targetSdkVersion` to `33`. ([#20721](https://github.com/expo/expo/pull/20721) by [@lukmccall](https://github.com/lukmccall))
## 4.0.0 — 2022-10-25
### 🛠 Breaking changes
- Bumped iOS deployment target to 13.0 and deprecated support for iOS 12. ([#18873](https://github.com/expo/expo/pull/18873) by [@tsapeta](https://github.com/tsapeta))
## 3.2.0 — 2022-04-18
### ⚠️ Notices
- On Android bump `compileSdkVersion` to `31`, `targetSdkVersion` to `31` and `Java` version to `11`. ([#16941](https://github.com/expo/expo/pull/16941) by [@bbarthec](https://github.com/bbarthec))
## 3.1.1 - 2022-02-01
### 🐛 Bug fixes
- Fix `Plugin with id 'maven' not found` build error from Android Gradle 7. ([#16080](https://github.com/expo/expo/pull/16080) by [@kudo](https://github.com/kudo))
## 3.1.0 — 2021-12-03
_This version does not introduce any user-facing changes._
## 3.0.0 — 2021-09-28
### 🛠 Breaking changes
- Dropped support for iOS 11.0 ([#14383](https://github.com/expo/expo/pull/14383) by [@cruzach](https://github.com/cruzach))
### 🐛 Bug fixes
- Fix building errors from use_frameworks! in Podfile. ([#14523](https://github.com/expo/expo/pull/14523) by [@kudo](https://github.com/kudo))
## 2.3.0-alpha.0 — 2021-08-17
_This version does not introduce any user-facing changes._
## 2.2.0 — 2021-06-16
### 🐛 Bug fixes
- Enable kotlin in all modules. ([#12716](https://github.com/expo/expo/pull/12716) by [@wschurman](https://github.com/wschurman))
## 2.1.1 — 2021-03-23
_This version does not introduce any user-facing changes._
## 2.1.0 — 2021-03-10
### 🎉 New features
- Updated Android build configuration to target Android 11 (added support for Android SDK 30). ([#11647](https://github.com/expo/expo/pull/11647) by [@bbarthec](https://github.com/bbarthec))
### 🐛 Bug fixes
- Remove peerDependencies and unimodulePeerDependencies from Expo modules. ([#11980](https://github.com/expo/expo/pull/11980) by [@brentvatne](https://github.com/brentvatne))
## 2.0.0 — 2021-01-15
### 🛠 Breaking changes
- Dropped support for iOS 10.0 ([#11344](https://github.com/expo/expo/pull/11344) by [@tsapeta](https://github.com/tsapeta))
## 1.3.0 — 2020-11-17
_This version does not introduce any user-facing changes._
## 1.2.0 — 2020-08-18
_This version does not introduce any user-facing changes._
## 1.1.1 — 2020-05-29
_This version does not introduce any user-facing changes._
## 1.1.0 — 2020-05-27
_This version does not introduce any user-facing changes._

View File

@@ -0,0 +1,25 @@
# expo-image-loader
Provides image loader
# Installation in managed Expo projects
For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
# Installation in bare React Native projects
For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
### Add the package to your npm dependencies
```
npm install expo-image-loader
```
### Configure for Android
No additional set up necessary.
# Contributing
Contributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).

View File

@@ -0,0 +1,32 @@
apply plugin: 'com.android.library'
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
apply from: expoModulesCorePlugin
applyKotlinExpoModulesCorePlugin()
useCoreDependencies()
useDefaultAndroidSdkVersions()
useExpoPublishing()
buildscript {
// Simple helper that allows the root project to override versions declared by this library.
ext.safeExtGet = { prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
}
group = 'host.exp.exponent'
version = '4.7.0'
android {
namespace "expo.modules.imageloader"
defaultConfig {
versionCode 8
versionName "4.7.0"
}
}
def glideVersion = safeExtGet('glideVersion', '4.16.0')
dependencies {
api "com.github.bumptech.glide:glide:${glideVersion}"
}

View File

@@ -0,0 +1,2 @@
<manifest>
</manifest>

View File

@@ -0,0 +1,105 @@
package expo.modules.imageloader
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import expo.modules.core.interfaces.InternalModule
import expo.modules.interfaces.imageloader.ImageLoaderInterface
import java.util.concurrent.ExecutionException
import java.util.concurrent.Future
class ImageLoaderModule(val context: Context) : InternalModule, ImageLoaderInterface {
override fun getExportedInterfaces(): List<Class<*>> {
return listOf(ImageLoaderInterface::class.java)
}
override fun loadImageForDisplayFromURL(url: String): Future<Bitmap> {
val future = SimpleSettableFuture<Bitmap>()
loadImageForDisplayFromURL(
url,
object : ImageLoaderInterface.ResultListener {
override fun onSuccess(bitmap: Bitmap) = future.set(bitmap)
override fun onFailure(cause: Throwable?) =
future.setException(ExecutionException(cause))
}
)
return future
}
override fun loadImageForDisplayFromURL(
url: String,
resultListener: ImageLoaderInterface.ResultListener
) {
Glide.with(context)
.asBitmap()
.load(url)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
resultListener.onSuccess(resource)
}
override fun onLoadCleared(placeholder: Drawable?) {
// no op
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
resultListener.onFailure(Exception("Loading bitmap failed"))
}
})
}
override fun loadImageForManipulationFromURL(url: String): Future<Bitmap> {
val future = SimpleSettableFuture<Bitmap>()
loadImageForManipulationFromURL(
url,
object : ImageLoaderInterface.ResultListener {
override fun onSuccess(bitmap: Bitmap) = future.set(bitmap)
override fun onFailure(cause: Throwable?) = future.setException(ExecutionException(cause))
}
)
return future
}
override fun loadImageForManipulationFromURL(
url: String,
resultListener: ImageLoaderInterface.ResultListener
) {
val normalizedUrl = normalizeAssetsUrl(url)
Glide.with(context)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.load(normalizedUrl)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
resultListener.onSuccess(resource)
}
override fun onLoadCleared(placeholder: Drawable?) {
// no op
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
resultListener.onFailure(Exception("Loading bitmap failed"))
}
})
}
private fun normalizeAssetsUrl(url: String): String {
var actualUrl = url
if (url.startsWith("asset:///")) {
actualUrl = "file:///android_asset/" + url.split("/").last()
}
return actualUrl
}
}

View File

@@ -0,0 +1,9 @@
package expo.modules.imageloader
import android.content.Context
import expo.modules.core.BasePackage
import expo.modules.core.interfaces.InternalModule
class ImageLoaderPackage : BasePackage() {
override fun createInternalModules(context: Context): List<InternalModule> = listOf(ImageLoaderModule(context))
}

View File

@@ -0,0 +1,120 @@
// Copied from React Native
package expo.modules.imageloader;
import androidx.annotation.Nullable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* A super simple Future-like class that can safely notify another Thread when a value is ready.
* Does not support canceling.
*/
public class SimpleSettableFuture<T> implements Future<T> {
private final CountDownLatch mReadyLatch = new CountDownLatch(1);
private @Nullable
T mResult;
private @Nullable
Exception mException;
/**
* Sets the result. If another thread has called {@link #get}, they will immediately receive the
* value. set or setException must only be called once.
*/
public void set(@Nullable T result) {
checkNotSet();
mResult = result;
mReadyLatch.countDown();
}
/**
* Sets the exception. If another thread has called {@link #get}, they will immediately receive
* the exception. set or setException must only be called once.
*/
public void setException(Exception exception) {
checkNotSet();
mException = exception;
mReadyLatch.countDown();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
throw new UnsupportedOperationException();
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return mReadyLatch.getCount() == 0;
}
@Override
public @Nullable
T get() throws InterruptedException, ExecutionException {
mReadyLatch.await();
if (mException != null) {
throw new ExecutionException(mException);
}
return mResult;
}
/**
* Wait up to the timeout time for another Thread to set a value on this future. If a value has
* already been set, this method will return immediately.
*
* <p>NB: For simplicity, we catch and wrap InterruptedException. Do NOT use this class if you are
* in the 1% of cases where you actually want to handle that.
*/
@Override
public @Nullable
T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (!mReadyLatch.await(timeout, unit)) {
throw new TimeoutException("Timed out waiting for result");
}
if (mException != null) {
throw new ExecutionException(mException);
}
return mResult;
}
/**
* Convenience wrapper for {@link #get()} that re-throws get()'s Exceptions as RuntimeExceptions.
*/
public @Nullable
T getOrThrow() {
try {
return get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Convenience wrapper for {@link #get(long, TimeUnit)} that re-throws get()'s Exceptions as
* RuntimeExceptions.
*/
public @Nullable
T getOrThrow(long timeout, TimeUnit unit) {
try {
return get(timeout, unit);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}
}
private void checkNotSet() {
if (mReadyLatch.getCount() == 0) {
throw new RuntimeException("Result has already been set!");
}
}
}

View File

@@ -0,0 +1,3 @@
{
"platforms": ["ios", "android"]
}

View File

@@ -0,0 +1 @@
module.exports = null;

View File

@@ -0,0 +1,32 @@
require 'json'
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
Pod::Spec.new do |s|
s.name = 'EXImageLoader'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = package['homepage']
s.platform = :ios, '13.4'
s.source = { git: 'https://github.com/expo/expo.git' }
s.static_framework = true
s.dependency 'React-Core'
s.dependency 'ExpoModulesCore'
# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'SWIFT_COMPILATION_MODE' => 'wholemodule'
}
if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0')
s.source_files = "#{s.name}/**/*.h"
s.vendored_frameworks = "#{s.name}.xcframework"
else
s.source_files = "#{s.name}/**/*.{h,m}"
end
end

View File

@@ -0,0 +1,10 @@
// Copyright 2019-present 650 Industries. All rights reserved.
#import <ExpoModulesCore/EXInternalModule.h>
#import <ExpoModulesCore/EXImageLoaderInterface.h>
#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>
@interface EXImageLoader : NSObject <RCTBridgeModule, EXInternalModule, EXImageLoaderInterface>
@end

View File

@@ -0,0 +1,41 @@
// Copyright 2019-present 650 Industries. All rights reserved.
#import <EXImageLoader/EXImageLoader.h>
#import <React/RCTImageLoaderProtocol.h>
#import <ExpoModulesCore/EXUtilities.h>
@interface EXImageLoader ()
@property (weak, nonatomic) RCTBridge *bridge;
@end
@implementation EXImageLoader
EX_REGISTER_MODULE();
+ (NSString *)moduleName
{
return @"EXImageLoader";
}
+ (const NSArray<Protocol *> *)exportedInterfaces
{
return @[@protocol(EXImageLoaderInterface)];
}
- (void)setBridge:(RCTBridge *)bridge
{
_bridge = bridge;
}
- (void)loadImageForURL:(NSURL *)imageURL
completionHandler:(EXImageLoaderCompletionBlock)completionHandler
{
[[_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] loadImageWithURLRequest:[NSURLRequest requestWithURL:imageURL]
callback:^(NSError *error, UIImage *loadedImage) {
completionHandler(error, loadedImage);
}];
}
@end

View File

@@ -0,0 +1,28 @@
{
"name": "expo-image-loader",
"version": "4.7.0",
"description": "Image loader",
"main": "index.js",
"keywords": [
"unimodules",
"image-loader",
"expo-image-loader"
],
"repository": {
"type": "git",
"url": "https://github.com/expo/expo.git",
"directory": "packages/expo-image-loader"
},
"bugs": {
"url": "https://github.com/expo/expo/issues"
},
"author": "650 Industries, Inc.",
"license": "MIT",
"homepage": "https://github.com/expo/expo/tree/main/packages/expo-image-loader",
"dependencies": {},
"devDependencies": {},
"peerDependencies": {
"expo": "*"
},
"gitHead": "4165b8d72e1b9a1889c2767534cc619e21468110"
}