@ -1,18 +1,37 @@
import ' package:flutter/foundation.dart ' show listEquals ;
import ' package:flutter/material.dart ' ;
import ' package:flutter/material.dart ' ;
import ' package:meshcore_open/connector/meshcore_connector.dart ' ;
import ' package:meshcore_open/connector/meshcore_connector.dart ' ;
import ' package:meshcore_open/models/companion_radio_stats.dart ' ;
import ' package:meshcore_open/models/companion_radio_stats.dart ' ;
import ' package:meshcore_open/l10n/l10n.dart ' ;
import ' package:meshcore_open/l10n/l10n.dart ' ;
import ' package:provider/provider.dart ' ;
import ' package:provider/provider.dart ' ;
class CompanionRadioStatsScreen extends State fu lWidget {
class CompanionRadioStatsScreen extends State less Widget {
const CompanionRadioStatsScreen ( { super . key } ) ;
const CompanionRadioStatsScreen ( { super . key } ) ;
@ override
@ override
State < CompanionRadioStatsScreen > createState ( ) = >
Widget build ( BuildContext context ) {
_CompanionRadioStatsScreenState ( ) ;
return Scaffold (
appBar: AppBar (
title: Text ( context . l10n . radioStats_screenTitle ) ,
centerTitle: true ,
) ,
body: const CompanionRadioStatsBody ( ) ,
) ;
}
}
/ / / Embeddable Radio Stats content ( no Scaffold ) — used by both
/ / / [ CompanionRadioStatsScreen ] and the settings shell ' s Radio Stats pane.
/ / / Acquires 1 s radio - stats polling while mounted and releases it on dispose .
class CompanionRadioStatsBody extends StatefulWidget {
const CompanionRadioStatsBody ( { super . key } ) ;
@ override
State < CompanionRadioStatsBody > createState ( ) = >
_CompanionRadioStatsBodyState ( ) ;
}
}
class _CompanionRadioStatsScreenState extends State < CompanionRadioStatsScreen > {
class _CompanionRadioStats BodyState extends State < CompanionRadioStatsBody > {
final List < double > _noiseHistory = [ ] ;
final List < double > _noiseHistory = [ ] ;
static const int _maxSamples = 120 ;
static const int _maxSamples = 120 ;
MeshCoreConnector ? _connector ;
MeshCoreConnector ? _connector ;
@ -52,83 +71,71 @@ class _CompanionRadioStatsScreenState extends State<CompanionRadioStatsScreen> {
@ override
@ override
Widget build ( BuildContext context ) {
Widget build ( BuildContext context ) {
final l10n = context . l10n ;
final l10n = context . l10n ;
return Scaffold (
return Selector < MeshCoreConnector , ( { bool connected , bool supported } ) > (
appBar: AppBar (
selector: ( _ , c ) = >
title: Text ( l10n . radioStats_screenTitle ) ,
( connected: c . isConnected , supported: c . supportsCompanionRadioStats ) ,
centerTitle: true ,
builder: ( context , state , _ ) {
) ,
if ( ! state . connected ) {
body: Selector < MeshCoreConnector , ( { bool connected , bool supported } ) > (
return Center ( child: Text ( l10n . radioStats_notConnected ) ) ;
selector: ( _ , c ) = > (
}
connected: c . isConnected ,
if ( ! state . supported ) {
supported: c . supportsCompanionRadioStats ,
return Center (
) ,
child: Padding (
builder: ( context , state , _ ) {
padding: const EdgeInsets . all ( 24 ) ,
if ( ! state . connected ) {
child: Text (
return Center ( child: Text ( l10n . radioStats_notConnected ) ) ;
l10n . radioStats_firmwareTooOld ,
}
textAlign: TextAlign . center ,
if ( ! state . supported ) {
return Center (
child: Padding (
padding: const EdgeInsets . all ( 24 ) ,
child: Text (
l10n . radioStats_firmwareTooOld ,
textAlign: TextAlign . center ,
) ,
) ,
) ,
) ;
) ,
}
) ;
final connector = context . read < MeshCoreConnector > ( ) ;
}
final scheme = Theme . of ( context ) . colorScheme ;
final connector = context . read < MeshCoreConnector > ( ) ;
final tt = Theme . of ( context ) . textTheme ;
final scheme = Theme . of ( context ) . colorScheme ;
final tt = Theme . of ( context ) . textTheme ;
return ValueListenableBuilder < CompanionRadioStats ? > (
valueListenable: connector . radioStatsNotifier ,
return ValueListenableBuilder < CompanionRadioStats ? > (
builder: ( context , stats , _ ) {
valueListenable: connector . radioStatsNotifier ,
return ListView (
builder: ( context , stats , _ ) {
padding: const EdgeInsets . all ( 16 ) ,
return ListView (
children: [
padding: const EdgeInsets . all ( 16 ) ,
if ( stats ! = null ) . . . [
children: [
Text (
if ( stats ! = null ) . . . [
l10n . radioStats_noiseFloor ( stats . noiseFloorDbm ) ,
Text (
style: tt . titleMedium ,
l10n . radioStats_noiseFloor ( stats . noiseFloorDbm ) ,
) ,
style: tt . titleMedium ,
const SizedBox ( height: 4 ) ,
Text ( l10n . radioStats_lastRssi ( stats . lastRssiDbm ) ) ,
Text (
l10n . radioStats_lastSnr (
stats . lastSnrDb . toStringAsFixed ( 1 ) ,
) ,
) ,
Text ( l10n . radioStats_txAir ( stats . txAirSecs ) ) ,
Text ( l10n . radioStats_rxAir ( stats . rxAirSecs ) ) ,
const SizedBox ( height: 16 ) ,
] else
Text ( l10n . radioStats_waiting ) ,
const SizedBox ( height: 16 ) ,
SizedBox (
height: 200 ,
child: CustomPaint (
painter: _NoiseChartPainter (
samples: List < double > . from ( _noiseHistory ) ,
colorScheme: scheme ,
textTheme: tt ,
) ,
child: const SizedBox . expand ( ) ,
) ,
) ,
) ,
const SizedBox ( height: 8 ) ,
const SizedBox ( height: 4 ) ,
Text ( l10n . radioStats_lastRssi ( stats . lastRssiDbm ) ) ,
Text (
Text (
l10n . radioStats_chartCaption ,
l10n . radioStats_lastSnr ( stats . lastSnrDb . toStringAsFixed ( 1 ) ) ,
style: tt . bodySmall ? . copyWith (
) ,
color: scheme . onSurfaceVariant ,
Text ( l10n . radioStats_txAir ( stats . txAirSecs ) ) ,
Text ( l10n . radioStats_rxAir ( stats . rxAirSecs ) ) ,
const SizedBox ( height: 16 ) ,
] else
Text ( l10n . radioStats_waiting ) ,
const SizedBox ( height: 16 ) ,
SizedBox (
height: 200 ,
child: CustomPaint (
painter: _NoiseChartPainter (
samples: List < double > . from ( _noiseHistory ) ,
colorScheme: scheme ,
textTheme: tt ,
) ,
) ,
child: const SizedBox . expand ( ) ,
) ,
) ,
] ,
) ,
) ;
const SizedBox ( height: 8 ) ,
} ,
Text (
) ;
l10n . radioStats_chartCaption ,
} ,
style: tt . bodySmall ? . copyWith ( color: scheme . onSurfaceVariant ) ,
) ,
) ,
] ,
) ;
} ,
) ;
} ,
) ;
) ;
}
}
}
}
@ -233,8 +240,8 @@ class _NoiseChartPainter extends CustomPainter {
@ override
@ override
bool shouldRepaint ( covariant _NoiseChartPainter oldDelegate ) {
bool shouldRepaint ( covariant _NoiseChartPainter oldDelegate ) {
return oldDelegate . samples. length ! = samples . length | |
return oldDelegate . colorScheme ! = colorScheme | |
oldDelegate . colorScheme ! = colorScheme ;
! listEquals ( oldDelegate . samples , samples ) ;
}
}
TextPainter _yAxisLabel ( double v ) {
TextPainter _yAxisLabel ( double v ) {