mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
Frontend events are being returned from the API (yey!)
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/utils/friendly_date_formatter.dart';
|
||||
import '../utils/friendly_date_formatter.dart';
|
||||
import '../model/event.dart';
|
||||
import '../model/device_type.dart';
|
||||
import '../utils/oott_api.dart';
|
||||
|
||||
class EventsList extends StatefulWidget {
|
||||
@override
|
||||
@@ -9,91 +9,63 @@ class EventsList extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _EventListState extends State<EventsList> {
|
||||
// Dummy events to display
|
||||
// TODO : Replace with API call
|
||||
List<Event> events = <Event>[
|
||||
Event(
|
||||
id: 5,
|
||||
title: 'New device found',
|
||||
description: 'Apple device @ 192.168.0.1 with MAC 56:e7:e3:07:d2:d5',
|
||||
isRead: false,
|
||||
deviceType: DeviceType.phone,
|
||||
dateTime: DateTime.now().subtract(Duration(minutes: 22)),
|
||||
),
|
||||
Event(
|
||||
id: 4,
|
||||
title: 'New device found',
|
||||
description: 'Apple device @ 192.168.0.1 with MAC 56:e7:e3:07:d2:d5',
|
||||
isRead: false,
|
||||
deviceType: DeviceType.pc,
|
||||
dateTime: DateTime.now().subtract(Duration(minutes: 87)),
|
||||
),
|
||||
Event(
|
||||
id: 3,
|
||||
title: 'New device found',
|
||||
description: 'Apple device @ 192.168.0.1 with MAC 56:e7:e3:07:d2:d5',
|
||||
isRead: false,
|
||||
deviceType: DeviceType.tablet,
|
||||
dateTime: DateTime.now().subtract(Duration(hours: 23)),
|
||||
),
|
||||
Event(
|
||||
id: 2,
|
||||
title: 'New device found',
|
||||
description: 'Apple device @ 192.168.0.1 with MAC 56:e7:e3:07:d2:d5',
|
||||
isRead: false,
|
||||
deviceType: DeviceType.server,
|
||||
dateTime: DateTime(2026, 01, 19, 14, 47),
|
||||
),
|
||||
Event(
|
||||
id: 1,
|
||||
title: 'New device found',
|
||||
description: 'Apple device @ 192.168.0.1 with MAC 56:e7:e3:07:d2:d5',
|
||||
isRead: false,
|
||||
deviceType: DeviceType.phone,
|
||||
dateTime: DateTime(2026, 01, 17, 14, 47),
|
||||
),
|
||||
];
|
||||
bool _isLoading = true;
|
||||
List<Event>? _events;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_getData();
|
||||
}
|
||||
|
||||
void _getData() async {
|
||||
_events = await BackendAPI.instance.listNotifications();
|
||||
_isLoading = false;
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Events')),
|
||||
body: ListView.separated(
|
||||
itemCount: events.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Dismissible(
|
||||
key: UniqueKey(),
|
||||
onDismissed: (direction) {
|
||||
setState(() {
|
||||
events.removeAt(index);
|
||||
});
|
||||
body: _isLoading
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: ListView.separated(
|
||||
itemCount: _events!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Dismissible(
|
||||
key: UniqueKey(),
|
||||
onDismissed: (direction) {
|
||||
setState(() {
|
||||
_events!.removeAt(index);
|
||||
});
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Event marked as read'),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
showCloseIcon: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
background: Container(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
alignment: Alignment.center,
|
||||
child: Icon(Icons.done),
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Event marked as read'),
|
||||
behavior: SnackBarBehavior.floating,
|
||||
showCloseIcon: true,
|
||||
),
|
||||
);
|
||||
},
|
||||
background: Container(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
alignment: Alignment.center,
|
||||
child: Icon(Icons.done),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: Icon(_events![index].notificationType.icon),
|
||||
title: Text(
|
||||
'${FriendlyDateFormatter().format(_events![index].createdOn)} - ${_events![index].title}',
|
||||
),
|
||||
subtitle: Text(_events![index].body),
|
||||
trailing: Icon(Icons.more_vert),
|
||||
onTap: () {},
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: Icon(events[index].deviceType.icon),
|
||||
title: Text(
|
||||
'${FriendlyDateFormatter().format(events[index].dateTime)} - ${events[index].title}',
|
||||
),
|
||||
subtitle: Text(events[index].description),
|
||||
trailing: Icon(Icons.more_vert),
|
||||
onTap: () {},
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ void main() {
|
||||
runApp(const MainApp());
|
||||
}
|
||||
|
||||
class MainApp extends StatelessWidget {
|
||||
final class MainApp extends StatelessWidget {
|
||||
const MainApp({super.key});
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum DeviceType {
|
||||
phone,
|
||||
pc,
|
||||
tablet,
|
||||
server;
|
||||
|
||||
IconData get icon {
|
||||
switch (this) {
|
||||
case phone:
|
||||
return Icons.phone_iphone;
|
||||
case pc:
|
||||
return Icons.computer;
|
||||
case tablet:
|
||||
return Icons.tablet;
|
||||
case server:
|
||||
return Icons.storage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,38 @@
|
||||
import 'device_type.dart';
|
||||
import 'notification_type.dart';
|
||||
|
||||
class Event {
|
||||
int id;
|
||||
String title;
|
||||
String description;
|
||||
bool isRead;
|
||||
DeviceType deviceType;
|
||||
DateTime dateTime;
|
||||
String body;
|
||||
bool isNew;
|
||||
NotificationType notificationType;
|
||||
DateTime createdOn;
|
||||
|
||||
Event({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.deviceType,
|
||||
required this.dateTime,
|
||||
this.isRead = false,
|
||||
required this.body,
|
||||
required this.notificationType,
|
||||
required this.createdOn,
|
||||
this.isNew = true,
|
||||
});
|
||||
|
||||
Event.fromJson(Map<String, dynamic> json)
|
||||
: id = json['id'] as int,
|
||||
createdOn = DateTime.parse(json['created_on'] as String),
|
||||
notificationType = NotificationType.fromString(
|
||||
json['notification_type'] as String,
|
||||
),
|
||||
title = json['title'] as String,
|
||||
body = json['body'] as String,
|
||||
isNew = json['is_new'] as bool;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'created_on': createdOn.toUtc().toIso8601String(),
|
||||
'notification_type': notificationType.toString,
|
||||
'title': title,
|
||||
'body': body,
|
||||
'is_new': isNew,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum NotificationType {
|
||||
newDeviceFound,
|
||||
deviceOnlineAfterTime,
|
||||
deviceChanged,
|
||||
other;
|
||||
|
||||
IconData get icon {
|
||||
switch (this) {
|
||||
case newDeviceFound:
|
||||
return Icons.devices;
|
||||
case deviceOnlineAfterTime:
|
||||
return Icons.timer;
|
||||
case deviceChanged:
|
||||
return Icons.change_circle;
|
||||
case other:
|
||||
return Icons.priority_high;
|
||||
}
|
||||
}
|
||||
|
||||
static NotificationType fromString(String value) =>
|
||||
switch (value.toLowerCase()) {
|
||||
"newdevicefound" => newDeviceFound,
|
||||
"deviceonlineaftertime" => deviceOnlineAfterTime,
|
||||
"devicechanged" => deviceChanged,
|
||||
_ => other,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:frontend/model/event.dart';
|
||||
|
||||
class BackendAPI {
|
||||
BackendAPI._singleton();
|
||||
|
||||
static final BackendAPI instance = BackendAPI._singleton();
|
||||
|
||||
static final String _baseUrl = 'http://localhost:3000/api';
|
||||
static final String _apiKey = 'super_secret';
|
||||
|
||||
final Dio _dio = Dio(
|
||||
BaseOptions(
|
||||
baseUrl: _baseUrl,
|
||||
headers: {
|
||||
HttpHeaders.contentTypeHeader: 'application/json',
|
||||
HttpHeaders.authorizationHeader: 'Bearer $_apiKey',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
Future<List<Event>> listNotifications() async {
|
||||
print('About to call /notifications');
|
||||
|
||||
Response response;
|
||||
response = await _dio.get('/notifications');
|
||||
|
||||
print('Received: ' + response.data.toString());
|
||||
|
||||
List<dynamic> list = response.data;
|
||||
print('List contains ' + list.length.toString() + ' items');
|
||||
|
||||
List<Event> events = List<Event>.from(
|
||||
list.map((item) => Event.fromJson(item)),
|
||||
);
|
||||
|
||||
print('Parsed ' + events.length.toString() + ' events');
|
||||
|
||||
return events;
|
||||
}
|
||||
}
|
||||
+56
-8
@@ -21,10 +21,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
||||
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.4.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -41,6 +41,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
dio:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dio
|
||||
sha256: b9d46faecab38fc8cc286f80bc4d61a3bb5d4ac49e51ed877b4d6706efe57b25
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.9.1"
|
||||
dio_web_adapter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dio_web_adapter
|
||||
sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -80,6 +96,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "17.1.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -132,18 +156,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.17"
|
||||
version: "0.12.18"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.1"
|
||||
version: "0.13.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -152,6 +176,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -225,10 +257,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
|
||||
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.7"
|
||||
version: "0.7.9"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -245,6 +285,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.0.2"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
sdks:
|
||||
dart: ">=3.10.8 <4.0.0"
|
||||
flutter: ">=3.35.0"
|
||||
|
||||
@@ -12,6 +12,7 @@ dependencies:
|
||||
go_router: ^17.1.0
|
||||
intl: ^0.20.2
|
||||
provider: ^6.1.5
|
||||
dio: ^5.9.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user