@@ -4,7 +4,9 @@ import 'package:stream_video_flutter/stream_video_flutter.dart';
44import '../app/user_auth_controller.dart' ;
55import '../di/injector.dart' ;
66import '../theme/app_palette.dart' ;
7+ import 'stats_battery_chart.dart' ;
78import 'stats_latency_chart.dart' ;
9+ import 'stats_thermal_chart.dart' ;
810
911class CallStatsScreen extends StatelessWidget {
1012 CallStatsScreen ({super .key, required this .call});
@@ -19,12 +21,26 @@ class CallStatsScreen extends StatelessWidget {
1921 final textTheme = streamVideoTheme.textTheme;
2022 final currentUser = _userAuthController.currentUser;
2123
22- return StreamBuilder <CallState >(
23- stream: call.state.asStream (),
24+ return StreamBuilder <CallMetrics ?>(
25+ stream: call.statsReporter? .stream,
26+ initialData: call.statsReporter? .currentMetrics,
2427 builder: (context, snapshot) {
2528 final state = snapshot.data;
26- final subscriberBitrate = state? .subscriberStats? .bitrateKbps;
27- final publisherBitrate = state? .publisherStats? .bitrateKbps;
29+
30+ if (state == null ) {
31+ return const Center (
32+ child: CircularProgressIndicator (),
33+ );
34+ }
35+
36+ final subscriberBitrate = state.subscriber? .bitrateKbps;
37+ final publisherBitrate = state.publisher? .bitrateKbps;
38+
39+ final batteryDrained =
40+ state.initialBatteryLevel != null &&
41+ state.batteryLevelHistory.isNotEmpty
42+ ? state.initialBatteryLevel! - state.batteryLevelHistory.last
43+ : null ;
2844
2945 return SafeArea (
3046 top: false ,
@@ -84,104 +100,183 @@ class CallStatsScreen extends StatelessWidget {
84100 SizedBox (
85101 height: 200 ,
86102 child: StatsLatencyChart (
87- latencyHistory: state! .latencyHistory,
103+ latencyHistory: state.latencyHistory,
88104 ),
89105 ),
90- const SizedBox (height: 16 ),
91- Padding (
92- padding: const EdgeInsets .all (16 ),
93- child: Row (
106+ if (snapshot.hasData) ...[
107+ const SizedBox (
108+ height: 16 ,
109+ ),
110+ Padding (
111+ padding: const EdgeInsets .all (16 ),
112+ child: Row (
113+ children: [
114+ const Icon (Icons .whatshot, color: Colors .white),
115+ const SizedBox (width: 8 ),
116+ Text (
117+ 'Thermal state' ,
118+ style: textTheme.title3.apply (
119+ color: Colors .white,
120+ ),
121+ ),
122+ ],
123+ ),
124+ ),
125+ const Padding (
126+ padding: EdgeInsets .symmetric (horizontal: 16 ),
127+ child: Text (
128+ 'Device thermal state history. Higher bars indicate more severe states.' ,
129+ style: TextStyle (color: Colors .white),
130+ ),
131+ ),
132+ const SizedBox (height: 16 ),
133+ SizedBox (
134+ height: 200 ,
135+ child: StatsThermalChart (
136+ thermalSeverityHistory: state.thermalStatusHistory,
137+ ),
138+ ),
139+ const SizedBox (
140+ height: 16 ,
141+ ),
142+ Padding (
143+ padding: const EdgeInsets .all (16 ),
144+ child: Row (
145+ children: [
146+ const Icon (Icons .battery_full, color: Colors .white),
147+ const SizedBox (width: 8 ),
148+ Text (
149+ 'Battery level' ,
150+ style: textTheme.title3.apply (
151+ color: Colors .white,
152+ ),
153+ ),
154+ ],
155+ ),
156+ ),
157+ const Padding (
158+ padding: EdgeInsets .symmetric (horizontal: 16 ),
159+ child: Text (
160+ 'Track device battery level throughout the call.' ,
161+ style: TextStyle (color: Colors .white),
162+ ),
163+ ),
164+ const SizedBox (height: 16 ),
165+ SizedBox (
166+ height: 200 ,
167+ child: StatsBatteryChart (
168+ batteryLevelHistory: state.batteryLevelHistory,
169+ ),
170+ ),
171+ Text (
172+ 'Battery percentage consumed during call: ${batteryDrained != null ? "$batteryDrained %" : "N/A" }' ,
173+ style: const TextStyle (color: Colors .white),
174+ ),
175+ const SizedBox (
176+ height: 16 ,
177+ ),
178+ Padding (
179+ padding: const EdgeInsets .all (16 ),
180+ child: Row (
181+ children: [
182+ const Icon (Icons .bar_chart, color: Colors .white),
183+ const SizedBox (width: 8 ),
184+ Text (
185+ 'Call performance' ,
186+ style: textTheme.title3.apply (
187+ color: Colors .white,
188+ ),
189+ ),
190+ ],
191+ ),
192+ ),
193+ const Padding (
194+ padding: EdgeInsets .symmetric (horizontal: 16 ),
195+ child: Text (
196+ 'Review the key data points below to assess call performance.' ,
197+ style: TextStyle (color: Colors .white),
198+ ),
199+ ),
200+ const SizedBox (
201+ height: 16 ,
202+ ),
203+ Row (
94204 children: [
95- const Icon ( Icons .bar_chart, color : Colors .white),
96- const SizedBox (width : 8 ),
97- Text (
98- 'Call performance' ,
99- style : textTheme.title3. apply (color : Colors .white ),
205+ Expanded (
206+ child : LatencyOrJitterItem (
207+ title : 'Latency' ,
208+ value : state.publisher ? .latency ?? 0 ,
209+ ),
100210 ),
101211 ],
102212 ),
103- ),
104- const Padding (
105- padding: EdgeInsets .symmetric (horizontal: 16 ),
106- child: Text (
107- 'Review the key data points below to assess call performance.' ,
108- style: TextStyle (color: Colors .white),
109- ),
110- ),
111- const SizedBox (height: 16 ),
112- Row (
113- children: [
114- Expanded (
115- child: LatencyOrJitterItem (
116- title: 'Latency' ,
117- value: state.publisherStats? .latency ?? 0 ,
118- ),
119- ),
120- ],
121- ),
122- Row (
123- children: [
124- Expanded (
125- child: LatencyOrJitterItem (
126- title: 'Receive jitter' ,
127- value: state.subscriberStats? .jitterInMs,
213+ Row (
214+ children: [
215+ Expanded (
216+ child: LatencyOrJitterItem (
217+ title: 'Receive jitter' ,
218+ value: state.subscriber? .jitterInMs,
219+ ),
128220 ),
129- ),
130- Expanded (
131- child : LatencyOrJitterItem (
132- title : 'Publish jitter' ,
133- value : state.publisherStats ? .jitterInMs ,
221+ Expanded (
222+ child : LatencyOrJitterItem (
223+ title : 'Publish jitter' ,
224+ value : state.publisher ? .jitterInMs ,
225+ ) ,
134226 ),
135- ) ,
136- ] ,
137- ),
138- Row (
139- children : [
140- Expanded (
141- child : StatsItem (
142- title : 'Publish bitrate' ,
143- value : publisherBitrate == null
144- ? '--'
145- : '${ state . publisherStats ?. bitrateKbps } Kbps' ,
227+ ] ,
228+ ) ,
229+ Row (
230+ children : [
231+ Expanded (
232+ child : StatsItem (
233+ title : 'Publish bitrate' ,
234+ value : publisherBitrate == null
235+ ? '--'
236+ : '${ state . publisher ?. bitrateKbps } Kbps' ,
237+ ) ,
146238 ),
147- ),
148- Expanded (
149- child : StatsItem (
150- title : 'Receive bitrate' ,
151- value : subscriberBitrate == null
152- ? '--'
153- : '${ state . subscriberStats ?. bitrateKbps } Kbps' ,
239+ Expanded (
240+ child : StatsItem (
241+ title : 'Receive bitrate' ,
242+ value : subscriberBitrate == null
243+ ? '--'
244+ : '${ state . subscriber ?. bitrateKbps } Kbps' ,
245+ ) ,
154246 ),
155- ) ,
156- ] ,
157- ),
158- Row (
159- children : [
160- Expanded (
161- child : StatsItem (
162- title : 'Publish resolution' ,
163- value :
164- "${ state . publisherStats ?. resolution } | ${ state . publisherStats ?. videoCodec ?. join ( '+' )}" ,
247+ ] ,
248+ ) ,
249+ Row (
250+ children : [
251+ Expanded (
252+ child : StatsItem (
253+ title : 'Publish resolution' ,
254+ value :
255+ "${ state . publisher ?. resolution } | ${ state . publisher ?. videoCodec ?. join ( '+' )}" ,
256+ ) ,
165257 ),
166- ),
167- Expanded (
168- child : StatsItem (
169- title : 'Reveive resolution' ,
170- value :
171- "${ state . subscriberStats ?. resolution } | ${ state . subscriberStats ?. videoCodec ?. join ( '+' )}" ,
258+ Expanded (
259+ child : StatsItem (
260+ title : 'Receive resolution' ,
261+ value :
262+ "${ state . subscriber ?. resolution } | ${ state . subscriber ?. videoCodec ?. join ( '+' )}" ,
263+ ) ,
172264 ),
173- ),
174- ],
175- ),
176- StatsItem (title: 'Region' , value: state.localStats? .sfu),
177- StatsItem (
178- title: 'SDK Version' ,
179- value: state.localStats? .sdkVersion,
180- ),
181- StatsItem (
182- title: 'WebRTC Version' ,
183- value: state.localStats? .webRtcVersion,
184- ),
265+ ],
266+ ),
267+ StatsItem (
268+ title: 'Region' ,
269+ value: state.clientEnvironment.sfu,
270+ ),
271+ StatsItem (
272+ title: 'SDK Version' ,
273+ value: state.clientEnvironment.sdkVersion,
274+ ),
275+ StatsItem (
276+ title: 'WebRTC Version' ,
277+ value: state.clientEnvironment.webRtcVersion,
278+ ),
279+ ],
185280 ],
186281 ],
187282 ),
0 commit comments