Skip to content

feat: ported thermometer screen. #2761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: flutter
Choose a base branch
from

Conversation

Yugesh-Kumar-S
Copy link
Collaborator

@Yugesh-Kumar-S Yugesh-Kumar-S commented Jun 30, 2025

Fixes #2760

Changes

  • Ported the thermometer screen to flutter app.

Screenshots / Recordings

simulated using virtual sensor

Screen_recording_20250708_013433.webm

Checklist:

  • No hard coding: I have used resources from strings.xml, dimens.xml and colors.xml without hard coding any value.
  • No end of file edits: No modifications done at end of resource files strings.xml, dimens.xml or colors.xml.
  • Code reformatting: I have reformatted code and fixed indentation in every file included in this pull request.
  • No extra space: My code does not contain any extra lines or extra spaces than the ones that are necessary.

Summary by Sourcery

Port the thermometer instrument into the Flutter app by adding its UI, state management, sensor integration, and navigation.

New Features:

  • Introduce ThermometerScreen with guide drawer and live temperature chart.
  • Implement ThermometerStateProvider to read ambient temperature via EnvironmentSensors and update chart data.
  • Create ThermometerCard widget to display gauge and temperature statistics.
  • Register '/thermometer' route and integrate it in InstrumentsScreen navigation.
  • Add UI strings and color theming entries for thermometer and snackbar.
  • Include environment_sensors dependency in pubspec for sensor access.

Enhancements:

  • Show a snackbar when the ambient temperature sensor is unavailable.
  • Adapt chart axis labels to display elapsed time in seconds, minutes, or hours.

Chores:

  • Reformat code and fix indentation across added files.

Summary by Sourcery

Port the thermometer instrument to the Flutter application by adding its UI, state management, sensor integration, and navigation support

New Features:

  • Introduce ThermometerScreen with a live temperature gauge and chart
  • Implement ThermometerStateProvider and TemperatureService to fetch ambient temperature via platform channels
  • Register '/thermometer' route and integrate it into the InstrumentsScreen navigation

Enhancements:

  • Show a snackbar if the ambient temperature sensor is unavailable
  • Adapt chart axis labels to display elapsed time in seconds, minutes, or hours

Build:

  • Add BODY_SENSORS permission and optional ambient_temperature feature declaration in AndroidManifest.xml

Chores:

  • Reformat code and fix indentation across all added files

Copy link

sourcery-ai bot commented Jun 30, 2025

Reviewer's Guide

This PR ports the thermometer instrument to the Flutter app by implementing Android native temperature sensor integration with MethodChannel and EventChannel in MainActivity, exposing a Flutter TemperatureService, adding a state provider to track and chart readings, creating new UI screens and widgets for real-time temperature display, and integrating navigation routes and resource constants.

Sequence diagram for temperature sensor data flow from Android to Flutter

sequenceDiagram
    participant User as actor User
    participant FlutterApp as Flutter (ThermometerScreen)
    participant TempService as TemperatureService (Flutter)
    participant MainActivity as MainActivity (Android)
    participant Sensor as Android SensorManager

    User->>FlutterApp: Navigates to ThermometerScreen
    FlutterApp->>TempService: initializeSensors()
    TempService->>MainActivity: MethodChannel: isTemperatureSensorAvailable
    MainActivity->>Sensor: getDefaultSensor(TYPE_AMBIENT_TEMPERATURE)
    MainActivity-->>TempService: true/false
    TempService->>MainActivity: MethodChannel: startTemperatureUpdates
    MainActivity->>Sensor: registerListener
    MainActivity-->>TempService: true
    TempService->>MainActivity: MethodChannel: getCurrentTemperature
    MainActivity-->>TempService: currentTemperature
    MainActivity-->>TempService: EventChannel: temperature_stream (continuous)
    loop Every sensor update
        MainActivity-->>TempService: EventChannel: temperature value
        TempService-->>FlutterApp: notifyListeners() (UI updates)
    end
