Commit 94df2172 authored by Administrator's avatar Administrator

ShowIntervalScreen and IntervalOverviewWidget

parent 3ae43d08
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_secure_storage","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-3.3.3/","dependencies":[]},{"name":"package_info","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.1/","dependencies":[]},{"name":"path_provider","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.11/","dependencies":[]},{"name":"shared_preferences","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences-0.5.8/","dependencies":[]},{"name":"sqflite","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]},{"name":"uni_links","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/uni_links-0.4.0/","dependencies":[]},{"name":"url_launcher","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-5.5.0/","dependencies":[]}],"android":[{"name":"flutter_secure_storage","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-3.3.3/","dependencies":[]},{"name":"package_info","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.1/","dependencies":[]},{"name":"path_provider","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.11/","dependencies":[]},{"name":"shared_preferences","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences-0.5.8/","dependencies":[]},{"name":"sqflite","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]},{"name":"uni_links","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/uni_links-0.4.0/","dependencies":[]},{"name":"url_launcher","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-5.5.0/","dependencies":[]}],"macos":[{"name":"package_info","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.1/","dependencies":[]},{"name":"path_provider_macos","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+3/","dependencies":[]},{"name":"shared_preferences_macos","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences_macos-0.0.1+10/","dependencies":[]},{"name":"sqflite","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]},{"name":"url_launcher_macos","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.0.1+7/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/","dependencies":[]},{"name":"shared_preferences_linux","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences_linux-0.0.2+1/","dependencies":["path_provider_linux"]},{"name":"url_launcher_linux","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.0.1+1/","dependencies":[]}],"windows":[],"web":[{"name":"shared_preferences_web","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences_web-0.1.2+7/","dependencies":[]},{"name":"url_launcher_web","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-0.1.2/","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_secure_storage","dependencies":[]},{"name":"package_info","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_linux","shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"sqflite","dependencies":[]},{"name":"uni_links","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_web","url_launcher_linux","url_launcher_macos"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]}],"date_created":"2020-09-07 18:16:58.238915","version":"1.20.3"}
\ No newline at end of file
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_secure_storage","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-3.3.3/","dependencies":[]},{"name":"package_info","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.1/","dependencies":[]},{"name":"path_provider","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.11/","dependencies":[]},{"name":"shared_preferences","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences-0.5.8/","dependencies":[]},{"name":"sqflite","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]},{"name":"uni_links","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/uni_links-0.4.0/","dependencies":[]},{"name":"url_launcher","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-5.5.0/","dependencies":[]}],"android":[{"name":"flutter_secure_storage","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_secure_storage-3.3.3/","dependencies":[]},{"name":"package_info","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.1/","dependencies":[]},{"name":"path_provider","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-1.6.11/","dependencies":[]},{"name":"shared_preferences","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences-0.5.8/","dependencies":[]},{"name":"sqflite","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]},{"name":"uni_links","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/uni_links-0.4.0/","dependencies":[]},{"name":"url_launcher","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-5.5.0/","dependencies":[]}],"macos":[{"name":"package_info","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/package_info-0.4.1/","dependencies":[]},{"name":"path_provider_macos","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.4+3/","dependencies":[]},{"name":"shared_preferences_macos","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences_macos-0.0.1+10/","dependencies":[]},{"name":"sqflite","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]},{"name":"url_launcher_macos","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.0.1+7/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.0.1+2/","dependencies":[]},{"name":"shared_preferences_linux","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences_linux-0.0.2+1/","dependencies":["path_provider_linux"]},{"name":"url_launcher_linux","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.0.1+1/","dependencies":[]}],"windows":[],"web":[{"name":"shared_preferences_web","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/shared_preferences_web-0.1.2+7/","dependencies":[]},{"name":"url_launcher_web","path":"/home/stefan/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_web-0.1.2/","dependencies":[]}]},"dependencyGraph":[{"name":"flutter_secure_storage","dependencies":[]},{"name":"package_info","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_linux","shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"sqflite","dependencies":[]},{"name":"uni_links","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_web","url_launcher_linux","url_launcher_macos"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]}],"date_created":"2020-09-08 16:12:47.709513","version":"1.20.3"}
\ No newline at end of file
......@@ -18,6 +18,7 @@ class Interval {
double firstDistance = 0;
double lastDistance = 0;
int index;
double weight;
int get id => _db?.id;
DateTime get timeStamp => _db.timeStamp;
......@@ -67,6 +68,7 @@ class Interval {
int get minFormPower => _db.minFormPower;
int get minHeartRate => _db.minHeartRate;
int get minPower => _db.minPower;
int get movingTime => _db.movingTime;
int get totalAscent => _db.totalAscent;
int get totalDescent => _db.totalDescent;
......@@ -143,6 +145,71 @@ class Interval {
return _records;
}
// calculated from other attributes:
double get ecor {
if (avgPower != null &&
avgSpeed != null &&
avgSpeed > 0 &&
weight != null &&
weight > 0)
return avgPower / avgSpeed / weight;
else
return null;
}
double get avgPace {
if (avgSpeed != null && avgSpeed != 0)
return 50 / 3 / avgSpeed;
else
return null;
}
double get avgSpeedPerHeartRate {
if (avgSpeed != null && avgHeartRate != null && avgHeartRate != 0)
return 100 * (avgSpeed / avgHeartRate);
else
return null;
}
double get avgPowerPerHeartRate {
if (avgPower != null &&
avgPower != -1 &&
avgHeartRate != null &&
avgHeartRate != null)
return avgPower / avgHeartRate;
else
return null;
}
int get elevationDifference {
if (totalAscent != null && totalDescent != null)
return totalAscent - totalDescent;
else
return null;
}
double get avgDoubleStrydCadence {
if (avgStrydCadence != null)
return avgStrydCadence * 2;
else
return null;
}
// easier check for data availability
bool get powerAvailable => !<num>[null, -1].contains(avgPower);
bool get heartRateAvailable => !<num>[null, -1].contains(avgHeartRate);
bool get ascentAvailable => totalAscent != null && totalDescent != null;
bool get cadenceAvailable => !<num>[null, -1].contains(avgStrydCadence);
bool get speedAvailable => !<num>[null, 0, -1].contains(avgSpeed);
bool get weightAvailable => !<num>[null, 0].contains(weight);
bool get paceAvailable => !<num>[null, -1].contains(avgPace);
bool get ecorAvailable => !<num>[null, -1].contains(ecor);
bool get groundTimeAvailable => !<num>[null, -1].contains(avgGroundTime);
bool get formPowerAvailable => !<num>[null, -1].contains(avgFormPower);
bool get verticalOscillationAvailable => !<num>[null, -1].contains(avgVerticalOscillation);
bool get strideCadenceAvailable => !<num>[null, -1].contains(avgDoubleStrydCadence);
bool get legSpringStiffnessAvailable => !<num>[null, -1].contains(avgLegSpringStiffness);
Future<void> calculateAndSave({RecordList<Event> records}) async {
distance = (records.last.distance - records.first.distance).round();
duration = records.last.timeStamp.difference(records.first.timeStamp);
......
import 'package:encrateia/models/athlete.dart';
import 'package:encrateia/models/interval.dart' as encrateia;
import 'package:encrateia/utils/my_color.dart';
import 'package:encrateia/widgets/interval_widgets/interval_overview_widget.dart';
import 'package:flutter/material.dart';
import 'package:encrateia/utils/icon_utils.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
class ShowIntervalScreen extends StatelessWidget {
const ShowIntervalScreen({
Key key,
@required this.interval,
@required this.intervals,
@required this.athlete,
}) : super(key: key);
final encrateia.Interval interval;
final List<encrateia.Interval> intervals;
final Athlete athlete;
List<Widget> tiles({@required BuildContext context}) {
return <Widget>[
navigationButton(
title: 'Overview',
color: MyColor.settings,
icon: MyIcon.metaData,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
IntervalOverviewWidget(interval: interval, athlete: athlete, ),
),
if (interval.heartRateAvailable)
navigationButton(
title: 'Heart Rate',
color: MyColor.navigate,
icon: MyIcon.heartRate,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalHeartRateWidget(interval: interval),
),
if (interval.powerAvailable)
navigationButton(
title: 'Power',
color: MyColor.navigate,
icon: MyIcon.power,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalPowerWidget(interval: interval),
),
if (interval.powerAvailable)
navigationButton(
title: 'Power Duration',
color: MyColor.navigate,
icon: MyIcon.powerDuration,
context: context,
nextWidget: ({encrateia.Interval interval}) => const Text(
'') // IntervalPowerDurationWidget(interval: interval),
),
if (interval.paceAvailable)
navigationButton(
title: 'Pace',
color: MyColor.navigate,
icon: MyIcon.speed,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalPaceWidget(interval: interval),
),
if (interval.speedAvailable)
navigationButton(
title: 'Speed',
color: MyColor.navigate,
icon: MyIcon.speed,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalSpeedWidget(interval: interval),
),
if (interval.speedAvailable && interval.powerAvailable)
navigationButton(
title: 'Ecor',
color: MyColor.navigate,
icon: MyIcon.power,
context: context,
nextWidget: ({encrateia.Interval interval}) => const Text(
'') // IntervalEcorWidget( interval: interval, athlete: athlete, ),
),
if (interval.groundTimeAvailable)
navigationButton(
title: 'Ground Time',
color: MyColor.navigate,
icon: MyIcon.groundTime,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalGroundTimeWidget(interval: interval),
),
if (interval.groundTimeAvailable)
navigationButton(
title: 'Leg Spring Stiffness',
color: MyColor.navigate,
icon: MyIcon.legSpringStiffness,
context: context,
nextWidget: ({encrateia.Interval interval}) => const Text(
'') // IntervalLegSpringStiffnessWidget(interval: interval),
),
if (interval.formPowerAvailable)
navigationButton(
title: 'Form Power',
color: MyColor.navigate,
icon: MyIcon.formPower,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalFormPowerWidget(interval: interval),
),
if (interval.cadenceAvailable)
navigationButton(
title: 'Cadence',
color: MyColor.navigate,
icon: MyIcon.cadence,
context: context,
nextWidget: ({encrateia.Interval interval}) => const Text(
'') // IntervalStrydCadenceWidget(interval: interval),
),
if (interval.verticalOscillationAvailable)
navigationButton(
title: 'Vertical Oscillation',
color: MyColor.navigate,
icon: MyIcon.verticalOscillation,
context: context,
nextWidget: ({encrateia.Interval interval}) => const Text(
'') // IntervalVerticalOscillationWidget(interval: interval),
),
navigationButton(
title: 'Altitude',
color: MyColor.navigate,
icon: MyIcon.altitude,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalAltitudeWidget(interval: interval),
),
navigationButton(
title: 'Metadata',
color: MyColor.settings,
icon: MyIcon.metaData,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
const Text('') // IntervalMetadataWidget(interval: interval),
),
navigationButton(
title: 'Tags',
color: MyColor.tag,
icon: MyIcon.tag,
context: context,
nextWidget: ({encrateia.Interval interval}) => const Text(
'') // IntervalTagWidget( interval: interval, athlete: athlete, ),
),
];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: MyColor.interval,
title: Text(
'Interval ${interval.index}',
overflow: TextOverflow.ellipsis,
),
),
body: SafeArea(
child: StaggeredGridView.count(
staggeredTiles: List<StaggeredTile>.filled(
tiles(context: context).length,
const StaggeredTile.fit(1),
),
crossAxisSpacing: 10,
padding: const EdgeInsets.all(10),
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait
? 2
: 4,
children: tiles(context: context),
),
),
);
}
Widget navigationButton({
@required BuildContext context,
@required Widget Function({encrateia.Interval interval}) nextWidget,
@required Widget icon,
@required String title,
@required Color color,
}) {
return RaisedButton.icon(
color: color ?? MyColor.primary,
textColor: MyColor.textColor(backgroundColor: color),
icon: icon,
label: Expanded(
child: Text(title),
),
onPressed: () => Navigator.push(
context,
MaterialPageRoute<BuildContext>(
builder: (BuildContext context) => const Text(
'') //ShowIntervalDetailScreen( interval: interval, intervals: intervals, nextWidget: nextWidget, title: title, ),
),
),
);
}
}
import 'package:encrateia/models/athlete.dart';
import 'package:encrateia/models/weight.dart';
import 'package:encrateia/utils/PQText.dart';
import 'package:encrateia/utils/enums.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:encrateia/models/interval.dart' as encrateia;
class IntervalOverviewWidget extends StatefulWidget {
const IntervalOverviewWidget({
this.interval,
this.athlete,
});
final encrateia.Interval interval;
final Athlete athlete;
@override
_IntervalOverviewWidgetState createState() => _IntervalOverviewWidgetState();
}
class _IntervalOverviewWidgetState extends State<IntervalOverviewWidget> {
@override
void initState() {
getData();
super.initState();
}
List<Widget> get tiles {
return <Widget>[
ListTile(
title: Row(children: <Widget>[
PQText(value: widget.interval.avgSpeed, pq: PQ.paceFromSpeed),
const Text(' / '),
PQText(value: widget.interval.maxSpeed, pq: PQ.paceFromSpeed),
]),
subtitle: const Text('avg / max pace'),
),
ListTile(
title: Row(children: <Widget>[
PQText(value: widget.interval.avgHeartRate, pq: PQ.heartRate),
const Text(' / '),
PQText(value: widget.interval.maxHeartRate, pq: PQ.heartRate),
]),
subtitle: const Text('avg / max heart rate'),
),
ListTile(
title: PQText(value: widget.interval.avgPower, pq: PQ.power),
subtitle: const Text('avg power'),
),
ListTile(
title: PQText(
value: widget.interval.avgPowerPerHeartRate, pq: PQ.powerPerHeartRate),
subtitle: const Text('power / heart rate'),
),
ListTile(
title: PQText(value: widget.interval.movingTime, pq: PQ.duration),
subtitle: const Text('moving time'),
),
ListTile(
title: Row(children: <Widget>[
PQText(value: widget.interval.totalAscent, pq: PQ.integer),
const Text(' - '),
PQText(value: widget.interval.totalDescent, pq: PQ.integer),
const Text(' = '),
PQText(value: widget.interval.elevationDifference, pq: PQ.elevation),
]),
subtitle: const Text('total ascent - descent = total climb'),
),
];
}
@override
Widget build(BuildContext context) {
return StaggeredGridView.count(
staggeredTiles:
List<StaggeredTile>.filled(tiles.length, const StaggeredTile.fit(1)),
mainAxisSpacing: 4,
crossAxisCount:
MediaQuery.of(context).orientation == Orientation.portrait ? 2 : 4,
children: tiles,
);
}
Future<void> getData() async {
final Weight weight = await Weight.getBy(
athletesId: widget.athlete.id,
date: widget.interval.timeStamp,
);
setState(() => widget.interval.weight = weight?.value);
}
}
......@@ -6,7 +6,7 @@ import 'package:encrateia/utils/my_button.dart';
import 'package:flutter/material.dart';
import 'package:encrateia/models/activity.dart';
import 'package:encrateia/models/interval.dart' as encrateia;
import 'package:encrateia/screens/show_lap_screen.dart';
import 'package:encrateia/screens/show_interval_screen.dart';
class IntervalsListWidget extends StatefulWidget {
const IntervalsListWidget({
......@@ -74,9 +74,9 @@ class _IntervalsListWidgetState extends State<IntervalsListWidget> {
Navigator.push(
context,
MaterialPageRoute<BuildContext>(
builder: (BuildContext context) => ShowLapScreen(
lap: null,
laps: null,
builder: (BuildContext context) => ShowIntervalScreen(
interval: interval,
intervals: intervals,
athlete: widget.athlete,
),
),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment