diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..0e14d8e
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "disabled"
+}
\ No newline at end of file
diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html
new file mode 100644
index 0000000..3993393
--- /dev/null
+++ b/android/build/reports/problems/problems-report.html
@@ -0,0 +1,663 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Gradle Configuration Cache
+
+
+
+
+
+
+ Loading...
+
+
+
+
+
+
+
diff --git a/assets/images/ecolab.png b/assets/images/ecolab.png
new file mode 100644
index 0000000..009eede
Binary files /dev/null and b/assets/images/ecolab.png differ
diff --git a/devtools_options.yaml b/devtools_options.yaml
new file mode 100644
index 0000000..fa0b357
--- /dev/null
+++ b/devtools_options.yaml
@@ -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:
diff --git a/lib/home.dart b/lib/home.dart
new file mode 100644
index 0000000..006f1de
--- /dev/null
+++ b/lib/home.dart
@@ -0,0 +1,170 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'sensor_bloc.dart';
+import 'sensor_state.dart';
+import 'sensor_event.dart';
+import 'model/sensor.dart';
+
+class HomeScreen extends StatefulWidget {
+ const HomeScreen({super.key});
+
+ @override
+ State createState() => _HomeScreenState();
+}
+
+class _HomeScreenState extends State {
+ String searchQuery = '';
+ bool isAscending = true;
+
+ @override
+ Widget build(BuildContext context) {
+ void _showEditDialog(Sensor sensor) {
+ final nameController = TextEditingController(text: sensor.name);
+ final descController = TextEditingController(text: sensor.description);
+ final bloc = context.read();
+
+ showDialog(
+ context: context,
+ builder: (context) => AlertDialog(
+ title: Text('Edit Sensor ${sensor.id}'),
+ content: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ TextField(
+ controller: nameController,
+ decoration: const InputDecoration(labelText: 'Name'),
+ ),
+ TextField(
+ controller: descController,
+ decoration: const InputDecoration(labelText: 'Description'),
+ ),
+ ],
+ ),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context),
+ child: const Text('Cancel'),
+ ),
+ ElevatedButton(
+ onPressed: () {
+ bloc.add(
+ EditSensorDetails(sensor.id, nameController.text, descController.text),
+ );
+ Navigator.pop(context);
+ },
+ child: const Text('Save'),
+ ),
+ ],
+ ),
+ );
+ }
+
+ return Scaffold(
+ appBar: AppBar(
+ toolbarHeight: 80,
+ title: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Image.asset(
+ 'assets/images/ecolab.png', // Ensure this path is correct
+ height: 40, // Adjust the height as needed
+ ),
+ const SizedBox(height: 10), // Add spacing between the image and the title
+ const Text('Thermal Sensors'),
+ ],
+ ),
+ bottom: PreferredSize(
+ preferredSize: const Size.fromHeight(80),
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: TextField(
+ onChanged: (val) => setState(() => searchQuery = val),
+ decoration: InputDecoration(
+ hintText: 'Search by name or description...',
+ prefixIcon: const Icon(Icons.search),
+ border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
+ ),
+ ),
+ ),
+ ),
+ ),
+ body: Column(
+ children: [
+ // Sorting toggle button
+ Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ IconButton(
+ icon: Icon(isAscending ? Icons.arrow_upward : Icons.arrow_downward),
+ tooltip: 'Sort by Temperature',
+ onPressed: () {
+ setState(() {
+ isAscending = !isAscending; // Toggle sorting order
+ });
+ },
+ ),
+ Text(
+ isAscending ? 'Sort Ascending' : 'Sort Descending',
+ style: const TextStyle(fontSize: 16),
+ ),
+ ],
+ ),
+ ),
+ // Sensor list
+ Expanded(
+ child: BlocBuilder(
+ builder: (context, state) {
+ final filteredSensors = state.sensors.where((sensor) {
+ final q = searchQuery.toLowerCase();
+ return sensor.name.toLowerCase().contains(q) ||
+ sensor.description.toLowerCase().contains(q);
+ }).toList();
+
+ filteredSensors.sort((a, b) => isAscending
+ ? a.value.compareTo(b.value)
+ : b.value.compareTo(a.value));
+
+ if (filteredSensors.isEmpty) {
+ return const Center(child: Text('No sensors found.'));
+ }
+
+ return ListView.builder(
+ itemCount: filteredSensors.length,
+ itemBuilder: (context, index) {
+ final sensor = filteredSensors[index];
+ return ListTile(
+ title: Text('${sensor.name} (${sensor.id})'),
+ subtitle: Text(
+ 'Value: ${sensor.value.toStringAsFixed(2)}\n${sensor.description}',
+ ),
+ isThreeLine: true,
+ trailing: Wrap(
+ spacing: 8,
+ children: [
+ IconButton(
+ icon: const Icon(Icons.refresh),
+ tooltip: 'Update Sensor',
+ onPressed: () {
+ context.read().add(UpdateSensorValue(sensor));
+ },
+ ),
+ IconButton(
+ icon: const Icon(Icons.edit),
+ tooltip: 'Edit Sensor',
+ onPressed: () => _showEditDialog(sensor),
+ ),
+ ],
+ ),
+ );
+ },
+ );
+ },
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/home_wrapper.dart b/lib/home_wrapper.dart
new file mode 100644
index 0000000..ce58129
--- /dev/null
+++ b/lib/home_wrapper.dart
@@ -0,0 +1,19 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'sensor_bloc.dart';
+import 'repository/sensor_repository.dart';
+import 'sensor_event.dart';
+import 'home.dart';
+
+class HomeWrapper extends StatelessWidget {
+ const HomeWrapper({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocProvider(
+ create: (context) => SensorBloc(SensorRepository())
+ ..add(StartSensorUpdates()),
+ child: const HomeScreen(),
+ );
+ }
+}
diff --git a/lib/main.dart b/lib/main.dart
index 927a1e0..69e69cb 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'home_wrapper.dart';
void main() {
runApp(const MyApp());
@@ -10,11 +11,9 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
- title: 'Flutter Demo',
- theme: ThemeData(
- colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
- ),
- home: Placeholder(),
+ title: 'Sensor App',
+ theme: ThemeData(primarySwatch: Colors.blue),
+ home: const HomeWrapper(),
);
}
}
diff --git a/lib/sensor_bloc.dart b/lib/sensor_bloc.dart
new file mode 100644
index 0000000..a34fe9a
--- /dev/null
+++ b/lib/sensor_bloc.dart
@@ -0,0 +1,66 @@
+import 'dart:async';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'sensor_event.dart';
+import 'sensor_state.dart';
+import 'repository/sensor_repository.dart';
+import 'model/sensor.dart';
+import 'dart:math';
+
+class SensorBloc extends Bloc {
+
+ final SensorRepository repository;
+ late final StreamSubscription _sensorSub;
+
+ SensorBloc(this.repository) : super(const SensorState()) {
+ on((event, emit) {
+ repository.initializeSensors();
+ _sensorSub = repository.sensorsStream.listen(
+ (sensorList) => add(SensorsUpdated(sensorList)),
+ );
+ });
+
+ on((event, emit) {
+ emit(state.copyWith(
+ sensors: event.sensors,
+ searchQuery: state.searchQuery
+ ));
+ });
+
+ on((event, emit) {
+ repository.updateSensor(event.sensor);
+ final updatedSensors = List.from(state.sensors);
+ final index = updatedSensors.indexWhere((s) => s.id == event.sensor.id);
+ if (index != -1) {
+ updatedSensors[index] = event.sensor;
+ emit(state.copyWith(
+ sensors: updatedSensors,
+ searchQuery: state.searchQuery,
+ ));
+ }
+ });
+
+ on((event, emit) {
+ repository.updateSensor(event.sensor.copyWith(value: 72));
+ });
+
+
+ on((event,emit){
+ emit(state.copyWith(searchQuery: event.query));
+ });
+
+ on((event, emit) {
+ final sensor = state.sensors.firstWhere((s) => s.id == event.sensorId);
+ final updated = sensor.copyWith(
+ name: event.sensorName,
+ description: event.sensorDescription
+ );
+ repository.updateSensor(updated);
+ });
+
+ @override
+ Future close() {
+ _sensorSub.cancel();
+ return super.close();
+ }
+}
+}
\ No newline at end of file
diff --git a/lib/sensor_event.dart b/lib/sensor_event.dart
new file mode 100644
index 0000000..f4531f8
--- /dev/null
+++ b/lib/sensor_event.dart
@@ -0,0 +1,54 @@
+import 'package:equatable/equatable.dart';
+import 'model/sensor.dart';
+
+abstract class SensorEvent extends Equatable {
+ const SensorEvent();
+ @override
+ List