Loading

Class diagram for thermometer state management and service integration

classDiagram
    class ThermometerStateProvider {
      - double _currentTemperature
      - Timer? _timeTimer
      - StreamSubscription<double>? _temperatureSubscription
      - List<double> _temperatureData
      - List<double> _timeData
      - List<FlSpot> temperatureChartData
      - double _startTime
      - double _currentTime
      - int _maxLength
      - double _temperatureMin
      - double _temperatureMax
      - double _temperatureSum
      - int _dataCount
      - bool _isSensorAvailable
      - bool _isInitialized
      + Future<void> initializeSensors()
      + void disposeSensors()
      + double getCurrentTemperature()
      + double getMinTemperature()
      + double getMaxTemperature()
      + double getAverageTemperature()
      + List<FlSpot> getTemperatureChartData()
      + int getDataLength()
      + double getCurrentTime()
      + double getMaxTime()
      + double getMinTime()
      + bool isSensorAvailable()
      + bool isInitialized()
      + double getTimeInterval()
    }

    class TemperatureService {
      <<static>>
      + Future<bool> isTemperatureSensorAvailable()
      + Future<double> getCurrentTemperature()
      + Future<bool> startTemperatureUpdates()
      + Future<void> stopTemperatureUpdates()
      + Stream<double> temperatureStream
      + void dispose()
    }

    ThermometerStateProvider --> TemperatureService : uses
Loading

Class diagram for Android MainActivity sensor integration

classDiagram
    class MainActivity {
      - SensorManager sensorManager
      - Sensor temperatureSensor
      - MethodChannel temperatureChannel
      - EventChannel temperatureEventChannel
      - EventChannel.EventSink temperatureEventSink
      - boolean isListening
      - float currentTemperature
      + void configureFlutterEngine(FlutterEngine)
      + void onSensorChanged(SensorEvent)
      + void onAccuracyChanged(Sensor, int)
      + void onDestroy()
      + void onPause()
      + void onResume()
    }
    MainActivity ..> SensorManager : uses
    MainActivity ..> Sensor : uses
    MainActivity ..> MethodChannel : exposes
    MainActivity ..> EventChannel : exposes
Loading

File-Level Changes

Change Details Files
Implement Android native temperature sensor integration
  • Register ambient temperature sensor and listener in MainActivity
  • Expose sensor availability, current value, start/stop methods via MethodChannel
  • Stream live temperature updates to Flutter via EventChannel
  • Validate and log sensor readings, handle lifecycle events
  • Add BODY_SENSORS permission and optional ambient_temperature feature in AndroidManifest
android/app/src/main/java/io/pslab/MainActivity.java
android/app/src/main/AndroidManifest.xml
Provide Flutter TemperatureService for native communication
  • Define MethodChannel and EventChannel for temperature paths
  • Implement isAvailable, getCurrent, start/stop update methods
  • Broadcast native events to a Dart StreamController
  • Handle platform exceptions and manage stream subscription
lib/others/temperature_service.dart
Add ThermometerStateProvider for data handling
  • Initialize sensor availability and start updates via TemperatureService
  • Track elapsed time and temperature readings in lists
  • Compute min, max, average, and prepare FlSpot chart data
  • Schedule periodic timer for time tracking and notify listeners
  • Dispose subscriptions and stop sensor updates on cleanup
lib/providers/thermometer_state_provider.dart
Create new Thermometer UI and widget
  • Build ThermometerScreen with provider, guide drawer, and snackbar
  • Implement responsive layout combining ThermometerCard and live chart
  • Develop ThermometerCard widget showing gauge and stats
  • Adapt chart axis labels for seconds, minutes, hours
  • Add related Flutter package imports for Provider and fl_chart
lib/view/thermometer_screen.dart
lib/view/widgets/thermometer_card.dart
Integrate routes, navigation, and resource constants
  • Register '/thermometer' route in main.dart
  • Add navigation case in InstrumentsScreen to push '/thermometer'
  • Define UI strings and theming entries in constants.dart
