Untitled
unknown
dart
a year ago
9.3 kB
9
Indexable
class AlertListPage extends StatefulWidget {
const AlertListPage({super.key});
@override
State<AlertListPage> createState() => _AlertListPageState();
}
class _AlertListPageState extends State<AlertListPage>
with WidgetsBindingObserver {
final int batchSize = 1;
int loadedAlertsCount = 3;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
debugPrint('alerts view initilize');
}
@override
void dispose() {
debugPrint('alerts view disposed');
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.detached) {}
if (state == AppLifecycleState.hidden) {}
}
int compareAlertLevels(String level1, String level2) {
final priorityOrder = {
'Emergency': 0,
'High': 1,
'Medium': 2,
'Low': 3,
'Resolved': 4
};
final priority1 =
priorityOrder[level1] ?? 999; // Default to lowest priority
final priority2 =
priorityOrder[level2] ?? 999; // Default to lowest priority
return priority1.compareTo(priority2);
}
double haversine(double lat1, double lon1, double lat2, double lon2) {
// Convert latitude and longitude from degrees to radians
lat1 = _degreesToRadians(lat1);
lon1 = _degreesToRadians(lon1);
lat2 = _degreesToRadians(lat2);
lon2 = _degreesToRadians(lon2);
// Haversine formula
double dlon = lon2 - lon1;
double dlat = lat2 - lat1;
double a = math.pow(math.sin(dlat / 2), 2) +
math.cos(lat1) * math.cos(lat2) * math.pow(math.sin(dlon / 2), 2);
double c = 2 * math.asin(math.sqrt(a));
double r = 6371.0; // Radius of the Earth in kilometers
// Calculate the result
double distance = c * r;
return distance;
}
double _degreesToRadians(double degrees) {
return degrees * math.pi / 180;
}
List<Alert> sortAlertsBySeverityAndDistance(
List<Alert> alerts, double userLatitude, double userLongitude) {
alerts.sort((a, b) => compareAlertLevels(a.severity, b.severity));
// Now sort within each severity level by distance
alerts.sort((a, b) {
final distance1 = haversine(
a.latitude ?? 0, a.longitude ?? 0, userLatitude, userLongitude);
final distance2 = haversine(
b.latitude ?? 0, b.longitude ?? 0, userLatitude, userLongitude);
if (distance1 < 0.1 && distance2 >= 0.1) {
return -1; // a is closer, should come first
} else if (distance1 >= 0.1 && distance2 < 0.1) {
return 1; // b is closer, should come first
} else {
return 0; // distances are either both close or both not close
}
});
return alerts;
}
@override
Widget build(BuildContext context) {
context.read<AlertCubit>().resumeSubscription();
bool? isAdmin = context.read<UserProvider>().user?.isAdmin;
return Scaffold(
appBar: AppBar(
title: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
width: 230,
child: Text(
'Detection Alerts',
style: TextStyle(
color: Colors.black54,
fontFamily: Fonts.beautiful_people,
fontWeight: FontWeight.w900,
fontSize: 25,
shadows: [
Shadow(
offset: Offset(0, 3),
blurRadius: 5,
color: Colors.white12,
),
],
),
textAlign: TextAlign.center,
),
),
const SizedBox(width: 4),
SizedBox(
child: Image.asset(
'assets/images/projectLogo.png',
fit: BoxFit.contain,
width: 40,
height: 40,
),
),
],
),
),
),
body: BlocBuilder<AlertCubit, AlertState>(
builder: (context, state) {
if (state is AlertStateInitial) {
return const Center(child: Text('Initializing...'));
} else if (state is AlertStateLoading) {
return const Center(child: CircularProgressIndicator());
} else if (state is AlertStateLoaded) {
final alerts = state.alertsList;
alerts.sort((a, b) => compareAlertLevels(a.severity, b.severity));
//TODO: add here the location of the user..
// + needs to fake locations!! and details...
final user = context.read<UserProvider>().user!;
List<Alert> userSortedAlerts = sortAlertsBySeverityAndDistance(
state.alertsList,
user.latitude ?? 23.09,
user.longitude ?? 41.121);
final displayedAlerts = isAdmin!
? alerts
: userSortedAlerts
.where((alert) =>
(alert.isConfirmed || alert.severity == 'Emergency') &&
alert.severity != 'Resolved')
.toList();
final alertsToShow =
displayedAlerts.take(loadedAlertsCount).toList();
if (alertsToShow.isEmpty) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.info_outline,
color: Colors.blueAccent,
size: 50,
),
SizedBox(height: 20),
Text(
'No alerts found!',
style: TextStyle(
color: Colors.black54,
fontFamily: 'Roboto',
fontWeight: FontWeight.w600,
fontSize: 20,
shadows: [
Shadow(
offset: Offset(0, 2),
blurRadius: 4,
color: Colors.black26,
),
],
),
textAlign: TextAlign.center,
),
SizedBox(height: 10),
Text(
'You are all caught up',
style: TextStyle(
color: Colors.black45,
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
fontSize: 16,
),
textAlign: TextAlign.center,
),
],
),
);
}
return Column(
children: [
Expanded(
child: ListView.builder(
itemCount: alertsToShow.length,
itemBuilder: (context, index) {
final alert = alertsToShow[index];
double lat1 = alert.latitude ?? 31.9803889;
double lon1 = alert.longitude ?? 34.8158181;
double lat2 = 31.9803889;
double lon2 = 34.8130534;
double distance = haversine(lat1, lon1, lat2, lon2);
return AlertCard(
alert: alert,
isClose: distance > 1000,
);
},
),
),
if (loadedAlertsCount < displayedAlerts.length) ...[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: loadMoreAlerts,
child: const Text('Load More'),
),
const SizedBox(width: 16),
ElevatedButton(
onPressed: () => loadAllAlerts(displayedAlerts.length),
child: const Text('Load All'),
),
],
)
]
],
);
} else if (state is AlertStateError) {
return Center(
child: Text('Error: ${state.message}'),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
void loadMoreAlerts() {
setState(() {
loadedAlertsCount = loadedAlertsCount + batchSize;
});
}
void loadAllAlerts(int totalAlerts) {
setState(() {
loadedAlertsCount = totalAlerts;
});
}
}
Editor is loading...
Leave a Comment