todos-contra-el-fuego-mobile/lib/models/firesApi.dart
vjrj 2bf42ce262 refactor: remove comunes-flutter dependency and inline components
Remove the external comunes-flutter library dependency and replace all its
components with local implementations:

- Utility functions: Created lib/utils/widget_utils.dart with compactWidgets()
  and ellipse() functions, replacing the comunes-flutter helpers with modern
  Dart null-safety patterns (whereType instead of where(notNull))
- Secret loader: Inlined as lib/utils/secret_loader.dart for loading JSON config
- Layout widgets: Replaced CenteredRow/CenteredColumn with standard Row/Column
  with MainAxisAlignment.center
- Intro screens: Copied AppIntroPage and MaterialAppWithIntro locally in
  lib/widgets/ with cleaned-up deprecated code patterns
- Button widget: Created lib/widgets/rounded_btn.dart for the RoundedBtn used
  in activeFires.dart

Changes span 20 files:
- 5 new utility/widget files created
- Updated imports in 15 files
- Removed path dependency from pubspec.yaml
- All functionality preserved, build verified with flutter pub get

Impact:
- Removes external dependency, simplifying project structure
- Modern Dart patterns (proper null-safety)
- Better code clarity with explicit widget properties
- Easier onboarding (no 'what is comunes-flutter?' questions)
2026-03-07 18:19:33 +01:00

