todos-contra-el-fuego-mobile/lib/models/firesApi.dart
vjrj 8da3752193 Fix 23 additional lint issues to reduce from 129 to 106 issues
- Add const constructors to @immutable classes (5 issues: prefer_const_constructors_in_immutables)
- Fix nullable value casts in firesApi.dart (3 issues: cast_nullable_to_non_nullable)
- Remove redundant default argument values (2 issues: avoid_redundant_argument_values)
- Make YourLocation immutable with final fields (2 issues: avoid_equals_and_hash_code_on_mutable_classes)
- Update imports and fix formatting

Reduces lint issues from 129 to 106. APK builds successfully (146 MB).
2026-03-11 23:45:06 +01:00

245 lines
8.9 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>? responseData = response.data;
if (responseData == null) {
throw Exception('Response data is null');
}
final Map<String, dynamic> data = responseData;
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>? responseData = response.data;
if (responseData == null) {
throw Exception('Response data is null');
}
final Map<String, dynamic> data = responseData;
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>? responseData = response.data;
if (responseData == null) {
throw Exception('Response data is null');
}
final Map<String, dynamic> data = responseData;
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) {
debugPrint(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>;
debugPrint(dataData['upsert'].toString());
}
return true;
} else {
debugPrint(response.data.toString());
return false;
}
} catch (e) {
debugPrint('Error marking false positive: $e');
return false;
}
}
}