lib/main.dart
lib/view/instruments_screen.dart
lib/constants.dart

Assessment against linked issues

Issue Objective Addressed Explanation
#2760 Maintain consistency with the existing PSLab Android app’s thermometer behavior.
#2760 Display real-time temperature(in C) using a responsive gauge and chart.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Yugesh-Kumar-S Yugesh-Kumar-S changed the title feat: port thermometer feat: ported thermometer Jun 30, 2025
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Yugesh-Kumar-S - I've reviewed your changes - here's some feedback:

  • In _showSensorErrorSnackbar, replace the hard-coded Colors.grey and white text color with the newly added snackBarBackgroundColor and snackBarContentColor constants to keep styling consistent.
  • When the temperature sensor is unavailable or on initialization error, cancel the periodic _timeTimer immediately to avoid running an idle timer unnecessarily.
  • You’re calling notifyListeners() both in the periodic timer and again on each sensor update—consider batching those state changes so you only rebuild once per cycle and reduce redundant widget rebuilds.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `_showSensorErrorSnackbar`, replace the hard-coded Colors.grey and white text color with the newly added `snackBarBackgroundColor` and `snackBarContentColor` constants to keep styling consistent.
- When the temperature sensor is unavailable or on initialization error, cancel the periodic `_timeTimer` immediately to avoid running an idle timer unnecessarily.
- You’re calling `notifyListeners()` both in the periodic timer and again on each sensor update—consider batching those state changes so you only rebuild once per cycle and reduce redundant widget rebuilds.

## Individual Comments

### Comment 1
<location> `lib/constants.dart:306` </location>
<code_context>
 String privacyPolicyMenu = 'Privacy Policy';
+String thermometerTitle = 'Thermometer';
+String thermometerIntro =
+    'Thermometer instrument is used to measure ambient temprature. It can be measured using inbuilt ambient temprature sensor or through SHT21.';
+String celsius = '°C';
+String temperatureSensorError = 'Temperature sensor error:';
</code_context>

<issue_to_address>
Typo in 'temprature' should be 'temperature'.

Please update all occurrences of 'temprature' in thermometerIntro to 'temperature'.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
String thermometerIntro =
    'Thermometer instrument is used to measure ambient temprature. It can be measured using inbuilt ambient temprature sensor or through SHT21.';
=======
String thermometerIntro =
    'Thermometer instrument is used to measure ambient temperature. It can be measured using inbuilt ambient temperature sensor or through SHT21.';
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Yugesh-Kumar-S Yugesh-Kumar-S marked this pull request as draft June 30, 2025 19:20
@Yugesh-Kumar-S Yugesh-Kumar-S changed the title feat: ported thermometer feat: ported thermometer screen. Jul 1, 2025
Copy link

github-actions bot commented Jul 1, 2025

@Yugesh-Kumar-S Yugesh-Kumar-S force-pushed the thermometer branch 2 times, most recently from 0eeda59 to 4195b96 Compare July 2, 2025 14:48
@Yugesh-Kumar-S Yugesh-Kumar-S marked this pull request as ready for review July 7, 2025 20:10
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Yugesh-Kumar-S - I've reviewed your changes - here's some feedback:

  • Consider extracting the Android sensor logic out of MainActivity into a dedicated plugin or helper class to keep your Flutter host activity clean and reusable.
  • Make sure to call TemperatureService.dispose (or otherwise close the StreamController) when the screen or app is torn down to avoid leaking the broadcast stream.
  • You’ve duplicated temperature‐validation logic in both Java and Dart—extract it into a shared utility or at least centralize the rules to prevent drift over time.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider extracting the Android sensor logic out of MainActivity into a dedicated plugin or helper class to keep your Flutter host activity clean and reusable.