233 lines
8.5 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import '../globals.dart' as globals;
import '../objectIdUtils.dart';
import '../redux/actions.dart';
import 'appState.dart';
import 'falsePositiveTypes.dart';
import 'yourLocation.dart';
class FiresApi {
FiresApi() {
_dio = Dio();
}
late final Dio _dio;
Future<String> createUser(
AppState state, String mobileToken, String lang) async {
final Map<String, String> params = <String, String>{
'token': state.firesApiKey,
'mobileToken': mobileToken,
'lang': lang
};
final String url = '${state.firesApiUrl}mobile/users';
try {
final Response<Map<String, dynamic>> response =
await _dio.post<Map<String, dynamic>>(url, data: params);
if (response.statusCode == 200) {
final Map<String, dynamic> data = response.data as Map<String, dynamic>;
final Map<String, dynamic> dataData =
data['data'] as Map<String, dynamic>;
return dataData['userId'] as String;
} else {
throw Exception('Unexpected error on create user');
}
} catch (e) {
throw Exception('Error creating user: $e');
}
}
Future<List<YourLocation>> fetchYourLocations(AppState state) async {
final String apiKey = state.firesApiKey;
final String mobileToken = state.user.token;
final String url =
'${state.firesApiUrl}mobile/subscriptions/all/$apiKey/$mobileToken';
try {
final Response<Map<String, dynamic>> response =
await _dio.get<Map<String, dynamic>>(url);
if (response.statusCode == 200) {
final Map<String, dynamic> data = response.data as Map<String, dynamic>;
final Map<String, dynamic> dataData =
data['data'] as Map<String, dynamic>;
final List<dynamic> dataSubscriptions =
dataData['subscriptions'] as List<dynamic>;
final List<YourLocation> subscribed = <YourLocation>[];
for (int i = 0; i < dataSubscriptions.length; i++) {
final Map<String, dynamic> el =
dataSubscriptions[i] as Map<String, dynamic>;
final Map<String, dynamic> location =
el['location'] as Map<String, dynamic>;
final double lat = (location['lat'] as num).toDouble();
final double lon = (location['lon'] as num).toDouble();
final Map<String, dynamic> id = el['_id'] as Map<String, dynamic>;
subscribed.add(YourLocation(
id: objectIdFromJson(id['_str'] as String),
lat: lat,
lon: lon,
subscribed: true,
distance: (el['distance'] as num).toInt()));
}
return subscribed;
} else {
throw Exception('Unexpected error fetching your locations');
}
} catch (e) {
throw Exception('Error fetching locations: $e');
}
}
Future<String> subscribe(AppState state, YourLocation loc) async {
final Map<String, Object> params = <String, Object>{
'token': state.firesApiKey,
'mobileToken': state.user.token,
'id': loc.id.hexString,
'lat': loc.lat,
'lon': loc.lon,
'distance': loc.distance
};
final String url = '${state.firesApiUrl}mobile/subscriptions';
try {
final Response<Map<String, dynamic>> response =
await _dio.post<Map<String, dynamic>>(url, data: params);
if (response.statusCode == 200) {
final Map<String, dynamic> data = response.data as Map<String, dynamic>;
final Map<String, dynamic> dataData =
data['data'] as Map<String, dynamic>;
return dataData['subsId'] as String;
} else {
throw Exception('Unexpected error on subscribe');
}
} catch (e) {
throw Exception('Error subscribing: $e');
}
}
Future<bool> unsubscribe(AppState state, String subsId) async {
final String apiKey = state.firesApiKey;
final String mobileToken = state.user.token;
final String url =
'${state.firesApiUrl}mobile/subscriptions/$apiKey/$mobileToken/$subsId';
try {
final Response<dynamic> response = await _dio.delete(url);
if (response.statusCode == 200) {
return true;
} else {
throw Exception('Unexpected error on unsubscribe');
}
} catch (e) {
throw Exception('Error unsubscribing: $e');
}
}
Future<UpdateFireMapStatsAction> getFiresInLocation(
{required AppState state,
required double lat,
required double lon,
required int distance}) async {
final String url =
'${state.firesApiUrl}fires-in-full/${state.firesApiKey}/$lat/$lon/$distance';
if (globals.isDevelopment) {
print(url);
}
try {
final Response<dynamic> response = await _dio.get(url);
if (response.statusCode == 200) {
final Map<String, dynamic> resultDecoded =
response.data as Map<String, dynamic>;
final int numFires = (resultDecoded['real'] as num).toInt();
final List<dynamic> fires = resultDecoded['fires'] as List<dynamic>;
final List<dynamic> falsePos =
resultDecoded['falsePos'] as List<dynamic>;
final List<dynamic> industries =
resultDecoded['industries'] as List<dynamic>;
if (globals.isDevelopment) {
// Could log: fires: ${fires.length} falsePos: ${falsePos.length} industries: ${industries.length}
}
return UpdateFireMapStatsAction(
numFires: numFires,
fires: fires,
falsePos: falsePos,
industries: industries);
} else
throw Exception('Wrong response trying to get fire data');
} catch (e) {
throw Exception('Error getting fires: $e');
}
}
Future<List<Polyline>> getMonitoredAreas({required AppState state}) async {
final String url =
'${state.firesApiUrl}status/subs-public-union/${state.firesApiKey}';
const Color color = Color(0xFF145A32);
try {
final Response<dynamic> response = await _dio.get(url);
if (response.statusCode == 200) {
final Map<String, dynamic> resultDecoded =
response.data as Map<String, dynamic>;
final List<Polyline> union = <Polyline>[];
final Map<String, dynamic> dataData =
resultDecoded['data'] as Map<String, dynamic>;
final Map<String, dynamic> unionData =
dataData['union'] as Map<String, dynamic>;
final String unionValue = unionData['value'] as String;
final List<dynamic> multipolygon =
(json.decode(unionValue) as Map<String, dynamic>)['geometry']
['coordinates'] as List<dynamic>;
for (final dynamic polygonDynamic in multipolygon) {
final List<dynamic> polygon = polygonDynamic as List<dynamic>;
for (final dynamic holeDynamic in polygon) {
final List<dynamic> hole = holeDynamic as List<dynamic>;
final List<LatLng> points = <LatLng>[];
for (final dynamic pointDynamic in hole) {
final List<dynamic> point = pointDynamic as List<dynamic>;
points.add(LatLng(
(point[1] as num).toDouble(), (point[0] as num).toDouble()));
}
union.add(Polyline(points: points, color: color, strokeWidth: 3.0));
}
}
return union;
} else
throw Exception('Wrong response trying to get fire data');
} catch (e) {
throw Exception('Error getting monitored areas: $e');
}
}
Future<bool> markFalsePositive(AppState state, String mobileToken,
String sealed, FalsePositiveType type) async {
final Map<String, String> params = <String, String>{
'token': state.firesApiKey,
'mobileToken': mobileToken,
'sealed': sealed,
'type': type.toString().split('.')[1]
};
final String url = '${state.firesApiUrl}mobile/falsepositive';
try {
final Response<dynamic> response = await _dio.post(url, data: params);
if (response.statusCode == 200) {
if (globals.isDevelopment) {
final Map<String, dynamic> data =
response.data as Map<String, dynamic>;
final Map<String, dynamic> dataData =
data['data'] as Map<String, dynamic>;
print(dataData['upsert']);
}
return true;
} else {
debugPrint(response.data.toString());
return false;
}
} catch (e) {
debugPrint('Error marking false positive: $e');
return false;
}
}
}