diff --git a/mercury_frontend/lib/main.dart b/mercury_frontend/lib/main.dart index 0030a96..7d384d0 100644 --- a/mercury_frontend/lib/main.dart +++ b/mercury_frontend/lib/main.dart @@ -1,7 +1,15 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'sensor_provider.dart'; +import 'package:timeago/timeago.dart' as timeago; void main() { - runApp(const MyApp()); + runApp( + ChangeNotifierProvider( + create: (context) => SensorProvider(), + child: const MyApp(), + ), + ); } class MyApp extends StatelessWidget { @@ -10,30 +18,28 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'Sensor App', theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + primarySwatch: Colors.blue, ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), + home: const SensorScreen(), ); } } -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - final String title; +class SensorScreen extends StatefulWidget { + const SensorScreen({super.key}); @override - State createState() => _MyHomePageState(); + _SensorScreenState createState() => _SensorScreenState(); } -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - _counter++; +class _SensorScreenState extends State { + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + Provider.of(context, listen: false).fetchData(); }); } @@ -41,25 +47,37 @@ class _MyHomePageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(widget.title), + title: const Text('Mercury'), ), body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('You have pushed the button this many times:'), - Text( - '$_counter', - style: Theme.of(context).textTheme.headlineMedium, - ), - ], + child: Consumer( + builder: (context, sensorProvider, child) { + if (sensorProvider.sensorData == null) { + if (sensorProvider.error != null) { + return Text('Error: ${sensorProvider.error}'); + } + return const CircularProgressIndicator(); + } else { + final data = sensorProvider.sensorData!; + final timeAgo = timeago.format(DateTime.fromMillisecondsSinceEpoch(data.timestamp)); + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('🌡️ Temperature: ${data.temperature}°C'), + Text('💧 Humidity: ${data.humidity}%'), + Text('❄️ Dew Point: ${data.dewPoint}°C'), + Text('🕒 $timeAgo'), + ], + ); + } + }, ), ), floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: const Icon(Icons.add), + onPressed: () { + Provider.of(context, listen: false).fetchData(); + }, + child: const Icon(Icons.refresh), ), ); } diff --git a/mercury_frontend/lib/sensor_data.dart b/mercury_frontend/lib/sensor_data.dart new file mode 100644 index 0000000..4e45549 --- /dev/null +++ b/mercury_frontend/lib/sensor_data.dart @@ -0,0 +1,22 @@ +class SensorData { + final double temperature; + final double humidity; + final double dewPoint; + final int timestamp; + + SensorData({ + required this.temperature, + required this.humidity, + required this.dewPoint, + required this.timestamp, + }); + + factory SensorData.fromJson(Map json) { + return SensorData( + temperature: json['temperature'], + humidity: json['humidity'], + dewPoint: json['dewPoint'], + timestamp: json['timestamp'], + ); + } +} \ No newline at end of file diff --git a/mercury_frontend/lib/sensor_provider.dart b/mercury_frontend/lib/sensor_provider.dart new file mode 100644 index 0000000..fc536c1 --- /dev/null +++ b/mercury_frontend/lib/sensor_provider.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'sensor_data.dart'; +import 'sensor_service.dart'; + +class SensorProvider with ChangeNotifier { + final SensorService _service = SensorService(); + SensorData? _sensorData; + + Error? _error; + + SensorData? get sensorData => _sensorData; + + Error? get error => _error; + + Future fetchData() async { + try { + _sensorData = await _service.fetchSensorData(); + } catch (e) { + _error = e as Error; + } + notifyListeners(); + } +} diff --git a/mercury_frontend/lib/sensor_service.dart b/mercury_frontend/lib/sensor_service.dart new file mode 100644 index 0000000..9c13342 --- /dev/null +++ b/mercury_frontend/lib/sensor_service.dart @@ -0,0 +1,17 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'sensor_data.dart'; + +class SensorService { + final String url = 'https://mercury.segin.one/sensor'; + + Future fetchSensorData() async { + final response = await http.get(Uri.parse(url)); + + if (response.statusCode == 200) { + return SensorData.fromJson(json.decode(response.body)); + } else { + throw Exception('Failed to load sensor data'); + } + } +} \ No newline at end of file diff --git a/mercury_frontend/pubspec.lock b/mercury_frontend/pubspec.lock index c2c57f7..34ba6cb 100644 --- a/mercury_frontend/pubspec.lock +++ b/mercury_frontend/pubspec.lock @@ -75,6 +75,30 @@ packages: description: flutter source: sdk version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + url: "https://pub.dev" + source: hosted + version: "1.3.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + intl: + dependency: transitive + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" leak_tracker: dependency: transitive description: @@ -131,6 +155,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.16.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -139,6 +171,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" sky_engine: dependency: transitive description: flutter @@ -192,6 +232,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.4" + timeago: + dependency: "direct main" + description: + name: timeago + sha256: "054cedf68706bb142839ba0ae6b135f6b68039f0b8301cbe8784ae653d5ff8de" + url: "https://pub.dev" + source: hosted + version: "3.7.0" + 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: @@ -208,6 +264,14 @@ packages: url: "https://pub.dev" source: hosted version: "14.3.1" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" sdks: dart: ">=3.7.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/mercury_frontend/pubspec.yaml b/mercury_frontend/pubspec.yaml index c10a03f..30e710d 100644 --- a/mercury_frontend/pubspec.yaml +++ b/mercury_frontend/pubspec.yaml @@ -34,6 +34,9 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 + provider: ^6.1.2 + http: ^1.3.0 + timeago: ^3.7.0 dev_dependencies: flutter_test: