wip: null safety
parent
87cbd2c096
commit
ce49610fae
|
@ -28,8 +28,7 @@ extension StatisticFunctions on Iterable<dynamic> {
|
|||
|
||||
List<num> nonZeros() {
|
||||
final List<num> values = toList().cast<num>();
|
||||
final Iterable<num> nonZeroValues =
|
||||
values.where((num value) => value != null && value != 0);
|
||||
final Iterable<num> nonZeroValues = values.where((num value) => value != 0);
|
||||
return nonZeroValues.toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ import '/models/power_zone.dart';
|
|||
import 'bar_chart_painter.dart';
|
||||
|
||||
class MyBarChart extends StatelessWidget {
|
||||
MyBarChart({Key? key,
|
||||
MyBarChart({
|
||||
Key? key,
|
||||
int? width,
|
||||
int? height,
|
||||
required num value,
|
||||
|
@ -34,7 +35,8 @@ class MyBarChart extends StatelessWidget {
|
|||
powerZones: powerZones,
|
||||
heartRateZones: heartRateZones,
|
||||
),
|
||||
_showPercentage = showPercentage, super(key: key);
|
||||
_showPercentage = showPercentage,
|
||||
super(key: key);
|
||||
|
||||
MyBarChart.visualizeDistributions(
|
||||
{Key? key, int? width, int? height, required List<BarZone> distributions})
|
||||
|
@ -44,7 +46,8 @@ class MyBarChart extends StatelessWidget {
|
|||
_maximum = distributions.last.upper!.toDouble(),
|
||||
_value = distributions.last.upper!.toDouble(),
|
||||
_barZones = distributions,
|
||||
_showPercentage = true, super(key: key);
|
||||
_showPercentage = true,
|
||||
super(key: key);
|
||||
|
||||
final double _width;
|
||||
final double _height;
|
||||
|
@ -56,7 +59,7 @@ class MyBarChart extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_barZones.isEmpty && _value == null || _value <= 0) {
|
||||
if (_barZones.isEmpty || _value <= 0) {
|
||||
return const Text('no data');
|
||||
} else {
|
||||
return SizedBox(
|
||||
|
|
|
@ -5,15 +5,16 @@ import '/models/athlete.dart';
|
|||
import '/models/event.dart';
|
||||
import '/models/record_list.dart';
|
||||
import '/models/weight.dart';
|
||||
import '/utils/pg_text.dart';
|
||||
import '/utils/enums.dart';
|
||||
import '/utils/icon_utils.dart';
|
||||
import '/utils/image_utils.dart' as image_utils;
|
||||
import '/utils/my_button.dart';
|
||||
import '/utils/pg_text.dart';
|
||||
import '/widgets/charts/activity_charts/activity_ecor_chart.dart';
|
||||
|
||||
class ActivityEcorWidget extends StatefulWidget {
|
||||
const ActivityEcorWidget({Key? key,
|
||||
const ActivityEcorWidget({
|
||||
Key? key,
|
||||
required this.activity,
|
||||
required this.athlete,
|
||||
}) : super(key: key);
|
||||
|
@ -49,7 +50,7 @@ class _ActivityEcorWidgetState extends State<ActivityEcorWidget> {
|
|||
value.speed! >= 1)
|
||||
.toList();
|
||||
|
||||
if (ecorRecords.isNotEmpty && ecorRecords != null) {
|
||||
if (ecorRecords.isNotEmpty && ecorRecords) {
|
||||
return ListTileTheme(
|
||||
iconColor: Colors.deepOrange,
|
||||
child: ListView(
|
||||
|
|
|
@ -9,7 +9,8 @@ import '/utils/my_button.dart';
|
|||
import '/utils/my_path.dart';
|
||||
|
||||
class ActivityPathWidget extends StatefulWidget {
|
||||
const ActivityPathWidget({Key? key,
|
||||
const ActivityPathWidget({
|
||||
Key? key,
|
||||
required this.activity,
|
||||
required this.athlete,
|
||||
}) : super(key: key);
|
||||
|
@ -41,7 +42,7 @@ class _ActivityPathWidgetState extends State<ActivityPathWidget> {
|
|||
value.positionLong != null && value.positionLat != null)
|
||||
.toList();
|
||||
|
||||
if (geoRecords.isNotEmpty && geoRecords != null) {
|
||||
if (geoRecords.isNotEmpty) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
RepaintBoundary(
|
||||
|
|
|
@ -8,14 +8,15 @@ import 'package:path_provider/path_provider.dart';
|
|||
import '/models/athlete.dart';
|
||||
import '/models/weight.dart';
|
||||
import '/screens/add_weight_screen.dart';
|
||||
import '/utils/pg_text.dart';
|
||||
import '/utils/enums.dart';
|
||||
import '/utils/icon_utils.dart';
|
||||
import '/utils/my_button.dart';
|
||||
import '/utils/my_button_style.dart';
|
||||
import '/utils/pg_text.dart';
|
||||
|
||||
class AthleteBodyWeightWidget extends StatefulWidget {
|
||||
const AthleteBodyWeightWidget({Key? key,
|
||||
const AthleteBodyWeightWidget({
|
||||
Key? key,
|
||||
this.athlete,
|
||||
this.callBackFunction,
|
||||
}) : super(key: key);
|
||||
|
@ -41,55 +42,54 @@ class _AthleteBodyWeightWidgetState extends State<AthleteBodyWeightWidget> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (weights != null) {
|
||||
if (weights.isNotEmpty) {
|
||||
rows = (weights.length < 8) ? weights.length : 8;
|
||||
return SingleChildScrollView(
|
||||
child: PaginatedDataTable(
|
||||
header: Row(
|
||||
children: <Widget>[
|
||||
MyButton.add(
|
||||
child: const Text('New weighting'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) => AddWeightScreen(
|
||||
weight: Weight(
|
||||
athlete: widget.athlete!,
|
||||
),
|
||||
numberOfWeights: weights.length,
|
||||
if (weights.isNotEmpty) {
|
||||
rows = (weights.length < 8) ? weights.length : 8;
|
||||
return SingleChildScrollView(
|
||||
child: PaginatedDataTable(
|
||||
header: Row(
|
||||
children: <Widget>[
|
||||
MyButton.add(
|
||||
child: const Text('New weighting'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) => AddWeightScreen(
|
||||
weight: Weight(
|
||||
athlete: widget.athlete!,
|
||||
),
|
||||
numberOfWeights: weights.length,
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
columns: const <DataColumn>[
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(
|
||||
label: Text('Weight'),
|
||||
numeric: true,
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
),
|
||||
DataColumn(label: Text('Edit'))
|
||||
const Spacer(),
|
||||
],
|
||||
rowsPerPage: 8,
|
||||
source: BodyWeightSource(
|
||||
weights: weights,
|
||||
context: context,
|
||||
callback: getData,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(25.0),
|
||||
child: Text('''
|
||||
columns: const <DataColumn>[
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(
|
||||
label: Text('Weight'),
|
||||
numeric: true,
|
||||
),
|
||||
DataColumn(label: Text('Edit'))
|
||||
],
|
||||
rowsPerPage: 8,
|
||||
source: BodyWeightSource(
|
||||
weights: weights,
|
||||
context: context,
|
||||
callback: getData,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(25.0),
|
||||
child: Text('''
|
||||
No weight data so far:
|
||||
|
||||
You can import your historic weight data by putting a weights.csv-file in the App's document directory.
|
||||
|
@ -102,39 +102,34 @@ Or you can simply enter your current weight using the New Weighting button.
|
|||
Please also enter at least a rough estimate default weight for your former activities.
|
||||
You can change these later.
|
||||
'''),
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Spacer(),
|
||||
ElevatedButton(
|
||||
style: MyButtonStyle.raisedButtonStyle(color: Colors.orange),
|
||||
child: const Text('Import Weights'),
|
||||
onPressed: () => importWeights(),
|
||||
),
|
||||
const Spacer(),
|
||||
MyButton.add(
|
||||
child: const Text('New weighting'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) => AddWeightScreen(
|
||||
weight: Weight(athlete: widget.athlete!),
|
||||
numberOfWeights: weights.length,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Spacer(),
|
||||
ElevatedButton(
|
||||
style: MyButtonStyle.raisedButtonStyle(color: Colors.orange),
|
||||
child: const Text('Import Weights'),
|
||||
onPressed: () => importWeights(),
|
||||
),
|
||||
const Spacer(),
|
||||
MyButton.add(
|
||||
child: const Text('New weighting'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) => AddWeightScreen(
|
||||
weight: Weight(athlete: widget.athlete!),
|
||||
numberOfWeights: weights.length,
|
||||
),
|
||||
);
|
||||
getData();
|
||||
}),
|
||||
const Spacer(),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return const Center(
|
||||
child: Text('loading'),
|
||||
),
|
||||
);
|
||||
getData();
|
||||
}),
|
||||
const Spacer(),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +148,8 @@ You can change these later.
|
|||
Weight weight;
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
final List<Directory> directories = await (getExternalStorageDirectories() as Future<List<Directory>>);
|
||||
final List<Directory> directories =
|
||||
await (getExternalStorageDirectories() as Future<List<Directory>>);
|
||||
directory = directories[0];
|
||||
} else {
|
||||
directory = await getApplicationDocumentsDirectory();
|
||||
|
|
|
@ -6,7 +6,8 @@ import '/models/tag_group.dart';
|
|||
import '/utils/my_color.dart';
|
||||
|
||||
class AthleteCurrentFilterWidget extends StatelessWidget {
|
||||
const AthleteCurrentFilterWidget({Key? key,
|
||||
const AthleteCurrentFilterWidget({
|
||||
Key? key,
|
||||
required this.athlete,
|
||||
required this.tagGroups,
|
||||
}) : super(key: key);
|
||||
|
@ -18,7 +19,7 @@ class AthleteCurrentFilterWidget extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
bool empty;
|
||||
|
||||
if (tagGroups != null && athlete!.filters.isNotEmpty) {
|
||||
if (athlete!.filters.isNotEmpty) {
|
||||
final List<Widget> widgets = <Widget>[];
|
||||
widgets.add(const Text('Current Filter: '));
|
||||
for (final TagGroup tagGroup in tagGroups) {
|
||||
|
|
|
@ -58,10 +58,6 @@ class _AthleteEcorWidgetState extends State<AthleteEcorWidget> {
|
|||
return const Center(
|
||||
child: Text('No ecor data available.'),
|
||||
);
|
||||
} else if (ecorActivities.first.weight == null) {
|
||||
return const Center(
|
||||
child: Text('Please enter your (historical) weight in the settings.'),
|
||||
);
|
||||
} else {
|
||||
return ListTileTheme(
|
||||
iconColor: Colors.orange,
|
||||
|
@ -80,7 +76,8 @@ class _AthleteEcorWidgetState extends State<AthleteEcorWidget> {
|
|||
const Text('Select Sport'),
|
||||
const SizedBox(width: 20),
|
||||
DropdownButton<String>(
|
||||
items: sports.map<DropdownMenuItem<String>>((String? value) {
|
||||
items:
|
||||
sports.map<DropdownMenuItem<String>>((String? value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value!),
|
||||
|
|
|
@ -9,7 +9,8 @@ import '/utils/my_button.dart';
|
|||
import '/utils/my_button_style.dart';
|
||||
|
||||
class AthleteHeartRateZoneSchemaWidget extends StatefulWidget {
|
||||
const AthleteHeartRateZoneSchemaWidget({Key? key,
|
||||
const AthleteHeartRateZoneSchemaWidget({
|
||||
Key? key,
|
||||
this.athlete,
|
||||
this.callBackFunction,
|
||||
}) : super(key: key);
|
||||
|
@ -36,114 +37,113 @@ class _AthleteHeartRateZoneSchemaWidgetState
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (heartRateZoneSchemas != null) {
|
||||
if (heartRateZoneSchemas.isNotEmpty) {
|
||||
rows =
|
||||
(heartRateZoneSchemas.length < 8) ? heartRateZoneSchemas.length : 8;
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: Text(
|
||||
'\nHeart Rate Zone Schemas ${offset + 1} - ${offset + rows} '
|
||||
'of ${heartRateZoneSchemas.length}',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
if (heartRateZoneSchemas.isNotEmpty) {
|
||||
rows =
|
||||
(heartRateZoneSchemas.length < 8) ? heartRateZoneSchemas.length : 8;
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: Text(
|
||||
'\nHeart Rate Zone Schemas ${offset + 1} - ${offset + rows} '
|
||||
'of ${heartRateZoneSchemas.length}',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
),
|
||||
DataTable(
|
||||
headingRowHeight: kMinInteractiveDimension * 0.80,
|
||||
dataRowHeight: kMinInteractiveDimension * 0.80,
|
||||
columnSpacing: 9,
|
||||
columns: const <DataColumn>[
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(label: Text('Name')),
|
||||
DataColumn(
|
||||
label: Text('Base (bpm)'),
|
||||
numeric: true,
|
||||
),
|
||||
),
|
||||
DataTable(
|
||||
headingRowHeight: kMinInteractiveDimension * 0.80,
|
||||
dataRowHeight: kMinInteractiveDimension * 0.80,
|
||||
columnSpacing: 9,
|
||||
columns: const <DataColumn>[
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(label: Text('Name')),
|
||||
DataColumn(
|
||||
label: Text('Base (bpm)'),
|
||||
numeric: true,
|
||||
),
|
||||
DataColumn(label: Text('Edit')),
|
||||
],
|
||||
rows: heartRateZoneSchemas
|
||||
.sublist(offset, offset + rows)
|
||||
.map((HeartRateZoneSchema heartRateZoneSchema) {
|
||||
return DataRow(
|
||||
key: ValueKey<int?>(heartRateZoneSchema.id),
|
||||
cells: <DataCell>[
|
||||
DataCell(Text(DateFormat('d MMM yyyy')
|
||||
.format(heartRateZoneSchema.date!))),
|
||||
DataCell(Text(heartRateZoneSchema.name!)),
|
||||
DataCell(Text(heartRateZoneSchema.base.toString())),
|
||||
DataCell(
|
||||
MyIcon.edit,
|
||||
onTap: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddHeartRateZoneSchemaScreen(
|
||||
heartRateZoneSchema: heartRateZoneSchema,
|
||||
numberOfSchemas: heartRateZoneSchemas.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Spacer(),
|
||||
MyButton.add(
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
DataColumn(label: Text('Edit')),
|
||||
],
|
||||
rows: heartRateZoneSchemas
|
||||
.sublist(offset, offset + rows)
|
||||
.map((HeartRateZoneSchema heartRateZoneSchema) {
|
||||
return DataRow(
|
||||
key: ValueKey<int?>(heartRateZoneSchema.id),
|
||||
cells: <DataCell>[
|
||||
DataCell(Text(DateFormat('d MMM yyyy')
|
||||
.format(heartRateZoneSchema.date!))),
|
||||
DataCell(Text(heartRateZoneSchema.name!)),
|
||||
DataCell(Text(heartRateZoneSchema.base.toString())),
|
||||
DataCell(
|
||||
MyIcon.edit,
|
||||
onTap: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddHeartRateZoneSchemaScreen(
|
||||
heartRateZoneSchema:
|
||||
HeartRateZoneSchema(athlete: widget.athlete!),
|
||||
heartRateZoneSchema: heartRateZoneSchema,
|
||||
numberOfSchemas: heartRateZoneSchemas.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
getData();
|
||||
}),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('<<'),
|
||||
onPressed: (offset == 0)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset > 8 ? offset = offset - rows : offset = 0;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('>>'),
|
||||
onPressed: (offset + rows == heartRateZoneSchemas.length)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset + rows < heartRateZoneSchemas.length - rows
|
||||
? offset = offset + rows
|
||||
: offset = heartRateZoneSchemas.length - rows;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
templateButtons(),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: Column(
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Text('''
|
||||
const Spacer(),
|
||||
MyButton.add(
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddHeartRateZoneSchemaScreen(
|
||||
heartRateZoneSchema:
|
||||
HeartRateZoneSchema(athlete: widget.athlete!),
|
||||
numberOfSchemas: heartRateZoneSchemas.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
getData();
|
||||
}),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('<<'),
|
||||
onPressed: (offset == 0)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset > 8 ? offset = offset - rows : offset = 0;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('>>'),
|
||||
onPressed: (offset + rows == heartRateZoneSchemas.length)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset + rows < heartRateZoneSchemas.length - rows
|
||||
? offset = offset + rows
|
||||
: offset = heartRateZoneSchemas.length - rows;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
templateButtons(),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
const Text('''
|
||||
No heart rate schema defined so far:
|
||||
|
||||
You can easily start with a pre defined heartRate schema,
|
||||
|
@ -152,31 +152,28 @@ just click on the button below und go from there.
|
|||
You could also create a schema from scratch.
|
||||
|
||||
'''),
|
||||
ElevatedButton(
|
||||
style: MyButtonStyle.raisedButtonStyle(color: Colors.green),
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddHeartRateZoneSchemaScreen(
|
||||
heartRateZoneSchema:
|
||||
HeartRateZoneSchema(athlete: widget.athlete!),
|
||||
numberOfSchemas: heartRateZoneSchemas.length,
|
||||
),
|
||||
ElevatedButton(
|
||||
style: MyButtonStyle.raisedButtonStyle(color: Colors.green),
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddHeartRateZoneSchemaScreen(
|
||||
heartRateZoneSchema:
|
||||
HeartRateZoneSchema(athlete: widget.athlete!),
|
||||
numberOfSchemas: heartRateZoneSchemas.length,
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
),
|
||||
templateButtons(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return const Center(child: Text('loading'));
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
),
|
||||
templateButtons(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ import '/utils/my_button.dart';
|
|||
import '/utils/my_button_style.dart';
|
||||
|
||||
class AthletePowerZoneSchemaWidget extends StatefulWidget {
|
||||
const AthletePowerZoneSchemaWidget({Key? key,
|
||||
const AthletePowerZoneSchemaWidget({
|
||||
Key? key,
|
||||
this.athlete,
|
||||
this.callBackFunction,
|
||||
}) : super(key: key);
|
||||
|
@ -36,116 +37,115 @@ class _AthletePowerZoneSchemaWidgetState
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (powerZoneSchemas != null) {
|
||||
if (powerZoneSchemas.isNotEmpty) {
|
||||
rows = (powerZoneSchemas.length < 8) ? powerZoneSchemas.length : 8;
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: Text(
|
||||
'\nPowerZoneSchemas ${offset + 1} - ${offset + rows} '
|
||||
'of ${powerZoneSchemas.length}',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
if (powerZoneSchemas.isNotEmpty) {
|
||||
rows = (powerZoneSchemas.length < 8) ? powerZoneSchemas.length : 8;
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Center(
|
||||
child: Text(
|
||||
'\nPowerZoneSchemas ${offset + 1} - ${offset + rows} '
|
||||
'of ${powerZoneSchemas.length}',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
),
|
||||
DataTable(
|
||||
headingRowHeight: kMinInteractiveDimension * 0.80,
|
||||
dataRowHeight: kMinInteractiveDimension * 0.80,
|
||||
columnSpacing: 9,
|
||||
columns: const <DataColumn>[
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(label: Text('Name')),
|
||||
DataColumn(
|
||||
label: Text('Base (W)'),
|
||||
numeric: true,
|
||||
),
|
||||
),
|
||||
DataTable(
|
||||
headingRowHeight: kMinInteractiveDimension * 0.80,
|
||||
dataRowHeight: kMinInteractiveDimension * 0.80,
|
||||
columnSpacing: 9,
|
||||
columns: const <DataColumn>[
|
||||
DataColumn(label: Text('Date')),
|
||||
DataColumn(label: Text('Name')),
|
||||
DataColumn(
|
||||
label: Text('Base (W)'),
|
||||
numeric: true,
|
||||
),
|
||||
DataColumn(label: Text('Edit')),
|
||||
],
|
||||
rows: powerZoneSchemas
|
||||
.sublist(offset, offset + rows)
|
||||
.map((PowerZoneSchema powerZoneSchema) {
|
||||
return DataRow(
|
||||
key: ValueKey<int?>(powerZoneSchema.id),
|
||||
cells: <DataCell>[
|
||||
DataCell(Text(
|
||||
DateFormat('d MMM yyyy').format(powerZoneSchema.date!))),
|
||||
DataCell(Text(powerZoneSchema.name!)),
|
||||
DataCell(Text(powerZoneSchema.base.toString())),
|
||||
DataCell(
|
||||
MyIcon.edit,
|
||||
onTap: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddPowerZoneSchemaScreen(
|
||||
powerZoneSchema: powerZoneSchema,
|
||||
numberOfSchemas: powerZoneSchemas.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Spacer(),
|
||||
MyButton.add(
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
DataColumn(label: Text('Edit')),
|
||||
],
|
||||
rows: powerZoneSchemas
|
||||
.sublist(offset, offset + rows)
|
||||
.map((PowerZoneSchema powerZoneSchema) {
|
||||
return DataRow(
|
||||
key: ValueKey<int?>(powerZoneSchema.id),
|
||||
cells: <DataCell>[
|
||||
DataCell(Text(
|
||||
DateFormat('d MMM yyyy').format(powerZoneSchema.date!))),
|
||||
DataCell(Text(powerZoneSchema.name!)),
|
||||
DataCell(Text(powerZoneSchema.base.toString())),
|
||||
DataCell(
|
||||
MyIcon.edit,
|
||||
onTap: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddPowerZoneSchemaScreen(
|
||||
powerZoneSchema:
|
||||
PowerZoneSchema(athlete: widget.athlete!),
|
||||
powerZoneSchema: powerZoneSchema,
|
||||
numberOfSchemas: powerZoneSchemas.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
getData();
|
||||
}),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('<<'),
|
||||
onPressed: (offset == 0)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset > 8 ? offset = offset - rows : offset = 0;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('>>'),
|
||||
onPressed: (offset + rows == powerZoneSchemas.length)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset + rows < powerZoneSchemas.length - rows
|
||||
? offset = offset + rows
|
||||
: offset = powerZoneSchemas.length - rows;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: templateButtons(),
|
||||
)
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: Column(
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Text('''
|
||||
const Spacer(),
|
||||
MyButton.add(
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddPowerZoneSchemaScreen(
|
||||
powerZoneSchema:
|
||||
PowerZoneSchema(athlete: widget.athlete!),
|
||||
numberOfSchemas: powerZoneSchemas.length,
|
||||
),
|
||||
),
|
||||
);
|
||||
getData();
|
||||
}),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('<<'),
|
||||
onPressed: (offset == 0)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset > 8 ? offset = offset - rows : offset = 0;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
MyButton.navigate(
|
||||
child: const Text('>>'),
|
||||
onPressed: (offset + rows == powerZoneSchemas.length)
|
||||
? null
|
||||
: () => setState(() {
|
||||
offset + rows < powerZoneSchemas.length - rows
|
||||
? offset = offset + rows
|
||||
: offset = powerZoneSchemas.length - rows;
|
||||
}),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: templateButtons(),
|
||||
)
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(25.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
const Text('''
|
||||
No power schema defined so far:
|
||||
|
||||
You can easily start with one of the three pre defined power schemas,
|
||||
|
@ -154,31 +154,27 @@ just click on one of the the buttons und go from there.
|
|||
You could also create a schema from scratch.
|
||||
|
||||
'''),
|
||||
ElevatedButton(
|
||||
style: MyButtonStyle.raisedButtonStyle(color: Colors.green),
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) =>
|
||||
AddPowerZoneSchemaScreen(
|
||||
powerZoneSchema:
|
||||
PowerZoneSchema(athlete: widget.athlete!),
|
||||
numberOfSchemas: powerZoneSchemas.length,
|
||||
),
|
||||
ElevatedButton(
|
||||
style: MyButtonStyle.raisedButtonStyle(color: Colors.green),
|
||||
child: const Text('New schema'),
|
||||
onPressed: () async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<BuildContext>(
|
||||
builder: (BuildContext context) => AddPowerZoneSchemaScreen(
|
||||
powerZoneSchema:
|
||||
PowerZoneSchema(athlete: widget.athlete!),
|
||||
numberOfSchemas: powerZoneSchemas.length,
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
),
|
||||
templateButtons(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return const Center(child: Text('loading'));
|
||||
),
|
||||
);
|
||||
getData();
|
||||
},
|
||||
),
|
||||
templateButtons(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ import '/utils/graph_utils.dart';
|
|||
import '/utils/my_button.dart';
|
||||
|
||||
class ActivityIntervalsChart extends StatefulWidget {
|
||||
const ActivityIntervalsChart({Key? key,
|
||||
const ActivityIntervalsChart({
|
||||
Key? key,
|
||||
this.records,
|
||||
required this.activity,
|
||||
required this.athlete,
|
||||
|
@ -112,7 +113,7 @@ class _ActivityIntervalsChartState extends State<ActivityIntervalsChart> {
|
|||
behaviors: <ChartBehavior<num>>[
|
||||
PanAndZoomBehavior<num>(),
|
||||
RangeAnnotation<num>(
|
||||
GraphUtils.rangeAnnotations(laps: laps) as List<AnnotationSegment<Object>>),
|
||||
GraphUtils.rangeAnnotations(laps: laps)),
|
||||
RangeAnnotation<num>(
|
||||
<RangeAnnotationSegment<int>>[
|
||||
if (interval.firstDistance! > 0 &&
|
||||
|
@ -206,7 +207,8 @@ class _ActivityIntervalsChartState extends State<ActivityIntervalsChart> {
|
|||
child: const Text('Select as start'),
|
||||
onPressed: () {
|
||||
if (interval.lastRecordId == 0 ||
|
||||
(selectedRecord!.id! < interval.lastRecordId!)) {
|
||||
(selectedRecord!.id! <
|
||||
interval.lastRecordId!)) {
|
||||
interval.firstRecordId = selectedRecord!.id;
|
||||
interval.firstDistance = selectedRecord!.distance;
|
||||
setState(() {});
|
||||
|
|
Reference in New Issue