- Make sure to call TemperatureService.dispose (or otherwise close the StreamController) when the screen or app is torn down to avoid leaking the broadcast stream.
- You’ve duplicated temperature‐validation logic in both Java and Dart—extract it into a shared utility or at least centralize the rules to prevent drift over time.

## Individual Comments

### Comment 1
<location> `lib/constants.dart:371` </location>
<code_context>
 String privacyPolicyMenu = 'Privacy Policy';
+String thermometerTitle = 'Thermometer';
+String thermometerIntro =
+    'Thermometer instrument is used to measure ambient temprature. It can be measured using inbuilt ambient temprature sensor or through SHT21.';
+String celsius = '°C';
+String temperatureSensorError = 'Temperature sensor error:';
</code_context>

<issue_to_address>
Typo in 'temprature' should be 'temperature'.

Please correct all instances of 'temprature' to 'temperature' in the thermometerIntro string to avoid user confusion.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
String thermometerIntro =
    'Thermometer instrument is used to measure ambient temprature. It can be measured using inbuilt ambient temprature sensor or through SHT21.';
=======
String thermometerIntro =
    'Thermometer instrument is used to measure ambient temperature. It can be measured using inbuilt ambient temperature sensor or through SHT21.';
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `lib/view/widgets/thermometer_card.dart:23` </location>
<code_context>
+    ThermometerStateProvider provider =
+        Provider.of<ThermometerStateProvider>(context);
+    double currentTemp = provider.getCurrentTemperature();
+    double minTemp = provider.getMinTemperature();
+    double maxTemp = provider.getMaxTemperature();
+    double avgTemp = provider.getAverageTemperature();
+    final cardMargin = screenWidth < 400 ? 8.0 : 12.0;
</code_context>

<issue_to_address>
Initial min/max temperature values may be misleading.

Returning 0 by default may cause confusion; consider using null or a sentinel value to indicate no data, and update the UI accordingly.

Suggested implementation:

```
    double? minTemp = provider.getMinTemperature();
    double? maxTemp = provider.getMaxTemperature();

```

You will also need to:
1. Update `ThermometerStateProvider.getMinTemperature()` and `getMaxTemperature()` to return `double?` and return `null` (or a sentinel value) when there is no data.
2. Update any UI code that displays `minTemp` and `maxTemp` to check for `null` and display a placeholder (e.g., "—" or "N/A") if the value is `null`. For example:
```dart
Text(minTemp != null ? minTemp.toStringAsFixed(1) : "—")
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +370 to +371
String thermometerIntro =
'Thermometer instrument is used to measure ambient temprature. It can be measured using inbuilt ambient temprature sensor or through SHT21.';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (typo): Typo in 'temprature' should be 'temperature'.

Please correct all instances of 'temprature' to 'temperature' in the thermometerIntro string to avoid user confusion.

Suggested change
String thermometerIntro =
'Thermometer instrument is used to measure ambient temprature. It can be measured using inbuilt ambient temprature sensor or through SHT21.';
String thermometerIntro =
'Thermometer instrument is used to measure ambient temperature. It can be measured using inbuilt ambient temperature sensor or through SHT21.';

Comment on lines +23 to +24
double minTemp = provider.getMinTemperature();
double maxTemp = provider.getMaxTemperature();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Initial min/max temperature values may be misleading.

Returning 0 by default may cause confusion; consider using null or a sentinel value to indicate no data, and update the UI accordingly.

Suggested implementation:

    double? minTemp = provider.getMinTemperature();
    double? maxTemp = provider.getMaxTemperature();

You will also need to:

  1. Update ThermometerStateProvider.getMinTemperature() and getMaxTemperature() to return double? and return null (or a sentinel value) when there is no data.
  2. Update any UI code that displays minTemp and maxTemp to check for null and display a placeholder (e.g., "—" or "N/A") if the value is null. For example:
Text(minTemp != null ? minTemp.toStringAsFixed(1) : "—")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Port the thermometer in the flutter app.
1 participant