Merge branch 'upgrade-2021-project' of gitea.mittenin.at:encrateia.informatom.com/encrateia into upgrade-2021-project

upgrade-2021-project
Stefan Haslinger 2022-02-27 18:23:36 +01:00
commit b5fc31ae70
208 changed files with 3603 additions and 3701 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,199 +1,29 @@
# Specify analysis options.
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# Until there are meta linter rules, each desired lint must be explicitly enabled.
# See: https://github.com/dart-lang/linter/issues/288
#
# For a list of lints, see: http://dart-lang.github.io/linter/lints/
# See the configuration guide for more
# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer
#
# There are other similar analysis options files in the flutter repos,
# which should be kept in sync with this file:
#
# - analysis_options.yaml (this file)
# - packages/flutter/lib/analysis_options_user.yaml
# - https://github.com/flutter/plugins/blob/master/analysis_options.yaml
# - https://github.com/flutter/engine/blob/master/analysis_options.yaml
#
# This file contains the analysis options used by Flutter tools, such as IntelliJ,
# Android Studio, and the `flutter analyze` command.
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
errors:
missing_required_param: warning
missing_return: warning
# Ignore analyzer hints for updating pubspecs when using Future or
# Stream and not importing dart:async
# Please see https://github.com/flutter/flutter/pull/24528 for details.
sdk_version_async_exported_from_core: ignore
exclude:
- "lib/i18n/messages_*.dart"
# HAS:20200527 This is generated code, so I cannot influence it
- "lib/model/model.dart"
- "lib/model/model.g.dart"
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
- always_declare_return_types
- always_put_control_body_on_new_line
# - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
- always_require_non_null_named_parameters
- always_specify_types
- annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
# - avoid_as # required for implicit-casts: true
- avoid_bool_literals_in_conditional_expressions
# - avoid_catches_without_on_clauses # we do this commonly
# - avoid_catching_errors # we do this commonly
- avoid_classes_with_only_static_members
# - avoid_double_and_int_checks # only useful when targeting JS runtime
- avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes
- avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls
# - avoid_implementing_value_types # not yet tested
- avoid_init_to_null
# - avoid_js_rounded_ints # only useful when targeting JS runtime
- avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # not yet tested
# - avoid_print # not yet tested
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
# - avoid_redundant_argument_values # not yet tested
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
# - avoid_returning_null # there are plenty of valid reasons to return null
# - avoid_returning_null_for_future # not yet tested
- avoid_returning_null_for_void
# - avoid_returning_this # there are plenty of valid reasons to return this
# - avoid_setters_without_getters # not yet tested
# - avoid_shadowing_type_parameters # not yet tested
- avoid_single_cascade_in_expression_statements
- avoid_slow_async_io
- avoid_types_as_parameter_names
# - avoid_types_on_closure_parameters # conflicts with always_specify_types
# - avoid_unnecessary_containers # not yet tested
- avoid_unused_constructor_parameters
- avoid_void_async
# - avoid_web_libraries_in_flutter # not yet tested
- await_only_futures
- camel_case_extensions
- camel_case_types
- cancel_subscriptions
# - cascade_invocations # not yet tested
# - close_sinks # not reliable enough
# - comment_references # blocked on https://github.com/flutter/flutter/issues/20765
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
- control_flow_in_finally
# - curly_braces_in_flow_control_structures # not yet tested
# - diagnostic_describe_all_properties # not yet tested
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
# - file_names # not yet tested
- flutter_style_todos
- hash_and_equals
- implementation_imports
# - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811
- iterable_contains_unrelated_type
# - join_return_with_assignment # not yet tested
- library_names
- library_prefixes
# - lines_longer_than_80_chars # not yet tested
- list_remove_unrelated_type
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181
# - missing_whitespace_between_adjacent_strings # not yet tested
- no_adjacent_strings_in_list
- no_duplicate_case_values
# - no_logic_in_create_state # not yet tested
# - no_runtimeType_toString # not yet tested
- non_constant_identifier_names
# - null_closures # not yet tested
# - omit_local_variable_types # opposite of always_specify_types
# - one_member_abstracts # too many false positives
# - only_throw_errors # https://github.com/flutter/flutter/issues/5792
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
# - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
# - prefer_asserts_with_message # not yet tested
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
# - prefer_constructors_over_static_methods # not yet tested
- prefer_contains
# - prefer_double_quotes # opposite of prefer_single_quotes
- prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
- prefer_final_fields
- prefer_final_in_for_each
- prefer_final_locals
- prefer_for_elements_to_map_fromIterable
- prefer_foreach
# - prefer_function_declarations_over_variables # not yet tested
- prefer_generic_function_type_aliases
- prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators
- prefer_initializing_formals
- prefer_inlined_adds
# - prefer_int_literals # not yet tested
# - prefer_interpolation_to_compose_strings # not yet tested
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_iterable_whereType
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
# - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932
# - prefer_relative_imports # not yet tested
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
- prefer_void_to_null
# - provide_deprecation_message # not yet tested
# - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml
- recursive_getters
- slash_for_doc_comments
# - sort_child_properties_last # not yet tested
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
# - type_annotate_public_apis # subset of always_specify_types
- type_init_formals
# - unawaited_futures # too many false positives
# - unnecessary_await_in_return # not yet tested
- unnecessary_brace_in_string_interps
- unnecessary_const
# - unnecessary_final # conflicts with prefer_final_locals
- unnecessary_getters_setters
# - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_statements
- unnecessary_string_interpolations
- unnecessary_this
- unrelated_type_equality_checks
# - unsafe_html # not yet tested
- use_full_hex_values_for_flutter_colors
# - use_function_type_syntax_for_parameters # not yet tested
# - use_key_in_widget_constructors # not yet tested
- use_rethrow_when_possible
# - use_setters_to_change_properties # not yet tested
# - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
- valid_regexps
- void_checks
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@ -576,7 +576,7 @@
* `2019-09-19 16:58` [6480ce2](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/6480ce2) - refactoring
* `2019-09-19 16:46` [3a1432a](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/3a1432a) - switch to sqfentity
* `2019-09-18 16:51` [0825952](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/0825952) - create table athletes, if it does not exist
* `2019-09-18 14:50` [49f873a](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/49f873a) - persisting athlete, todo: create database and table
* `2019-09-18 14:50` [49f873a](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/49f873a) - persisting athlete, create database and table
* `2019-08-18 15:11` [6e6b0f5](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/6e6b0f5) - lots of small reformattings and reorganisations
* `2019-08-17 20:21` [3c79a87](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/3c79a87) - fix all linting issues
* `2019-08-17 11:51` [fe55e2a](https://gitlab.informatom.com/3-schweinehunde/encrateia/-/commit/fe55e2a) - store data in scoped model

View File

@ -6,9 +6,9 @@ import '/models/athlete.dart';
import '/utils/icon_utils.dart';
Future<void> analyseActivities({
@required BuildContext context,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Athlete athlete,
required Flushbar<Object> flushbar,
}) async {
List<Activity> activities;
activities = await athlete.activities;

View File

@ -7,9 +7,9 @@ import '/models/tag_group.dart';
import '/utils/icon_utils.dart';
Future<void> autoTagging({
@required BuildContext context,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Athlete athlete,
required Flushbar<Object> flushbar,
}) async {
if (await athlete.checkForSchemas()) {
flushbar = Flushbar<Object>(

View File

@ -5,9 +5,9 @@ import '/models/athlete.dart';
import '/utils/my_button.dart';
Future<void> deleteAthlete({
@required BuildContext context,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Athlete? athlete,
required Flushbar<Object> flushbar,
}) {
return showDialog<void>(
context: context,
@ -32,7 +32,7 @@ Future<void> deleteAthlete({
),
MyButton.delete(
onPressed: () async {
await athlete.delete();
await athlete!.delete();
Navigator.of(context)
.popUntil((Route<dynamic> route) => route.isFirst);
},

View File

@ -6,10 +6,10 @@ import '/models/athlete.dart';
import '/utils/icon_utils.dart';
Future<void> downloadActivity({
@required BuildContext context,
@required Activity activity,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Activity activity,
required Athlete athlete,
required Flushbar<Object> flushbar,
}) async {
await flushbar.dismiss();
flushbar = Flushbar<Object>(

View File

@ -11,9 +11,9 @@ import '/models/athlete.dart';
import '/utils/icon_utils.dart';
Future<void> downloadDemoData({
@required BuildContext context,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Athlete athlete,
required Flushbar<Object>? flushbar,
}) async {
if (await athlete.checkForSchemas()) {
List<Activity> activities;

View File

@ -7,9 +7,9 @@ import '/models/athlete.dart';
import '/utils/icon_utils.dart';
Future<void> importActivitiesLocally({
@required BuildContext context,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Athlete athlete,
required Flushbar<Object> flushbar,
}) async {
List<Activity> activities;

View File

@ -6,10 +6,10 @@ import '/models/athlete.dart';
import '/models/log.dart';
Future<void> parseActivity({
@required BuildContext context,
@required Activity activity,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Activity activity,
required Athlete athlete,
required Flushbar<Object>? flushbar,
}) async {
await flushbar?.dismiss();
flushbar = Flushbar<Object>(
@ -23,9 +23,9 @@ Future<void> parseActivity({
try {
percentageStream = activity.parse(athlete: athlete);
await for (final int value in percentageStream) {
if (value == -2)
if (value == -2) {
await flushbar?.dismiss();
else if (value == -1) {
} else if (value == -1) {
await flushbar?.dismiss();
flushbar = Flushbar<Object>(
message: 'Analysing »${activity.name}«',

View File

@ -6,9 +6,9 @@ import '/models/athlete.dart';
import '/utils/icon_utils.dart';
Future<void> queryStrava({
@required BuildContext context,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Athlete athlete,
required Flushbar<Object> flushbar,
}) async {
flushbar = Flushbar<Object>(
message: 'Downloading new activities',

View File

@ -8,8 +8,8 @@ import '/models/power_zone_schema.dart';
import '/models/weight.dart';
Future<void> setupDemoAthlete({
@required BuildContext context,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Flushbar<Object>? flushbar,
}) async {
final Athlete athlete = Athlete();
await athlete.setupStandaloneAthlete();

View File

@ -9,9 +9,9 @@ import '/models/athlete.dart';
import '/utils/icon_utils.dart';
Future<void> updateJob({
@required BuildContext context,
@required Athlete athlete,
@required Flushbar<Object> flushbar,
required BuildContext context,
required Athlete athlete,
required Flushbar<Object> flushbar,
}) async {
List<Activity> activities;

View File

@ -6,10 +6,12 @@ import 'utils/my_theme.dart';
Future<void> main() async {
await setup();
runApp(MyApp());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(

View File

@ -1607,7 +1607,7 @@ class DbAthlete extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbAthlete] to use this feature';
throw UnimplementedError(msg);
}
@ -4307,7 +4307,7 @@ class DbActivity extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbActivity] to use this feature';
throw UnimplementedError(msg);
}
@ -6679,7 +6679,7 @@ class DbEvent extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbEvent] to use this feature';
throw UnimplementedError(msg);
}
@ -8952,7 +8952,7 @@ class DbLap extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbLap] to use this feature';
throw UnimplementedError(msg);
}
@ -11592,7 +11592,7 @@ class DbInterval extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbInterval] to use this feature';
throw UnimplementedError(msg);
}
@ -13116,7 +13116,7 @@ class DbWeight extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbWeight] to use this feature';
throw UnimplementedError(msg);
}
@ -14104,7 +14104,7 @@ class DbHeartRateZoneSchema extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbHeartRateZoneSchema] to use this feature';
throw UnimplementedError(msg);
}
@ -15114,7 +15114,7 @@ class DbHeartRateZone extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbHeartRateZone] to use this feature';
throw UnimplementedError(msg);
}
@ -16157,7 +16157,7 @@ class DbPowerZoneSchema extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbPowerZoneSchema] to use this feature';
throw UnimplementedError(msg);
}
@ -17149,7 +17149,7 @@ class DbPowerZone extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbPowerZone] to use this feature';
throw UnimplementedError(msg);
}
@ -18272,7 +18272,7 @@ class DbTag extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbTag] to use this feature';
throw UnimplementedError(msg);
}
@ -19305,7 +19305,7 @@ class DbTagGroup extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbTagGroup] to use this feature';
throw UnimplementedError(msg);
}
@ -20250,7 +20250,7 @@ class DbLapTagging extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbLapTagging] to use this feature';
throw UnimplementedError(msg);
}
@ -21177,7 +21177,7 @@ class DbActivityTagging extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbActivityTagging] to use this feature';
throw UnimplementedError(msg);
}
@ -22107,7 +22107,7 @@ class DbIntervalTagging extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbIntervalTagging] to use this feature';
throw UnimplementedError(msg);
}
@ -22994,7 +22994,7 @@ class DbLog extends TableBase {
@override
Future<BoolResult> recover([bool recoverChilds = true]) {
// not implemented because:
final msg =
const msg =
'set useSoftDeleting:true in the table definition of [DbLog] to use this feature';
throw UnimplementedError(msg);
}

View File

@ -4,7 +4,7 @@ import 'dart:io';
import 'package:fit_parser/fit_parser.dart';
// ignore: implementation_imports
import 'package:fit_parser/src/value.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
@ -37,25 +37,25 @@ class Activity {
Activity._fromDb(this._db);
Activity.fromStrava({
@required SummaryActivity summaryActivity,
@required Athlete athlete,
required SummaryActivity summaryActivity,
required Athlete athlete,
}) {
_db = DbActivity()
..athletesId = athlete.id
..name = summaryActivity.name
..type = summaryActivity.type
..distance = summaryActivity.distance.toInt()
..distance = summaryActivity.distance!.toInt()
..stravaId = summaryActivity.id;
}
Activity.fromLocalDirectory({@required Athlete athlete}) {
Activity.fromLocalDirectory({required Athlete athlete}) {
_db = DbActivity()
..athletesId = athlete.id
..stravaId = DateTime.now().millisecondsSinceEpoch
..name = 'new activity';
}
Activity.manual({@required Athlete athlete}) {
Activity.manual({required Athlete athlete}) {
_db = DbActivity()
..athletesId = athlete.id
..stravaId = DateTime.now().millisecondsSinceEpoch
@ -68,178 +68,181 @@ class Activity {
..timeCreated = DateTime.now();
}
DbActivity _db;
DbActivity _db = DbActivity();
List<Event> cachedRecords = <Event>[];
List<Lap> cachedLaps = <Lap>[];
List<encrateia.Interval> cachedIntervals = <encrateia.Interval>[];
List<Tag> cachedTags = <Tag>[];
double glidingMeasureAttribute;
double cachedWeight;
double cachedEcor;
PowerZoneSchema _powerZoneSchema;
PowerZone _powerZone;
HeartRateZone _heartRateZone;
HeartRateZoneSchema _heartRateZoneSchema;
int distanceSoFar;
int movingTimeSoFar;
double? glidingMeasureAttribute;
double? cachedWeight;
double? cachedEcor;
PowerZoneSchema? _powerZoneSchema;
PowerZone? _powerZone;
HeartRateZone? _heartRateZone;
HeartRateZoneSchema? _heartRateZoneSchema;
late int distanceSoFar;
late int movingTimeSoFar;
// Getter
int get id => _db?.id;
int? get id => _db.id;
DateTime get startTime => _db.startTime;
DateTime get timeCreated => _db.timeCreated;
DateTime get timeStamp => _db.timeStamp;
DateTime? get startTime => _db.startTime;
DateTime? get timeCreated => _db.timeCreated;
DateTime? get timeStamp => _db.timeStamp;
String get event => _db.event;
String get eventType => _db.eventType;
String get name => _db.name;
String get sport => _db.sport;
String get state => _db.state;
String get subSport => _db.subSport;
String get trigger => _db.trigger;
String get type => _db.type;
String? get event => _db.event;
String? get eventType => _db.eventType;
String? get name => _db.name;
String? get sport => _db.sport;
String? get state => _db.state;
String? get subSport => _db.subSport;
String? get trigger => _db.trigger;
String? get type => _db.type;
bool get excluded => _db.excluded;
bool get manual => _db.manual;
bool get nonParsable => _db.nonParsable;
bool? get excluded => _db.excluded;
bool? get manual => _db.manual;
bool? get nonParsable => _db.nonParsable;
double get avgFormPower => _db.avgFormPower;
double get avgFractionalCadence => _db.avgFractionalCadence;
double get avgGroundTime => _db.avgGroundTime;
double get avgLegSpringStiffness => _db.avgLegSpringStiffness;
double get avgPower => _db.avgPower;
double get avgPowerRatio => _db.avgPowerRatio;
double get avgRunningCadence => _db.avgRunningCadence;
double get avgSpeed => _db.avgSpeed;
double get avgSpeedByDistance => _db.avgSpeedByDistance;
double get avgSpeedByMeasurements => _db.avgSpeedByMeasurements;
double get avgSpeedBySpeed => _db.avgSpeedBySpeed;
double get avgStanceTime => _db.avgStanceTime;
double get avgStanceTimePercent => _db.avgStanceTimePercent;
double get avgStrideRatio => _db.avgStrideRatio;
double get avgStrydCadence => _db.avgStrydCadence;
double get avgVerticalOscillation => _db.avgVerticalOscillation;
double get cp => _db.cp;
double get ftp => _db.ftp;
double get maxFractionalCadence => _db.maxFractionalCadence;
double get maxSpeed => _db.maxSpeed;
double get minSpeed => _db.minSpeed;
double get necLat => _db.necLat;
double get necLong => _db.necLong;
double get sdevFormPower => _db.sdevFormPower;
double get sdevGroundTime => _db.sdevGroundTime;
double get sdevHeartRate => _db.sdevHeartRate;
double get sdevLegSpringStiffness => _db.sdevLegSpringStiffness;
double get sdevPace => _db.sdevPace;
double get sdevPower => _db.sdevPower;
double get sdevPowerRatio => _db.sdevPowerRatio;
double get sdevSpeed => _db.sdevSpeed;
double get sdevStrideRatio => _db.sdevStrideRatio;
double get sdevStrydCadence => _db.sdevStrydCadence;
double get sdevVerticalOscillation => _db.sdevVerticalOscillation;
double get startPositionLat => _db.startPositionLat;
double get startPositionLong => _db.startPositionLong;
double get swcLat => _db.swcLat;
double get swcLong => _db.swcLong;
double get totalFractionalCycles => _db.totalFractionalCycles;
double? get avgFormPower => _db.avgFormPower;
double? get avgFractionalCadence => _db.avgFractionalCadence;
double? get avgGroundTime => _db.avgGroundTime;
double? get avgLegSpringStiffness => _db.avgLegSpringStiffness;
double? get avgPower => _db.avgPower;
double? get avgPowerRatio => _db.avgPowerRatio;
double? get avgRunningCadence => _db.avgRunningCadence;
double? get avgSpeed => _db.avgSpeed;
double? get avgSpeedByDistance => _db.avgSpeedByDistance;
double? get avgSpeedByMeasurements => _db.avgSpeedByMeasurements;
double? get avgSpeedBySpeed => _db.avgSpeedBySpeed;
double? get avgStanceTime => _db.avgStanceTime;
double? get avgStanceTimePercent => _db.avgStanceTimePercent;
double? get avgStrideRatio => _db.avgStrideRatio;
double? get avgStrydCadence => _db.avgStrydCadence;
double? get avgVerticalOscillation => _db.avgVerticalOscillation;
double? get cp => _db.cp;
double? get ftp => _db.ftp;
double? get maxFractionalCadence => _db.maxFractionalCadence;
double? get maxSpeed => _db.maxSpeed;
double? get minSpeed => _db.minSpeed;
double? get necLat => _db.necLat;
double? get necLong => _db.necLong;
double? get sdevFormPower => _db.sdevFormPower;
double? get sdevGroundTime => _db.sdevGroundTime;
double? get sdevHeartRate => _db.sdevHeartRate;
double? get sdevLegSpringStiffness => _db.sdevLegSpringStiffness;
double? get sdevPace => _db.sdevPace;
double? get sdevPower => _db.sdevPower;
double? get sdevPowerRatio => _db.sdevPowerRatio;
double? get sdevSpeed => _db.sdevSpeed;
double? get sdevStrideRatio => _db.sdevStrideRatio;
double? get sdevStrydCadence => _db.sdevStrydCadence;
double? get sdevVerticalOscillation => _db.sdevVerticalOscillation;
double? get startPositionLat => _db.startPositionLat;
double? get startPositionLong => _db.startPositionLong;
double? get swcLat => _db.swcLat;
double? get swcLong => _db.swcLong;
double? get totalFractionalCycles => _db.totalFractionalCycles;
int get athletesId => _db.athletesId;
int get avgHeartRate => _db.avgHeartRate;
int get avgTemperature => _db.avgTemperature;
int get distance => _db.distance;
int get maxHeartRate => _db.maxHeartRate;
int get maxPower => _db.maxPower;
int get maxRunningCadence => _db.maxRunningCadence;
int get maxTemperature => _db.maxTemperature;
int get minHeartRate => _db.minHeartRate;
int get minPower => _db.minPower;
int get movingTime => _db.movingTime;
int get numLaps => _db.numLaps;
int get numSessions => _db.numSessions;
int get serialNumber => _db.serialNumber;
int get stravaId => _db.stravaId;
int get totalAscent => _db.totalAscent;
int get totalCalories => _db.totalCalories;
int get totalDescent => _db.totalDescent;
int get totalDistance => _db.totalDistance;
int get totalElapsedTime => _db.totalElapsedTime;
int get totalStrides => _db.totalStrides;
int get totalTimerTime => _db.totalTimerTime;
int get totalTrainingEffect => _db.totalTrainingEffect;
int? get athletesId => _db.athletesId;
int? get avgHeartRate => _db.avgHeartRate;
int? get avgTemperature => _db.avgTemperature;
int? get distance => _db.distance;
int? get maxHeartRate => _db.maxHeartRate;
int? get maxPower => _db.maxPower;
int? get maxRunningCadence => _db.maxRunningCadence;
int? get maxTemperature => _db.maxTemperature;
int? get minHeartRate => _db.minHeartRate;
int? get minPower => _db.minPower;
int? get movingTime => _db.movingTime;
int? get numLaps => _db.numLaps;
int? get numSessions => _db.numSessions;
int? get serialNumber => _db.serialNumber;
int? get stravaId => _db.stravaId;
int? get totalAscent => _db.totalAscent;
int? get totalCalories => _db.totalCalories;
int? get totalDescent => _db.totalDescent;
int? get totalDistance => _db.totalDistance;
int? get totalElapsedTime => _db.totalElapsedTime;
int? get totalStrides => _db.totalStrides;
int? get totalTimerTime => _db.totalTimerTime;
int? get totalTrainingEffect => _db.totalTrainingEffect;
// calculated from other attributes:
double get avgPace {
if (avgSpeed != null && avgSpeed != 0)
return 50 / 3 / avgSpeed;
else
double? get avgPace {
if (avgSpeed != null && avgSpeed != 0) {
return 50 / 3 / avgSpeed!;
} else {
return null;
}
}
double get avgSpeedPerHeartRate {
if (avgSpeed != null && heartRateAvailable)
return 60 * avgSpeed / avgHeartRate;
else
double? get avgSpeedPerHeartRate {
if (avgSpeed != null && heartRateAvailable) {
return 60 * avgSpeed! / avgHeartRate!;
} else {
return null;
}
}
double get avgPowerPerHeartRate {
if (powerAvailable && heartRateAvailable)
return avgPower / avgHeartRate;
else
double? get avgPowerPerHeartRate {
if (powerAvailable && heartRateAvailable) {
return avgPower! / avgHeartRate!;
} else {
return null;
}
}
int get elevationDifference =>
ascentAvailable ? totalAscent - totalDescent : null;
int? get elevationDifference =>
ascentAvailable ? totalAscent! - totalDescent! : null;
double get avgDoubleStrydCadence =>
cadenceAvailable ? avgStrydCadence * 2 : null;
double? get avgDoubleStrydCadence =>
cadenceAvailable ? avgStrydCadence! * 2 : null;
// easier check for data availability
bool get powerAvailable => !<num>[null, -1].contains(avgPower);
bool get powerRatioAvailable => !<num>[null, -1].contains(avgPowerRatio);
bool get heartRateAvailable => !<num>[null, -1].contains(avgHeartRate);
bool get powerAvailable => !<num?>[null, -1].contains(avgPower);
bool get powerRatioAvailable => !<num?>[null, -1].contains(avgPowerRatio);
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(avgSpeedByDistance);
bool get paceAvailable => !<num>[null, -1].contains(avgPace);
bool get cadenceAvailable => !<num?>[null, -1].contains(avgStrydCadence);
bool get speedAvailable => !<num?>[null, 0, -1].contains(avgSpeedByDistance);
bool get paceAvailable => !<num?>[null, -1].contains(avgPace);
bool get ecorAvailable => powerAvailable && speedAvailable;
bool get groundTimeAvailable => !<num>[null, -1].contains(avgGroundTime);
bool get formPowerAvailable => !<num>[null, -1].contains(avgFormPower);
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 strideRatioAvailable => !<num>[null, -1].contains(avgStrideRatio);
!<num?>[null, -1].contains(avgVerticalOscillation);
bool get strideRatioAvailable => !<num?>[null, -1].contains(avgStrideRatio);
bool get strideCadenceAvailable =>
!<num>[null, -1].contains(avgDoubleStrydCadence);
!<num?>[null, -1].contains(avgDoubleStrydCadence);
bool get legSpringStiffnessAvailable =>
!<num>[null, -1].contains(avgLegSpringStiffness);
!<num?>[null, -1].contains(avgLegSpringStiffness);
// Setter
set excluded(bool value) => _db.excluded = value;
set ftp(double value) => _db.ftp = value;
set manual(bool value) => _db.manual = value;
set maxHeartRate(int value) => _db.maxHeartRate = value;
set name(String value) => _db.name = value;
set nonParsable(bool value) => _db.nonParsable = value;
set state(String value) => _db.state = value;
set timeStamp(DateTime value) => _db.timeStamp = value;
set timeCreated(DateTime value) => _db.timeCreated = value;
set totalDistance(int value) => _db.totalDistance = value;
set totalAscent(int value) => _db.totalAscent = value;
set totalDescent(int value) => _db.totalDescent = value;
set avgHeartRate(int value) => _db.avgHeartRate = value;
set avgPower(double value) => _db.avgPower = value;
set sport(String value) => _db.sport = value;
set subSport(String value) => _db.subSport = value;
set movingTime(int value) => _db.movingTime = value;
set excluded(bool? value) => _db.excluded = value;
set ftp(double? value) => _db.ftp = value;
set manual(bool? value) => _db.manual = value;
set maxHeartRate(int? value) => _db.maxHeartRate = value;
set name(String? value) => _db.name = value;
set nonParsable(bool? value) => _db.nonParsable = value;
set state(String? value) => _db.state = value;
set timeStamp(DateTime? value) => _db.timeStamp = value;
set timeCreated(DateTime? value) => _db.timeCreated = value;
set totalDistance(int? value) => _db.totalDistance = value;
set totalAscent(int? value) => _db.totalAscent = value;
set totalDescent(int? value) => _db.totalDescent = value;
set avgHeartRate(int? value) => _db.avgHeartRate = value;
set avgPower(double? value) => _db.avgPower = value;
set sport(String? value) => _db.sport = value;
set subSport(String? value) => _db.subSport = value;
set movingTime(int? value) => _db.movingTime = value;
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<int?> save() async => await _db.save();
// intermediate data structures used for parsing
Lap currentLap;
List<Event> eventsForCurrentLap;
late Lap currentLap;
late List<Event> eventsForCurrentLap;
@override
String toString() => '< Activity | $name | $startTime >';
@ -261,7 +264,7 @@ class Activity {
case ActivityAttr.avgPace:
return avgPace;
case ActivityAttr.avgHeartRate:
return avgHeartRate.toDouble();
return avgHeartRate!.toDouble();
case ActivityAttr.avgDoubleStrydCadence:
return avgDoubleStrydCadence;
case ActivityAttr.ftp:
@ -271,18 +274,18 @@ class Activity {
case ActivityAttr.movingTimeThisYear:
return movingTimeSoFar / 3600;
case ActivityAttr.distance:
return distance / 1000;
return distance! / 1000;
}
}
Future<void> download({@required Athlete athlete}) async {
Future<void> download({required Athlete? athlete}) async {
await StravaFitDownload.byId(id: stravaId.toString(), athlete: athlete);
setState('downloaded');
}
static Future<void> importFromLocalDirectory({Athlete athlete}) async {
static Future<void> importFromLocalDirectory({Athlete? athlete}) async {
if (Platform.isAndroid) {
final List<Directory> directories = await getExternalStorageDirectories();
final List<Directory> directories = await (getExternalStorageDirectories() as Future<List<Directory>>);
final Directory localDir = directories[0];
final Directory appDocDir = await getApplicationDocumentsDirectory();
@ -292,7 +295,7 @@ class Activity {
);
await for (final FileSystemEntity entity in entityStream) {
final Activity activity = Activity.fromLocalDirectory(athlete: athlete);
final Activity activity = Activity.fromLocalDirectory(athlete: athlete!);
// ignore: avoid_slow_async_io
final bool isFile = await FileSystemEntity.isFile(entity.path);
if (isFile == true && entity.path.toLowerCase().endsWith('.fit')) {
@ -311,7 +314,7 @@ class Activity {
);
await for (final FileSystemEntity entity in entityStream) {
final Activity activity = Activity.fromLocalDirectory(athlete: athlete);
final Activity activity = Activity.fromLocalDirectory(athlete: athlete!);
// ignore: avoid_slow_async_io
final bool isFile = await FileSystemEntity.isFile(entity.path);
if (isFile == true && entity.path.endsWith('.fit')) {
@ -331,7 +334,7 @@ class Activity {
Future<List<Event>> get records async {
if (cachedRecords.isEmpty) {
final List<DbEvent> dbEventList = await _db.getDbEvents().toList();
final List<DbEvent> dbEventList = await _db.getDbEvents()!.toList();
final Iterable<DbEvent> dbRecordList =
dbEventList.where((DbEvent dbEvent) => dbEvent.event == 'record');
cachedRecords = dbRecordList.map(Event.exDb).toList();
@ -340,7 +343,7 @@ class Activity {
}
Future<List<Event>> get events async {
final List<DbEvent> dbEventList = await _db.getDbEvents().toList();
final List<DbEvent> dbEventList = await _db.getDbEvents()!.toList();
return dbEventList.map(Event.exDb).toList();
}
@ -351,22 +354,22 @@ class Activity {
return cachedTags;
}
Future<double> get weight async {
Future<double?> get weight async {
if (cachedWeight == null) {
final Weight weight = await Weight.getBy(
final Weight weight = await (Weight.getBy(
athletesId: athletesId,
date: timeCreated,
);
) as Future<Weight>);
cachedWeight = weight.value;
}
return cachedWeight;
}
Future<double> get ecor async {
Future<double?> get ecor async {
if (cachedEcor == null) {
final double weightValue = await weight;
final double? weightValue = await weight;
cachedEcor = (powerAvailable && speedAvailable && weightValue != null)
? avgPower / avgSpeed / weightValue
? avgPower! / avgSpeed! / weightValue
: -1;
}
return cachedEcor;
@ -415,18 +418,18 @@ class Activity {
return true;
}
Stream<int> parse({@required Athlete athlete}) async* {
Stream<int> parse({required Athlete? athlete}) async* {
int counter = 0;
int percentage;
int? percentage;
final Directory appDocDir = await getApplicationDocumentsDirectory();
final FitFile fitFile =
FitFile(path: appDocDir.path + '/$stravaId.fit').parse();
print('Parsing .fit-File for »$name« done.');
debugPrint('Parsing .fit-File for »$name« done.');
// delete left overs from prior runs:
await _db.getDbEvents().delete();
await _db.getDbLaps().delete();
await _db.getDbEvents()!.delete();
await _db.getDbLaps()!.delete();
_db
..avgPower = null
..minPower = null
@ -462,9 +465,9 @@ class Activity {
yield -2;
}
Future<int> handleDataMessage({DataMessage dataMessage}) async {
if (dataMessage.definitionMessage.globalMessageName == null) {
switch (dataMessage.definitionMessage.globalMessageNumber) {
Future<int?> handleDataMessage({required DataMessage dataMessage}) async {
if (dataMessage.definitionMessage!.globalMessageName == null) {
switch (dataMessage.definitionMessage!.globalMessageNumber) {
// Garmin Forerunner 235uses global message numbers, which are not specified:
case 13:
case 22:
@ -486,13 +489,13 @@ class Activity {
case 329:
break;
default:
print('Message number ' +
dataMessage.definitionMessage.globalMessageNumber.toString() +
debugPrint('Message number ' +
dataMessage.definitionMessage!.globalMessageNumber.toString() +
' unknown.');
debugger();
}
} else {
switch (dataMessage.definitionMessage.globalMessageName) {
switch (dataMessage.definitionMessage!.globalMessageName) {
case 'developer_data_id':
case 'device_info':
case 'device_settings':
@ -505,7 +508,7 @@ class Activity {
case 'file_id':
_db
..serialNumber =
(dataMessage.get('serial_number') as double)?.round()
(dataMessage.get('serial_number') as double?)?.round()
..timeCreated =
dateTimeFromStrava(dataMessage.get('time_created') as double);
await save();
@ -513,9 +516,9 @@ class Activity {
case 'sport':
_db
..sportName = dataMessage.get('name') as String
..sport = dataMessage.get('sport') as String
..subSport = dataMessage.get('sub_sport') as String;
..sportName = dataMessage.get('name') as String?
..sport = dataMessage.get('sport') as String?
..subSport = dataMessage.get('sub_sport') as String?;
await save();
break;
@ -567,92 +570,93 @@ class Activity {
final DateTime startTime =
dateTimeFromStrava(dataMessage.get('start_time') as double);
if (name == 'new activity')
if (name == 'new activity') {
name =
'Activity on ' + DateFormat.yMMMMd('en_US').format(startTime);
}
_db
..timeStamp =
dateTimeFromStrava(dataMessage.get('timestamp') as double)
..startTime = startTime
..startPositionLat = dataMessage.get('start_position_lat') as double
..startPositionLat = dataMessage.get('start_position_lat') as double?
..startPositionLong =
dataMessage.get('start_position_long') as double
dataMessage.get('start_position_long') as double?
..totalElapsedTime =
(dataMessage.get('total_elapsed_time') as double)?.round()
(dataMessage.get('total_elapsed_time') as double?)?.round()
..totalTimerTime =
(dataMessage.get('total_timer_time') as double)?.round()
(dataMessage.get('total_timer_time') as double?)?.round()
..distance = (distance ??
(dataMessage.get('total_distance') as double)?.round())
(dataMessage.get('total_distance') as double?)?.round())
..totalDistance =
(dataMessage.get('total_distance') as double)?.round()
(dataMessage.get('total_distance') as double?)?.round()
..totalStrides =
(dataMessage.get('total_strides') as double)?.round()
..necLat = dataMessage.get('nec_lat') as double
..necLong = dataMessage.get('nec_long') as double
..swcLat = dataMessage.get('swc_lat') as double
..swcLong = dataMessage.get('swc_long') as double
(dataMessage.get('total_strides') as double?)?.round()
..necLat = dataMessage.get('nec_lat') as double?
..necLong = dataMessage.get('nec_long') as double?
..swcLat = dataMessage.get('swc_lat') as double?
..swcLong = dataMessage.get('swc_long') as double?
..totalCalories =
(dataMessage.get('total_calories') as double)?.round()
(dataMessage.get('total_calories') as double?)?.round()
..avgSpeed = dataMessage.get('avg_speed') == 65.535
? dataMessage.get('enhanced_avg_speed') as double
: dataMessage.get('avg_speed') as double
? dataMessage.get('enhanced_avg_speed') as double?
: dataMessage.get('avg_speed') as double?
..maxSpeed = dataMessage.get('max_speed') == 65.535
? dataMessage.get('enhanced_max_speed') as double
: dataMessage.get('max_speed') as double
..totalAscent = (dataMessage.get('total_ascent') as double)?.round()
? dataMessage.get('enhanced_max_speed') as double?
: dataMessage.get('max_speed') as double?
..totalAscent = (dataMessage.get('total_ascent') as double?)?.round()
..totalDescent =
(dataMessage.get('total_descent') as double)?.round()
(dataMessage.get('total_descent') as double?)?.round()
..maxRunningCadence =
(dataMessage.get('max_running_cadence') as double)?.round()
(dataMessage.get('max_running_cadence') as double?)?.round()
..firstLapIndex =
(dataMessage.get('first_lap_index') as double)?.round()
..numLaps = (dataMessage.get('num_laps') as double)?.round()
(dataMessage.get('first_lap_index') as double?)?.round()
..numLaps = (dataMessage.get('num_laps') as double?)?.round()
..event = dataMessage.get('event')?.toString()
..type = type ?? dataMessage.get('event_type') as String
..eventType = dataMessage.get('event_type') as String
..eventGroup = (dataMessage.get('event_group') as double)?.round()
..trigger = dataMessage.get('trigger') as String
..type = type ?? dataMessage.get('event_type') as String?
..eventType = dataMessage.get('event_type') as String?
..eventGroup = (dataMessage.get('event_group') as double?)?.round()
..trigger = dataMessage.get('trigger') as String?
..avgVerticalOscillation =
dataMessage.get('avg_vertical_oscillation') as double
dataMessage.get('avg_vertical_oscillation') as double?
..avgStanceTimePercent =
dataMessage.get('avg_stance_time_percent') as double
..avgStanceTime = dataMessage.get('avg_stance_time') as double
..sport = dataMessage.get('sport') as String
..subSport = dataMessage.get('sub_sport') as String
dataMessage.get('avg_stance_time_percent') as double?
..avgStanceTime = dataMessage.get('avg_stance_time') as double?
..sport = dataMessage.get('sport') as String?
..subSport = dataMessage.get('sub_sport') as String?
..avgHeartRate =
(dataMessage.get('avg_heart_rate') as double)?.round()
(dataMessage.get('avg_heart_rate') as double?)?.round()
..maxHeartRate =
(dataMessage.get('max_heart_rate') as double)?.round()
(dataMessage.get('max_heart_rate') as double?)?.round()
..avgRunningCadence =
dataMessage.get('avg_running_cadence') as double
dataMessage.get('avg_running_cadence') as double?
..totalTrainingEffect =
(dataMessage.get('total_training_effect') as double)?.round()
(dataMessage.get('total_training_effect') as double?)?.round()
..avgTemperature =
(dataMessage.get('avg_temperature') as double)?.round()
(dataMessage.get('avg_temperature') as double?)?.round()
..maxTemperature =
(dataMessage.get('max_temperature') as double)?.round()
(dataMessage.get('max_temperature') as double?)?.round()
..avgFractionalCadence =
dataMessage.get('avg_fractional_cadence') as double
dataMessage.get('avg_fractional_cadence') as double?
..maxFractionalCadence =
dataMessage.get('max_fractional_cadence') as double
dataMessage.get('max_fractional_cadence') as double?
..totalFractionalCycles =
dataMessage.get('total_fractional_cycles') as double;
dataMessage.get('total_fractional_cycles') as double?;
await save();
break;
case 'activity':
_db
..numSessions = (dataMessage.get('num_sessions') as double)?.round()
..numSessions = (dataMessage.get('num_sessions') as double?)?.round()
..localTimestamp = dateTimeFromStrava(
dataMessage.get('local_timestamp') as double);
await save();
break;
default:
print('Messages of type ' +
dataMessage.definitionMessage.globalMessageName +
debugPrint('Messages of type ' +
dataMessage.definitionMessage!.globalMessageName! +
' are not implemented yet.');
print(dataMessage.values.map((Value v) => v.fieldName).toList());
debugPrint(dataMessage.values.map((Value v) => v.fieldName).toList().toString());
// Use this debugger to implement additional message types!
// debugger();
}
@ -666,7 +670,7 @@ class Activity {
eventsForCurrentLap = <Event>[];
}
static Future<void> queryStrava({Athlete athlete}) async {
static Future<void> queryStrava({required Athlete athlete}) async {
final StravaClient stravaClient =
StravaClient(clientId: clientId, secret: secret);
@ -679,7 +683,7 @@ class Activity {
final DateTime now = DateTime.now();
final DateTime startDate =
DateTime.now().subtract(Duration(days: athlete.downloadInterval));
DateTime.now().subtract(Duration(days: athlete.downloadInterval!));
final List<SummaryActivity> summaryActivities = await stravaClient
.activities
@ -703,24 +707,24 @@ class Activity {
});
}
Future<PowerZoneSchema> get powerZoneSchema async =>
Future<PowerZoneSchema?> get powerZoneSchema async =>
_powerZoneSchema ??= await PowerZoneSchema.getBy(
athletesId: athletesId,
date: timeCreated,
);
Future<HeartRateZoneSchema> get heartRateZoneSchema async =>
Future<HeartRateZoneSchema?> get heartRateZoneSchema async =>
_heartRateZoneSchema ??= await HeartRateZoneSchema.getBy(
athletesId: athletesId,
date: timeCreated,
);
Future<PowerZone> get powerZone async {
Future<PowerZone?> get powerZone async {
if (_powerZone == null) {
final DbPowerZone dbPowerZone = await DbPowerZone()
final DbPowerZone? dbPowerZone = await DbPowerZone()
.select()
.powerZoneSchemataId
.equals((await powerZoneSchema).id)
.equals((await powerZoneSchema)!.id)
.and
.lowerLimit
.lessThanOrEquals(avgPower)
@ -733,12 +737,12 @@ class Activity {
return _powerZone;
}
Future<HeartRateZone> get heartRateZone async {
Future<HeartRateZone?> get heartRateZone async {
if (_heartRateZone == null) {
final DbHeartRateZone dbHeartRateZone = await DbHeartRateZone()
final DbHeartRateZone? dbHeartRateZone = await DbHeartRateZone()
.select()
.heartRateZoneSchemataId
.equals((await heartRateZoneSchema).id)
.equals((await heartRateZoneSchema)!.id)
.and
.lowerLimit
.lessThanOrEquals(avgHeartRate)
@ -752,11 +756,11 @@ class Activity {
return _heartRateZone;
}
Future<void> autoTagger({@required Athlete athlete}) async {
final PowerZone powerZone = await this.powerZone;
Future<void> autoTagger({required Athlete? athlete}) async {
final PowerZone powerZone = await (this.powerZone as Future<PowerZone>);
if (powerZone.id != null) {
final Tag powerTag = await Tag.autoPowerTag(
athlete: athlete,
athlete: athlete!,
color: powerZone.color,
sortOrder: powerZone.lowerLimit,
name: powerZone.name,
@ -768,10 +772,10 @@ class Activity {
);
}
final HeartRateZone heartRateZone = await this.heartRateZone;
final HeartRateZone heartRateZone = await (this.heartRateZone as Future<HeartRateZone>);
if (heartRateZone.id != null) {
final Tag heartRateTag = await Tag.autoHeartRateTag(
athlete: athlete,
athlete: athlete!,
color: heartRateZone.color,
sortOrder: heartRateZone.lowerLimit,
name: heartRateZone.name,
@ -789,7 +793,7 @@ class Activity {
}
Future<List<BarZone>> powerZoneCounts() async {
final PowerZoneSchema powerZoneSchema = await this.powerZoneSchema;
final PowerZoneSchema powerZoneSchema = await (this.powerZoneSchema as Future<PowerZoneSchema>);
final List<Event> records = await this.records;
final List<Event> powerRecords =
records.where((Event record) => record.power != null).toList();
@ -800,7 +804,7 @@ class Activity {
Future<List<BarZone>> heartRateZoneCounts() async {
final HeartRateZoneSchema heartRateZoneSchema =
await this.heartRateZoneSchema;
await (this.heartRateZoneSchema as Future<HeartRateZoneSchema>);
final List<Event> records = await this.records;
final List<Event> heartRateRecords =
records.where((Event record) => record.heartRate != null).toList();
@ -814,7 +818,7 @@ class Activity {
if (cachedLaps.isEmpty) {
int counter = 1;
final List<DbLap> dbLapList = await _db.getDbLaps().toList();
final List<DbLap> dbLapList = await _db.getDbLaps()!.toList();
cachedLaps = dbLapList.map(Lap.exDb).toList();
for (final Lap lap in cachedLaps) {
@ -832,7 +836,7 @@ class Activity {
int counter = 1;
final List<DbInterval> dbIntervalList =
await _db.getDbIntervals().toList();
await _db.getDbIntervals()!.toList();
cachedIntervals = dbIntervalList.map(encrateia.Interval.exDb).toList();
for (final encrateia.Interval interval in cachedIntervals) {
@ -845,13 +849,13 @@ class Activity {
return cachedIntervals;
}
static Future<Activity> byId(int id) async {
final DbActivity dbActivity = await DbActivity().getById(id);
static Future<Activity> byId(int? id) async {
final DbActivity? dbActivity = await DbActivity().getById(id);
return exDb(dbActivity);
}
Future<BoolResult> deleteEvents() async => await _db.getDbEvents().delete();
Future<BoolResult> deleteLaps() async => await _db.getDbLaps().delete();
Future<BoolResult> deleteEvents() async => await _db.getDbEvents()!.delete();
Future<BoolResult> deleteLaps() async => await _db.getDbLaps()!.delete();
static Activity exDb(DbActivity db) => Activity._fromDb(db);
static Activity exDb(DbActivity? db) => Activity._fromDb(db);
}

View File

@ -1,5 +1,4 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import '/model/model.dart' show DbActivityTagging;
import '/models/activity.dart';
@ -16,8 +15,8 @@ class ActivityList<E> extends DelegatingList<E> {
final List<Activity> _activities;
void enrichGlidingAverage({
@required int fullDecay,
@required ActivityAttr activityAttr,
required int fullDecay,
required ActivityAttr activityAttr,
}) {
_activities.asMap().forEach((int index, Activity activity) {
double sumOfAvg =
@ -26,8 +25,8 @@ class ActivityList<E> extends DelegatingList<E> {
for (int olderIndex = index + 1;
olderIndex < _activities.length;
olderIndex++) {
final double daysAgo = activity.timeCreated
.difference(_activities[olderIndex].timeCreated)
final double daysAgo = activity.timeCreated!
.difference(_activities[olderIndex].timeCreated!)
.inHours /
24;
if (daysAgo > fullDecay) {
@ -43,12 +42,12 @@ class ActivityList<E> extends DelegatingList<E> {
}
Future<ActivityList<Activity>> applyFilter({
Athlete athlete,
List<TagGroup> tagGroups,
required Athlete athlete,
List<TagGroup>? tagGroups,
bool firstGroupWithData = true,
}) async {
List<int> activityIds = <int>[];
List<int> tagIds = <int>[];
List<int?> activityIds = <int>[];
List<int?> tagIds = <int>[];
if (athlete.filters.isEmpty) {
return ActivityList<Activity>(_activities);
@ -58,7 +57,7 @@ class ActivityList<E> extends DelegatingList<E> {
// get active filters for TagGroup
for (final TagGroup tagGroup in tagGroups) {
tagIds = tagGroup.cachedTags.map((Tag tag) => tag.id).toList();
tagIds.removeWhere((int tagId) => !athlete.filters.contains(tagId));
tagIds.removeWhere((int? tagId) => !athlete.filters.contains(tagId));
// If there are restrictions for this group:
if (tagIds.isNotEmpty) {
@ -69,7 +68,7 @@ class ActivityList<E> extends DelegatingList<E> {
.inValues(tagIds)
.toList();
// ... and the Activity's ids
final List<int> activityIdsFromThisGroup = dbTaggings
final List<int?> activityIdsFromThisGroup = dbTaggings
.map((DbActivityTagging dbActivityTagging) =>
dbActivityTagging.activitiesId)
.toList();
@ -80,10 +79,10 @@ class ActivityList<E> extends DelegatingList<E> {
{
firstGroupWithData = false;
activityIds = activityIdsFromThisGroup;
} else
// For the others: intersect.
} else {
activityIds.removeWhere(
(int tagId) => !activityIdsFromThisGroup.contains(tagId));
(int? tagId) => !activityIdsFromThisGroup.contains(tagId));
}
}
}
}
@ -95,12 +94,12 @@ class ActivityList<E> extends DelegatingList<E> {
}
Future<ActivityList<Activity>> filterByTagGroup({
@required TagGroup tagGroup,
required TagGroup tagGroup,
}) async {
List<int> activityIds = <int>[];
List<int?> activityIds = <int>[];
final List<Tag> tags = await tagGroup.tags;
final List<int> tagIds = tags.map((Tag tag) => tag.id).toList();
final List<int?> tagIds = tags.map((Tag tag) => tag.id).toList();
if (tagIds.isNotEmpty) {
final List<DbActivityTagging> dbTaggings =

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart' show DbActivityTagging;
@ -7,9 +6,9 @@ import '/models/tag.dart';
class ActivityTagging {
ActivityTagging({
@required Activity activity,
@required Tag tag,
bool system,
required Activity activity,
required Tag tag,
bool? system,
}) {
_db = DbActivityTagging()
..activitiesId = activity.id
@ -19,18 +18,18 @@ class ActivityTagging {
ActivityTagging._fromDb(this._db);
DbActivityTagging _db;
DbActivityTagging? _db;
int get id => _db?.id;
int get activitiesId => _db.activitiesId;
int get tagsId => _db.tagsId;
int? get id => _db?.id;
int? get activitiesId => _db!.activitiesId;
int? get tagsId => _db!.tagsId;
static Future<ActivityTagging> createBy({
@required Activity activity,
@required Tag tag,
bool system,
required Activity activity,
required Tag tag,
bool? system,
}) async {
final DbActivityTagging dbActivityTagging = await DbActivityTagging()
final DbActivityTagging? dbActivityTagging = await DbActivityTagging()
.select()
.activitiesId
.equals(activity.id)
@ -39,21 +38,21 @@ class ActivityTagging {
.equals(tag.id)
.toSingle();
if (dbActivityTagging != null)
if (dbActivityTagging != null) {
return ActivityTagging._fromDb(dbActivityTagging);
else {
} else {
final ActivityTagging activityTagging = ActivityTagging(
activity: activity, tag: tag, system: system ?? false);
await activityTagging._db.save();
await activityTagging._db!.save();
return activityTagging;
}
}
static Future<ActivityTagging> getBy({
@required Activity activity,
@required Tag tag,
static Future<ActivityTagging?> getBy({
required Activity activity,
required Tag tag,
}) async {
final DbActivityTagging dbActivityTagging = await DbActivityTagging()
final DbActivityTagging? dbActivityTagging = await DbActivityTagging()
.select()
.activitiesId
.equals(activity.id)
@ -61,23 +60,24 @@ class ActivityTagging {
.tagsId
.equals(tag.id)
.toSingle();
if (dbActivityTagging != null)
if (dbActivityTagging != null) {
return ActivityTagging._fromDb(dbActivityTagging);
}
return null;
}
static Future<void> deleteBy({
@required Activity activity,
@required Tag tag,
required Activity activity,
required Tag tag,
}) async {
final DbActivityTagging dbActivityTagging = await DbActivityTagging()
final DbActivityTagging dbActivityTagging = await (DbActivityTagging()
.select()
.activitiesId
.equals(activity.id)
.and
.tagsId
.equals(tag.id)
.toSingle();
.toSingle() as Future<DbActivityTagging>);
await dbActivityTagging.delete();
}
@ -85,7 +85,7 @@ class ActivityTagging {
String toString() =>
'< ActivityTagging | actvityId $activitiesId | tagId $tagsId >';
Future<BoolResult> delete() async => await _db.delete();
Future<BoolResult> delete() async => await _db!.delete();
static ActivityTagging exDb(DbActivityTagging db) =>
ActivityTagging._fromDb(db);

View File

@ -26,37 +26,37 @@ class Athlete {
Athlete();
Athlete._fromDb(this._db);
String email;
String password;
String? email;
String? password;
DbAthlete _db = DbAthlete();
List<int> filters = <int>[];
List<int?> filters = <int?>[];
int get id => _db?.id;
String get firstName => _db.firstName;
String get geoState => _db.geoState;
String get lastName => _db.lastName;
String get photoPath => _db.photoPath;
String get state => _db.state;
String get stravaUsername => _db.stravaUsername;
String get stravaAccessToken => _db.stravaAccessToken;
String get stravaTokenType => _db.stravaTokenType;
String get stravaRefreshToken => _db.stravaRefreshToken;
int get downloadInterval => _db.downloadInterval;
int get recordAggregationCount => _db.recordAggregationCount;
int get stravaExpiresAt => _db.stravaExpiresAt;
int get stravaExpiresIn => _db.stravaExpiresIn;
int get stravaId => _db.stravaId;
int? get id => _db.id;
String? get firstName => _db.firstName;
String? get geoState => _db.geoState;
String? get lastName => _db.lastName;
String? get photoPath => _db.photoPath;
String? get state => _db.state;
String? get stravaUsername => _db.stravaUsername;
String? get stravaAccessToken => _db.stravaAccessToken;
String? get stravaTokenType => _db.stravaTokenType;
String? get stravaRefreshToken => _db.stravaRefreshToken;
int? get downloadInterval => _db.downloadInterval;
int? get recordAggregationCount => _db.recordAggregationCount;
int? get stravaExpiresAt => _db.stravaExpiresAt;
int? get stravaExpiresIn => _db.stravaExpiresIn;
int? get stravaId => _db.stravaId;
set downloadInterval(int value) => _db.downloadInterval = value;
set firstName(String value) => _db.firstName = value;
set lastName(String value) => _db.lastName = value;
set recordAggregationCount(int value) => _db.recordAggregationCount = value;
set stravaAccessToken(String value) => _db.stravaAccessToken = value;
set stravaTokenType(String value) => _db.stravaTokenType = value;
set stravaRefreshToken(String value) => _db.stravaRefreshToken = value;
set stravaExpiresAt(int value) => _db.stravaExpiresAt = value;
set stravaExpiresIn(int value) => _db.stravaExpiresIn = value;
set downloadInterval(int? value) => _db.downloadInterval = value;
set firstName(String? value) => _db.firstName = value;
set lastName(String? value) => _db.lastName = value;
set recordAggregationCount(int? value) => _db.recordAggregationCount = value;
set stravaAccessToken(String? value) => _db.stravaAccessToken = value;
set stravaTokenType(String? value) => _db.stravaTokenType = value;
set stravaRefreshToken(String? value) => _db.stravaRefreshToken = value;
set stravaExpiresAt(int? value) => _db.stravaExpiresAt = value;
set stravaExpiresIn(int? value) => _db.stravaExpiresIn = value;
@override
String toString() => '< Athlete | $firstName $lastName | $stravaId >';
@ -123,13 +123,13 @@ class Athlete {
Future<List<Activity>> get activities async {
final List<DbActivity> dbActivityList =
await _db.getDbActivities().orderByDesc('timeCreated').toList();
await _db.getDbActivities()!.orderByDesc('timeCreated').toList();
return dbActivityList.map(Activity.exDb).toList();
}
Future<List<Activity>> get validActivities async {
final List<DbActivity> dbActivityList = await _db
.getDbActivities()
.getDbActivities()!
.excluded
.equalsOrNull(false)
.and
@ -142,25 +142,25 @@ class Athlete {
Future<List<Weight>> get weights async {
final List<DbWeight> dbWeightList =
await _db.getDbWeights().orderByDesc('date').toList();
await _db.getDbWeights()!.orderByDesc('date').toList();
return dbWeightList.map(Weight.exDb).toList();
}
Future<List<PowerZoneSchema>> get powerZoneSchemas async {
final List<DbPowerZoneSchema> dbPowerZoneSchemaList =
await _db.getDbPowerZoneSchemas().orderByDesc('date').toList();
await _db.getDbPowerZoneSchemas()!.orderByDesc('date').toList();
return dbPowerZoneSchemaList.map(PowerZoneSchema.exDb).toList();
}
Future<List<HeartRateZoneSchema>> get heartRateZoneSchemas async {
final List<DbHeartRateZoneSchema> dbHeartRateZoneSchemaList =
await _db.getDbHeartRateZoneSchemas().orderByDesc('date').toList();
await _db.getDbHeartRateZoneSchemas()!.orderByDesc('date').toList();
return dbHeartRateZoneSchemaList.map(HeartRateZoneSchema.exDb).toList();
}
Future<List<TagGroup>> get tagGroups async {
final List<DbTagGroup> dbTagGroupList =
await _db.getDbTagGroups().orderBy('name').toList();
await _db.getDbTagGroups()!.orderBy('name').toList();
final List<TagGroup> tagGroups = dbTagGroupList.map(TagGroup.exDb).toList();
for (final TagGroup tagGroup in tagGroups) {
@ -171,7 +171,7 @@ class Athlete {
Future<List<encrateia.Interval>> get intervals async {
final List<DbInterval> dbIntervalList =
await _db.getDbIntervals().orderByDesc('timeStamp').toList();
await _db.getDbIntervals()!.orderByDesc('timeStamp').toList();
return dbIntervalList.map(encrateia.Interval.exDb).toList();
}
@ -183,14 +183,15 @@ class Athlete {
await activity.deleteLaps();
// ignore: avoid_slow_async_io
if (await File(appDocDir.path + '/$stravaId.fit').exists())
if (await File(appDocDir.path + '/$stravaId.fit').exists()) {
await File(appDocDir.path + '/$stravaId.fit').delete();
}
}
await _db.getDbActivities().delete();
await _db.getDbActivities()!.delete();
return await _db.delete();
}
Future<int> save() async => await _db.save();
Future<int?> save() async => await _db.save();
Future<bool> checkForSchemas() async =>
(await powerZoneSchemas).isNotEmpty &&

View File

@ -10,8 +10,8 @@ class BarZone {
return <BarZone>[
for (final PowerZone powerZone in powerZones)
BarZone(
lower: powerZone.lowerLimit.toDouble(),
upper: powerZone.upperLimit.toDouble(),
lower: powerZone.lowerLimit!.toDouble(),
upper: powerZone.upperLimit!.toDouble(),
color: powerZone.color,
)
];
@ -23,14 +23,14 @@ class BarZone {
return <BarZone>[
for (final HeartRateZone heartRateZone in heartRateZones)
BarZone(
lower: heartRateZone.lowerLimit.toDouble(),
upper: heartRateZone.upperLimit.toDouble(),
lower: heartRateZone.lowerLimit!.toDouble(),
upper: heartRateZone.upperLimit!.toDouble(),
color: heartRateZone.color,
)
];
}
double lower;
double upper;
int color;
double? lower;
double? upper;
int? color;
}

View File

@ -5,7 +5,7 @@ import '/models/plot_point.dart';
import '/models/power_duration.dart';
class CriticalPower extends PowerDuration {
CriticalPower({List<Event> records}) {
CriticalPower({required List<Event> records}) {
PowerDuration(records: records);
}
@ -13,15 +13,16 @@ class CriticalPower extends PowerDuration {
final List<DoublePlotPoint> plotPoints = <DoublePlotPoint>[];
powerMap.forEach((int duration, double power) {
if (duration > 60 && duration < 1200)
if (duration > 60 && duration < 1200) {
plotPoints.add(DoublePlotPoint(
domain: duration,
measure: power,
));
}
});
plotPoints.sort(
(DoublePlotPoint a, DoublePlotPoint b) => a.domain.compareTo(b.domain));
(DoublePlotPoint a, DoublePlotPoint b) => a.domain!.compareTo(b.domain!));
return plotPoints;
}
@ -78,5 +79,5 @@ class CriticalPower extends PowerDuration {
return this;
}
static int scaled({int seconds}) => (200 * log(seconds)).round();
static int scaled({required int seconds}) => (200 * log(seconds)).round();
}

View File

@ -13,146 +13,146 @@ import '/utils/date_time_utils.dart';
class Event {
Event({
@required DataMessage dataMessage,
@required this.activity,
required DataMessage dataMessage,
required this.activity,
}) {
if (dataMessage.any('max_heart_rate') != false) {
_db = DbEvent()
..event = dataMessage.get('event') as String
..eventType = dataMessage.get('event_type') as String
..heartRate = (dataMessage.get('max_heart_rate') as double)?.round()
..event = dataMessage.get('event') as String?
..eventType = dataMessage.get('event_type') as String?
..heartRate = (dataMessage.get('max_heart_rate') as double?)?.round()
..timeStamp =
dateTimeFromStrava(dataMessage.get('timestamp') as double);
} else if (dataMessage.values.any((Value value) =>
value.fieldName == 'event_type' &&
<String>['start', 'stop', 'stop_all'].contains(value.value))) {
_db = DbEvent()
..activitiesId = activity.id
..event = dataMessage.get('event') as String
..eventType = dataMessage.get('event_type') as String
..eventGroup = (dataMessage.get('event_group') as double)?.round()
..timerTrigger = dataMessage.get('timer_trigger') as String
..activitiesId = activity!.id
..event = dataMessage.get('event') as String?
..eventType = dataMessage.get('event_type') as String?
..eventGroup = (dataMessage.get('event_group') as double?)?.round()
..timerTrigger = dataMessage.get('timer_trigger') as String?
..timeStamp =
dateTimeFromStrava(dataMessage.get('timestamp') as double);
} else if (dataMessage.values.any((Value value) =>
value.fieldName == 'event_type' &&
<String>['marker'].contains(value.value))) {
_db = DbEvent()
..activitiesId = activity.id
..activitiesId = activity!.id
..event = dataMessage.get('event')?.toString()
..eventType = dataMessage.get('event_type') as String
..eventGroup = (dataMessage.get('event_group') as double)?.round()
..data = dataMessage.get('data') as double
..eventType = dataMessage.get('event_type') as String?
..eventGroup = (dataMessage.get('event_group') as double?)?.round()
..data = dataMessage.get('data') as double?
..timeStamp =
dateTimeFromStrava(dataMessage.get('timestamp') as double);
} else {
// Use this debugger to include new event messages, such as heart rate alerts, ...
debugger();
print(dataMessage.get('event'));
debugPrint(dataMessage.get('event'));
}
}
Event._fromDb(this._db);
Event.fromRecord({
@required DataMessage dataMessage,
@required this.activity,
@required int lapsId,
required DataMessage dataMessage,
required Activity this.activity,
required int? lapsId,
}) {
_db = DbEvent()
..activitiesId = activity.id
..activitiesId = activity!.id
..lapsId = lapsId
..event = 'record'
..timeStamp = dateTimeFromStrava(dataMessage.get('timestamp') as double)
..positionLat = dataMessage.get('position_lat') as double
..positionLong = dataMessage.get('position_long') as double
..distance = dataMessage.get('distance') as double
..altitude = dataMessage.get('altitude') as double ??
dataMessage.get('enhanced_altitude') as double
..speed = dataMessage.get('speed') as double ??
dataMessage.get('enhanced_speed') as double
..heartRate = (dataMessage.get('heart_rate') as double)?.round()
..cadence = dataMessage.get('cadence') as double
..fractionalCadence = dataMessage.get('fractional_cadence') as double
..power = (dataMessage.get('Power') as double)?.round()
..strydCadence = dataMessage.get('Cadence') as double
..groundTime = dataMessage.get('Ground Time') as double
..verticalOscillation = dataMessage.get('Vertical Oscillation') as double
..formPower = (dataMessage.get('Form Power') as double)?.round()
..legSpringStiffness = dataMessage.get('Leg Spring Stiffness') as double;
..positionLat = dataMessage.get('position_lat') as double?
..positionLong = dataMessage.get('position_long') as double?
..distance = dataMessage.get('distance') as double?
..altitude = dataMessage.get('altitude') as double? ??
dataMessage.get('enhanced_altitude') as double?
..speed = dataMessage.get('speed') as double? ??
dataMessage.get('enhanced_speed') as double?
..heartRate = (dataMessage.get('heart_rate') as double?)?.round()
..cadence = dataMessage.get('cadence') as double?
..fractionalCadence = dataMessage.get('fractional_cadence') as double?
..power = (dataMessage.get('Power') as double?)?.round()
..strydCadence = dataMessage.get('Cadence') as double?
..groundTime = dataMessage.get('Ground Time') as double?
..verticalOscillation = dataMessage.get('Vertical Oscillation') as double?
..formPower = (dataMessage.get('Form Power') as double?)?.round()
..legSpringStiffness = dataMessage.get('Leg Spring Stiffness') as double?;
}
Event.fromLap({
@required DataMessage dataMessage,
@required this.activity,
@required int lapsId,
required DataMessage dataMessage,
required Activity this.activity,
required int? lapsId,
}) {
_db = DbEvent()
..activitiesId = activity.id
..activitiesId = activity!.id
..lapsId = lapsId
..positionLat = dataMessage.get('end_position_lat') as double
..positionLong = dataMessage.get('end_position_long') as double
..positionLat = dataMessage.get('end_position_lat') as double?
..positionLong = dataMessage.get('end_position_long') as double?
..timeStamp = dateTimeFromStrava(dataMessage.get('timestamp') as double)
..event = dataMessage.get('event')?.toString()
..eventType = dataMessage.get('event_type') as String
..eventGroup = (dataMessage.get('event_group') as double)?.round()
..speed = dataMessage.get('avg_speed') as double
..eventType = dataMessage.get('event_type') as String?
..eventGroup = (dataMessage.get('event_group') as double?)?.round()
..speed = dataMessage.get('avg_speed') as double?
..verticalOscillation =
dataMessage.get('avg_vertical_oscillation') as double
..fractionalCadence = dataMessage.get('avg_fractional_cadence') as double
..heartRate = (dataMessage.get('avg_heart_rate') as double)?.round()
..cadence = dataMessage.get('avg_running_cadence') as double
..timerTrigger = dataMessage.get('lap_trigger') as String
..distance = dataMessage.get('total_distance') as double;
dataMessage.get('avg_vertical_oscillation') as double?
..fractionalCadence = dataMessage.get('avg_fractional_cadence') as double?
..heartRate = (dataMessage.get('avg_heart_rate') as double?)?.round()
..cadence = dataMessage.get('avg_running_cadence') as double?
..timerTrigger = dataMessage.get('lap_trigger') as String?
..distance = dataMessage.get('total_distance') as double?;
}
DbEvent _db;
Activity activity;
Lap lap;
int index;
DbEvent? _db;
Activity? activity;
Lap? lap;
int? index;
int get id => _db?.id;
DateTime get timeStamp => _db.timeStamp;
String get event => _db.event;
String get eventType => _db.eventType;
String get timerTrigger => _db.timerTrigger;
double get altitude => _db.altitude;
double get cadence => _db.cadence;
double get data => _db.data;
double get distance => _db.distance;
double get fractionalCadence => _db.fractionalCadence;
double get groundTime => _db.groundTime;
double get legSpringStiffness => _db.legSpringStiffness;
double get positionLat => _db.positionLat;
double get positionLong => _db.positionLong;
double get speed => _db.speed;
double get strydCadence => _db.strydCadence;
double get verticalOscillation => _db.verticalOscillation;
int get eventGroup => _db.eventGroup;
int get formPower => _db.formPower;
int get heartRate => _db.heartRate;
int get power => _db.power;
int? get id => _db?.id;
DateTime? get timeStamp => _db!.timeStamp;
String? get event => _db!.event;
String? get eventType => _db!.eventType;
String? get timerTrigger => _db!.timerTrigger;
double? get altitude => _db!.altitude;
double? get cadence => _db!.cadence;
double? get data => _db!.data;
double? get distance => _db!.distance;
double? get fractionalCadence => _db!.fractionalCadence;
double? get groundTime => _db!.groundTime;
double? get legSpringStiffness => _db!.legSpringStiffness;
double? get positionLat => _db!.positionLat;
double? get positionLong => _db!.positionLong;
double? get speed => _db!.speed;
double? get strydCadence => _db!.strydCadence;
double? get verticalOscillation => _db!.verticalOscillation;
int? get eventGroup => _db!.eventGroup;
int? get formPower => _db!.formPower;
int? get heartRate => _db!.heartRate;
int? get power => _db!.power;
set event(String value) => _db.event = value;
set eventType(String value) => _db.eventType = value;
set eventGroup(int value) => _db.eventGroup = value;
set timerTrigger(String value) => _db.timerTrigger = value;
set timeStamp(DateTime value) => _db.timeStamp = value;
set positionLat(double value) => _db.positionLat = value;
set positionLong(double value) => _db.positionLong = value;
set distance(double value) => _db.distance = value;
set altitude(double value) => _db.altitude = value;
set speed(double value) => _db.speed = value;
set heartRate(int value) => _db.heartRate = value;
set cadence(double value) => _db.cadence = value;
set fractionalCadence(double value) => _db.fractionalCadence = value;
set power(int value) => _db.power = value;
set strydCadence(double value) => _db.strydCadence = value;
set groundTime(double value) => _db.groundTime = value;
set verticalOscillation(double value) => _db.verticalOscillation = value;
set formPower(int value) => _db.formPower = value;
set legSpringStiffness(double value) => _db.legSpringStiffness = value;
set data(double value) => _db.data = value;
set event(String? value) => _db!.event = value;
set eventType(String? value) => _db!.eventType = value;
set eventGroup(int? value) => _db!.eventGroup = value;
set timerTrigger(String? value) => _db!.timerTrigger = value;
set timeStamp(DateTime? value) => _db!.timeStamp = value;
set positionLat(double? value) => _db!.positionLat = value;
set positionLong(double? value) => _db!.positionLong = value;
set distance(double? value) => _db!.distance = value;
set altitude(double? value) => _db!.altitude = value;
set speed(double? value) => _db!.speed = value;
set heartRate(int? value) => _db!.heartRate = value;
set cadence(double? value) => _db!.cadence = value;
set fractionalCadence(double? value) => _db!.fractionalCadence = value;
set power(int? value) => _db!.power = value;
set strydCadence(double? value) => _db!.strydCadence = value;
set groundTime(double? value) => _db!.groundTime = value;
set verticalOscillation(double? value) => _db!.verticalOscillation = value;
set formPower(int? value) => _db!.formPower = value;
set legSpringStiffness(double? value) => _db!.legSpringStiffness = value;
set data(double? value) => _db!.data = value;
@override
String toString() => '< Event | $event | $index >';
@ -177,7 +177,7 @@ class Event {
}
static Future<BoolCommitResult> upsertAll(List<Event> events) async {
final List<DbEvent> dbEvents = events
final List<DbEvent?> dbEvents = events
.where((Event event) => event._db != null)
.map((Event event) => event._db)
.toList();
@ -185,5 +185,5 @@ class Event {
}
static Event exDb(DbEvent dbEvent) => Event._fromDb(dbEvent);
Future<int> save() async => await _db.save();
Future<int?> save() async => await _db!.save();
}

View File

@ -1,5 +1,7 @@
import 'dart:math';
import 'package:flutter/foundation.dart';
import '/models/activity.dart';
import '/models/activity_list.dart';
import '/models/event.dart';
@ -8,7 +10,7 @@ import '/models/tag_group.dart';
import 'athlete.dart';
Future<List<Activity>> deriveBacklog({
Athlete athlete,
required Athlete athlete,
}) async {
final List<Activity> unfilteredActivities = await athlete.activities;
final TagGroup autoEffortTagGroup =
@ -22,20 +24,20 @@ Future<List<Activity>> deriveBacklog({
return backlog;
}
Future<void> catchUp({List<Activity> backlog}) async {
Future<void> catchUp({required List<Activity> backlog}) async {
for (final Activity activity in backlog) {
print('calculating ftp for ${activity.name} ...');
debugPrint('calculating ftp for ${activity.name} ...');
final List<Event> records = await activity.records;
final List<Event> powerRecords = records
.where((Event value) => value.power != null && value.power > 100)
.where((Event value) => value.power != null && value.power! > 100)
.toList();
activity.ftp = calculate(records: powerRecords);
activity.save();
print('ftp calculated');
debugPrint('ftp calculated');
}
}
double calculate({List<Event> records}) {
double calculate({required List<Event> records}) {
final PowerDuration powerDuration = PowerDuration(records: records);
final PowerDuration ftpCurve = powerDuration.normalize();
final double ftp = ftpCurve.powerMap.values.toList().reduce(max);

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart' show DbHeartRateZone;
@ -6,13 +5,13 @@ import '/models/heart_rate_zone_schema.dart';
class HeartRateZone {
HeartRateZone(
{@required HeartRateZoneSchema heartRateZoneSchema,
String name,
int lowerPercentage,
int upperPercentage,
int lowerLimit,
int upperLimit,
int color}) {
{required HeartRateZoneSchema heartRateZoneSchema,
String? name,
int? lowerPercentage,
int? upperPercentage,
int? lowerLimit,
int? upperLimit,
int? color}) {
_db = DbHeartRateZone()
..heartRateZoneSchemataId = heartRateZoneSchema.id
..name = name ?? 'My Zone'
@ -22,39 +21,41 @@ class HeartRateZone {
..upperPercentage = upperPercentage ?? 0
..color = color ?? 0xFFFFc107;
if (lowerPercentage != null)
_db.lowerLimit =
(lowerPercentage * heartRateZoneSchema.base / 100).round();
if (upperPercentage != null)
_db.upperLimit =
(upperPercentage * heartRateZoneSchema.base / 100).round();
if (lowerPercentage != null) {
_db!.lowerLimit =
(lowerPercentage * heartRateZoneSchema.base! / 100).round();
}
if (upperPercentage != null) {
_db!.upperLimit =
(upperPercentage * heartRateZoneSchema.base! / 100).round();
}
}
HeartRateZone._fromDb(this._db);
DbHeartRateZone _db;
DbHeartRateZone? _db;
int get id => _db?.id;
String get name => _db.name;
int get color => _db.color;
int get lowerLimit => _db.lowerLimit;
int get lowerPercentage => _db.lowerPercentage;
int get upperLimit => _db.upperLimit;
int get upperPercentage => _db.upperPercentage;
int? get id => _db?.id;
String? get name => _db!.name;
int? get color => _db!.color;
int? get lowerLimit => _db!.lowerLimit;
int? get lowerPercentage => _db!.lowerPercentage;
int? get upperLimit => _db!.upperLimit;
int? get upperPercentage => _db!.upperPercentage;
set id(int value) => _db.id = value;
set color(int value) => _db.color = value;
set heartRateZoneSchemataId(int value) => _db.heartRateZoneSchemataId = value;
set lowerLimit(int value) => _db.lowerLimit = value;
set lowerPercentage(int value) => _db.lowerPercentage = value;
set name(String value) => _db.name = value;
set upperLimit(int value) => _db.upperLimit = value;
set upperPercentage(int value) => _db.upperPercentage = value;
set id(int? value) => _db!.id = value;
set color(int? value) => _db!.color = value;
set heartRateZoneSchemataId(int? value) => _db!.heartRateZoneSchemataId = value;
set lowerLimit(int? value) => _db!.lowerLimit = value;
set lowerPercentage(int? value) => _db!.lowerPercentage = value;
set name(String? value) => _db!.name = value;
set upperLimit(int? value) => _db!.upperLimit = value;
set upperPercentage(int? value) => _db!.upperPercentage = value;
@override
String toString() => '< HeartRateZone | $name | $lowerLimit >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<BoolCommitResult> upsertAll(
List<HeartRateZone> heartRateZones) async {
@ -63,5 +64,5 @@ class HeartRateZone {
.toList());
}
static HeartRateZone exDb(DbHeartRateZone db) => HeartRateZone._fromDb(db);
static HeartRateZone exDb(DbHeartRateZone? db) => HeartRateZone._fromDb(db);
}

View File

@ -6,7 +6,7 @@ import '/models/athlete.dart';
import '/models/heart_rate_zone.dart';
class HeartRateZoneSchema {
HeartRateZoneSchema({@required Athlete athlete}) {
HeartRateZoneSchema({required Athlete athlete}) {
_db = DbHeartRateZoneSchema()
..athletesId = athlete.id
..base = 180
@ -15,7 +15,7 @@ class HeartRateZoneSchema {
}
HeartRateZoneSchema._fromDb(this._db);
HeartRateZoneSchema.likeGarmin({Athlete athlete}) {
HeartRateZoneSchema.likeGarmin({required Athlete athlete}) {
_db = DbHeartRateZoneSchema()
..athletesId = athlete.id
..name = 'max HR based'
@ -23,7 +23,7 @@ class HeartRateZoneSchema {
..base = 180;
}
HeartRateZoneSchema.likeStefanDillinger({Athlete athlete}) {
HeartRateZoneSchema.likeStefanDillinger({required Athlete athlete}) {
_db = DbHeartRateZoneSchema()
..athletesId = athlete.id
..name = 'threshold heart rate based'
@ -31,21 +31,21 @@ class HeartRateZoneSchema {
..base = 165;
}
DbHeartRateZoneSchema _db;
DbHeartRateZoneSchema? _db;
int get id => _db?.id;
DateTime get date => _db.date;
String get name => _db.name;
int get base => _db.base;
int? get id => _db?.id;
DateTime? get date => _db!.date;
String? get name => _db!.name;
int? get base => _db!.base;
set id(int value) => _db.id = value;
set base(int value) => _db.base = value;
set date(DateTime value) => _db.date = value;
set name(String value) => _db.name = value;
set id(int? value) => _db!.id = value;
set base(int? value) => _db!.base = value;
set date(DateTime? value) => _db!.date = value;
set name(String? value) => _db!.name = value;
Future<List<HeartRateZone>> get heartRateZones async {
final List<DbHeartRateZone> dbHeartRateZoneList =
await _db.getDbHeartRateZones().orderBy('lowerLimit').toList();
await _db!.getDbHeartRateZones()!.orderBy('lowerLimit').toList();
final List<HeartRateZone> heartRateZones =
dbHeartRateZoneList.map(HeartRateZone.exDb).toList();
return heartRateZones;
@ -130,12 +130,12 @@ class HeartRateZoneSchema {
@override
String toString() => '< HeartRateZoneSchema | $name | $date >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<HeartRateZoneSchema> getBy({
int athletesId,
DateTime date,
static Future<HeartRateZoneSchema?> getBy({
int? athletesId,
DateTime? date,
}) async {
List<DbHeartRateZoneSchema> dbHeartRateZoneSchemas;
dbHeartRateZoneSchemas = await DbHeartRateZoneSchema()
@ -148,9 +148,9 @@ class HeartRateZoneSchema {
.orderByDesc('date')
.top(1)
.toList();
if (dbHeartRateZoneSchemas.isNotEmpty)
if (dbHeartRateZoneSchemas.isNotEmpty) {
return HeartRateZoneSchema._fromDb(dbHeartRateZoneSchemas.first);
else
} else {
dbHeartRateZoneSchemas = await DbHeartRateZoneSchema()
.select()
.athletesId
@ -158,6 +158,7 @@ class HeartRateZoneSchema {
.orderBy('date')
.top(1)
.toList();
}
return (dbHeartRateZoneSchemas.isNotEmpty)
? HeartRateZoneSchema._fromDb(dbHeartRateZoneSchemas.first)
: null;

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '../model/model.dart'
@ -23,85 +22,85 @@ class Interval {
Interval._fromDb(this._db);
DbInterval _db;
Activity activity;
DbInterval? _db;
Activity? activity;
List<Event> _records = <Event>[];
List<Tag> cachedTags = <Tag>[];
double firstDistance = 0;
double lastDistance = 0;
int index;
double weight;
PowerZoneSchema _powerZoneSchema;
PowerZone _powerZone;
HeartRateZone _heartRateZone;
HeartRateZoneSchema _heartRateZoneSchema;
double? firstDistance = 0;
double? lastDistance = 0;
int? index;
double? weight;
PowerZoneSchema? _powerZoneSchema;
PowerZone? _powerZone;
HeartRateZone? _heartRateZone;
HeartRateZoneSchema? _heartRateZoneSchema;
int get id => _db?.id;
DateTime get timeStamp => _db.timeStamp;
int? get id => _db?.id;
DateTime? get timeStamp => _db!.timeStamp;
double get avgCadence => _db.avgCadence;
double get avgFormPower => _db.avgFormPower;
double get avgGroundTime => _db.avgGroundTime;
double get avgLegSpringStiffness => _db.avgLegSpringStiffness;
double get avgPower => _db.avgPower;
double get avgSpeed => _db.avgSpeed;
double get avgSpeedByMeasurements => _db.avgSpeedByMeasurements;
double get avgSpeedByDistance => _db.avgSpeedByDistance;
double get avgSpeedBySpeed => _db.avgSpeedBySpeed;
double get avgStrydCadence => _db.avgStrydCadence;
double get avgVerticalOscillation => _db.avgVerticalOscillation;
double get cp => _db.cp;
double get ftp => _db.ftp;
double get maxCadence => _db.maxCadence;
double get maxGroundTime => _db.maxGroundTime;
double get maxLegSpringStiffness => _db.maxLegSpringStiffness;
double get maxSpeed => _db.maxSpeed;
double get maxStrydCadence => _db.maxStrydCadence;
double get maxVerticalOscillation => _db.maxVerticalOscillation;
double get minCadence => _db.minCadence;
double get minGroundTime => _db.minGroundTime;
double get minLegSpringStiffness => _db.minLegSpringStiffness;
double get minSpeed => _db.minSpeed;
double get minStrydCadence => _db.minStrydCadence;
double get minVerticalOscillation => _db.minVerticalOscillation;
double get sdevCadence => _db.sdevCadence;
double get sdevFormPower => _db.sdevFormPower;
double get sdevGroundTime => _db.sdevGroundTime;
double get sdevHeartRate => _db.sdevHeartRate;
double get sdevLegSpringStiffness => _db.sdevLegSpringStiffness;
double get sdevPace => _db.sdevPace;
double get sdevPower => _db.sdevPower;
double get sdevSpeed => _db.sdevSpeed;
double get sdevStrydCadence => _db.sdevStrydCadence;
double get sdevVerticalOscillation => _db.sdevVerticalOscillation;
int get activitiesId => _db.activitiesId;
int get athletesId => _db.athletesId;
int get firstRecordId => _db.firstRecordId;
int get lastRecordId => _db.lastRecordId;
int get avgHeartRate => _db.avgHeartRate;
int get distance => _db.distance;
Duration get duration => Duration(seconds: _db.duration ?? 0);
int get maxFormPower => _db.maxFormPower;
int get maxHeartRate => _db.maxHeartRate;
int get maxPower => _db.maxPower;
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;
double? get avgCadence => _db!.avgCadence;
double? get avgFormPower => _db!.avgFormPower;
double? get avgGroundTime => _db!.avgGroundTime;
double? get avgLegSpringStiffness => _db!.avgLegSpringStiffness;
double? get avgPower => _db!.avgPower;
double? get avgSpeed => _db!.avgSpeed;
double? get avgSpeedByMeasurements => _db!.avgSpeedByMeasurements;
double? get avgSpeedByDistance => _db!.avgSpeedByDistance;
double? get avgSpeedBySpeed => _db!.avgSpeedBySpeed;
double? get avgStrydCadence => _db!.avgStrydCadence;
double? get avgVerticalOscillation => _db!.avgVerticalOscillation;
double? get cp => _db!.cp;
double? get ftp => _db!.ftp;
double? get maxCadence => _db!.maxCadence;
double? get maxGroundTime => _db!.maxGroundTime;
double? get maxLegSpringStiffness => _db!.maxLegSpringStiffness;
double? get maxSpeed => _db!.maxSpeed;
double? get maxStrydCadence => _db!.maxStrydCadence;
double? get maxVerticalOscillation => _db!.maxVerticalOscillation;
double? get minCadence => _db!.minCadence;
double? get minGroundTime => _db!.minGroundTime;
double? get minLegSpringStiffness => _db!.minLegSpringStiffness;
double? get minSpeed => _db!.minSpeed;
double? get minStrydCadence => _db!.minStrydCadence;
double? get minVerticalOscillation => _db!.minVerticalOscillation;
double? get sdevCadence => _db!.sdevCadence;
double? get sdevFormPower => _db!.sdevFormPower;
double? get sdevGroundTime => _db!.sdevGroundTime;
double? get sdevHeartRate => _db!.sdevHeartRate;
double? get sdevLegSpringStiffness => _db!.sdevLegSpringStiffness;
double? get sdevPace => _db!.sdevPace;
double? get sdevPower => _db!.sdevPower;
double? get sdevSpeed => _db!.sdevSpeed;
double? get sdevStrydCadence => _db!.sdevStrydCadence;
double? get sdevVerticalOscillation => _db!.sdevVerticalOscillation;
int? get activitiesId => _db!.activitiesId;
int? get athletesId => _db!.athletesId;
int? get firstRecordId => _db!.firstRecordId;
int? get lastRecordId => _db!.lastRecordId;
int? get avgHeartRate => _db!.avgHeartRate;
int? get distance => _db!.distance;
Duration get duration => Duration(seconds: _db!.duration ?? 0);
int? get maxFormPower => _db!.maxFormPower;
int? get maxHeartRate => _db!.maxHeartRate;
int? get maxPower => _db!.maxPower;
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;
set timeStamp(DateTime value) => _db.timeStamp = value;
set firstRecordId(int value) => _db.firstRecordId = value;
set lastRecordId(int value) => _db.lastRecordId = value;
set athletesId(int value) => _db.athletesId = value;
set activitiesId(int value) => _db.activitiesId = value;
set distance(int value) => _db.distance = value;
set duration(Duration value) => _db.duration = value.inSeconds;
set ftp(double value) => _db.ftp = value;
set timeStamp(DateTime? value) => _db!.timeStamp = value;
set firstRecordId(int? value) => _db!.firstRecordId = value;
set lastRecordId(int? value) => _db!.lastRecordId = value;
set athletesId(int? value) => _db!.athletesId = value;
set activitiesId(int? value) => _db!.activitiesId = value;
set distance(int? value) => _db!.distance = value;
set duration(Duration value) => _db!.duration = value.inSeconds;
set ftp(double? value) => _db!.ftp = value;
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
Future<void> setValues() async {
final RecordList<Event> recordList = RecordList<Event>(await records);
@ -166,79 +165,85 @@ class Interval {
}
// calculated from other attributes:
double get ecor {
double? get ecor {
if (avgPower != null &&
avgSpeed != null &&
avgSpeed > 0 &&
avgSpeed! > 0 &&
weight != null &&
weight > 0)
return avgPower / avgSpeed / weight;
else
weight! > 0) {
return avgPower! / avgSpeed! / weight!;
} else {
return null;
}
}
double get avgPace {
if (avgSpeedByDistance != null && avgSpeedByDistance != 0)
return 50 / 3 / avgSpeedByDistance;
else
double? get avgPace {
if (avgSpeedByDistance != null && avgSpeedByDistance != 0) {
return 50 / 3 / avgSpeedByDistance!;
} else {
return null;
}
}
double get avgSpeedPerHeartRate {
if (avgSpeed != null && avgHeartRate != null && avgHeartRate != 0)
return 100 * (avgSpeed / avgHeartRate);
else
double? get avgSpeedPerHeartRate {
if (avgSpeed != null && avgHeartRate != null && avgHeartRate != 0) {
return 100 * (avgSpeed! / avgHeartRate!);
} else {
return null;
}
}
double get avgPowerPerHeartRate {
double? get avgPowerPerHeartRate {
if (avgPower != null &&
avgPower != -1 &&
avgHeartRate != null &&
avgHeartRate != null)
return avgPower / avgHeartRate;
else
avgHeartRate != null) {
return avgPower! / avgHeartRate!;
} else {
return null;
}
}
int get elevationDifference {
if (totalAscent != null && totalDescent != null)
return totalAscent - totalDescent;
else
int? get elevationDifference {
if (totalAscent != null && totalDescent != null) {
return totalAscent! - totalDescent!;
} else {
return null;
}
}
double get avgDoubleStrydCadence {
if (avgStrydCadence != null)
return avgStrydCadence * 2;
else
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 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(avgSpeedByDistance);
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 cadenceAvailable => !<num?>[null, -1].contains(avgStrydCadence);
bool get speedAvailable => !<num?>[null, 0, -1].contains(avgSpeedByDistance);
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);
!<num?>[null, -1].contains(avgVerticalOscillation);
bool get strideCadenceAvailable =>
!<num>[null, -1].contains(avgDoubleStrydCadence);
!<num?>[null, -1].contains(avgDoubleStrydCadence);
bool get legSpringStiffnessAvailable =>
!<num>[null, -1].contains(avgLegSpringStiffness);
!<num?>[null, -1].contains(avgLegSpringStiffness);
Future<PowerZone> get powerZone async {
Future<PowerZone?> get powerZone async {
if (_powerZone == null) {
final DbPowerZone dbPowerZone = await DbPowerZone()
final DbPowerZone? dbPowerZone = await DbPowerZone()
.select()
.powerZoneSchemataId
.equals((await powerZoneSchema).id)
.equals((await powerZoneSchema)!.id)
.and
.lowerLimit
.lessThanOrEquals(avgPower)
@ -251,12 +256,12 @@ class Interval {
return _powerZone;
}
Future<HeartRateZone> get heartRateZone async {
Future<HeartRateZone?> get heartRateZone async {
if (_heartRateZone == null) {
final DbHeartRateZone dbHeartRateZone = await DbHeartRateZone()
final DbHeartRateZone? dbHeartRateZone = await DbHeartRateZone()
.select()
.heartRateZoneSchemataId
.equals((await heartRateZoneSchema).id)
.equals((await heartRateZoneSchema)!.id)
.and
.lowerLimit
.lessThanOrEquals(avgHeartRate)
@ -270,9 +275,9 @@ class Interval {
return _heartRateZone;
}
Future<HeartRateZoneSchema> get heartRateZoneSchema async {
Future<HeartRateZoneSchema?> get heartRateZoneSchema async {
if (_heartRateZoneSchema == null) {
final DbActivity dbActivity = await DbActivity().getById(activitiesId);
final DbActivity dbActivity = await (DbActivity().getById(activitiesId) as Future<DbActivity>);
_heartRateZoneSchema = await HeartRateZoneSchema.getBy(
athletesId: dbActivity.athletesId,
@ -282,9 +287,9 @@ class Interval {
return _heartRateZoneSchema;
}
Future<PowerZoneSchema> get powerZoneSchema async {
Future<PowerZoneSchema?> get powerZoneSchema async {
if (_powerZoneSchema == null) {
final DbActivity dbActivity = await DbActivity().getById(activitiesId);
final DbActivity dbActivity = await (DbActivity().getById(activitiesId) as Future<DbActivity>);
_powerZoneSchema = await PowerZoneSchema.getBy(
athletesId: dbActivity.athletesId,
@ -294,11 +299,11 @@ class Interval {
return _powerZoneSchema;
}
Future<void> autoTagger({@required Athlete athlete}) async {
final PowerZone powerZone = await this.powerZone;
Future<void> autoTagger({required Athlete? athlete}) async {
final PowerZone powerZone = await (this.powerZone as Future<PowerZone>);
if (powerZone.id != null) {
final Tag powerTag = await Tag.autoPowerTag(
athlete: athlete,
athlete: athlete!,
sortOrder: powerZone.lowerLimit,
color: powerZone.color,
name: powerZone.name,
@ -310,10 +315,10 @@ class Interval {
);
}
final HeartRateZone heartRateZone = await this.heartRateZone;
final HeartRateZone heartRateZone = await (this.heartRateZone as Future<HeartRateZone>);
if (heartRateZone.id != null) {
final Tag heartRateTag = await Tag.autoHeartRateTag(
athlete: athlete,
athlete: athlete!,
sortOrder: heartRateZone.lowerLimit,
color: heartRateZone.color,
name: heartRateZone.name,
@ -326,15 +331,15 @@ class Interval {
}
}
Future<void> calculateAndSave({RecordList<Event> records}) async {
distance = (records.last.distance - records.first.distance).round();
duration = records.last.timeStamp.difference(records.first.timeStamp);
Future<void> calculateAndSave({required RecordList<Event> records}) async {
distance = (records.last.distance! - records.first.distance!).round();
duration = records.last.timeStamp!.difference(records.first.timeStamp!);
ftp = ftp_lib.calculate(records: records);
timeStamp = records.first.timeStamp;
await setValues();
}
Future<void> copyTaggings({Lap lap}) async {
Future<void> copyTaggings({required Lap lap}) async {
final List<Tag> tags = await Tag.allByLap(lap: lap);
for (final Tag tag in tags) {
await IntervalTagging(tag: tag, interval: this).save();

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart' show DbIntervalTagging;
@ -7,9 +6,9 @@ import '/models/tag.dart';
class IntervalTagging {
IntervalTagging({
@required encrateia.Interval interval,
@required Tag tag,
bool system,
required encrateia.Interval interval,
required Tag tag,
bool? system,
}) {
_db = DbIntervalTagging()
..intervalsId = interval.id
@ -19,25 +18,25 @@ class IntervalTagging {
IntervalTagging._fromDb(this._db);
DbIntervalTagging _db;
DbIntervalTagging? _db;
int get id => _db?.id;
int get intervalsId => _db.intervalsId;
int get tagsId => _db.tagsId;
int? get id => _db?.id;
int? get intervalsId => _db!.intervalsId;
int? get tagsId => _db!.tagsId;
@override
String toString() =>
'< IntervalTagging | intervalId $intervalsId | tagId $tagsId >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<IntervalTagging> createBy({
@required encrateia.Interval interval,
@required Tag tag,
bool system,
required encrateia.Interval interval,
required Tag tag,
bool? system,
}) async {
final DbIntervalTagging dbIntervalTagging = await DbIntervalTagging()
final DbIntervalTagging? dbIntervalTagging = await DbIntervalTagging()
.select()
.intervalsId
.equals(interval.id)
@ -46,9 +45,9 @@ class IntervalTagging {
.equals(tag.id)
.toSingle();
if (dbIntervalTagging != null)
if (dbIntervalTagging != null) {
return IntervalTagging._fromDb(dbIntervalTagging);
else {
} else {
final IntervalTagging intervalTagging = IntervalTagging(
interval: interval,
tag: tag,
@ -59,11 +58,11 @@ class IntervalTagging {
}
}
static Future<IntervalTagging> getBy({
@required encrateia.Interval interval,
@required Tag tag,
static Future<IntervalTagging?> getBy({
required encrateia.Interval interval,
required Tag tag,
}) async {
final DbIntervalTagging dbIntervalTagging = await DbIntervalTagging()
final DbIntervalTagging? dbIntervalTagging = await DbIntervalTagging()
.select()
.intervalsId
.equals(interval.id)
@ -77,17 +76,17 @@ class IntervalTagging {
}
static Future<void> deleteBy({
@required encrateia.Interval interval,
@required Tag tag,
required encrateia.Interval interval,
required Tag tag,
}) async {
final DbIntervalTagging dbIntervalTagging = await DbIntervalTagging()
final DbIntervalTagging dbIntervalTagging = await (DbIntervalTagging()
.select()
.intervalsId
.equals(interval.id)
.and
.tagsId
.equals(tag.id)
.toSingle();
.toSingle() as Future<DbIntervalTagging>);
await dbIntervalTagging.delete();
}

View File

@ -1,5 +1,4 @@
import 'package:fit_parser/fit_parser.dart';
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart'
@ -24,216 +23,222 @@ class Lap {
Lap._fromDb(this._db);
Activity activity;
bool copied;
DbLap _db;
HeartRateZone _heartRateZone;
HeartRateZoneSchema _heartRateZoneSchema;
List<BarZone> heartRateDistributions;
List<BarZone> powerDistributions;
List<Event> _records;
PowerZone _powerZone;
PowerZoneSchema _powerZoneSchema;
double weight;
int index;
Activity? activity;
bool? copied;
DbLap? _db = DbLap();
HeartRateZone? _heartRateZone;
HeartRateZoneSchema? _heartRateZoneSchema;
late List<BarZone> heartRateDistributions;
late List<BarZone> powerDistributions;
List<Event>? _records;
PowerZone? _powerZone;
PowerZoneSchema? _powerZoneSchema;
double? weight;
int? index;
int get id => _db?.id;
DateTime get startTime => _db.startTime;
DateTime get timeStamp => _db.timeStamp;
String get event => _db.event;
String get eventType => _db.eventType;
String get lapTrigger => _db.lapTrigger;
String get sport => _db.sport;
String get subSport => _db.subSport;
double get avgFormPower => _db.avgFormPower;
double get avgFractionalCadence => _db.avgFractionalCadence;
double get avgGroundTime => _db.avgGroundTime;
double get avgLegSpringStiffness => _db.avgLegSpringStiffness;
double get avgPower => _db.avgPower;
double get avgRunningCadence => _db.avgRunningCadence;
double get avgSpeed => _db.avgSpeed;
double get avgSpeedByMeasurements => _db.avgSpeedByMeasurements;
double get avgSpeedBySpeed => _db.avgSpeedBySpeed;
double get avgSpeedByDistance => _db.avgSpeedByDistance;
double get avgStanceTime => _db.avgStanceTime;
double get avgStanceTimePercent => _db.avgStanceTimePercent;
double get avgStrydCadence => _db.avgStrydCadence;
double get avgVerticalOscillation => _db.avgVerticalOscillation;
double get cp => _db.cp;
double get ftp => _db.ftp;
double get endPositionLat => _db.endPositionLat;
double get endPositionLong => _db.endPositionLong;
double get maxFractionalCadence => _db.maxFractionalCadence;
double get maxSpeed => _db.maxSpeed;
double get minSpeed => _db.minSpeed;
double get sdevFormPower => _db.sdevFormPower;
double get sdevGroundTime => _db.sdevGroundTime;
double get sdevHeartRate => _db.sdevHeartRate;
double get sdevLegSpringStiffness => _db.sdevLegSpringStiffness;
double get sdevPace => _db.sdevPace;
double get sdevPower => _db.sdevPower;
double get sdevSpeed => _db.sdevSpeed;
double get sdevStrydCadence => _db.sdevStrydCadence;
double get sdevVerticalOscillation => _db.sdevVerticalOscillation;
double get startPositionLat => _db.startPositionLat;
double get startPositionLong => _db.startPositionLong;
double get totalFractionalCycles => _db.totalFractionalCycles;
int get activitiesId => _db.activitiesId;
int get avgHeartRate => _db.avgHeartRate;
int get avgTemperature => _db.avgTemperature;
int get eventGroup => _db.eventGroup;
int get intensity => _db.intensity;
int get maxHeartRate => _db.maxHeartRate;
int get maxPower => _db.maxPower;
int get maxRunningCadence => _db.maxRunningCadence;
int get maxTemperature => _db.maxTemperature;
int get minHeartRate => _db.minHeartRate;
int get minPower => _db.minPower;
int get movingTime => _db.movingTime;
int get totalAscent => _db.totalAscent;
int get totalCalories => _db.totalCalories;
int get totalDescent => _db.totalDescent;
int get totalDistance => _db.totalDistance;
int get totalElapsedTime => _db.totalElapsedTime;
int get totalStrides => _db.totalStrides;
int get totalTimerTime => _db.totalTimerTime;
int? get id => _db!.id;
DateTime? get startTime => _db!.startTime;
DateTime? get timeStamp => _db!.timeStamp;
String? get event => _db!.event;
String? get eventType => _db!.eventType;
String? get lapTrigger => _db!.lapTrigger;
String? get sport => _db!.sport;
String? get subSport => _db!.subSport;
double? get avgFormPower => _db!.avgFormPower;
double? get avgFractionalCadence => _db!.avgFractionalCadence;
double? get avgGroundTime => _db!.avgGroundTime;
double? get avgLegSpringStiffness => _db!.avgLegSpringStiffness;
double? get avgPower => _db!.avgPower;
double? get avgRunningCadence => _db!.avgRunningCadence;
double? get avgSpeed => _db!.avgSpeed;
double? get avgSpeedByMeasurements => _db!.avgSpeedByMeasurements;
double? get avgSpeedBySpeed => _db!.avgSpeedBySpeed;
double? get avgSpeedByDistance => _db!.avgSpeedByDistance;
double? get avgStanceTime => _db!.avgStanceTime;
double? get avgStanceTimePercent => _db!.avgStanceTimePercent;
double? get avgStrydCadence => _db!.avgStrydCadence;
double? get avgVerticalOscillation => _db!.avgVerticalOscillation;
double? get cp => _db!.cp;
double? get ftp => _db!.ftp;
double? get endPositionLat => _db!.endPositionLat;
double? get endPositionLong => _db!.endPositionLong;
double? get maxFractionalCadence => _db!.maxFractionalCadence;
double? get maxSpeed => _db!.maxSpeed;
double? get minSpeed => _db!.minSpeed;
double? get sdevFormPower => _db!.sdevFormPower;
double? get sdevGroundTime => _db!.sdevGroundTime;
double? get sdevHeartRate => _db!.sdevHeartRate;
double? get sdevLegSpringStiffness => _db!.sdevLegSpringStiffness;
double? get sdevPace => _db!.sdevPace;
double? get sdevPower => _db!.sdevPower;
double? get sdevSpeed => _db!.sdevSpeed;
double? get sdevStrydCadence => _db!.sdevStrydCadence;
double? get sdevVerticalOscillation => _db!.sdevVerticalOscillation;
double? get startPositionLat => _db!.startPositionLat;
double? get startPositionLong => _db!.startPositionLong;
double? get totalFractionalCycles => _db!.totalFractionalCycles;
int? get activitiesId => _db!.activitiesId;
int? get avgHeartRate => _db!.avgHeartRate;
int? get avgTemperature => _db!.avgTemperature;
int? get eventGroup => _db!.eventGroup;
int? get intensity => _db!.intensity;
int? get maxHeartRate => _db!.maxHeartRate;
int? get maxPower => _db!.maxPower;
int? get maxRunningCadence => _db!.maxRunningCadence;
int? get maxTemperature => _db!.maxTemperature;
int? get minHeartRate => _db!.minHeartRate;
int? get minPower => _db!.minPower;
int? get movingTime => _db!.movingTime;
int? get totalAscent => _db!.totalAscent;
int? get totalCalories => _db!.totalCalories;
int? get totalDescent => _db!.totalDescent;
int? get totalDistance => _db!.totalDistance;
int? get totalElapsedTime => _db!.totalElapsedTime;
int? get totalStrides => _db!.totalStrides;
int? get totalTimerTime => _db!.totalTimerTime;
// calculated from other attributes:
double get ecor {
double? get ecor {
if (avgPower != null &&
avgSpeed != null &&
avgSpeed > 0 &&
avgSpeed! > 0 &&
weight != null &&
weight > 0)
return avgPower / avgSpeed / weight;
else
weight! > 0) {
return avgPower! / avgSpeed! / weight!;
} else {
return null;
}
}
double get avgPace {
if (avgSpeed != null && avgSpeed != 0)
return 50 / 3 / avgSpeed;
else
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
double? get avgSpeedPerHeartRate {
if (avgSpeed != null && avgHeartRate != null && avgHeartRate != 0) {
return 100 * (avgSpeed! / avgHeartRate!);
} else {
return null;
}
}
double get avgPowerPerHeartRate {
double? get avgPowerPerHeartRate {
if (avgPower != null &&
avgPower != -1 &&
avgHeartRate != null &&
avgHeartRate != null)
return avgPower / avgHeartRate;
else
avgHeartRate != null) {
return avgPower! / avgHeartRate!;
} else {
return null;
}
}
int get elevationDifference {
if (totalAscent != null && totalDescent != null)
return totalAscent - totalDescent;
else
int? get elevationDifference {
if (totalAscent != null && totalDescent != null) {
return totalAscent! - totalDescent!;
} else {
return null;
}
}
double get avgDoubleStrydCadence {
if (avgStrydCadence != null)
return avgStrydCadence * 2;
else
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 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(avgSpeedByDistance);
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 cadenceAvailable => !<num?>[null, -1].contains(avgStrydCadence);
bool get speedAvailable => !<num?>[null, 0, -1].contains(avgSpeedByDistance);
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);
!<num?>[null, -1].contains(avgVerticalOscillation);
bool get strideCadenceAvailable =>
!<num>[null, -1].contains(avgDoubleStrydCadence);
!<num?>[null, -1].contains(avgDoubleStrydCadence);
bool get legSpringStiffnessAvailable =>
!<num>[null, -1].contains(avgLegSpringStiffness);
!<num?>[null, -1].contains(avgLegSpringStiffness);
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Lap fromLap({
DataMessage dataMessage,
Activity activity,
Lap lap,
required DataMessage dataMessage,
required Activity activity,
required Lap lap,
}) {
lap._db
..activitiesId = activity.id
..avgSpeed = dataMessage.get('avg_speed') == 65.535
? dataMessage.get('enhanced_avg_speed') as double
: dataMessage.get('avg_speed') as double
? dataMessage.get('enhanced_avg_speed') as double?
: dataMessage.get('avg_speed') as double?
..maxSpeed = dataMessage.get('max_speed') == 65.535
? dataMessage.get('enhanced_max_speed') as double
: dataMessage.get('max_speed') as double
? dataMessage.get('enhanced_max_speed') as double?
: dataMessage.get('max_speed') as double?
..timeStamp = dateTimeFromStrava(dataMessage.get('timestamp') as double)
..startTime = dateTimeFromStrava(dataMessage.get('start_time') as double)
..startPositionLat = dataMessage.get('start_position_lat') as double
..startPositionLong = dataMessage.get('start_position_long') as double
..endPositionLat = dataMessage.get('end_position_lat') as double
..endPositionLong = dataMessage.get('end_position_long') as double
..startPositionLat = dataMessage.get('end_position_lat') as double
..avgHeartRate = (dataMessage.get('avg_heart_rate') as double)?.round()
..maxHeartRate = (dataMessage.get('max_heart_rate') as double)?.round()
..avgRunningCadence = dataMessage.get('avg_running_cadence') as double
..event = dataMessage.get('event') as String
..eventType = dataMessage.get('event_type') as String
..eventGroup = (dataMessage.get('event_group') as double)?.round()
..sport = dataMessage.get('sport') as String
..subSport = dataMessage.get('sub_sport') as String
..startPositionLat = dataMessage.get('start_position_lat') as double?
..startPositionLong = dataMessage.get('start_position_long') as double?
..endPositionLat = dataMessage.get('end_position_lat') as double?
..endPositionLong = dataMessage.get('end_position_long') as double?
..startPositionLat = dataMessage.get('end_position_lat') as double?
..avgHeartRate = (dataMessage.get('avg_heart_rate') as double?)?.round()
..maxHeartRate = (dataMessage.get('max_heart_rate') as double?)?.round()
..avgRunningCadence = dataMessage.get('avg_running_cadence') as double?
..event = dataMessage.get('event') as String?
..eventType = dataMessage.get('event_type') as String?
..eventGroup = (dataMessage.get('event_group') as double?)?.round()
..sport = dataMessage.get('sport') as String?
..subSport = dataMessage.get('sub_sport') as String?
..avgVerticalOscillation =
dataMessage.get('avg_vertical_oscillation') as double
dataMessage.get('avg_vertical_oscillation') as double?
..totalElapsedTime =
(dataMessage.get('total_elapsed_time') as double)?.round()
(dataMessage.get('total_elapsed_time') as double?)?.round()
..totalTimerTime =
(dataMessage.get('total_timer_time') as double)?.round()
..totalDistance = (dataMessage.get('total_distance') as double)?.round()
..totalStrides = (dataMessage.get('total_strides') as double)?.round()
..totalCalories = (dataMessage.get('total_calories') as double)?.round()
..totalAscent = (dataMessage.get('total_ascent') as double)?.round()
..totalDescent = (dataMessage.get('total_descent') as double)?.round()
(dataMessage.get('total_timer_time') as double?)?.round()
..totalDistance = (dataMessage.get('total_distance') as double?)?.round()
..totalStrides = (dataMessage.get('total_strides') as double?)?.round()
..totalCalories = (dataMessage.get('total_calories') as double?)?.round()
..totalAscent = (dataMessage.get('total_ascent') as double?)?.round()
..totalDescent = (dataMessage.get('total_descent') as double?)?.round()
..avgStanceTimePercent =
dataMessage.get('avg_stance_time_percent') as double
..avgStanceTime = dataMessage.get('avg_stance_time') as double
dataMessage.get('avg_stance_time_percent') as double?
..avgStanceTime = dataMessage.get('avg_stance_time') as double?
..maxRunningCadence =
(dataMessage.get('max_running_cadence') as double)?.round()
..intensity = dataMessage.get('intensity') as int
..lapTrigger = dataMessage.get('lap_trigger') as String
..avgTemperature = (dataMessage.get('avg_temperature') as double)?.round()
..maxTemperature = (dataMessage.get('max_temperature') as double)?.round()
(dataMessage.get('max_running_cadence') as double?)?.round()
..intensity = dataMessage.get('intensity') as int?
..lapTrigger = dataMessage.get('lap_trigger') as String?
..avgTemperature = (dataMessage.get('avg_temperature') as double?)?.round()
..maxTemperature = (dataMessage.get('max_temperature') as double?)?.round()
..avgFractionalCadence =
dataMessage.get('avg_fractional_cadence') as double
dataMessage.get('avg_fractional_cadence') as double?
..maxFractionalCadence =
dataMessage.get('max_fractional_cadence') as double
dataMessage.get('max_fractional_cadence') as double?
..totalFractionalCycles =
dataMessage.get('total_fractional_cycles') as double;
dataMessage.get('total_fractional_cycles') as double?;
return lap;
}
Future<List<Event>> get records async {
Future<List<Event>?> get records async {
_records ??= await Event.recordsByLap(this);
return _records;
}
Future<PowerZoneSchema> get powerZoneSchema async {
Future<PowerZoneSchema?> get powerZoneSchema async {
if (_powerZoneSchema == null) {
final DbActivity dbActivity = await DbActivity().getById(activitiesId);
final DbActivity dbActivity = await (DbActivity().getById(activitiesId) as Future<DbActivity>);
_powerZoneSchema = await PowerZoneSchema.getBy(
athletesId: dbActivity.athletesId,
@ -243,9 +248,9 @@ class Lap {
return _powerZoneSchema;
}
Future<HeartRateZoneSchema> get heartRateZoneSchema async {
Future<HeartRateZoneSchema?> get heartRateZoneSchema async {
if (_heartRateZoneSchema == null) {
final DbActivity dbActivity = await DbActivity().getById(activitiesId);
final DbActivity dbActivity = await (DbActivity().getById(activitiesId) as Future<DbActivity>);
_heartRateZoneSchema = await HeartRateZoneSchema.getBy(
athletesId: dbActivity.athletesId,
@ -256,7 +261,7 @@ class Lap {
}
Future<void> setAverages() async {
final RecordList<Event> recordList = RecordList<Event>(await records);
final RecordList<Event> recordList = RecordList<Event>(await (records as Future<List<Event>>));
final RecordList<Event> eventList = RecordList<Event>(await events);
_db
..avgPower = recordList.avgPower()
@ -292,12 +297,12 @@ class Lap {
await save();
}
Future<PowerZone> get powerZone async {
Future<PowerZone?> get powerZone async {
if (_powerZone == null) {
final DbPowerZone dbPowerZone = await DbPowerZone()
final DbPowerZone? dbPowerZone = await DbPowerZone()
.select()
.powerZoneSchemataId
.equals((await powerZoneSchema).id)
.equals((await powerZoneSchema)!.id)
.and
.lowerLimit
.lessThanOrEquals(avgPower)
@ -310,12 +315,12 @@ class Lap {
return _powerZone;
}
Future<HeartRateZone> get heartRateZone async {
Future<HeartRateZone?> get heartRateZone async {
if (_heartRateZone == null) {
final DbHeartRateZone dbHeartRateZone = await DbHeartRateZone()
final DbHeartRateZone? dbHeartRateZone = await DbHeartRateZone()
.select()
.heartRateZoneSchemataId
.equals((await heartRateZoneSchema).id)
.equals((await heartRateZoneSchema)!.id)
.and
.lowerLimit
.lessThanOrEquals(avgHeartRate)
@ -329,11 +334,11 @@ class Lap {
return _heartRateZone;
}
Future<void> autoTagger({@required Athlete athlete}) async {
final PowerZone powerZone = await this.powerZone;
Future<void> autoTagger({required Athlete? athlete}) async {
final PowerZone powerZone = await (this.powerZone as Future<PowerZone>);
if (powerZone.id != null) {
final Tag powerTag = await Tag.autoPowerTag(
athlete: athlete,
athlete: athlete!,
sortOrder: powerZone.lowerLimit,
color: powerZone.color,
name: powerZone.name,
@ -345,10 +350,10 @@ class Lap {
);
}
final HeartRateZone heartRateZone = await this.heartRateZone;
final HeartRateZone heartRateZone = await (this.heartRateZone as Future<HeartRateZone>);
if (heartRateZone.id != null) {
final Tag heartRateTag = await Tag.autoHeartRateTag(
athlete: athlete,
athlete: athlete!,
sortOrder: heartRateZone.lowerLimit,
color: heartRateZone.color,
name: heartRateZone.name,
@ -362,8 +367,8 @@ class Lap {
}
Future<List<BarZone>> powerZoneCounts() async {
final PowerZoneSchema powerZoneSchema = await this.powerZoneSchema;
final List<Event> records = await this.records;
final PowerZoneSchema powerZoneSchema = await (this.powerZoneSchema as Future<PowerZoneSchema>);
final List<Event> records = await (this.records as Future<List<Event>>);
final List<Event> powerRecords =
records.where((Event record) => record.power != null).toList();
final List<BarZone> powerZoneCounts = await RecordList<Event>(powerRecords)
@ -373,8 +378,8 @@ class Lap {
Future<List<BarZone>> heartRateZoneCounts() async {
final HeartRateZoneSchema heartRateZoneSchema =
await this.heartRateZoneSchema;
final List<Event> records = await this.records;
await (this.heartRateZoneSchema as Future<HeartRateZoneSchema>);
final List<Event> records = await (this.records as Future<List<Event>>);
final List<Event> heartRateRecords =
records.where((Event record) => record.heartRate != null).toList();
final List<BarZone> heartRateZoneCounts =
@ -384,7 +389,7 @@ class Lap {
}
Future<List<Event>> get events async {
final List<DbEvent> dbEvents = await _db.getDbEvents().toList();
final List<DbEvent> dbEvents = await _db!.getDbEvents()!.toList();
return dbEvents.map(Event.exDb).toList();
}

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart' show DbLapTagging;
@ -7,9 +6,9 @@ import '/models/tag.dart';
class LapTagging {
LapTagging({
@required Lap lap,
@required Tag tag,
bool system,
required Lap lap,
required Tag tag,
bool? system,
}) {
_db = DbLapTagging()
..lapsId = lap.id
@ -19,24 +18,24 @@ class LapTagging {
LapTagging._fromDb(this._db);
DbLapTagging _db;
DbLapTagging? _db;
int get id => _db?.id;
int get lapsId => _db.lapsId;
int get tagsId => _db.tagsId;
int? get id => _db?.id;
int? get lapsId => _db!.lapsId;
int? get tagsId => _db!.tagsId;
@override
String toString() => '< LapTagging | lapId $lapsId | tagId $tagsId >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<LapTagging> createBy({
@required Lap lap,
@required Tag tag,
bool system,
required Lap lap,
required Tag tag,
bool? system,
}) async {
final DbLapTagging dbLapTagging = await DbLapTagging()
final DbLapTagging? dbLapTagging = await DbLapTagging()
.select()
.lapsId
.equals(lap.id)
@ -45,9 +44,9 @@ class LapTagging {
.equals(tag.id)
.toSingle();
if (dbLapTagging != null)
if (dbLapTagging != null) {
return LapTagging._fromDb(dbLapTagging);
else {
} else {
final LapTagging lapTagging = LapTagging(
lap: lap,
tag: tag,
@ -58,11 +57,11 @@ class LapTagging {
}
}
static Future<LapTagging> getBy({
@required Lap lap,
@required Tag tag,
static Future<LapTagging?> getBy({
required Lap lap,
required Tag tag,
}) async {
final DbLapTagging dbLapTagging = await DbLapTagging()
final DbLapTagging? dbLapTagging = await DbLapTagging()
.select()
.lapsId
.equals(lap.id)
@ -74,17 +73,17 @@ class LapTagging {
}
static Future<void> deleteBy({
@required Lap lap,
@required Tag tag,
required Lap lap,
required Tag tag,
}) async {
final DbLapTagging dbLapTagging = await DbLapTagging()
final DbLapTagging dbLapTagging = await (DbLapTagging()
.select()
.lapsId
.equals(lap.id)
.and
.tagsId
.equals(tag.id)
.toSingle();
.toSingle() as Future<DbLapTagging>);
await dbLapTagging.delete();
}

View File

@ -1,6 +1,5 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart';
@ -10,10 +9,10 @@ import '/model/model.dart';
class Log {
Log({
@required String message,
@required String method,
@required String stackTrace,
String comment,
required String message,
required String method,
required String stackTrace,
String? comment,
}) {
_db = DbLog()
..comment = comment
@ -26,14 +25,14 @@ class Log {
}
Log._fromDb(this._db);
DbLog _db;
DbLog? _db;
DateTime get dateTime => _db.dateTime;
String get comment => _db.comment;
String get message => _db.message;
String get method => _db.method;
String get stackTrace => _db.stackTrace;
int get id => _db?.id;
DateTime? get dateTime => _db!.dateTime;
String? get comment => _db!.comment;
String? get message => _db!.message;
String? get method => _db!.method;
String? get stackTrace => _db!.stackTrace;
int? get id => _db?.id;
@override
String toString() => '< Log | $dateTime | $message >';
@ -49,8 +48,8 @@ class Log {
return dbLogList.map(Log.exDb).toList();
}
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<void> deleteAll() async {
final List<Log> logs = await all();

View File

@ -4,20 +4,20 @@ import '/models/event.dart';
import '/models/plot_point.dart';
class MinimumPowerDuration {
MinimumPowerDuration({List<Event> records}) {
MinimumPowerDuration({required List<Event> records}) {
for (int index = 0; index < records.length - 1; index++) {
final int power = records[index].power;
final int power = records[index].power!;
final DateTime nextLower = records
.sublist(index + 1, records.length)
.firstWhere((Event record) => record.power < power,
.firstWhere((Event record) => record.power! < power,
orElse: () => records.last)
.timeStamp;
.timeStamp!;
final DateTime recentLower = records
.sublist(0, index)
.lastWhere((Event record) => record.power < power,
.lastWhere((Event record) => record.power! < power,
orElse: () => records.first)
.timeStamp;
.timeStamp!;
final int persistedFor = nextLower.difference(recentLower).inSeconds;
@ -47,9 +47,9 @@ class MinimumPowerDuration {
});
plotPoints
.sort((IntPlotPoint a, IntPlotPoint b) => a.domain.compareTo(b.domain));
.sort((IntPlotPoint a, IntPlotPoint b) => a.domain!.compareTo(b.domain!));
return plotPoints;
}
static int scaled({int seconds}) => (200 * log(seconds)).round();
static int scaled({required int seconds}) => (200 * log(seconds)).round();
}

View File

@ -1,8 +1,8 @@
class IntPlotPoint {
IntPlotPoint({this.domain, this.measure});
int domain;
int measure;
int? domain;
int? measure;
@override
String toString() => '< IntPlotPoint | $domain | $measure >';
@ -11,8 +11,8 @@ class IntPlotPoint {
class DoublePlotPoint {
DoublePlotPoint({this.domain, this.measure});
int domain;
double measure;
int? domain;
double? measure;
@override
String toString() => '< DoublePlotPoint | $domain | $measure >';
@ -21,8 +21,8 @@ class DoublePlotPoint {
class EnergyPoint {
EnergyPoint({this.energy, this.duration});
int energy;
int duration;
int? energy;
int? duration;
@override
String toString() => '< EnergyPlotPoint | $energy | $duration >';

View File

@ -4,19 +4,19 @@ import '/models/event.dart';
import '/models/plot_point.dart';
class PowerDuration {
PowerDuration({List<Event> records}) {
PowerDuration({required List<Event> records}) {
final Map<int, EnergyPoint> powerSum = <int, EnergyPoint>{};
for (int index = 1; index <= records.length - 1; index++) {
final int power = records[index].power;
final int power = records[index].power!;
final int duration = records[index]
.timeStamp
.difference(records[index - 1].timeStamp)
.timeStamp!
.difference(records[index - 1].timeStamp!)
.inSeconds;
powerSum.forEach((int start, EnergyPoint energyPoint) {
final int newEnergy = energyPoint.energy + power * duration;
final int newDuration = energyPoint.duration + duration;
final int newEnergy = energyPoint.energy! + power * duration;
final int newDuration = energyPoint.duration! + duration;
powerSum[start] = EnergyPoint(
energy: newEnergy,
@ -65,7 +65,7 @@ class PowerDuration {
});
plotPoints.sort(
(DoublePlotPoint a, DoublePlotPoint b) => a.domain.compareTo(b.domain));
(DoublePlotPoint a, DoublePlotPoint b) => a.domain!.compareTo(b.domain!));
return plotPoints;
}
@ -75,5 +75,5 @@ class PowerDuration {
return this;
}
static int scaled({int seconds}) => (200 * log(seconds)).round();
static int scaled({required int seconds}) => (200 * log(seconds)).round();
}

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart' show DbPowerZone;
@ -6,13 +5,13 @@ import '/models/power_zone_schema.dart';
class PowerZone {
PowerZone(
{@required PowerZoneSchema powerZoneSchema,
String name,
int lowerPercentage,
int upperPercentage,
int lowerLimit,
int upperLimit,
int color}) {
{required PowerZoneSchema powerZoneSchema,
String? name,
int? lowerPercentage,
int? upperPercentage,
int? lowerLimit,
int? upperLimit,
int? color}) {
_db = DbPowerZone()
..powerZoneSchemataId = powerZoneSchema.id
..name = name ?? 'My Zone'
@ -22,42 +21,44 @@ class PowerZone {
..upperPercentage = upperPercentage ?? 0
..color = color ?? 0xFFFFc107;
if (lowerPercentage != null)
_db.lowerLimit = (lowerPercentage * powerZoneSchema.base / 100).round();
if (upperPercentage != null)
_db.upperLimit = (upperPercentage * powerZoneSchema.base / 100).round();
if (lowerPercentage != null) {
_db!.lowerLimit = (lowerPercentage * powerZoneSchema.base! / 100).round();
}
if (upperPercentage != null) {
_db!.upperLimit = (upperPercentage * powerZoneSchema.base! / 100).round();
}
}
PowerZone._fromDb(this._db);
DbPowerZone _db;
DbPowerZone? _db;
int get id => _db?.id;
String get name => _db.name;
int get color => _db.color;
int get lowerLimit => _db.lowerLimit;
int get lowerPercentage => _db.lowerPercentage;
int get upperLimit => _db.upperLimit;
int get upperPercentage => _db.upperPercentage;
int? get id => _db?.id;
String? get name => _db!.name;
int? get color => _db!.color;
int? get lowerLimit => _db!.lowerLimit;
int? get lowerPercentage => _db!.lowerPercentage;
int? get upperLimit => _db!.upperLimit;
int? get upperPercentage => _db!.upperPercentage;
set id(int value) => _db.id = value;
set color(int value) => _db.color = value;
set lowerLimit(int value) => _db.lowerLimit = value;
set lowerPercentage(int value) => _db.lowerPercentage = value;
set name(String value) => _db.name = value;
set powerZoneSchemataId(int value) => _db.powerZoneSchemataId = value;
set upperLimit(int value) => _db.upperLimit = value;
set upperPercentage(int value) => _db.upperPercentage = value;
set id(int? value) => _db!.id = value;
set color(int? value) => _db!.color = value;
set lowerLimit(int? value) => _db!.lowerLimit = value;
set lowerPercentage(int? value) => _db!.lowerPercentage = value;
set name(String? value) => _db!.name = value;
set powerZoneSchemataId(int? value) => _db!.powerZoneSchemataId = value;
set upperLimit(int? value) => _db!.upperLimit = value;
set upperPercentage(int? value) => _db!.upperPercentage = value;
@override
String toString() => '< PowerZone | $name | $lowerLimit >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<BoolCommitResult> upsertAll(List<PowerZone> powerZones) async {
return await DbPowerZone().upsertAll(
powerZones.map((PowerZone powerZone) => powerZone._db).toList());
}
static PowerZone exDb(DbPowerZone db) => PowerZone._fromDb(db);
static PowerZone exDb(DbPowerZone? db) => PowerZone._fromDb(db);
}

View File

@ -6,7 +6,7 @@ import '/models/athlete.dart';
import '/models/power_zone.dart';
class PowerZoneSchema {
PowerZoneSchema({@required Athlete athlete}) {
PowerZoneSchema({required Athlete athlete}) {
_db = DbPowerZoneSchema()
..athletesId = athlete.id
..base = 250
@ -15,7 +15,7 @@ class PowerZoneSchema {
}
PowerZoneSchema._fromDb(this._db);
PowerZoneSchema.likeStryd({Athlete athlete}) {
PowerZoneSchema.likeStryd({required Athlete athlete}) {
_db = DbPowerZoneSchema()
..athletesId = athlete.id
..name = 'CP based'
@ -24,7 +24,7 @@ class PowerZoneSchema {
}
// https://www.velopress.com/jim-vances-running-power-zones/
PowerZoneSchema.likeJimVance({Athlete athlete}) {
PowerZoneSchema.likeJimVance({required Athlete athlete}) {
_db = DbPowerZoneSchema()
..athletesId = athlete.id
..name = 'FTP based'
@ -32,7 +32,7 @@ class PowerZoneSchema {
..base = 250;
}
PowerZoneSchema.likeStefanDillinger({Athlete athlete}) {
PowerZoneSchema.likeStefanDillinger({required Athlete athlete}) {
_db = DbPowerZoneSchema()
..athletesId = athlete.id
..name = 'FTP based'
@ -40,24 +40,24 @@ class PowerZoneSchema {
..base = 250;
}
DbPowerZoneSchema _db;
DbPowerZoneSchema? _db;
int get id => _db?.id;
DateTime get date => _db.date;
String get name => _db.name;
int get base => _db.base;
int? get id => _db?.id;
DateTime? get date => _db!.date;
String? get name => _db!.name;
int? get base => _db!.base;
set id(int value) => _db.id = value;
set base(int value) => _db.base = value;
set date(DateTime value) => _db.date = value;
set name(String value) => _db.name = value;
set id(int? value) => _db!.id = value;
set base(int? value) => _db!.base = value;
set date(DateTime? value) => _db!.date = value;
set name(String? value) => _db!.name = value;
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
Future<List<PowerZone>> get powerZones async {
final List<DbPowerZone> dbPowerZoneList =
await _db.getDbPowerZones().orderBy('lowerLimit').toList();
await _db!.getDbPowerZones()!.orderBy('lowerLimit').toList();
return dbPowerZoneList.map(PowerZone.exDb).toList();
}
@ -199,7 +199,7 @@ class PowerZoneSchema {
@override
String toString() => '< PowerZoneSchema | $name | $date >';
static Future<PowerZoneSchema> getBy({int athletesId, DateTime date}) async {
static Future<PowerZoneSchema?> getBy({int? athletesId, DateTime? date}) async {
List<DbPowerZoneSchema> dbPowerZoneSchemas;
dbPowerZoneSchemas = await DbPowerZoneSchema()
@ -212,9 +212,9 @@ class PowerZoneSchema {
.orderByDesc('date')
.top(1)
.toList();
if (dbPowerZoneSchemas.isNotEmpty)
if (dbPowerZoneSchemas.isNotEmpty) {
return PowerZoneSchema._fromDb(dbPowerZoneSchemas.first);
else
} else {
dbPowerZoneSchemas = await DbPowerZoneSchema()
.select()
.athletesId
@ -222,6 +222,7 @@ class PowerZoneSchema {
.orderBy('date')
.top(1)
.toList();
}
return (dbPowerZoneSchemas.isNotEmpty)
? PowerZoneSchema._fromDb(dbPowerZoneSchemas.first)
: null;

View File

@ -1,5 +1,4 @@
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import '/models/event.dart';
import '/models/plot_point.dart';
@ -22,33 +21,34 @@ class RecordList<E> extends DelegatingList<E> {
// AVERAGES:
// Power
double avgPower() {
final Iterable<int> powers = _records
final Iterable<int?> powers = _records
.where((Event record) =>
record.power != null && record.power > 0 && record.power < 2000)
record.power != null && record.power! > 0 && record.power! < 2000)
.map((Event record) => record.power);
return powers.isNotEmpty ? powers.mean() : -1;
}
double sdevPower() => _records
.where((Event record) =>
record.power != null && record.power > 0 && record.power < 2000)
record.power != null && record.power! > 0 && record.power! < 2000)
.map((Event record) => record.power)
.sdev();
int movingTime() {
int movingTime = 0;
DateTime lastTimestamp;
double lastSpeed = 0;
DateTime? lastTimestamp;
double? lastSpeed = 0;
for (final Event record in _records) {
if (record.event == 'record') {
if (record.speed != null && record.timeStamp != null) {
if (record.speed > 0) {
if (lastSpeed > 0)
if (record.speed! > 0) {
if (lastSpeed! > 0) {
movingTime +=
record.timeStamp.difference(lastTimestamp).inSeconds;
else
record.timeStamp!.difference(lastTimestamp!).inSeconds;
} else {
movingTime += 1;
}
}
lastTimestamp = record.timeStamp;
lastSpeed = record.speed;
@ -75,11 +75,11 @@ class RecordList<E> extends DelegatingList<E> {
// Heart Rate
int avgHeartRate() {
final Iterable<int> heartRates = _records
final Iterable<int?> heartRates = _records
.where((Event record) =>
record.heartRate != null &&
record.heartRate > 0 &&
record.heartRate < 2000)
record.heartRate! > 0 &&
record.heartRate! < 2000)
.map((Event record) => record.heartRate);
return heartRates.isNotEmpty ? heartRates.mean().round() : -1;
@ -88,8 +88,8 @@ class RecordList<E> extends DelegatingList<E> {
double sdevHeartRate() => _records
.where((Event record) =>
record.heartRate != null &&
record.heartRate > 0 &&
record.heartRate < 2000)
record.heartRate! > 0 &&
record.heartRate! < 2000)
.map((Event record) => record.heartRate)
.sdev();
@ -114,14 +114,14 @@ class RecordList<E> extends DelegatingList<E> {
}
double avgSpeedBySpeed() {
final Map<DateTime, double> speedMap = <DateTime, double>{
final Map<DateTime?, double?> speedMap = <DateTime?, double?>{
for (final Event record in _records) record.timeStamp: record.speed
};
return speedMap.meanUsingSpeed();
}
double avgSpeedByDistance() {
final Map<DateTime, double> speedMap = <DateTime, double>{
final Map<DateTime?, double?> speedMap = <DateTime?, double?>{
for (final Event record in _records) record.timeStamp: record.distance,
};
return speedMap.meanUsingDistance();
@ -133,8 +133,8 @@ class RecordList<E> extends DelegatingList<E> {
.sdev();
double sdevPace() => _records
.where((Event record) => record.speed != null && record.speed > 1)
.map((Event record) => 50 / 3 / record.speed)
.where((Event record) => record.speed != null && record.speed! > 1)
.map((Event record) => 50 / 3 / record.speed!)
.sdev();
double minSpeed() {
@ -308,16 +308,16 @@ class RecordList<E> extends DelegatingList<E> {
// Form Power
double avgFormPower() {
final Iterable<int> formPowers = _records
final Iterable<int?> formPowers = _records
.where((Event record) =>
record.formPower != null && record.formPower < 200)
record.formPower != null && record.formPower! < 200)
.map((Event record) => record.formPower);
return formPowers.isNotEmpty ? formPowers.mean() : -1;
}
double sdevFormPower() => _records
.where(
(Event record) => record.formPower != null && record.formPower < 200)
(Event record) => record.formPower != null && record.formPower! < 200)
.map((Event record) => record.formPower)
.sdev();
@ -342,7 +342,7 @@ class RecordList<E> extends DelegatingList<E> {
record.formPower != null &&
record.formPower != 0)
.map((Event record) =>
(record.power - record.formPower) / record.power * 100);
(record.power! - record.formPower!) / record.power! * 100);
return powerRatios.isNotEmpty ? powerRatios.mean() : -1;
}
@ -354,7 +354,7 @@ class RecordList<E> extends DelegatingList<E> {
record.formPower != null &&
record.formPower != 0)
.map((Event record) =>
(record.power - record.formPower) / record.power * 100)
(record.power! - record.formPower!) / record.power! * 100)
.sdev();
// Stride Ratio
@ -369,9 +369,9 @@ class RecordList<E> extends DelegatingList<E> {
.map((Event record) =>
10000 /
6 *
record.speed /
record.strydCadence /
record.verticalOscillation);
record.speed! /
record.strydCadence! /
record.verticalOscillation!);
return strydRatios.isNotEmpty ? strydRatios.mean() : -1;
}
@ -386,9 +386,9 @@ class RecordList<E> extends DelegatingList<E> {
.map((Event record) =>
10000 /
6 *
record.speed /
record.strydCadence /
record.verticalOscillation)
record.speed! /
record.strydCadence! /
record.verticalOscillation!)
.sdev();
// Ascend and descend
@ -401,8 +401,9 @@ class RecordList<E> extends DelegatingList<E> {
.cast<double>();
for (final double altitude in altitudes) {
if (lastAltitude != 0 && altitude > lastAltitude)
if (lastAltitude != 0 && altitude > lastAltitude) {
sumOfAscents += altitude - lastAltitude;
}
lastAltitude = altitude;
}
return sumOfAscents;
@ -417,8 +418,9 @@ class RecordList<E> extends DelegatingList<E> {
.cast<double>();
for (final double altitude in altitudes) {
if (lastAltitude != 0 && altitude < lastAltitude)
if (lastAltitude != 0 && altitude < lastAltitude) {
sumOfDescents += lastAltitude - altitude;
}
lastAltitude = altitude;
}
return sumOfDescents;
@ -427,8 +429,8 @@ class RecordList<E> extends DelegatingList<E> {
// END OF AVERAGES
List<IntPlotPoint> toIntDataPoints({
int amount,
@required LapIntAttr attribute,
int? amount,
required LapIntAttr attribute,
}) {
int index = 0;
final List<IntPlotPoint> plotPoints = <IntPlotPoint>[];
@ -437,18 +439,18 @@ class RecordList<E> extends DelegatingList<E> {
for (final Event record in _records) {
switch (attribute) {
case LapIntAttr.power:
sum += record.power;
sum += record.power!;
break;
case LapIntAttr.formPower:
sum += record.formPower;
sum += record.formPower!;
break;
case LapIntAttr.heartRate:
sum += record.heartRate;
sum += record.heartRate!;
}
if (index++ % amount == amount - 1) {
if (index++ % amount! == amount - 1) {
plotPoints.add(IntPlotPoint(
domain: record.distance.round(),
domain: record.distance!.round(),
measure: (sum / amount).round(),
));
sum = 0;
@ -458,9 +460,9 @@ class RecordList<E> extends DelegatingList<E> {
}
List<DoublePlotPoint> toDoubleDataPoints({
int amount,
@required LapDoubleAttr attribute,
double weight,
int? amount,
required LapDoubleAttr attribute,
double? weight,
}) {
int index = 0;
final List<DoublePlotPoint> plotPoints = <DoublePlotPoint>[];
@ -469,50 +471,50 @@ class RecordList<E> extends DelegatingList<E> {
for (final Event record in _records) {
switch (attribute) {
case LapDoubleAttr.powerPerHeartRate:
sum = sum + (record.power / record.heartRate);
sum = sum + (record.power! / record.heartRate!);
break;
case LapDoubleAttr.speedPerHeartRate:
sum = sum + 60 * (record.speed / record.heartRate);
sum = sum + 60 * (record.speed! / record.heartRate!);
break;
case LapDoubleAttr.groundTime:
sum = sum + record.groundTime;
sum = sum + record.groundTime!;
break;
case LapDoubleAttr.strydCadence:
sum = sum + 2 * record.strydCadence;
sum = sum + 2 * record.strydCadence!;
break;
case LapDoubleAttr.verticalOscillation:
sum = sum + record.verticalOscillation;
sum = sum + record.verticalOscillation!;
break;
case LapDoubleAttr.legSpringStiffness:
sum = sum + record.legSpringStiffness;
sum = sum + record.legSpringStiffness!;
break;
case LapDoubleAttr.powerRatio:
sum = sum + ((record.power - record.formPower) / record.power * 100);
sum = sum + ((record.power! - record.formPower!) / record.power! * 100);
break;
case LapDoubleAttr.strideRatio:
sum = sum +
(10000 /
6 *
record.speed /
record.strydCadence /
record.verticalOscillation);
record.speed! /
record.strydCadence! /
record.verticalOscillation!);
break;
case LapDoubleAttr.ecor:
sum = sum + (record.power / record.speed / weight);
sum = sum + (record.power! / record.speed! / weight!);
break;
case LapDoubleAttr.pace:
sum = sum + (50 / 3 / record.speed);
sum = sum + (50 / 3 / record.speed!);
break;
case LapDoubleAttr.speed:
sum = sum + record.speed * 3.6;
sum = sum + record.speed! * 3.6;
break;
case LapDoubleAttr.altitude:
sum = sum + record.altitude;
sum = sum + record.altitude!;
}
if (index++ % amount == amount - 1) {
if (index++ % amount! == amount - 1) {
plotPoints.add(DoublePlotPoint(
domain: record.distance.round(),
domain: record.distance!.round(),
measure: sum / amount,
));
sum = 0;
@ -522,7 +524,7 @@ class RecordList<E> extends DelegatingList<E> {
}
Future<List<BarZone>> powerZoneCounts(
{PowerZoneSchema powerZoneSchema}) async {
{required PowerZoneSchema powerZoneSchema}) async {
final List<BarZone> distributions = <BarZone>[];
double counter = 0.0;
@ -531,8 +533,8 @@ class RecordList<E> extends DelegatingList<E> {
for (final PowerZone powerZone in powerZones) {
final int numberInZone = _records
.where((Event event) =>
(event.power >= powerZone.lowerLimit) &&
(event.power <= powerZone.upperLimit))
(event.power! >= powerZone.lowerLimit!) &&
(event.power! <= powerZone.upperLimit!))
.length;
distributions.add(BarZone(
lower: counter,
@ -545,7 +547,7 @@ class RecordList<E> extends DelegatingList<E> {
}
Future<List<BarZone>> heartRateZoneCounts(
{HeartRateZoneSchema heartRateZoneSchema}) async {
{required HeartRateZoneSchema heartRateZoneSchema}) async {
final List<BarZone> distributions = <BarZone>[];
double counter = 0.0;
@ -555,8 +557,8 @@ class RecordList<E> extends DelegatingList<E> {
for (final HeartRateZone heartRateZone in heartRateZones) {
final int numberInZone = _records
.where((Event event) =>
(event.heartRate >= heartRateZone.lowerLimit) &&
(event.heartRate <= heartRateZone.upperLimit))
(event.heartRate! >= heartRateZone.lowerLimit!) &&
(event.heartRate! <= heartRateZone.upperLimit!))
.length;
distributions.add(BarZone(
lower: counter,

View File

@ -3,7 +3,7 @@ import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:html/dom.dart';
import 'package:html/parser.dart' show parse;
import 'package:path_provider/path_provider.dart';
@ -21,7 +21,7 @@ abstract class StravaFitDownload {
'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
};
static Future<int> byId({String id, Athlete athlete}) async {
static Future<int?> byId({String? id, Athlete? athlete}) async {
final String exportUri = baseUri + 'activities/$id/export_original';
final Directory appDocDir = await getApplicationDocumentsDirectory();
@ -32,10 +32,10 @@ abstract class StravaFitDownload {
final bool loggedIn = await logInIfNecessary(dio: dio, athlete: athlete);
if (loggedIn == true) {
print('Starting download for $exportUri');
debugPrint('Starting download for $exportUri');
final Response<dynamic> downloadResponse =
await dio.download(exportUri, appDocDir.path + '/$id.fit');
print('Download fit file for activity $id completed.');
debugPrint('Download fit file for activity $id completed.');
return downloadResponse.statusCode;
} else {
@ -44,48 +44,48 @@ abstract class StravaFitDownload {
}
static Future<bool> logInIfNecessary(
{@required Dio dio, @required Athlete athlete}) async {
{required Dio dio, required Athlete? athlete}) async {
Response<dynamic> dashboardResponse = await getDashboard(dio: dio);
if (dashboardResponse.data.toString().contains('logged-in')) {
print('Already logged in to Strava');
debugPrint('Already logged in to Strava');
return true;
}
await login(dio: dio, athlete: athlete);
await login(dio: dio, athlete: athlete!);
dashboardResponse = await getDashboard(dio: dio);
if (dashboardResponse.data.toString().contains('logged-in')) {
print('Successfully logged in to Strava');
debugPrint('Successfully logged in to Strava');
return true;
} else {
print('Error: Could not log in to Strava');
debugPrint('Error: Could not log in to Strava');
return false;
}
}
static Future<Response<dynamic>> getDashboard({Dio dio}) async {
static Future<Response<dynamic>> getDashboard({required Dio dio}) async {
return await dio.get<dynamic>(
dashboardUri,
options: Options(headers: headers, validateStatus: (_) => true),
);
}
static Future<void> login({Dio dio, Athlete athlete}) async {
static Future<void> login({required Dio dio, required Athlete athlete}) async {
final Response<dynamic> homePageResponse = await dio.get<dynamic>(
loginUri,
options: Options(headers: headers),
);
final Document document = parse(homePageResponse.data);
final String csrfParam =
document.querySelector('meta[name="csrf-param"]').attributes['content'];
final String csrfToken =
document.querySelector('meta[name="csrf-token"]').attributes['content'];
final String? csrfParam =
document.querySelector('meta[name="csrf-param"]')!.attributes['content'];
final String? csrfToken =
document.querySelector('meta[name="csrf-token"]')!.attributes['content'];
await dio.post<dynamic>(
sessionUri,
options: Options(headers: headers, validateStatus: (_) => true),
data: <String, String>{
data: <String?, String?>{
'email': athlete.email,
'password': athlete.password,
'remember_me': 'on',
@ -94,7 +94,7 @@ abstract class StravaFitDownload {
);
}
static Future<bool> credentialsAreValid({@required Athlete athlete}) async {
static Future<bool> credentialsAreValid({required Athlete athlete}) async {
final Dio dio = Dio();
final CookieJar cookieJar = CookieJar();
dio.interceptors.add(CookieManager(cookieJar));

View File

@ -3,7 +3,7 @@ import 'package:strava_flutter/domain/model/model_authentication_response.dart';
import '/models/athlete.dart' as encrateia;
Future<void> persist({encrateia.Athlete athlete}) async {
Future<void> persist({required encrateia.Athlete athlete}) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
athlete
..stravaAccessToken = prefs.getString('strava_accessToken')
@ -15,23 +15,24 @@ Future<void> persist({encrateia.Athlete athlete}) async {
await athlete.save();
}
Future<void> load({encrateia.Athlete athlete}) async {
Future<void> load({required encrateia.Athlete athlete}) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('strava_accessToken', athlete.stravaAccessToken);
await prefs.setInt('strava_expires_at', athlete.stravaExpiresAt);
await prefs.setInt('strava_expires_in', athlete.stravaExpiresIn);
await prefs.setString('strava_token_type', athlete.stravaTokenType);
await prefs.setString('strava_refreshToken', athlete.stravaRefreshToken);
await prefs.setString('strava_accessToken', athlete.stravaAccessToken!);
await prefs.setInt('strava_expires_at', athlete.stravaExpiresAt!);
await prefs.setInt('strava_expires_in', athlete.stravaExpiresIn!);
await prefs.setString('strava_token_type', athlete.stravaTokenType!);
await prefs.setString('strava_refreshToken', athlete.stravaRefreshToken!);
final TokenResponse _token = TokenResponse(
tokenType: athlete.stravaTokenType,
expiresAt: athlete.stravaExpiresAt,
expiresIn: athlete.stravaExpiresIn,
accessToken: athlete.stravaAccessToken,
refreshToken: athlete.stravaRefreshToken);
//FIXME: We don't use the Response yet!
TokenResponse(
tokenType: athlete.stravaTokenType!,
expiresAt: athlete.stravaExpiresAt!,
expiresIn: athlete.stravaExpiresIn!,
accessToken: athlete.stravaAccessToken!,
refreshToken: athlete.stravaRefreshToken!);
}
Future<void> delete({encrateia.Athlete athlete}) async {
Future<void> delete({required encrateia.Athlete athlete}) async {
athlete
..stravaAccessToken = null
..stravaExpiresAt = null

View File

@ -1,4 +1,3 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart'
show BoolCommitResult, BoolResult;
@ -12,10 +11,10 @@ import 'lap.dart';
class Tag {
Tag({
@required TagGroup tagGroup,
String name,
int color,
int sortOrder,
required TagGroup tagGroup,
String? name,
int? color,
int? sortOrder,
}) {
_db = DbTag()
..tagGroupsId = tagGroup.id
@ -25,32 +24,32 @@ class Tag {
}
Tag._fromDb(this._db);
DbTag _db;
DbTag? _db;
bool selected = false;
int get id => _db?.id;
int get tagGroupsId => _db.tagGroupsId;
String get name => _db.name;
bool get system => _db.system;
int get color => _db.color;
int? get id => _db?.id;
int? get tagGroupsId => _db!.tagGroupsId;
String? get name => _db!.name;
bool? get system => _db!.system;
int? get color => _db!.color;
set color(int value) => _db.color = value;
set name(String value) => _db.name = value;
set color(int? value) => _db!.color = value;
set name(String? value) => _db!.name = value;
@override
String toString() => '< Tag | $name >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<List<Tag>> allByActivity({@required Activity activity}) async {
static Future<List<Tag>> allByActivity({required Activity activity}) async {
final List<DbActivityTagging> dbActivityTaggings = await DbActivityTagging()
.select()
.activitiesId
.equals(activity.id)
.toList();
if (dbActivityTaggings.isNotEmpty) {
final List<int> tagIds = dbActivityTaggings
final List<int?> tagIds = dbActivityTaggings
.map(
(DbActivityTagging dbActivityTagging) => dbActivityTagging.tagsId)
.toList();
@ -67,11 +66,11 @@ class Tag {
}
}
static Future<List<Tag>> allByLap({@required Lap lap}) async {
static Future<List<Tag>> allByLap({required Lap lap}) async {
final List<DbLapTagging> dbLapTaggings =
await DbLapTagging().select().lapsId.equals(lap.id).toList();
if (dbLapTaggings.isNotEmpty) {
final List<int> tagIds = dbLapTaggings
final List<int?> tagIds = dbLapTaggings
.map((DbLapTagging dbLapTagging) => dbLapTagging.tagsId)
.toList();
final List<DbTag> dbTags = await DbTag()
@ -88,14 +87,14 @@ class Tag {
}
static Future<List<Tag>> allByInterval(
{@required encrateia.Interval interval}) async {
{required encrateia.Interval interval}) async {
final List<DbIntervalTagging> dbIntervalTaggings = await DbIntervalTagging()
.select()
.intervalsId
.equals(interval.id)
.toList();
if (dbIntervalTaggings.isNotEmpty) {
final List<int> tagIds = dbIntervalTaggings
final List<int?> tagIds = dbIntervalTaggings
.map(
(DbIntervalTagging dbIntervalTagging) => dbIntervalTagging.tagsId)
.toList();
@ -117,12 +116,12 @@ class Tag {
}
static Future<Tag> autoPowerTag({
@required Athlete athlete,
@required String name,
@required int sortOrder,
@required int color,
required Athlete athlete,
required String? name,
required int? sortOrder,
required int? color,
}) async {
DbTag dbPowerTag;
DbTag? dbPowerTag;
final TagGroup autoPowerTagGroup =
await TagGroup.autoPowerTagGroup(athlete: athlete);
@ -148,12 +147,12 @@ class Tag {
}
static Future<Tag> autoHeartRateTag({
@required Athlete athlete,
@required String name,
@required int sortOrder,
@required int color,
required Athlete athlete,
required String? name,
required int? sortOrder,
required int? color,
}) async {
DbTag dbHeartRateTag;
DbTag? dbHeartRateTag;
final TagGroup autoHeartRateTagGroup =
await TagGroup.autoHeartRateTagGroup(athlete: athlete);

View File

@ -11,7 +11,7 @@ import 'interval.dart' as encrateia;
import 'lap.dart';
class TagGroup {
TagGroup({@required Athlete athlete}) {
TagGroup({required Athlete athlete}) {
_db = DbTagGroup()
..athletesId = athlete.id
..color = Colors.lightGreen.value
@ -22,10 +22,10 @@ class TagGroup {
TagGroup._fromDb(this._db);
TagGroup.by(
{@required Athlete athlete,
@required String name,
@required bool system,
@required int color}) {
{required Athlete athlete,
required String name,
required bool system,
required int color}) {
_db = DbTagGroup()
..athletesId = athlete.id
..color = color
@ -33,31 +33,31 @@ class TagGroup {
..name = name;
}
DbTagGroup _db;
List<Tag> cachedTags;
DbTagGroup? _db;
late List<Tag> cachedTags;
int get id => _db?.id;
String get name => _db.name;
bool get system => _db.system;
int get color => _db.color;
int? get id => _db?.id;
String? get name => _db!.name;
bool? get system => _db!.system;
int? get color => _db!.color;
set color(int value) => _db.color = value;
set name(String value) => _db.name = value;
set color(int? value) => _db!.color = value;
set name(String? value) => _db!.name = value;
Future<List<Tag>> get tags async {
final List<DbTag> dbTags =
await _db.getDbTags().orderBy('sortOrder').orderBy('name').toList();
await _db!.getDbTags()!.orderBy('sortOrder').orderBy('name').toList();
return dbTags.map(Tag.exDb).toList();
}
@override
String toString() => '< TagGroup | $name >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<TagGroup> autoPowerTagGroup({@required Athlete athlete}) async {
final DbTagGroup dbTagGroup = await DbTagGroup()
static Future<TagGroup> autoPowerTagGroup({required Athlete athlete}) async {
final DbTagGroup? dbTagGroup = await DbTagGroup()
.select()
.system
.equals(true)
@ -68,23 +68,23 @@ class TagGroup {
.name
.equals('Auto Power Zones')
.toSingle();
if (dbTagGroup != null)
if (dbTagGroup != null) {
return TagGroup._fromDb(dbTagGroup);
else {
} else {
final TagGroup autoPowerTagGroup = TagGroup.by(
name: 'Auto Power Zones',
athlete: athlete,
system: true,
color: MyColor.bitterSweet.value,
);
await autoPowerTagGroup._db.save();
await autoPowerTagGroup._db!.save();
return autoPowerTagGroup;
}
}
static Future<TagGroup> autoHeartRateTagGroup(
{@required Athlete athlete}) async {
final DbTagGroup dbTagGroup = await DbTagGroup()
{required Athlete athlete}) async {
final DbTagGroup? dbTagGroup = await DbTagGroup()
.select()
.system
.equals(true)
@ -95,23 +95,23 @@ class TagGroup {
.name
.equals('Auto Heart Rate Zones')
.toSingle();
if (dbTagGroup != null)
if (dbTagGroup != null) {
return TagGroup._fromDb(dbTagGroup);
else {
} else {
final TagGroup autoHeartRateTagGroup = TagGroup.by(
name: 'Auto Heart Rate Zones',
athlete: athlete,
system: true,
color: MyColor.grapeFruit.value,
);
await autoHeartRateTagGroup._db.save();
await autoHeartRateTagGroup._db!.save();
return autoHeartRateTagGroup;
}
}
static Future<TagGroup> autoEffortTagGroup(
{@required Athlete athlete}) async {
final DbTagGroup dbTagGroup = await DbTagGroup()
{required Athlete athlete}) async {
final DbTagGroup? dbTagGroup = await DbTagGroup()
.select()
.athletesId
.equals(athlete.id)
@ -119,23 +119,23 @@ class TagGroup {
.name
.equals('Effort')
.toSingle();
if (dbTagGroup != null)
if (dbTagGroup != null) {
return TagGroup._fromDb(dbTagGroup);
else {
} else {
final TagGroup autoEffortTagGroup = TagGroup.by(
name: 'Effort',
athlete: athlete,
system: false,
color: MyColor.brightGoldenYellow.value,
);
await autoEffortTagGroup._db.save();
await autoEffortTagGroup._db!.save();
return autoEffortTagGroup;
}
}
static Future<List<TagGroup>> includingActivityTaggings({
@required Athlete athlete,
@required Activity activity,
required Athlete athlete,
required Activity activity,
}) async {
final List<TagGroup> tagGroups = await athlete.tagGroups;
@ -144,7 +144,7 @@ class TagGroup {
.activitiesId
.equals(activity.id)
.toList();
final Iterable<int> selectedTagIds = dbActivityTaggings
final Iterable<int?> selectedTagIds = dbActivityTaggings
.map((DbActivityTagging dbActivityTagging) => dbActivityTagging.tagsId);
for (final TagGroup tagGroup in tagGroups) {
@ -157,15 +157,15 @@ class TagGroup {
}
static Future<List<TagGroup>> includingLapTaggings({
@required Athlete athlete,
@required Lap lap,
required Athlete athlete,
required Lap lap,
}) async {
final List<TagGroup> tagGroups = await athlete.tagGroups;
final List<DbLapTagging> dbLapTaggings =
await DbLapTagging().select().lapsId.equals(lap.id).toList();
final Iterable<int> selectedTagIds =
final Iterable<int?> selectedTagIds =
dbLapTaggings.map((DbLapTagging dbLapTagging) => dbLapTagging.tagsId);
for (final TagGroup tagGroup in tagGroups) {
@ -178,8 +178,8 @@ class TagGroup {
}
static Future<List<TagGroup>> includingIntervalTaggings({
@required Athlete athlete,
@required encrateia.Interval interval,
required Athlete athlete,
required encrateia.Interval interval,
}) async {
final List<TagGroup> tagGroups = await athlete.tagGroups;
@ -189,7 +189,7 @@ class TagGroup {
.equals(interval.id)
.toList();
final Iterable<int> selectedTagIds = dbIntervalTaggings
final Iterable<int?> selectedTagIds = dbIntervalTaggings
.map((DbIntervalTagging dbIntervalTagging) => dbIntervalTagging.tagsId);
for (final TagGroup tagGroup in tagGroups) {
@ -201,20 +201,20 @@ class TagGroup {
return tagGroups;
}
static Future<List<TagGroup>> allByAthlete({Athlete athlete}) async {
static Future<List<TagGroup>> allByAthlete({required Athlete athlete}) async {
final List<DbTagGroup> dbTagGroups =
await DbTagGroup().select().athletesId.equals(athlete.id).toList();
return dbTagGroups.map(TagGroup.exDb).toList();
}
static Future<void> deleteAllAutoTags({Athlete athlete}) async {
static Future<void> deleteAllAutoTags({required Athlete athlete}) async {
final TagGroup autoPowerTagGroup =
await TagGroup.autoPowerTagGroup(athlete: athlete);
await autoPowerTagGroup._db.getDbTags().delete();
await autoPowerTagGroup._db!.getDbTags()!.delete();
final TagGroup autoHeartRateTagGroup =
await TagGroup.autoHeartRateTagGroup(athlete: athlete);
await autoHeartRateTagGroup._db.getDbTags().delete();
await autoHeartRateTagGroup._db!.getDbTags()!.delete();
}
static TagGroup exDb(DbTagGroup db) => TagGroup._fromDb(db);

View File

@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:sqfentity_gen/sqfentity_gen.dart';
import '/model/model.dart';
import '/models/athlete.dart';
class Weight {
Weight({@required Athlete athlete}) {
Weight({required Athlete athlete}) {
_db = DbWeight()
..athletesId = athlete.id
..value = 70
@ -13,22 +12,22 @@ class Weight {
}
Weight._fromDb(this._db);
DbWeight _db;
DbWeight? _db;
int get id => _db?.id;
DateTime get date => _db.date;
double get value => _db.value;
int? get id => _db?.id;
DateTime? get date => _db!.date;
double? get value => _db!.value;
set date(DateTime value) => _db.date = value;
set value(double value) => _db.value = value;
set date(DateTime? value) => _db!.date = value;
set value(double? value) => _db!.value = value;
@override
String toString() => '< Weight | $date | $value >';
Future<BoolResult> delete() async => await _db.delete();
Future<int> save() async => await _db.save();
Future<BoolResult> delete() async => await _db!.delete();
Future<int?> save() async => await _db!.save();
static Future<Weight> getBy({int athletesId, DateTime date}) async {
static Future<Weight?> getBy({int? athletesId, DateTime? date}) async {
List<DbWeight> dbWeights;
dbWeights = await DbWeight()
@ -41,9 +40,9 @@ class Weight {
.orderByDesc('date')
.top(1)
.toList();
if (dbWeights.isNotEmpty)
if (dbWeights.isNotEmpty) {
return Weight._fromDb(dbWeights.first);
else
} else {
dbWeights = await DbWeight()
.select()
.athletesId
@ -51,6 +50,7 @@ class Weight {
.orderBy('date')
.top(1)
.toList();
}
return (dbWeights.isNotEmpty) ? Weight._fromDb(dbWeights.first) : null;
}

View File

@ -8,18 +8,18 @@ import '/utils/my_color.dart';
class AddFilterScreen extends StatefulWidget {
const AddFilterScreen({
Key key,
Key? key,
this.athlete,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_AddFilterScreenState createState() => _AddFilterScreenState();
}
class _AddFilterScreenState extends State<AddFilterScreen> {
List<TagGroup> tagGroups;
List<TagGroup>? tagGroups;
@override
void initState() {
@ -56,21 +56,21 @@ class _AddFilterScreenState extends State<AddFilterScreen> {
crossAxisSpacing: 3,
childAspectRatio: 3,
),
itemCount: tagGroups == null ? 0 : tagGroups.length,
itemCount: tagGroups == null ? 0 : tagGroups!.length,
itemBuilder: (BuildContext context, int index) => Card(
child: ListTile(
title: Text(tagGroups[index].name),
title: Text(tagGroups![index].name!),
subtitle: Wrap(
spacing: 10,
children: <Widget>[
for (Tag tag in tagGroups[index].cachedTags)
for (Tag tag in tagGroups![index].cachedTags)
FilterChip(
label: Text(
tag.name,
tag.name!,
style: TextStyle(
color: MyColor.textColor(
selected:
widget.athlete.filters.contains(tag.id),
widget.athlete!.filters.contains(tag.id),
backgroundColor: Color(tag.color ?? 99999),
),
),
@ -80,14 +80,15 @@ class _AddFilterScreenState extends State<AddFilterScreen> {
),
onSelected: (bool selected) {
setState(() {
if (selected)
widget.athlete.filters.add(tag.id);
else
widget.athlete.filters.removeWhere(
(int tagId) => tagId == tag.id);
if (selected) {
widget.athlete!.filters.add(tag.id);
} else {
widget.athlete!.filters.removeWhere(
(int? tagId) => tagId == tag.id);
}
});
},
selected: widget.athlete.filters.contains(tag.id),
selected: widget.athlete!.filters.contains(tag.id),
selectedColor: Color(tag.color ?? 99999),
backgroundColor: MyColor.white,
elevation: 3,
@ -115,7 +116,7 @@ class _AddFilterScreenState extends State<AddFilterScreen> {
}
Future<void> getData() async {
tagGroups = await widget.athlete.tagGroups;
tagGroups = await widget.athlete!.tagGroups;
setState(() {});
}
}

View File

@ -13,12 +13,12 @@ import 'add_heart_rate_zone_screen.dart';
class AddHeartRateZoneSchemaScreen extends StatefulWidget {
const AddHeartRateZoneSchemaScreen({
Key key,
Key? key,
this.heartRateZoneSchema,
@required this.numberOfSchemas,
required this.numberOfSchemas,
}) : super(key: key);
final HeartRateZoneSchema heartRateZoneSchema;
final HeartRateZoneSchema? heartRateZoneSchema;
final int numberOfSchemas;
@override
@ -30,7 +30,7 @@ class _AddHeartRateZoneSchemaScreenState
extends State<AddHeartRateZoneSchemaScreen> {
List<HeartRateZone> heartRateZones = <HeartRateZone>[];
int offset = 0;
int rows;
int? rows;
@override
void initState() {
@ -67,8 +67,8 @@ class _AddHeartRateZoneSchemaScreenState
),
resetIcon: null,
format: DateFormat('yyyy-MM-dd'),
initialValue: widget.heartRateZoneSchema.date,
onShowPicker: (BuildContext context, DateTime currentValue) {
initialValue: widget.heartRateZoneSchema!.date,
onShowPicker: (BuildContext context, DateTime? currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime(1969),
@ -76,21 +76,21 @@ class _AddHeartRateZoneSchemaScreenState
lastDate: DateTime(2100),
);
},
onChanged: (DateTime value) =>
onChanged: (DateTime? value) =>
copyHeartRateZoneSchema(date: value),
),
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
initialValue: widget.heartRateZoneSchema.name,
initialValue: widget.heartRateZoneSchema!.name,
onChanged: (String value) =>
widget.heartRateZoneSchema.name = value,
widget.heartRateZoneSchema!.name = value,
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Base value in bpm',
helperText: 'e.g. maximum heart rate, threshold heart rate',
),
initialValue: widget.heartRateZoneSchema.base.toString(),
initialValue: widget.heartRateZoneSchema!.base.toString(),
keyboardType: TextInputType.number,
onChanged: (String value) =>
updateHeartRateZoneBase(base: int.parse(value)),
@ -109,16 +109,16 @@ class _AddHeartRateZoneSchemaScreenState
],
rows: heartRateZones.map((HeartRateZone heartRateZone) {
return DataRow(
key: ValueKey<int>(heartRateZone.id),
key: ValueKey<int?>(heartRateZone.id),
cells: <DataCell>[
DataCell(Text(heartRateZone.name)),
DataCell(Text(heartRateZone.name!)),
DataCell(Text(heartRateZone.lowerLimit.toString() +
' - ' +
heartRateZone.upperLimit.toString())),
DataCell(CircleColor(
circleSize: 20,
elevation: 0,
color: Color(heartRateZone.color),
color: Color(heartRateZone.color!),
)),
DataCell(
MyIcon.edit,
@ -129,7 +129,7 @@ class _AddHeartRateZoneSchemaScreenState
builder: (BuildContext context) =>
AddHeartRateZoneScreen(
heartRateZone: heartRateZone,
base: widget.heartRateZoneSchema.base,
base: widget.heartRateZoneSchema!.base,
numberOfZones: heartRateZones.length,
),
),
@ -154,8 +154,8 @@ class _AddHeartRateZoneSchemaScreenState
builder: (BuildContext context) =>
AddHeartRateZoneScreen(
heartRateZone: HeartRateZone(
heartRateZoneSchema: widget.heartRateZoneSchema),
base: widget.heartRateZoneSchema.base,
heartRateZoneSchema: widget.heartRateZoneSchema!),
base: widget.heartRateZoneSchema!.base,
numberOfZones: heartRateZones.length,
),
),
@ -172,7 +172,7 @@ class _AddHeartRateZoneSchemaScreenState
if (widget.numberOfSchemas > 1)
MyButton.delete(
onPressed: () => deleteHeartRateZoneSchema(
heartRateZoneSchema: widget.heartRateZoneSchema,
heartRateZoneSchema: widget.heartRateZoneSchema!,
),
),
const SizedBox(width: 5),
@ -189,39 +189,39 @@ class _AddHeartRateZoneSchemaScreenState
}
Future<void> saveHeartRateZoneSchema(BuildContext context) async {
await widget.heartRateZoneSchema.save();
await widget.heartRateZoneSchema!.save();
await HeartRateZone.upsertAll(heartRateZones);
Navigator.of(context).pop();
}
Future<void> getData() async {
heartRateZones = await widget.heartRateZoneSchema.heartRateZones;
heartRateZones = await widget.heartRateZoneSchema!.heartRateZones;
setState(() {});
}
Future<void> deleteHeartRateZoneSchema(
{HeartRateZoneSchema heartRateZoneSchema}) async {
{required HeartRateZoneSchema heartRateZoneSchema}) async {
await heartRateZoneSchema.delete();
Navigator.of(context).pop();
}
void updateHeartRateZoneBase({int base}) {
void updateHeartRateZoneBase({int? base}) {
setState(() {
widget.heartRateZoneSchema.base = base;
widget.heartRateZoneSchema!.base = base;
for (final HeartRateZone heartRateZone in heartRateZones) {
heartRateZone.lowerLimit =
(heartRateZone.lowerPercentage * base / 100).round();
(heartRateZone.lowerPercentage! * base! / 100).round();
heartRateZone.upperLimit =
(heartRateZone.upperPercentage * base / 100).round();
(heartRateZone.upperPercentage! * base / 100).round();
}
});
}
Future<void> copyHeartRateZoneSchema({DateTime date}) async {
Future<void> copyHeartRateZoneSchema({DateTime? date}) async {
widget.heartRateZoneSchema
..date = date
..id = null;
final int heartRateZoneSchemaId = await widget.heartRateZoneSchema.save();
final int? heartRateZoneSchemaId = await widget.heartRateZoneSchema!.save();
for (final HeartRateZone heartRateZone in heartRateZones) {
heartRateZone
..heartRateZoneSchemataId = heartRateZoneSchemaId

View File

@ -7,11 +7,11 @@ import '/utils/my_color.dart';
class AddHeartRateZoneScreen extends StatefulWidget {
const AddHeartRateZoneScreen(
{Key key, this.heartRateZone, this.base, @required this.numberOfZones})
{Key? key, this.heartRateZone, this.base, required this.numberOfZones})
: super(key: key);
final HeartRateZone heartRateZone;
final int base;
final HeartRateZone? heartRateZone;
final int? base;
final int numberOfZones;
@override
@ -35,8 +35,8 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
Navigator.of(context).pop();
MaterialColorPicker(
onColorChange: (Color color) =>
widget.heartRateZone.color = color.value,
selectedColor: Color(widget.heartRateZone.color));
widget.heartRateZone!.color = color.value,
selectedColor: Color(widget.heartRateZone!.color!));
},
),
],
@ -48,9 +48,9 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
Future<void> openColorPicker() async {
_openDialog(
MaterialColorPicker(
selectedColor: Color(widget.heartRateZone.color),
selectedColor: Color(widget.heartRateZone!.color!),
onColorChange: (Color color) =>
setState(() => widget.heartRateZone.color = color.value),
setState(() => widget.heartRateZone!.color = color.value),
onBack: () {},
),
);
@ -59,15 +59,15 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
@override
Widget build(BuildContext context) {
final TextEditingController lowerLimitController =
TextEditingController(text: widget.heartRateZone.lowerLimit.toString());
TextEditingController(text: widget.heartRateZone!.lowerLimit.toString());
final TextEditingController upperLimitController =
TextEditingController(text: widget.heartRateZone.upperLimit.toString());
TextEditingController(text: widget.heartRateZone!.upperLimit.toString());
final TextEditingController lowerPercentageController =
TextEditingController(
text: widget.heartRateZone.lowerPercentage.toString());
text: widget.heartRateZone!.lowerPercentage.toString());
final TextEditingController upperPercentageController =
TextEditingController(
text: widget.heartRateZone.upperPercentage.toString());
text: widget.heartRateZone!.upperPercentage.toString());
return Scaffold(
appBar: AppBar(
@ -80,8 +80,8 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
initialValue: widget.heartRateZone.name,
onChanged: (String value) => widget.heartRateZone.name = value,
initialValue: widget.heartRateZone!.name,
onChanged: (String value) => widget.heartRateZone!.name = value,
),
TextFormField(
decoration:
@ -89,11 +89,11 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
controller: lowerLimitController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.heartRateZone.lowerLimit = int.parse(value);
widget.heartRateZone.lowerPercentage =
(int.parse(value) * 100 / widget.base).round();
widget.heartRateZone!.lowerLimit = int.parse(value);
widget.heartRateZone!.lowerPercentage =
(int.parse(value) * 100 / widget.base!).round();
lowerPercentageController.text =
(int.parse(value) * 100 / widget.base).round().toString();
(int.parse(value) * 100 / widget.base!).round().toString();
},
),
TextFormField(
@ -102,11 +102,11 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
controller: upperLimitController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.heartRateZone.upperLimit = int.parse(value);
widget.heartRateZone.upperPercentage =
(int.parse(value) * 100 / widget.base).round();
widget.heartRateZone!.upperLimit = int.parse(value);
widget.heartRateZone!.upperPercentage =
(int.parse(value) * 100 / widget.base!).round();
upperPercentageController.text =
(int.parse(value) * 100 / widget.base).round().toString();
(int.parse(value) * 100 / widget.base!).round().toString();
},
),
TextFormField(
@ -115,11 +115,11 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
controller: lowerPercentageController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.heartRateZone.lowerPercentage = int.parse(value);
widget.heartRateZone.lowerLimit =
(int.parse(value) * widget.base / 100).round();
widget.heartRateZone!.lowerPercentage = int.parse(value);
widget.heartRateZone!.lowerLimit =
(int.parse(value) * widget.base! / 100).round();
lowerLimitController.text =
(int.parse(value) * widget.base / 100).round().toString();
(int.parse(value) * widget.base! / 100).round().toString();
},
),
TextFormField(
@ -128,11 +128,11 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
controller: upperPercentageController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.heartRateZone.upperPercentage = int.parse(value);
widget.heartRateZone.upperLimit =
(int.parse(value) * widget.base / 100).round();
widget.heartRateZone!.upperPercentage = int.parse(value);
widget.heartRateZone!.upperLimit =
(int.parse(value) * widget.base! / 100).round();
upperLimitController.text =
(int.parse(value) * widget.base / 100).round().toString();
(int.parse(value) * widget.base! / 100).round().toString();
},
),
const SizedBox(height: 10),
@ -140,7 +140,7 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
const Text('Color'),
const Spacer(),
CircleAvatar(
backgroundColor: Color(widget.heartRateZone.color),
backgroundColor: Color(widget.heartRateZone!.color!),
radius: 20.0,
),
const Spacer(),
@ -169,12 +169,12 @@ class _AddHeartRateZoneScreenState extends State<AddHeartRateZoneScreen> {
}
Future<void> saveHeartRateZone(BuildContext context) async {
await widget.heartRateZone.save();
await widget.heartRateZone!.save();
Navigator.of(context).pop();
}
Future<void> deleteHeartRateZone(BuildContext context) async {
await widget.heartRateZone.delete();
await widget.heartRateZone!.delete();
Navigator.of(context).pop();
}
}

View File

@ -13,12 +13,12 @@ import 'add_power_zone_screen.dart';
class AddPowerZoneSchemaScreen extends StatefulWidget {
const AddPowerZoneSchemaScreen({
Key key,
Key? key,
this.powerZoneSchema,
@required this.numberOfSchemas,
required this.numberOfSchemas,
}) : super(key: key);
final PowerZoneSchema powerZoneSchema;
final PowerZoneSchema? powerZoneSchema;
final int numberOfSchemas;
@override
@ -29,7 +29,7 @@ class AddPowerZoneSchemaScreen extends StatefulWidget {
class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
List<PowerZone> powerZones = <PowerZone>[];
int offset = 0;
int rows;
int? rows;
@override
void initState() {
@ -63,9 +63,9 @@ class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
DateTimeField(
decoration: const InputDecoration(labelText: 'Valid from'),
format: DateFormat('yyyy-MM-dd'),
initialValue: widget.powerZoneSchema.date,
initialValue: widget.powerZoneSchema!.date,
resetIcon: null,
onShowPicker: (BuildContext context, DateTime currentValue) {
onShowPicker: (BuildContext context, DateTime? currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime(1969),
@ -73,19 +73,19 @@ class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
lastDate: DateTime(2100),
);
},
onChanged: (DateTime value) => copyPowerZoneSchema(date: value),
onChanged: (DateTime? value) => copyPowerZoneSchema(date: value),
),
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
initialValue: widget.powerZoneSchema.name,
onChanged: (String value) => widget.powerZoneSchema.name = value,
initialValue: widget.powerZoneSchema!.name,
onChanged: (String value) => widget.powerZoneSchema!.name = value,
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Base value in W',
helperText: 'e.g. Critical Power, Functional Threshold Power',
),
initialValue: widget.powerZoneSchema.base.toString(),
initialValue: widget.powerZoneSchema!.base.toString(),
keyboardType: TextInputType.number,
onChanged: (String value) =>
updatePowerZoneBase(base: int.parse(value)),
@ -104,16 +104,16 @@ class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
],
rows: powerZones.map((PowerZone powerZone) {
return DataRow(
key: ValueKey<int>(powerZone.id),
key: ValueKey<int?>(powerZone.id),
cells: <DataCell>[
DataCell(Text(powerZone.name)),
DataCell(Text(powerZone.name!)),
DataCell(Text(powerZone.lowerLimit.toString() +
' - ' +
powerZone.upperLimit.toString())),
DataCell(CircleColor(
circleSize: 20,
elevation: 0,
color: Color(powerZone.color),
color: Color(powerZone.color!),
)),
DataCell(
MyIcon.edit,
@ -124,7 +124,7 @@ class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
builder: (BuildContext context) =>
AddPowerZoneScreen(
powerZone: powerZone,
base: widget.powerZoneSchema.base,
base: widget.powerZoneSchema!.base,
numberOfZones: powerZones.length,
),
),
@ -148,8 +148,8 @@ class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
MaterialPageRoute<BuildContext>(
builder: (BuildContext context) => AddPowerZoneScreen(
powerZone: PowerZone(
powerZoneSchema: widget.powerZoneSchema),
base: widget.powerZoneSchema.base,
powerZoneSchema: widget.powerZoneSchema!),
base: widget.powerZoneSchema!.base,
numberOfZones: powerZones.length,
),
),
@ -166,7 +166,7 @@ class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
if (widget.numberOfSchemas > 1)
MyButton.delete(
onPressed: () => deletePowerZoneSchema(
powerZoneSchema: widget.powerZoneSchema,
powerZoneSchema: widget.powerZoneSchema!,
),
),
const SizedBox(width: 5),
@ -182,37 +182,37 @@ class _AddPowerZoneSchemaScreenState extends State<AddPowerZoneSchemaScreen> {
}
Future<void> savePowerZoneSchema(BuildContext context) async {
await widget.powerZoneSchema.save();
await widget.powerZoneSchema!.save();
await PowerZone.upsertAll(powerZones);
Navigator.of(context).pop();
}
Future<void> getData() async {
powerZones = await widget.powerZoneSchema.powerZones;
powerZones = await widget.powerZoneSchema!.powerZones;
setState(() {});
}
Future<void> deletePowerZoneSchema({PowerZoneSchema powerZoneSchema}) async {
Future<void> deletePowerZoneSchema({required PowerZoneSchema powerZoneSchema}) async {
await powerZoneSchema.delete();
Navigator.of(context).pop();
}
Future<void> updatePowerZoneBase({int base}) {
Future<void>? updatePowerZoneBase({int? base}) {
setState(() {
widget.powerZoneSchema.base = base;
widget.powerZoneSchema!.base = base;
for (final PowerZone powerZone in powerZones) {
powerZone.lowerLimit = (powerZone.lowerPercentage * base / 100).round();
powerZone.upperLimit = (powerZone.upperPercentage * base / 100).round();
powerZone.lowerLimit = (powerZone.lowerPercentage! * base! / 100).round();
powerZone.upperLimit = (powerZone.upperPercentage! * base / 100).round();
}
});
return null;
}
Future<void> copyPowerZoneSchema({DateTime date}) async {
Future<void> copyPowerZoneSchema({DateTime? date}) async {
widget.powerZoneSchema
..date = date
..id = null;
final int powerZoneSchemaId = await widget.powerZoneSchema.save();
final int? powerZoneSchemaId = await widget.powerZoneSchema!.save();
for (final PowerZone powerZone in powerZones) {
powerZone
..powerZoneSchemataId = powerZoneSchemaId

View File

@ -7,11 +7,11 @@ import '/utils/my_color.dart';
class AddPowerZoneScreen extends StatefulWidget {
const AddPowerZoneScreen(
{Key key, this.powerZone, this.base, @required this.numberOfZones})
{Key? key, this.powerZone, this.base, required this.numberOfZones})
: super(key: key);
final PowerZone powerZone;
final int base;
final PowerZone? powerZone;
final int? base;
final int numberOfZones;
@override
@ -35,8 +35,8 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
Navigator.of(context).pop();
MaterialColorPicker(
onColorChange: (Color color) =>
widget.powerZone.color = color.value,
selectedColor: Color(widget.powerZone.color));
widget.powerZone!.color = color.value,
selectedColor: Color(widget.powerZone!.color!));
},
),
],
@ -48,9 +48,9 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
Future<void> openColorPicker() async {
_openDialog(
MaterialColorPicker(
selectedColor: Color(widget.powerZone.color),
selectedColor: Color(widget.powerZone!.color!),
onColorChange: (Color color) =>
setState(() => widget.powerZone.color = color.value),
setState(() => widget.powerZone!.color = color.value),
onBack: () {},
),
);
@ -59,15 +59,15 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
@override
Widget build(BuildContext context) {
final TextEditingController lowerLimitController =
TextEditingController(text: widget.powerZone.lowerLimit.toString());
TextEditingController(text: widget.powerZone!.lowerLimit.toString());
final TextEditingController upperLimitController =
TextEditingController(text: widget.powerZone.upperLimit.toString());
TextEditingController(text: widget.powerZone!.upperLimit.toString());
final TextEditingController lowerPercentageController =
TextEditingController(
text: widget.powerZone.lowerPercentage.toString());
text: widget.powerZone!.lowerPercentage.toString());
final TextEditingController upperPercentageController =
TextEditingController(
text: widget.powerZone.upperPercentage.toString());
text: widget.powerZone!.upperPercentage.toString());
return Scaffold(
appBar: AppBar(
@ -80,19 +80,19 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
initialValue: widget.powerZone.name,
onChanged: (String value) => widget.powerZone.name = value,
initialValue: widget.powerZone!.name,
onChanged: (String value) => widget.powerZone!.name = value,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Lower Limit in W'),
controller: lowerLimitController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.powerZone.lowerLimit = int.parse(value);
widget.powerZone.lowerPercentage =
(int.parse(value) * 100 / widget.base).round();
widget.powerZone!.lowerLimit = int.parse(value);
widget.powerZone!.lowerPercentage =
(int.parse(value) * 100 / widget.base!).round();
lowerPercentageController.text =
(int.parse(value) * 100 / widget.base).round().toString();
(int.parse(value) * 100 / widget.base!).round().toString();
},
),
TextFormField(
@ -100,11 +100,11 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
controller: upperLimitController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.powerZone.upperLimit = int.parse(value);
widget.powerZone.upperPercentage =
(int.parse(value) * 100 / widget.base).round();
widget.powerZone!.upperLimit = int.parse(value);
widget.powerZone!.upperPercentage =
(int.parse(value) * 100 / widget.base!).round();
upperPercentageController.text =
(int.parse(value) * 100 / widget.base).round().toString();
(int.parse(value) * 100 / widget.base!).round().toString();
},
),
TextFormField(
@ -113,11 +113,11 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
controller: lowerPercentageController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.powerZone.lowerPercentage = int.parse(value);
widget.powerZone.lowerLimit =
(int.parse(value) * widget.base / 100).round();
widget.powerZone!.lowerPercentage = int.parse(value);
widget.powerZone!.lowerLimit =
(int.parse(value) * widget.base! / 100).round();
lowerLimitController.text =
(int.parse(value) * widget.base / 100).round().toString();
(int.parse(value) * widget.base! / 100).round().toString();
},
),
TextFormField(
@ -126,11 +126,11 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
controller: upperPercentageController,
keyboardType: TextInputType.number,
onChanged: (String value) {
widget.powerZone.upperPercentage = int.parse(value);
widget.powerZone.upperLimit =
(int.parse(value) * widget.base / 100).round();
widget.powerZone!.upperPercentage = int.parse(value);
widget.powerZone!.upperLimit =
(int.parse(value) * widget.base! / 100).round();
upperLimitController.text =
(int.parse(value) * widget.base / 100).round().toString();
(int.parse(value) * widget.base! / 100).round().toString();
},
),
const SizedBox(height: 10),
@ -138,7 +138,7 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
const Text('Color'),
const Spacer(),
CircleAvatar(
backgroundColor: Color(widget.powerZone.color),
backgroundColor: Color(widget.powerZone!.color!),
radius: 20.0,
),
const Spacer(),
@ -166,12 +166,12 @@ class _AddPowerZoneScreenState extends State<AddPowerZoneScreen> {
}
Future<void> savePowerZone(BuildContext context) async {
await widget.powerZone.save();
await widget.powerZone!.save();
Navigator.of(context).pop();
}
Future<void> deletePowerZone(BuildContext context) async {
await widget.powerZone.delete();
await widget.powerZone!.delete();
Navigator.of(context).pop();
}
}

View File

@ -10,11 +10,11 @@ import 'add_tag_screen.dart';
class AddTagGroupScreen extends StatefulWidget {
const AddTagGroupScreen({
Key key,
Key? key,
this.tagGroup,
}) : super(key: key);
final TagGroup tagGroup;
final TagGroup? tagGroup;
@override
_AddTagGroupScreenState createState() => _AddTagGroupScreenState();
@ -23,7 +23,7 @@ class AddTagGroupScreen extends StatefulWidget {
class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
List<Tag> tags = <Tag>[];
int offset = 0;
int rows;
int? rows;
@override
void initState() {
@ -47,8 +47,8 @@ class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
Navigator.of(context).pop();
MaterialColorPicker(
onColorChange: (Color color) =>
widget.tagGroup.color = color.value,
selectedColor: Color(widget.tagGroup.color));
widget.tagGroup!.color = color.value,
selectedColor: Color(widget.tagGroup!.color!));
},
),
],
@ -60,9 +60,9 @@ class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
Future<void> openColorPicker() async {
_openDialog(
MaterialColorPicker(
selectedColor: Color(widget.tagGroup.color),
selectedColor: Color(widget.tagGroup!.color!),
onColorChange: (Color color) =>
setState(() => widget.tagGroup.color = color.value),
setState(() => widget.tagGroup!.color = color.value),
onBack: () {},
),
);
@ -81,15 +81,15 @@ class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
initialValue: widget.tagGroup.name,
onChanged: (String value) => widget.tagGroup.name = value,
initialValue: widget.tagGroup!.name,
onChanged: (String value) => widget.tagGroup!.name = value,
),
const SizedBox(height: 20),
Row(children: <Widget>[
const Text('Color'),
const Spacer(),
CircleAvatar(
backgroundColor: Color(widget.tagGroup.color),
backgroundColor: Color(widget.tagGroup!.color!),
radius: 20.0,
),
const Spacer(),
@ -111,13 +111,13 @@ class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
],
rows: tags.map((Tag tag) {
return DataRow(
key: ValueKey<int>(tag.id),
key: ValueKey<int?>(tag.id),
cells: <DataCell>[
DataCell(Text(tag.name)),
DataCell(Text(tag.name!)),
DataCell(CircleColor(
circleSize: 20,
elevation: 0,
color: Color(tag.color),
color: Color(tag.color!),
)),
DataCell(
MyIcon.edit,
@ -148,7 +148,7 @@ class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
context,
MaterialPageRoute<BuildContext>(
builder: (BuildContext context) => AddTagScreen(
tag: Tag(tagGroup: widget.tagGroup),
tag: Tag(tagGroup: widget.tagGroup!),
),
),
);
@ -163,7 +163,7 @@ class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
children: <Widget>[
MyButton.delete(
onPressed: () => deleteTagGroup(
tagGroup: widget.tagGroup,
tagGroup: widget.tagGroup!,
),
),
const SizedBox(width: 5),
@ -179,17 +179,17 @@ class _AddTagGroupScreenState extends State<AddTagGroupScreen> {
}
Future<void> saveTagGroup(BuildContext context) async {
await widget.tagGroup.save();
await widget.tagGroup!.save();
await Tag.upsertAll(tags);
Navigator.of(context).pop();
}
Future<void> getData() async {
tags = await widget.tagGroup.tags;
tags = await widget.tagGroup!.tags;
setState(() {});
}
Future<void> deleteTagGroup({TagGroup tagGroup}) async {
Future<void> deleteTagGroup({required TagGroup tagGroup}) async {
await tagGroup.delete();
Navigator.of(context).pop();
}

View File

@ -7,13 +7,13 @@ import '/utils/my_color.dart';
class AddTagScreen extends StatefulWidget {
const AddTagScreen({
Key key,
Key? key,
this.tag,
this.base,
}) : super(key: key);
final Tag tag;
final int base;
final Tag? tag;
final int? base;
@override
_AddTagScreenState createState() => _AddTagScreenState();
@ -36,8 +36,8 @@ class _AddTagScreenState extends State<AddTagScreen> {
Navigator.of(context).pop();
MaterialColorPicker(
onColorChange: (Color color) =>
widget.tag.color = color.value,
selectedColor: Color(widget.tag.color));
widget.tag!.color = color.value,
selectedColor: Color(widget.tag!.color!));
},
),
],
@ -49,9 +49,9 @@ class _AddTagScreenState extends State<AddTagScreen> {
Future<void> openColorPicker() async {
_openDialog(
MaterialColorPicker(
selectedColor: Color(widget.tag.color),
selectedColor: Color(widget.tag!.color!),
onColorChange: (Color color) =>
setState(() => widget.tag.color = color.value),
setState(() => widget.tag!.color = color.value),
onBack: () {},
),
);
@ -70,15 +70,15 @@ class _AddTagScreenState extends State<AddTagScreen> {
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
initialValue: widget.tag.name,
onChanged: (String value) => widget.tag.name = value,
initialValue: widget.tag!.name,
onChanged: (String value) => widget.tag!.name = value,
),
const SizedBox(height: 10),
Row(children: <Widget>[
const Text('Color'),
const Spacer(),
CircleAvatar(
backgroundColor: Color(widget.tag.color),
backgroundColor: Color(widget.tag!.color!),
radius: 20.0,
),
const Spacer(),
@ -105,12 +105,12 @@ class _AddTagScreenState extends State<AddTagScreen> {
}
Future<void> saveTag(BuildContext context) async {
await widget.tag.save();
await widget.tag!.save();
Navigator.of(context).pop();
}
Future<void> deleteTag(BuildContext context) async {
await widget.tag.delete();
await widget.tag!.delete();
Navigator.of(context).pop();
}
}

View File

@ -7,10 +7,10 @@ import '/utils/my_button.dart';
import '/utils/my_color.dart';
class AddWeightScreen extends StatelessWidget {
const AddWeightScreen({Key key, this.weight, @required this.numberOfWeights})
const AddWeightScreen({Key? key, this.weight, required this.numberOfWeights})
: super(key: key);
final Weight weight;
final Weight? weight;
final int numberOfWeights;
@override
@ -27,8 +27,8 @@ class AddWeightScreen extends StatelessWidget {
DateTimeField(
decoration: const InputDecoration(labelText: 'Date'),
format: DateFormat('yyyy-MM-dd'),
initialValue: weight.date,
onShowPicker: (BuildContext context, DateTime currentValue) {
initialValue: weight!.date,
onShowPicker: (BuildContext context, DateTime? currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime(1990),
@ -36,14 +36,14 @@ class AddWeightScreen extends StatelessWidget {
lastDate: DateTime(2100),
);
},
onChanged: (DateTime value) => weight.date = value,
onChanged: (DateTime? value) => weight!.date = value,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Weight in kg'),
initialValue: weight.value.toString(),
initialValue: weight!.value.toString(),
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
onChanged: (String value) => weight.value = double.parse(value),
onChanged: (String value) => weight!.value = double.parse(value),
),
const SizedBox(height: 20),
Row(
@ -66,12 +66,12 @@ class AddWeightScreen extends StatelessWidget {
}
Future<void> saveWeight(BuildContext context) async {
await weight.save();
await weight!.save();
Navigator.of(context).pop();
}
Future<void> deleteWeight(BuildContext context) async {
await weight.delete();
await weight!.delete();
Navigator.of(context).pop();
}
}

View File

@ -6,8 +6,8 @@ import '/widgets/activity_widgets/edit_activity_widget.dart';
class EditActivityScreen extends StatelessWidget {
const EditActivityScreen({
Key key,
@required this.activity,
Key? key,
required this.activity,
}) : super(key: key);
final Activity activity;

View File

@ -12,7 +12,7 @@ import 'onboarding_screens/onboarding_introduction_screen.dart';
import 'show_athlete_screen.dart';
class Dashboard extends StatefulWidget {
const Dashboard();
const Dashboard({Key? key}) : super(key: key);
@override
_DashboardState createState() => _DashboardState();
@ -21,7 +21,7 @@ class Dashboard extends StatefulWidget {
class _DashboardState extends State<Dashboard> {
List<Athlete> athletes = <Athlete>[];
List<Log> logs = <Log>[];
String version;
String? version;
@override
void initState() {
@ -31,9 +31,9 @@ class _DashboardState extends State<Dashboard> {
@override
Widget build(BuildContext context) {
if (athletes.isEmpty)
if (athletes.isEmpty) {
return Container();
else {
} else {
return Scaffold(
appBar: AppBar(
backgroundColor: MyColor.primary,
@ -48,7 +48,7 @@ class _DashboardState extends State<Dashboard> {
Card(
child: ListTile(
leading: athlete.photoPath != null
? Image.network(athlete.photoPath)
? Image.network(athlete.photoPath!)
: MyIcon.runningBig,
title: Text('${athlete.firstName} ${athlete.lastName}'),
onTap: () async {

View File

@ -7,11 +7,11 @@ import '/widgets/athlete_widgets/edit_strava_athlete_widget.dart';
class EditAthleteScreen extends StatelessWidget {
const EditAthleteScreen({
Key key,
Key? key,
this.athlete,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
Widget build(BuildContext context) {
@ -21,7 +21,7 @@ class EditAthleteScreen extends StatelessWidget {
title: const Text('Athlete Credentials'),
),
body: SafeArea(
child: (athlete.state == 'standalone')
child: (athlete!.state == 'standalone')
? EditStandaloneAthleteWidget(athlete: athlete)
: EditStravaAthleteWidget(athlete: athlete),
));

View File

@ -9,11 +9,11 @@ import '/utils/my_color.dart';
class EditEventScreen extends StatefulWidget {
const EditEventScreen({
Key key,
Key? key,
this.record,
}) : super(key: key);
final Event record;
final Event? record;
@override
_EditEventScreenState createState() => _EditEventScreenState();
@ -40,43 +40,43 @@ class _EditEventScreenState extends State<EditEventScreen> {
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Event'),
onChanged: (String value) => widget.record.event = value,
initialValue: widget.record.event,
onChanged: (String value) => widget.record!.event = value,
initialValue: widget.record!.event,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Event Type'),
onChanged: (String value) =>
widget.record.eventType = value,
initialValue: widget.record.eventType,
widget.record!.eventType = value,
initialValue: widget.record!.eventType,
),
TextFormField(
decoration:
const InputDecoration(labelText: 'Event Group'),
onChanged: (String value) =>
widget.record.eventGroup = int.parse(value),
initialValue: widget.record.eventGroup.toString(),
widget.record!.eventGroup = int.parse(value),
initialValue: widget.record!.eventGroup.toString(),
keyboardType: TextInputType.number),
TextFormField(
decoration:
const InputDecoration(labelText: 'Timer Trigger'),
onChanged: (String value) =>
widget.record.timerTrigger = value,
initialValue: widget.record.timerTrigger,
widget.record!.timerTrigger = value,
initialValue: widget.record!.timerTrigger,
),
DateTimeField(
decoration: const InputDecoration(labelText: 'Time Stamp'),
format: DateFormat('yyyy-MM-dd HH:mm:SS'),
initialValue: widget.record.timeStamp,
initialValue: widget.record!.timeStamp,
resetIcon: null,
onShowPicker:
(BuildContext context, DateTime currentValue) async {
final DateTime date = await showDatePicker(
(BuildContext context, DateTime? currentValue) async {
final DateTime? date = await showDatePicker(
context: context,
firstDate: DateTime(1969),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime(2100));
if (date != null) {
final TimeOfDay time = await showTimePicker(
final TimeOfDay? time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(
currentValue ?? DateTime.now()),
@ -86,19 +86,19 @@ class _EditEventScreenState extends State<EditEventScreen> {
return currentValue;
}
},
onChanged: (DateTime value) =>
widget.record.timeStamp = value,
onChanged: (DateTime? value) =>
widget.record!.timeStamp = value,
),
Row(children: <Widget>[
Flexible(
child: TextFormField(
decoration: const InputDecoration(
labelText: 'Latitude Degrees'),
onChanged: (String value) => widget.record.positionLat =
widget.record.positionLat
onChanged: (String value) => widget.record!.positionLat =
widget.record!.positionLat!
.setDegrees(int.parse(value)),
initialValue:
widget.record.positionLat.fullDegrees.toString(),
widget.record!.positionLat!.fullDegrees.toString(),
keyboardType: TextInputType.number,
),
),
@ -106,11 +106,11 @@ class _EditEventScreenState extends State<EditEventScreen> {
child: TextFormField(
decoration: const InputDecoration(
labelText: 'Latitude Minutes'),
onChanged: (String value) => widget.record.positionLat =
widget.record.positionLat
onChanged: (String value) => widget.record!.positionLat =
widget.record!.positionLat!
.setMinutes(int.parse(value)),
initialValue:
widget.record.positionLat.fullMinutes.toString(),
widget.record!.positionLat!.fullMinutes.toString(),
keyboardType: TextInputType.number,
),
),
@ -118,11 +118,11 @@ class _EditEventScreenState extends State<EditEventScreen> {
child: TextFormField(
decoration: const InputDecoration(
labelText: 'Latitude Seconds'),
onChanged: (String value) => widget.record.positionLat =
widget.record.positionLat
onChanged: (String value) => widget.record!.positionLat =
widget.record!.positionLat!
.setSeconds(double.parse(value)),
initialValue:
widget.record.positionLat.seconds.toString(),
widget.record!.positionLat!.seconds.toString(),
keyboardType: TextInputType.number,
),
),
@ -133,11 +133,11 @@ class _EditEventScreenState extends State<EditEventScreen> {
decoration: const InputDecoration(
labelText: 'Longitude Degrees'),
onChanged: (String value) =>
widget.record.positionLong = widget
.record.positionLong
widget.record!.positionLong = widget
.record!.positionLong!
.setDegrees(int.parse(value)),
initialValue:
widget.record.positionLong.fullDegrees.toString(),
widget.record!.positionLong!.fullDegrees.toString(),
keyboardType: TextInputType.number,
),
),
@ -146,11 +146,11 @@ class _EditEventScreenState extends State<EditEventScreen> {
decoration: const InputDecoration(
labelText: 'Longitude Minutes'),
onChanged: (String value) =>
widget.record.positionLong = widget
.record.positionLong
widget.record!.positionLong = widget
.record!.positionLong!
.setMinutes(int.parse(value)),
initialValue:
widget.record.positionLong.fullMinutes.toString(),
widget.record!.positionLong!.fullMinutes.toString(),
keyboardType: TextInputType.number,
),
),
@ -159,11 +159,11 @@ class _EditEventScreenState extends State<EditEventScreen> {
decoration: const InputDecoration(
labelText: 'Longitude Seconds'),
onChanged: (String value) =>
widget.record.positionLong = widget
.record.positionLong
widget.record!.positionLong = widget
.record!.positionLong!
.setSeconds(double.parse(value)),
initialValue:
widget.record.positionLong.seconds.toString(),
widget.record!.positionLong!.seconds.toString(),
keyboardType: TextInputType.number,
),
),
@ -171,103 +171,103 @@ class _EditEventScreenState extends State<EditEventScreen> {
TextFormField(
decoration: const InputDecoration(labelText: 'Distance'),
onChanged: (String value) =>
widget.record.distance = double.parse(value),
initialValue: widget.record.distance.toString(),
widget.record!.distance = double.parse(value),
initialValue: widget.record!.distance.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Altitude'),
onChanged: (String value) =>
widget.record.altitude = double.parse(value),
initialValue: widget.record.altitude.toString(),
widget.record!.altitude = double.parse(value),
initialValue: widget.record!.altitude.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Speed'),
onChanged: (String value) =>
widget.record.speed = double.parse(value),
initialValue: widget.record.speed.toString(),
widget.record!.speed = double.parse(value),
initialValue: widget.record!.speed.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Heart Rate'),
onChanged: (String value) =>
widget.record.heartRate = int.parse(value),
initialValue: widget.record.heartRate.toString(),
widget.record!.heartRate = int.parse(value),
initialValue: widget.record!.heartRate.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Cadence'),
onChanged: (String value) =>
widget.record.cadence = double.parse(value),
initialValue: widget.record.cadence.toString(),
widget.record!.cadence = double.parse(value),
initialValue: widget.record!.cadence.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration:
const InputDecoration(labelText: 'Fractional Cadence'),
onChanged: (String value) =>
widget.record.fractionalCadence = double.parse(value),
initialValue: widget.record.fractionalCadence.toString(),
widget.record!.fractionalCadence = double.parse(value),
initialValue: widget.record!.fractionalCadence.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Power'),
onChanged: (String value) =>
widget.record.power = int.parse(value),
initialValue: widget.record.power.toString(),
widget.record!.power = int.parse(value),
initialValue: widget.record!.power.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration:
const InputDecoration(labelText: 'Stryd Cadence'),
onChanged: (String value) =>
widget.record.strydCadence = double.parse(value),
initialValue: widget.record.strydCadence.toString(),
widget.record!.strydCadence = double.parse(value),
initialValue: widget.record!.strydCadence.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Ground Time'),
onChanged: (String value) =>
widget.record.groundTime = double.parse(value),
initialValue: widget.record.groundTime.toString(),
widget.record!.groundTime = double.parse(value),
initialValue: widget.record!.groundTime.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Vertical Oscillation'),
onChanged: (String value) =>
widget.record.verticalOscillation = double.parse(value),
initialValue: widget.record.verticalOscillation.toString(),
widget.record!.verticalOscillation = double.parse(value),
initialValue: widget.record!.verticalOscillation.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Form Power'),
onChanged: (String value) =>
widget.record.formPower = int.parse(value),
initialValue: widget.record.formPower.toString(),
widget.record!.formPower = int.parse(value),
initialValue: widget.record!.formPower.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Leg Spring Stiffness'),
onChanged: (String value) =>
widget.record.legSpringStiffness = double.parse(value),
initialValue: widget.record.legSpringStiffness.toString(),
widget.record!.legSpringStiffness = double.parse(value),
initialValue: widget.record!.legSpringStiffness.toString(),
keyboardType: TextInputType.number,
),
TextFormField(
decoration: const InputDecoration(labelText: 'Data'),
onChanged: (String value) =>
widget.record.data = double.parse(value),
initialValue: widget.record.data.toString(),
widget.record!.data = double.parse(value),
initialValue: widget.record!.data.toString(),
keyboardType: TextInputType.number,
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: MyButton.save(
onPressed: () async {
await widget.record.save();
await widget.record!.save();
Navigator.of(context).pop();
},
),

View File

@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
import '/models/log.dart';
import '/screens/show_log_detail_screen.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/my_button.dart';
import '/utils/my_color.dart';
class LogListScreen extends StatefulWidget {
const LogListScreen({
Key key,
Key? key,
}) : super(key: key);
@override
@ -62,15 +62,15 @@ class _LogListScreenState extends State<LogListScreen> {
],
rows: logs.map((Log log) {
return DataRow(
key: ValueKey<int>(log.id),
key: ValueKey<int?>(log.id),
cells: <DataCell>[
DataCell(PQText(
value: log.dateTime,
pq: PQ.dateTime,
format: DateTimeFormat.compact,
)),
DataCell(Text(log.message)),
DataCell(Text(log.method)),
DataCell(Text(log.message!)),
DataCell(Text(log.method!)),
DataCell(MyButton.navigate(
child: const Text('Details'),
onPressed: () async {

View File

@ -5,6 +5,8 @@ import 'package:url_launcher/url_launcher.dart';
import '/utils/my_color.dart';
class IntroductionTextScreen extends StatelessWidget {
const IntroductionTextScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
@ -16,10 +18,10 @@ class IntroductionTextScreen extends StatelessWidget {
child: Markdown(
onTapLink: (
String _text,
String url,
String? url,
String _title,
) =>
launch(url),
launch(url!),
data: '''
## What is Encrateia?

View File

@ -9,11 +9,11 @@ import '/widgets/athlete_widgets/athlete_body_weight_widget.dart';
class OnBoardingBodyWeightScreen extends StatefulWidget {
const OnBoardingBodyWeightScreen({
Key key,
Key? key,
this.athlete,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_OnBoardingBodyWeightScreenState createState() =>
@ -64,14 +64,14 @@ class _OnBoardingBodyWeightScreenState
}
Future<void> getData() async {
final List<Weight> weights = await widget.athlete.weights;
print(weights.length);
final List<Weight> weights = await widget.athlete!.weights;
debugPrint(weights.length.toString());
setState(() => weightHasBeenEntered = weights.isNotEmpty);
}
Future<void> nextButton() async {
await widget.athlete.save();
print('OK');
await widget.athlete!.save();
debugPrint('OK');
Navigator.pushReplacement(
context,
MaterialPageRoute<BuildContext>(

View File

@ -1,7 +1,7 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart';
import '/actions/setupDemoAthlete.dart';
import '/actions/setup_demo_athlete.dart';
import '/models/athlete.dart';
import '/screens/onboarding_screens/onboarding_finished_screen.dart';
import '/screens/onboarding_screens/onboarding_strava_credentials_screen.dart';
@ -12,7 +12,7 @@ import '/utils/my_color.dart';
import 'onboarding_standalone_credentials_screen.dart';
class OnboardingCreateUserScreen extends StatefulWidget {
const OnboardingCreateUserScreen();
const OnboardingCreateUserScreen({Key? key}) : super(key: key);
@override
_OnboardingCreateUserScreenState createState() =>
@ -22,7 +22,7 @@ class OnboardingCreateUserScreen extends StatefulWidget {
class _OnboardingCreateUserScreenState
extends State<OnboardingCreateUserScreen> {
Athlete athlete = Athlete();
Flushbar<Object> flushbar;
Flushbar<Object>? flushbar;
@override
Widget build(BuildContext context) {

View File

@ -6,7 +6,7 @@ import '/utils/my_button_style.dart';
import '/utils/my_color.dart';
class OnboardingFinishedScreen extends StatelessWidget {
const OnboardingFinishedScreen();
const OnboardingFinishedScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -9,11 +9,11 @@ import '/widgets/athlete_widgets/athlete_heart_rate_zone_schema_widget.dart';
class OnBoardingHeartRateZoneSchemaScreen extends StatefulWidget {
const OnBoardingHeartRateZoneSchemaScreen({
Key key,
Key? key,
this.athlete,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_OnBoardingHeartRateZoneSchemaScreenState createState() =>
@ -71,13 +71,13 @@ class _OnBoardingHeartRateZoneSchemaScreenState
Future<void> getData() async {
final List<HeartRateZoneSchema> heartRateZoneSchemas =
await widget.athlete.heartRateZoneSchemas;
await widget.athlete!.heartRateZoneSchemas;
setState(() =>
heartRateZoneSchemaHasBeenEntered = heartRateZoneSchemas.isNotEmpty);
}
Future<void> nextButton() async {
await widget.athlete.save();
await widget.athlete!.save();
Navigator.pushReplacement(
context,
MaterialPageRoute<BuildContext>(

View File

@ -7,7 +7,7 @@ import 'introduction_text_screen.dart';
import 'onboarding_create_user.dart';
class OnboardingIntroductionScreen extends StatelessWidget {
const OnboardingIntroductionScreen();
const OnboardingIntroductionScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -44,7 +44,7 @@ class OnboardingIntroductionScreen extends StatelessWidget {
context,
MaterialPageRoute<BuildContext>(
builder: (BuildContext _) =>
IntroductionTextScreen(),
const IntroductionTextScreen(),
),
),
),

View File

@ -9,11 +9,11 @@ import '/widgets/athlete_widgets/athlete_power_zone_schema_widget.dart';
class OnBoardingPowerZoneSchemaScreen extends StatefulWidget {
const OnBoardingPowerZoneSchemaScreen({
Key key,
Key? key,
this.athlete,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_OnBoardingPowerZoneSchemaScreenState createState() =>
@ -70,12 +70,12 @@ class _OnBoardingPowerZoneSchemaScreenState
Future<void> getData() async {
final List<PowerZoneSchema> powerZoneSchemas =
await widget.athlete.powerZoneSchemas;
await widget.athlete!.powerZoneSchemas;
setState(() => powerZoneSchemaHasBeenEntered = powerZoneSchemas.isNotEmpty);
}
Future<void> nextButton() async {
await widget.athlete.save();
await widget.athlete!.save();
Navigator.pushReplacement(
context,
MaterialPageRoute<BuildContext>(

View File

@ -6,11 +6,11 @@ import '/widgets/athlete_widgets/edit_standalone_athlete_widget.dart';
class OnBoardingStandaloneCredentialsScreen extends StatelessWidget {
const OnBoardingStandaloneCredentialsScreen({
Key key,
Key? key,
this.athlete,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
Widget build(BuildContext context) {

View File

@ -6,8 +6,8 @@ import '/widgets/athlete_widgets/edit_strava_athlete_widget.dart';
class OnBoardingStravaCredentialsScreen extends StatelessWidget {
const OnBoardingStravaCredentialsScreen({
Key key,
@required this.athlete,
Key? key,
required this.athlete,
}) : super(key: key);
final Athlete athlete;

View File

@ -8,13 +8,13 @@ import '/utils/my_color.dart';
import '/widgets/charts/activity_charts/activity_intervals_chart.dart';
class SelectIntervalScreen extends StatefulWidget {
const SelectIntervalScreen({
@required this.activity,
@required this.athlete,
});
const SelectIntervalScreen({Key? key,
required this.activity,
required this.athlete,
}) : super(key: key);
final Activity activity;
final Athlete athlete;
final Activity? activity;
final Athlete? athlete;
@override
_SelectIntervalScreenState createState() => _SelectIntervalScreenState();
@ -33,7 +33,7 @@ class _SelectIntervalScreenState extends State<SelectIntervalScreen> {
Widget build(BuildContext context) {
if (records.isNotEmpty) {
final List<Event> paceRecords = records
.where((Event value) => value.speed != null && value.speed > 0)
.where((Event value) => value.speed != null && value.speed! > 0)
.toList();
return Scaffold(
@ -46,12 +46,12 @@ class _SelectIntervalScreenState extends State<SelectIntervalScreen> {
records: RecordList<Event>(paceRecords),
activity: widget.activity,
athlete: widget.athlete,
minimum: widget.activity.avgSpeed * 3.6 / 2,
maximum: widget.activity.avgSpeed * 3.6 * 2,
minimum: widget.activity!.avgSpeed! * 3.6 / 2,
maximum: widget.activity!.avgSpeed! * 3.6 * 2,
),
),
);
} else
} else {
return Scaffold(
appBar: AppBar(
backgroundColor: MyColor.settings,
@ -59,10 +59,11 @@ class _SelectIntervalScreenState extends State<SelectIntervalScreen> {
),
body: const Text('Loading...'),
);
}
}
Future<void> getData() async {
records = RecordList<Event>(await widget.activity.records);
records = RecordList<Event>(await widget.activity!.records);
setState(() {});
}
}

View File

@ -5,17 +5,17 @@ import '/utils/my_color.dart';
class ShowActivityDetailScreen extends StatelessWidget {
const ShowActivityDetailScreen({
Key key,
Key? key,
this.activity,
this.widget,
this.title,
this.backgroundColor,
}) : super(key: key);
final Activity activity;
final Widget widget;
final String title;
final Color backgroundColor;
final Activity? activity;
final Widget? widget;
final String? title;
final Color? backgroundColor;
@override
Widget build(BuildContext context) {
@ -23,11 +23,11 @@ class ShowActivityDetailScreen extends StatelessWidget {
appBar: AppBar(
backgroundColor: backgroundColor ?? MyColor.activity,
title: Text(
'$title: ${activity.name}',
'$title: ${activity!.name}',
overflow: TextOverflow.ellipsis,
),
),
body: SafeArea(child: widget),
body: SafeArea(child: widget!),
);
}
}

View File

@ -39,13 +39,13 @@ import '/widgets/laps_list_widget.dart';
class ShowActivityScreen extends StatefulWidget {
const ShowActivityScreen({
Key key,
@required this.activity,
@required this.athlete,
Key? key,
required this.activity,
required this.athlete,
}) : super(key: key);
final Activity activity;
final Athlete athlete;
final Activity? activity;
final Athlete? athlete;
@override
_ShowActivityScreenState createState() => _ShowActivityScreenState();
@ -53,7 +53,7 @@ class ShowActivityScreen extends StatefulWidget {
class _ShowActivityScreenState extends State<ShowActivityScreen> {
Flushbar<Object> flushbar = Flushbar<Object>();
Weight weight;
Weight? weight;
List<Widget> get tiles {
return <Widget>[
@ -77,7 +77,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.cachedLaps.isNotEmpty)
if (widget.activity!.cachedLaps.isNotEmpty)
navigationButton(
title: 'Laps List',
color: MyColor.lap,
@ -111,7 +111,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.heartRateAvailable)
if (widget.activity!.heartRateAvailable)
navigationButton(
title: 'Heart Rate',
color: MyColor.navigate,
@ -122,7 +122,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.powerAvailable)
if (widget.activity!.powerAvailable)
navigationButton(
title: 'Power',
color: MyColor.navigate,
@ -133,7 +133,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.powerAvailable)
if (widget.activity!.powerAvailable)
navigationButton(
title: 'Power Duration',
color: MyColor.navigate,
@ -144,7 +144,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.powerAvailable && widget.activity.heartRateAvailable)
if (widget.activity!.powerAvailable && widget.activity!.heartRateAvailable)
navigationButton(
title: 'Power / Heart Rate',
color: MyColor.navigate,
@ -155,7 +155,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.paceAvailable)
if (widget.activity!.paceAvailable)
navigationButton(
title: 'Pace',
color: MyColor.navigate,
@ -166,7 +166,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.speedAvailable)
if (widget.activity!.speedAvailable)
navigationButton(
title: 'Speed',
color: MyColor.navigate,
@ -178,7 +178,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.ecorAvailable)
if (widget.activity!.ecorAvailable)
navigationButton(
title: 'Ecor',
color: MyColor.navigate,
@ -189,7 +189,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.speedAvailable)
if (widget.activity!.speedAvailable)
navigationButton(
title: 'Speed / Heart Rate',
color: MyColor.navigate,
@ -200,7 +200,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.groundTimeAvailable)
if (widget.activity!.groundTimeAvailable)
navigationButton(
title: 'Ground Time',
color: MyColor.navigate,
@ -211,7 +211,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.formPowerAvailable)
if (widget.activity!.formPowerAvailable)
navigationButton(
title: 'Form Power',
color: MyColor.navigate,
@ -222,7 +222,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.powerRatioAvailable)
if (widget.activity!.powerRatioAvailable)
navigationButton(
title: 'Power Ratio',
color: MyColor.navigate,
@ -233,7 +233,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.verticalOscillationAvailable)
if (widget.activity!.verticalOscillationAvailable)
navigationButton(
title: 'Vertical Oscillation',
color: MyColor.navigate,
@ -244,7 +244,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.strideRatioAvailable)
if (widget.activity!.strideRatioAvailable)
navigationButton(
title: 'Stride Ratio',
color: MyColor.navigate,
@ -255,7 +255,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.strideCadenceAvailable)
if (widget.activity!.strideCadenceAvailable)
navigationButton(
title: 'Cadence',
color: MyColor.navigate,
@ -266,7 +266,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.legSpringStiffnessAvailable)
if (widget.activity!.legSpringStiffnessAvailable)
navigationButton(
title: 'Leg Spring Stiffness',
color: MyColor.navigate,
@ -277,7 +277,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (widget.activity.powerAvailable)
if (widget.activity!.powerAvailable)
navigationButton(
title: 'FTP',
color: MyColor.navigate,
@ -288,7 +288,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
athlete: widget.athlete,
),
),
if (kDebugMode && widget.activity.powerAvailable)
if (kDebugMode && widget.activity!.powerAvailable)
navigationButton(
title: 'Work / CP',
color: MyColor.navigate,
@ -340,7 +340,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
onPressed: () => autoTagger(),
),
if (<String>['new', 'downloaded', 'persisted']
.contains(widget.activity.state))
.contains(widget.activity!.state))
ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.add,
@ -351,7 +351,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
),
onPressed: () => download(),
),
if (<String>['downloaded', 'persisted'].contains(widget.activity.state))
if (<String>['downloaded', 'persisted'].contains(widget.activity!.state))
ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.add,
@ -362,7 +362,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
),
onPressed: () => parse(),
),
if (widget.activity.excluded == true)
if (widget.activity!.excluded == true)
ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.include,
@ -404,7 +404,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
),
),
if (<String>['new', 'downloaded', 'persisted']
.contains(widget.activity.state))
.contains(widget.activity!.state))
ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.delete,
@ -430,7 +430,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
appBar: AppBar(
backgroundColor: MyColor.activity,
title: Text(
widget.activity.name ?? '',
widget.activity!.name ?? '',
overflow: TextOverflow.ellipsis,
),
),
@ -450,12 +450,12 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
}
Widget navigationButton({
@required BuildContext context,
@required Widget nextWidget,
@required Widget icon,
@required String title,
@required Color color,
Color backgroundColor,
required BuildContext context,
required Widget nextWidget,
required Widget icon,
required String title,
required Color color,
Color? backgroundColor,
}) {
return ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
@ -485,7 +485,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
icon: MyIcon.stravaDownloadWhite,
)..show(context);
await widget.activity.autoTagger(athlete: widget.athlete);
await widget.activity!.autoTagger(athlete: widget.athlete);
await flushbar.dismiss();
flushbar = Flushbar<Object>(
@ -497,30 +497,30 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
}
Future<void> exclude() async {
widget.activity.excluded = true;
await widget.activity.save();
widget.activity!.excluded = true;
await widget.activity!.save();
setState(() {});
}
Future<void> include() async {
widget.activity.excluded = false;
await widget.activity.save();
widget.activity!.excluded = false;
await widget.activity!.save();
setState(() {});
}
Future<void> delete() async {
await widget.activity.delete();
await widget.activity!.delete();
Navigator.of(context).pop();
}
Future<void> download() async {
flushbar = Flushbar<Object>(
message: 'Download .fit-File for »${widget.activity.name}«',
message: 'Download .fit-File for »${widget.activity!.name}«',
duration: const Duration(seconds: 10),
icon: MyIcon.stravaDownloadWhite,
)..show(context);
await widget.activity.download(athlete: widget.athlete);
await widget.activity!.download(athlete: widget.athlete);
await flushbar.dismiss();
flushbar = Flushbar<Object>(
@ -531,7 +531,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
await parse();
flushbar = Flushbar<Object>(
message: 'Analysis finished for »${widget.activity.name}«',
message: 'Analysis finished for »${widget.activity!.name}«',
duration: const Duration(seconds: 2),
animationDuration: const Duration(milliseconds: 0),
)..show(context);
@ -539,21 +539,21 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
Future<void> parse() async {
Flushbar<Object> flushbar = Flushbar<Object>(
message: '0% of storing »${widget.activity.name}«',
message: '0% of storing »${widget.activity!.name}«',
duration: const Duration(seconds: 10),
animationDuration: const Duration(milliseconds: 0),
titleText: const LinearProgressIndicator(value: 0),
)..show(context);
final Stream<int> percentageStream =
widget.activity.parse(athlete: widget.athlete);
widget.activity!.parse(athlete: widget.athlete);
await for (final int value in percentageStream) {
if (value == -2)
await flushbar?.dismiss();
else if (value == -1) {
await flushbar?.dismiss();
if (value == -2) {
await flushbar.dismiss();
} else if (value == -1) {
await flushbar.dismiss();
flushbar = Flushbar<Object>(
message: 'Analysing »${widget.activity.name}«',
message: 'Analysing »${widget.activity!.name}«',
duration: const Duration(seconds: 1),
animationDuration: const Duration(milliseconds: 0),
)..show(context);
@ -561,7 +561,7 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
await flushbar.dismiss();
flushbar = Flushbar<Object>(
titleText: LinearProgressIndicator(value: value / 100),
message: '$value% of storing »${widget.activity.name}«',
message: '$value% of storing »${widget.activity!.name}«',
duration: const Duration(seconds: 3),
animationDuration: const Duration(milliseconds: 0),
)..show(context);
@ -571,8 +571,8 @@ class _ShowActivityScreenState extends State<ShowActivityScreen> {
}
Future<void> getData() async {
await widget.activity.laps;
await widget.activity.weight;
await widget.activity!.laps;
await widget.activity!.weight;
setState(() {});
}
}

View File

@ -5,17 +5,17 @@ import '/utils/my_color.dart';
class ShowAthleteDetailScreen extends StatelessWidget {
const ShowAthleteDetailScreen({
Key key,
Key? key,
this.athlete,
this.widget,
this.title,
this.backgroundColor,
}) : super(key: key);
final Athlete athlete;
final Widget widget;
final String title;
final Color backgroundColor;
final Athlete? athlete;
final Widget? widget;
final String? title;
final Color? backgroundColor;
@override
Widget build(BuildContext context) {
@ -23,11 +23,11 @@ class ShowAthleteDetailScreen extends StatelessWidget {
appBar: AppBar(
backgroundColor: backgroundColor ?? MyColor.athlete,
title: Text(
'$title: ${athlete.firstName} ${athlete.lastName}',
'$title: ${athlete!.firstName} ${athlete!.lastName}',
overflow: TextOverflow.ellipsis,
),
),
body: SafeArea(child: widget),
body: SafeArea(child: widget!),
);
}
}

View File

@ -41,11 +41,11 @@ import 'edit_athlete_screen.dart';
class ShowAthleteScreen extends StatefulWidget {
const ShowAthleteScreen({
Key key,
Key? key,
this.athlete,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_ShowAthleteScreenState createState() => _ShowAthleteScreenState();
@ -53,8 +53,8 @@ class ShowAthleteScreen extends StatefulWidget {
class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
Flushbar<Object> flushbar = Flushbar<Object>();
Visibility floatingActionButton;
bool floatingActionButtonVisible;
Visibility? floatingActionButton;
late bool floatingActionButtonVisible;
List<Widget> get tiles {
return <Widget>[
@ -174,7 +174,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
onPressed: () async {
await importActivitiesLocally(
context: context,
athlete: widget.athlete,
athlete: widget.athlete!,
flushbar: flushbar,
);
},
@ -206,7 +206,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(color: MyColor.activity),
icon: MyIcon.addActivity,
onPressed: () => goToEditActivityScreen(athlete: widget.athlete),
onPressed: () => goToEditActivityScreen(athlete: widget.athlete!),
label: const Expanded(
child: Text('Create Activity manually'),
),
@ -214,7 +214,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(color: MyColor.settings),
icon: MyIcon.secrets,
onPressed: () => goToEditAthleteScreen(athlete: widget.athlete),
onPressed: () => goToEditAthleteScreen(athlete: widget.athlete!),
label: const Expanded(
child: Text('Credentials'),
),
@ -249,7 +249,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
),
onPressed: () => analyseActivities(
context: context,
athlete: widget.athlete,
athlete: widget.athlete!,
flushbar: flushbar,
),
),
@ -263,7 +263,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
),
onPressed: () => autoTagging(
context: context,
athlete: widget.athlete,
athlete: widget.athlete!,
flushbar: flushbar,
),
),
@ -275,11 +275,11 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
),
onPressed: () => downloadDemoData(
context: context,
athlete: widget.athlete,
athlete: widget.athlete!,
flushbar: flushbar,
),
),
if (widget.athlete.stravaId != null)
if (widget.athlete!.stravaId != null)
ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.settings,
@ -290,7 +290,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
child: Text('Delete Strava Token'),
),
onPressed: () async {
await strava_token.delete(athlete: widget.athlete);
await strava_token.delete(athlete: widget.athlete!);
setState(() {});
}),
];
@ -299,7 +299,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
@override
void initState() {
floatingActionButtonVisible =
widget.athlete.email != null && widget.athlete.password != null;
widget.athlete!.email != null && widget.athlete!.password != null;
super.initState();
}
@ -309,7 +309,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
appBar: AppBar(
backgroundColor: MyColor.athlete,
title: Text(
'${widget.athlete.firstName} ${widget.athlete.lastName}',
'${widget.athlete!.firstName} ${widget.athlete!.lastName}',
overflow: TextOverflow.ellipsis,
),
),
@ -320,7 +320,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
setState(() => floatingActionButtonVisible = false);
updateJob(
context: context,
athlete: widget.athlete,
athlete: widget.athlete!,
flushbar: flushbar,
);
setState(() => floatingActionButtonVisible = true);
@ -345,15 +345,15 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
}
Widget navigationButton({
@required Widget nextWidget,
@required Widget icon,
@required String title,
@required Color color,
Color backgroundColor,
required Widget nextWidget,
required Widget icon,
required String title,
required Color color,
Color? backgroundColor,
}) {
return ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: color ?? MyColor.primary,
color: color,
textColor: MyColor.textColor(backgroundColor: color)),
icon: icon,
label: Expanded(
@ -373,7 +373,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
);
}
Future<void> goToEditAthleteScreen({@required Athlete athlete}) async {
Future<void> goToEditAthleteScreen({required Athlete athlete}) async {
await athlete.readCredentials();
await Navigator.push(
context,
@ -383,7 +383,7 @@ class _ShowAthleteScreenState extends State<ShowAthleteScreen> {
);
}
Future<void> goToEditActivityScreen({@required Athlete athlete}) async {
Future<void> goToEditActivityScreen({required Athlete athlete}) async {
final Activity activity = Activity.manual(athlete: athlete);
await Navigator.push(
context,

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import '/models/event.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/my_button.dart';
import '/utils/my_color.dart';
@ -9,33 +9,33 @@ import 'edit_event_screen.dart';
class ShowEventScreen extends StatelessWidget {
const ShowEventScreen({
Key key,
Key? key,
this.record,
}) : super(key: key);
final Event record;
final Event? record;
List<Widget> tiles({@required BuildContext context}) {
List<Widget> tiles({required BuildContext context}) {
return <Widget>[
ListTile(
title: Text(record.event),
title: Text(record!.event!),
subtitle: const Text('Event'),
),
ListTile(
title: PQText(value: record.eventType, pq: PQ.text),
title: PQText(value: record!.eventType, pq: PQ.text),
subtitle: const Text('Event Type'),
),
ListTile(
title: PQText(value: record.eventGroup, pq: PQ.integer),
title: PQText(value: record!.eventGroup, pq: PQ.integer),
subtitle: const Text('Event Group'),
),
ListTile(
title: PQText(value: record.timerTrigger, pq: PQ.text),
title: PQText(value: record!.timerTrigger, pq: PQ.text),
subtitle: const Text('Timer Trigger'),
),
ListTile(
title: PQText(
value: record.timeStamp,
value: record!.timeStamp,
pq: PQ.dateTime,
format: DateTimeFormat.longDateTime,
),
@ -43,112 +43,112 @@ class ShowEventScreen extends StatelessWidget {
),
ListTile(
title: PQText(
value: record.timeStamp.toString(),
value: record!.timeStamp.toString(),
pq: PQ.text,
),
subtitle: const Text('Time Stamp'),
),
ListTile(
title: PQText(
value: record.positionLat,
value: record!.positionLat,
pq: PQ.latitude,
),
subtitle: const Text('Latitude'),
),
ListTile(
title: PQText(
value: record.positionLong,
value: record!.positionLong,
pq: PQ.longitude,
),
subtitle: const Text('Longitude'),
),
ListTile(
title: PQText(
value: record.distance,
value: record!.distance,
pq: PQ.distanceInMeters,
),
subtitle: const Text('Distance'),
),
ListTile(
title: PQText(
value: record.altitude,
value: record!.altitude,
pq: PQ.elevation,
),
subtitle: const Text('Altitude'),
),
ListTile(
title: PQText(
value: record.speed,
value: record!.speed,
pq: PQ.speed,
),
subtitle: const Text('Speed'),
),
ListTile(
title: PQText(
value: record.heartRate,
value: record!.heartRate,
pq: PQ.heartRate,
),
subtitle: const Text('Heart Rate'),
),
ListTile(
title: PQText(
value: record.cadence,
value: record!.cadence,
pq: PQ.cadence,
),
subtitle: const Text('Cadence'),
),
ListTile(
title: PQText(
value: record.fractionalCadence,
value: record!.fractionalCadence,
pq: PQ.percentage,
),
subtitle: const Text('Fractional Cadence'),
),
ListTile(
title: PQText(
value: record.power,
value: record!.power,
pq: PQ.power,
),
subtitle: const Text('Power'),
),
ListTile(
title: PQText(
value: record.strydCadence,
value: record!.strydCadence,
pq: PQ.cadence,
),
subtitle: const Text('Stryd Cadence'),
),
ListTile(
title: PQText(
value: record.groundTime,
value: record!.groundTime,
pq: PQ.groundTime,
),
subtitle: const Text('Ground Time'),
),
ListTile(
title: PQText(
value: record.verticalOscillation,
value: record!.verticalOscillation,
pq: PQ.verticalOscillation,
),
subtitle: const Text('Vertical Oscillation'),
),
ListTile(
title: PQText(
value: record.formPower,
value: record!.formPower,
pq: PQ.power,
),
subtitle: const Text('Form Power'),
),
ListTile(
title: PQText(
value: record.legSpringStiffness,
value: record!.legSpringStiffness,
pq: PQ.legSpringStiffness,
),
subtitle: const Text('Leg Spring Stiffness'),
),
ListTile(
title: PQText(
value: record.data,
value: record!.data,
pq: PQ.integer,
),
subtitle: const Text('Data'),
@ -169,8 +169,8 @@ class ShowEventScreen extends StatelessWidget {
return Scaffold(
appBar: AppBar(
backgroundColor: MyColor.activity,
title: Text('Event ${record.timeStamp.toString()} /'
' ${record.distance} m')),
title: Text('Event ${record!.timeStamp.toString()} /'
' ${record!.distance} m')),
body: SafeArea(
child: GridView.count(
mainAxisSpacing: 4,

View File

@ -5,16 +5,16 @@ import '/utils/my_color.dart';
class ShowIntervalDetailScreen extends StatefulWidget {
const ShowIntervalDetailScreen({
Key key,
@required this.interval,
@required this.intervals,
@required this.nextWidget,
@required this.title,
Key? key,
required this.interval,
required this.intervals,
required this.nextWidget,
required this.title,
}) : super(key: key);
final encrateia.Interval interval;
final List<encrateia.Interval> intervals;
final Widget Function({encrateia.Interval interval}) nextWidget;
final List<encrateia.Interval?> intervals;
final Widget Function({encrateia.Interval? interval}) nextWidget;
final String title;
@override
@ -23,9 +23,9 @@ class ShowIntervalDetailScreen extends StatefulWidget {
}
class _ShowIntervalDetailScreenState extends State<ShowIntervalDetailScreen> {
encrateia.Interval currentInterval;
encrateia.Interval? currentInterval;
double dragAmount = 0;
int currentIntervalIndex;
late int currentIntervalIndex;
@override
void initState() {
@ -48,7 +48,7 @@ class _ShowIntervalDetailScreenState extends State<ShowIntervalDetailScreen> {
child: GestureDetector(
child: widget.nextWidget(interval: currentInterval),
onHorizontalDragUpdate: (DragUpdateDetails details) {
dragAmount = dragAmount + details.primaryDelta;
dragAmount = dragAmount + details.primaryDelta!;
},
onHorizontalDragEnd: (DragEndDetails details) {
if (dragAmount < -50) {

View File

@ -24,26 +24,26 @@ import '/widgets/interval_widgets/interval_vertical_oscillation_widget.dart';
class ShowIntervalScreen extends StatelessWidget {
const ShowIntervalScreen({
Key key,
@required this.interval,
@required this.intervals,
@required this.activity,
@required this.athlete,
Key? key,
required this.interval,
required this.intervals,
required this.activity,
required this.athlete,
}) : super(key: key);
final encrateia.Interval interval;
final List<encrateia.Interval> intervals;
final Athlete athlete;
final Activity activity;
final Athlete? athlete;
final Activity? activity;
List<Widget> tiles({@required BuildContext context}) {
List<Widget> tiles({required BuildContext context}) {
return <Widget>[
navigationButton(
title: 'Overview',
color: MyColor.settings,
icon: MyIcon.metaData,
context: context,
nextWidget: ({encrateia.Interval interval}) => IntervalOverviewWidget(
nextWidget: ({encrateia.Interval? interval}) => IntervalOverviewWidget(
interval: interval,
athlete: athlete,
),
@ -54,7 +54,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.heartRate,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalHeartRateWidget(interval: interval),
),
if (interval.powerAvailable)
@ -63,7 +63,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.power,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalPowerWidget(interval: interval),
),
if (interval.powerAvailable)
@ -72,7 +72,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.powerDuration,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalPowerDurationWidget(interval: interval),
),
if (interval.paceAvailable)
@ -81,7 +81,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.speed,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalPaceWidget(interval: interval),
),
if (interval.speedAvailable)
@ -90,7 +90,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.speed,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalSpeedWidget(interval: interval),
),
if (interval.speedAvailable && interval.powerAvailable)
@ -99,7 +99,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.power,
context: context,
nextWidget: ({encrateia.Interval interval}) => IntervalEcorWidget(
nextWidget: ({encrateia.Interval? interval}) => IntervalEcorWidget(
interval: interval,
athlete: athlete,
),
@ -110,7 +110,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.groundTime,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalGroundTimeWidget(interval: interval),
),
if (interval.groundTimeAvailable)
@ -119,7 +119,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.legSpringStiffness,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalLegSpringStiffnessWidget(interval: interval),
),
if (interval.formPowerAvailable)
@ -128,7 +128,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.formPower,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalFormPowerWidget(interval: interval),
),
if (interval.cadenceAvailable)
@ -137,7 +137,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.cadence,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalStrydCadenceWidget(interval: interval),
),
if (interval.verticalOscillationAvailable)
@ -146,7 +146,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.verticalOscillation,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalVerticalOscillationWidget(interval: interval),
),
navigationButton(
@ -154,7 +154,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.altitude,
context: context,
nextWidget: ({encrateia.Interval interval}) =>
nextWidget: ({encrateia.Interval? interval}) =>
IntervalAltitudeWidget(interval: interval),
),
navigationButton(
@ -162,7 +162,7 @@ class ShowIntervalScreen extends StatelessWidget {
color: MyColor.tag,
icon: MyIcon.tag,
context: context,
nextWidget: ({encrateia.Interval interval}) => IntervalTagWidget(
nextWidget: ({encrateia.Interval? interval}) => IntervalTagWidget(
interval: interval,
athlete: athlete,
),
@ -177,7 +177,7 @@ class ShowIntervalScreen extends StatelessWidget {
),
onPressed: () async {
await interval.delete();
activity.cachedIntervals = <encrateia.Interval>[];
activity!.cachedIntervals = <encrateia.Interval>[];
Navigator.of(context).pop();
},
),
@ -210,15 +210,15 @@ class ShowIntervalScreen extends StatelessWidget {
}
Widget navigationButton({
@required BuildContext context,
@required Widget Function({encrateia.Interval interval}) nextWidget,
@required Widget icon,
@required String title,
@required Color color,
required BuildContext context,
required Widget Function({encrateia.Interval? interval}) nextWidget,
required Widget icon,
required String title,
required Color color,
}) {
return ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: color ?? MyColor.primary,
color: color,
textColor: MyColor.textColor(backgroundColor: color)),
icon: icon,
label: Expanded(

View File

@ -5,16 +5,16 @@ import '/utils/my_color.dart';
class ShowLapDetailScreen extends StatefulWidget {
const ShowLapDetailScreen({
Key key,
@required this.lap,
@required this.laps,
@required this.nextWidget,
@required this.title,
Key? key,
required this.lap,
required this.laps,
required this.nextWidget,
required this.title,
}) : super(key: key);
final Lap lap;
final List<Lap> laps;
final Widget Function({Lap lap}) nextWidget;
final Widget Function({Lap? lap}) nextWidget;
final String title;
@override
@ -22,7 +22,7 @@ class ShowLapDetailScreen extends StatefulWidget {
}
class _ShowLapDetailScreenState extends State<ShowLapDetailScreen> {
Lap currentLap;
Lap? currentLap;
double dragAmount = 0;
@override
@ -37,7 +37,7 @@ class _ShowLapDetailScreenState extends State<ShowLapDetailScreen> {
appBar: AppBar(
backgroundColor: MyColor.lap,
title: Text(
'Lap ${currentLap.index.toString()}: ${widget.title}',
'Lap ${currentLap!.index.toString()}: ${widget.title}',
overflow: TextOverflow.ellipsis,
),
),
@ -45,20 +45,20 @@ class _ShowLapDetailScreenState extends State<ShowLapDetailScreen> {
child: GestureDetector(
child: widget.nextWidget(lap: currentLap),
onHorizontalDragUpdate: (DragUpdateDetails details) {
dragAmount = dragAmount + details.primaryDelta;
dragAmount = dragAmount + details.primaryDelta!;
},
onHorizontalDragEnd: (DragEndDetails details) {
if (dragAmount < -50) {
dragAmount = 0;
if (currentLap.index < widget.laps.length) {
if (currentLap!.index! < widget.laps.length) {
setState(
() => currentLap = widget.laps[currentLap.index - 1 + 1]);
() => currentLap = widget.laps[currentLap!.index! - 1 + 1]);
}
} else if (dragAmount > 50) {
dragAmount = 0;
if (currentLap.index > 1) {
if (currentLap!.index! > 1) {
setState(
() => currentLap = widget.laps[currentLap.index - 1 - 1]);
() => currentLap = widget.laps[currentLap!.index! - 1 - 1]);
}
}
},

View File

@ -24,24 +24,24 @@ import '/widgets/lap_widgets/lap_vertical_oscillation_widget.dart';
class ShowLapScreen extends StatelessWidget {
const ShowLapScreen({
Key key,
@required this.lap,
@required this.laps,
@required this.athlete,
Key? key,
required this.lap,
required this.laps,
required this.athlete,
}) : super(key: key);
final Lap lap;
final List<Lap> laps;
final Athlete athlete;
final Athlete? athlete;
List<Widget> tiles({@required BuildContext context}) {
List<Widget> tiles({required BuildContext context}) {
return <Widget>[
navigationButton(
title: 'Overview',
color: MyColor.settings,
icon: MyIcon.metaData,
context: context,
nextWidget: ({Lap lap}) =>
nextWidget: ({Lap? lap}) =>
LapOverviewWidget(lap: lap, athlete: athlete),
),
if (lap.heartRateAvailable)
@ -50,7 +50,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.heartRate,
context: context,
nextWidget: ({Lap lap}) => LapHeartRateWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapHeartRateWidget(lap: lap),
),
if (lap.powerAvailable)
navigationButton(
@ -58,7 +58,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.power,
context: context,
nextWidget: ({Lap lap}) => LapPowerWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapPowerWidget(lap: lap),
),
if (lap.powerAvailable)
navigationButton(
@ -66,7 +66,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.powerDuration,
context: context,
nextWidget: ({Lap lap}) => LapPowerDurationWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapPowerDurationWidget(lap: lap),
),
if (lap.paceAvailable)
navigationButton(
@ -74,7 +74,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.speed,
context: context,
nextWidget: ({Lap lap}) => LapPaceWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapPaceWidget(lap: lap),
),
if (lap.speedAvailable)
navigationButton(
@ -82,7 +82,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.speed,
context: context,
nextWidget: ({Lap lap}) => LapSpeedWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapSpeedWidget(lap: lap),
),
if (lap.speedAvailable && lap.powerAvailable)
navigationButton(
@ -90,7 +90,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.power,
context: context,
nextWidget: ({Lap lap}) => LapEcorWidget(
nextWidget: ({Lap? lap}) => LapEcorWidget(
lap: lap,
athlete: athlete,
),
@ -101,7 +101,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.groundTime,
context: context,
nextWidget: ({Lap lap}) => LapGroundTimeWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapGroundTimeWidget(lap: lap),
),
if (lap.groundTimeAvailable)
navigationButton(
@ -109,7 +109,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.legSpringStiffness,
context: context,
nextWidget: ({Lap lap}) => LapLegSpringStiffnessWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapLegSpringStiffnessWidget(lap: lap),
),
if (lap.formPowerAvailable)
navigationButton(
@ -117,7 +117,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.formPower,
context: context,
nextWidget: ({Lap lap}) => LapFormPowerWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapFormPowerWidget(lap: lap),
),
if (lap.cadenceAvailable)
navigationButton(
@ -125,7 +125,7 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.cadence,
context: context,
nextWidget: ({Lap lap}) => LapStrydCadenceWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapStrydCadenceWidget(lap: lap),
),
if (lap.verticalOscillationAvailable)
navigationButton(
@ -133,28 +133,28 @@ class ShowLapScreen extends StatelessWidget {
color: MyColor.navigate,
icon: MyIcon.verticalOscillation,
context: context,
nextWidget: ({Lap lap}) => LapVerticalOscillationWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapVerticalOscillationWidget(lap: lap),
),
navigationButton(
title: 'Altitude',
color: MyColor.navigate,
icon: MyIcon.altitude,
context: context,
nextWidget: ({Lap lap}) => LapAltitudeWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapAltitudeWidget(lap: lap),
),
navigationButton(
title: 'Metadata',
color: MyColor.settings,
icon: MyIcon.metaData,
context: context,
nextWidget: ({Lap lap}) => LapMetadataWidget(lap: lap),
nextWidget: ({Lap? lap}) => LapMetadataWidget(lap: lap),
),
navigationButton(
title: 'Tags',
color: MyColor.tag,
icon: MyIcon.tag,
context: context,
nextWidget: ({Lap lap}) => LapTagWidget(
nextWidget: ({Lap? lap}) => LapTagWidget(
lap: lap,
athlete: athlete,
),
@ -188,15 +188,15 @@ class ShowLapScreen extends StatelessWidget {
}
Widget navigationButton({
@required BuildContext context,
@required Widget Function({Lap lap}) nextWidget,
@required Widget icon,
@required String title,
@required Color color,
required BuildContext context,
required Widget Function({Lap? lap}) nextWidget,
required Widget icon,
required String title,
required Color color,
}) {
return ElevatedButton.icon(
style: MyButtonStyle.raisedButtonStyle(
color: color ?? MyColor.primary,
color: color,
textColor: MyColor.textColor(backgroundColor: color)),
icon: icon,
label: Expanded(

View File

@ -1,17 +1,17 @@
import 'package:flutter/material.dart';
import '/models/log.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/my_color.dart';
class ShowLogDetailScreen extends StatelessWidget {
const ShowLogDetailScreen({
Key key,
Key? key,
this.log,
}) : super(key: key);
final Log log;
final Log? log;
@override
Widget build(BuildContext context) {
@ -24,26 +24,26 @@ class ShowLogDetailScreen extends StatelessWidget {
children: <Widget>[
ListTile(
title: PQText(
value: log.dateTime,
value: log!.dateTime,
pq: PQ.dateTime,
format: DateTimeFormat.longDateTime,
),
subtitle: const Text('Point in Time'),
),
ListTile(
title: Text(log.message),
title: Text(log!.message!),
subtitle: const Text('Message'),
),
ListTile(
title: Text(log.method),
title: Text(log!.method!),
subtitle: const Text('Method'),
),
ListTile(
title: Text(log.comment),
title: Text(log!.comment!),
subtitle: const Text('Comment'),
),
ListTile(
title: Text(log.stackTrace),
title: Text(log!.stackTrace!),
subtitle: const Text('stacktrace'),
),
],

View File

@ -7,9 +7,9 @@ import '/utils/my_button.dart';
import '/utils/my_color.dart';
class ShowTagGroupScreen extends StatefulWidget {
const ShowTagGroupScreen({Key key, this.tagGroup}) : super(key: key);
const ShowTagGroupScreen({Key? key, this.tagGroup}) : super(key: key);
final TagGroup tagGroup;
final TagGroup? tagGroup;
@override
_AddTagGroupScreenState createState() => _AddTagGroupScreenState();
@ -18,7 +18,7 @@ class ShowTagGroupScreen extends StatefulWidget {
class _AddTagGroupScreenState extends State<ShowTagGroupScreen> {
List<Tag> tags = <Tag>[];
int offset = 0;
int rows;
int? rows;
@override
void initState() {
@ -39,7 +39,7 @@ class _AddTagGroupScreenState extends State<ShowTagGroupScreen> {
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
initialValue: widget.tagGroup.name,
initialValue: widget.tagGroup!.name,
readOnly: true,
),
const SizedBox(height: 20),
@ -47,7 +47,7 @@ class _AddTagGroupScreenState extends State<ShowTagGroupScreen> {
const Text('Color'),
const Spacer(),
CircleAvatar(
backgroundColor: Color(widget.tagGroup.color),
backgroundColor: Color(widget.tagGroup!.color!),
radius: 20.0,
),
const Spacer(),
@ -64,13 +64,13 @@ class _AddTagGroupScreenState extends State<ShowTagGroupScreen> {
],
rows: tags.map((Tag tag) {
return DataRow(
key: ValueKey<int>(tag.id),
key: ValueKey<int?>(tag.id),
cells: <DataCell>[
DataCell(Text(tag.name)),
DataCell(Text(tag.name!)),
DataCell(CircleColor(
circleSize: 20,
elevation: 0,
color: Color(tag.color),
color: Color(tag.color!),
)),
],
);
@ -91,7 +91,7 @@ class _AddTagGroupScreenState extends State<ShowTagGroupScreen> {
}
Future<void> getData() async {
tags = await widget.tagGroup.tags;
tags = await widget.tagGroup!.tags;
setState(() {});
}
}

View File

@ -8,9 +8,9 @@ import '/secrets/secrets.dart';
import '/utils/my_color.dart';
class StravaGetUser extends StatefulWidget {
const StravaGetUser({this.athlete});
const StravaGetUser({Key? key, this.athlete}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_StravaGetUserState createState() => _StravaGetUserState();
@ -33,11 +33,9 @@ class _StravaGetUserState extends State<StravaGetUser> {
backgroundColor: MyColor.primary,
),
body: SafeArea(
child: Container(
child: Padding(
padding: const EdgeInsets.all(20),
child: Text(widget.athlete.stateText),
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Text(widget.athlete!.stateText),
),
),
);
@ -56,15 +54,15 @@ class _StravaGetUserState extends State<StravaGetUser> {
final DetailedAthlete stravaAthlete =
await stravaClient.athletes.getAuthenticatedAthlete();
await widget.athlete.updateFromStravaAthlete(stravaAthlete);
await widget.athlete!.updateFromStravaAthlete(stravaAthlete);
}
Future<void> getData() async {
if (widget.athlete.firstName == null) {
if (widget.athlete!.firstName == null) {
await loginToStrava();
setState(() {});
}
if (widget.athlete.state == 'fromStrava') {
if (widget.athlete!.state == 'fromStrava') {
Navigator.of(context).pop();
}
}

View File

@ -13,7 +13,7 @@ Future<void> setup() async {
Future<void> _createHintFile() async {
if (Platform.isAndroid) {
final List<Directory> directories = await getExternalStorageDirectories();
final List<Directory> directories = await (getExternalStorageDirectories() as Future<List<Directory>>);
final File hintFile =
File('${directories[0].path}/put_your_fit_files_here.txt');
await hintFile.writeAsString(

View File

@ -6,25 +6,25 @@ import '/models/athlete.dart';
import '/utils/enums.dart';
class AthleteScatterChart extends StatefulWidget {
const AthleteScatterChart({
@required this.athlete,
@required this.activities,
@required this.firstAttr,
@required this.secondAttr,
@required this.chartTitleText,
@required this.firstAxesText,
@required this.secondAxesText,
const AthleteScatterChart({Key? key,
required this.athlete,
required this.activities,
required this.firstAttr,
required this.secondAttr,
required this.chartTitleText,
required this.firstAxesText,
required this.secondAxesText,
this.flipVerticalAxis,
});
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
final List<Activity> activities;
final ActivityAttr firstAttr;
final ActivityAttr secondAttr;
final String chartTitleText;
final String firstAxesText;
final String secondAxesText;
final bool flipVerticalAxis;
final bool? flipVerticalAxis;
@override
_AthleteScatterChartState createState() => _AthleteScatterChartState();
@ -38,8 +38,8 @@ class _AthleteScatterChartState extends State<AthleteScatterChart> {
@override
Widget build(BuildContext context) {
final List<Series<Activity, double>> data = <Series<Activity, double>>[
Series<Activity, double>(
final List<Series<Activity, double?>> data = <Series<Activity, double?>>[
Series<Activity, double?>(
id: widget.firstAttr.toString() +
' vs. ' +
widget.secondAttr.toString(),
@ -49,9 +49,9 @@ class _AthleteScatterChartState extends State<AthleteScatterChart> {
b: 0,
a: opacity(activity: activity)),
domainFn: (Activity activity, _) =>
activity.getAttribute(widget.firstAttr) as double,
activity.getAttribute(widget.firstAttr) as double?,
measureFn: (Activity activity, _) =>
activity.getAttribute(widget.secondAttr) as double,
activity.getAttribute(widget.secondAttr) as double?,
data: widget.activities.reversed.toList(),
radiusPxFn: (Activity activity, _) =>
activity == widget.activities.first ? 5 : 3,
@ -66,7 +66,7 @@ class _AthleteScatterChartState extends State<AthleteScatterChart> {
? 1
: 2,
child: ScatterPlotChart(
data,
data as List<Series<dynamic, num>>,
animate: false,
primaryMeasureAxis: const NumericAxisSpec(
tickProviderSpec: BasicNumericTickProviderSpec(
@ -103,8 +103,8 @@ class _AthleteScatterChartState extends State<AthleteScatterChart> {
);
}
int opacity({Activity activity}) {
int opacity({required Activity activity}) {
return 255 -
(DateTime.now().difference(activity.timeStamp).inDays / 2).round();
(DateTime.now().difference(activity.timeStamp!).inDays / 2).round();
}
}

View File

@ -9,36 +9,36 @@ import '/models/athlete.dart';
import '/screens/show_activity_screen.dart';
import '/utils/enums.dart';
import '/utils/my_button.dart';
import 'PQText.dart';
import 'pg_text.dart';
class AthleteTimeSeriesChart extends StatefulWidget {
const AthleteTimeSeriesChart({
@required this.athlete,
@required this.activities,
@required this.activityAttr,
@required this.chartTitleText,
const AthleteTimeSeriesChart({Key? key,
required this.athlete,
required this.activities,
required this.activityAttr,
required this.chartTitleText,
this.fullDecay,
this.flipVerticalAxis,
});
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
final List<Activity> activities;
final ActivityAttr activityAttr;
final String chartTitleText;
final int fullDecay;
final bool flipVerticalAxis;
final int? fullDecay;
final bool? flipVerticalAxis;
@override
_AthleteTimeSeriesChartState createState() => _AthleteTimeSeriesChartState();
}
class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
Activity selectedActivity;
List<Activity> displayedActivities;
Activity? selectedActivity;
late List<Activity> displayedActivities;
int pagingOffset = 0;
final int xAxesDays = 60;
final int amountDisplayed = 40;
int numberOfActivities;
late int numberOfActivities;
@override
void initState() {
@ -50,7 +50,7 @@ class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
final List<SeriesDatum<dynamic>> selectedDatum = model.selectedDatum;
if (selectedDatum.isNotEmpty) {
setState(() => selectedActivity = selectedDatum[1].datum as Activity);
setState(() => selectedActivity = selectedDatum[1].datum as Activity?);
}
}
@ -62,16 +62,16 @@ class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
@override
Widget build(BuildContext context) {
final List<Series<Activity, DateTime>> data = <Series<Activity, DateTime>>[
Series<Activity, DateTime>(
final List<Series<Activity, DateTime?>> data = <Series<Activity, DateTime?>>[
Series<Activity, DateTime?>(
id: widget.activityAttr.toString(),
colorFn: (_, __) => MaterialPalette.blue.shadeDefault,
domainFn: (Activity activity, _) => activity.timeCreated,
measureFn: (Activity activity, _) =>
activity.getAttribute(widget.activityAttr) as num,
activity.getAttribute(widget.activityAttr) as num?,
data: displayedActivities,
),
Series<Activity, DateTime>(
Series<Activity, DateTime?>(
id: 'gliding_' + widget.activityAttr.toString(),
colorFn: (_, __) => MaterialPalette.green.shadeDefault,
domainFn: (Activity activity, _) => activity.timeCreated,
@ -88,7 +88,7 @@ class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
? 1
: 2,
child: TimeSeriesChart(
data,
data as List<Series<dynamic, DateTime>>,
animate: true,
flipVerticalAxis: widget.flipVerticalAxis ?? false,
selectionModels: <SelectionModelConfig<DateTime>>[
@ -169,7 +169,7 @@ class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
],
),
if (selectedActivity != null)
Container(
SizedBox(
height: 200,
child: GridView.count(
padding: const EdgeInsets.all(5),
@ -182,7 +182,7 @@ class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
mainAxisSpacing: 3,
children: <Widget>[
MyButton.activity(
child: Text(selectedActivity.name),
child: Text(selectedActivity!.name!),
onPressed: () => Navigator.push(
context,
MaterialPageRoute<BuildContext>(
@ -195,7 +195,7 @@ class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
),
ListTile(
title: PQText(
value: selectedActivity.timeCreated,
value: selectedActivity!.timeCreated,
pq: PQ.dateTime,
format: DateTimeFormat.longDateTime,
),
@ -203,30 +203,30 @@ class _AthleteTimeSeriesChartState extends State<AthleteTimeSeriesChart> {
),
ListTile(
title: PQText(
value: selectedActivity.distance,
value: selectedActivity!.distance,
pq: PQ.distance,
),
subtitle: const Text('Distance'),
),
ListTile(
title: PQText(
value: selectedActivity.avgSpeed,
value: selectedActivity!.avgSpeed,
pq: PQ.paceFromSpeed,
),
subtitle: const Text('Average speed'),
),
ListTile(
title: PQText(value: selectedActivity.avgPower, pq: PQ.power),
title: PQText(value: selectedActivity!.avgPower, pq: PQ.power),
subtitle: const Text('Average power'),
),
if (selectedActivity.ftp != null)
if (selectedActivity!.ftp != null)
ListTile(
title: PQText(value: selectedActivity.ftp, pq: PQ.power),
title: PQText(value: selectedActivity!.ftp, pq: PQ.power),
subtitle: const Text('FTP'),
),
ListTile(
title: PQText(
value: selectedActivity.avgHeartRate,
value: selectedActivity!.avgHeartRate,
pq: PQ.heartRate,
),
subtitle: const Text('Average heart rate')),

View File

@ -7,14 +7,14 @@ import '/models/athlete.dart';
import '/utils/enums.dart';
class AthleteVolumeChart extends StatefulWidget {
const AthleteVolumeChart({
@required this.athlete,
@required this.activities,
@required this.volumeAttr,
@required this.chartTitleText,
});
const AthleteVolumeChart({Key? key,
required this.athlete,
required this.activities,
required this.volumeAttr,
required this.chartTitleText,
}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
final List<Activity> activities;
final ActivityAttr volumeAttr;
final String chartTitleText;
@ -34,11 +34,11 @@ class _AthleteVolumeChartState extends State<AthleteVolumeChart> {
final List<Series<Activity, DateTime>> data = <Series<Activity, DateTime>>[
Series<Activity, DateTime>(
id: widget.volumeAttr.toString(),
colorFn: (Activity activity, __) => colorForYear(activity: activity),
colorFn: (Activity activity, __) => colorForYear(activity: activity)!,
domainFn: (Activity activity, _) =>
movedIntoThisYear(activity: activity),
measureFn: (Activity activity, _) =>
activity.getAttribute(widget.volumeAttr) as num,
activity.getAttribute(widget.volumeAttr) as num?,
data: widget.activities,
),
];
@ -88,26 +88,26 @@ class _AthleteVolumeChartState extends State<AthleteVolumeChart> {
),
Wrap(children: <Widget>[
const Text('Legend:'),
for (Color color in colorPalette) legendTextWidget(color: color)
for (Color? color in colorPalette) legendTextWidget(color: color)
])
],
);
}
DateTime movedIntoThisYear({Activity activity}) => DateTime(
DateTime movedIntoThisYear({required Activity activity}) => DateTime(
DateTime.now().year,
activity.timeStamp.month,
activity.timeStamp.day,
activity.timeStamp.hour,
activity.timeStamp.minute,
activity.timeStamp.second);
activity.timeStamp!.month,
activity.timeStamp!.day,
activity.timeStamp!.hour,
activity.timeStamp!.minute,
activity.timeStamp!.second);
Color colorForYear({Activity activity}) {
final int yearsAgo = DateTime.now().year - activity.timeStamp.year;
Color? colorForYear({required Activity activity}) {
final int yearsAgo = DateTime.now().year - activity.timeStamp!.year;
return colorPalette[yearsAgo % colorPalette.length];
}
final List<Color> colorPalette = <Color>[
final List<Color?> colorPalette = <Color?>[
MaterialPalette.blue.shadeDefault,
MaterialPalette.red.shadeDefault,
MaterialPalette.green.shadeDefault,
@ -121,12 +121,12 @@ class _AthleteVolumeChartState extends State<AthleteVolumeChart> {
MaterialPalette.gray.shadeDefault,
];
Widget legendTextWidget({Color color}) {
Widget legendTextWidget({Color? color}) {
final int yearsAgo = colorPalette.indexOf(color);
final painting.Color materialColor = painting.Color.fromRGBO(
colorPalette[yearsAgo % colorPalette.length].r,
colorPalette[yearsAgo % colorPalette.length].g,
colorPalette[yearsAgo % colorPalette.length].b,
colorPalette[yearsAgo % colorPalette.length]!.r,
colorPalette[yearsAgo % colorPalette.length]!.g,
colorPalette[yearsAgo % colorPalette.length]!.b,
1.0);
final int year = DateTime.now().year - yearsAgo;
return Text(' $year ', style: painting.TextStyle(color: materialColor));

View File

@ -5,12 +5,12 @@ import '/utils/my_color.dart';
class BarChartPainter extends CustomPainter {
BarChartPainter({
@required this.width,
@required this.height,
@required this.value,
@required this.maximum,
@required this.minimum,
@required this.barZones,
required this.width,
required this.height,
required this.value,
required this.maximum,
required this.minimum,
required this.barZones,
this.showPercentage,
});
@ -21,7 +21,7 @@ class BarChartPainter extends CustomPainter {
final double minimum;
final double strokeWidth = 0.5;
final List<BarZone> barZones;
bool showPercentage = false;
bool? showPercentage = false;
@override
void paint(Canvas canvas, Size size) {
@ -58,22 +58,22 @@ class BarChartPainter extends CustomPainter {
double lowerInPixel;
double upperInPixel;
if (value < barZone.lower) {
if (value < barZone.lower!) {
continue;
}
if (value >= barZone.upper) {
if (value >= barZone.upper!) {
lowerInPixel = (width - 2 * strokeWidth) /
(maximum - minimum) *
(barZone.lower - minimum) +
(barZone.lower! - minimum) +
strokeWidth;
upperInPixel = (width - 2 * strokeWidth) /
(maximum - minimum) *
(barZone.upper - minimum) +
(barZone.upper! - minimum) +
strokeWidth;
} else {
lowerInPixel = (width - 2 * strokeWidth) /
(maximum - minimum) *
(barZone.lower - minimum) +
(barZone.lower! - minimum) +
strokeWidth;
upperInPixel = (width - 2 * strokeWidth) /
(maximum - minimum) *
@ -87,13 +87,13 @@ class BarChartPainter extends CustomPainter {
Offset(upperInPixel, height - strokeWidth),
),
Paint()
..color = Color(barZone.color)
..color = Color(barZone.color!)
..strokeWidth = strokeWidth
..style = PaintingStyle.fill);
if (showPercentage == true) {
final int percentage =
((barZone.upper - barZone.lower) / (maximum - minimum) * 100)
((barZone.upper! - barZone.lower!) / (maximum - minimum) * 100)
.round();
String percentageString;
switch (percentage) {

View File

@ -5,15 +5,16 @@ class Db {
factory Db.create() {
_dB ??= Db();
return _dB;
return _dB!;
}
static Db _dB;
static Db? _dB;
static bool _isConnected = false;
Future<bool> connect() async {
if (_isConnected == false)
if (_isConnected == false) {
_isConnected = await DbEncrateia().initializeDB();
}
return _isConnected;
}
}

View File

@ -9,24 +9,24 @@ import '/models/power_zone.dart';
// ignore: avoid_classes_with_only_static_members
class GraphUtils {
static List<RangeAnnotationSegment<int>> rangeAnnotations({List<Lap> laps}) {
static List<RangeAnnotationSegment<int?>> rangeAnnotations({required List<Lap> laps}) {
final List<Color> colorArray = <Color>[
MaterialPalette.white,
MaterialPalette.gray.shade200,
];
return <RangeAnnotationSegment<int>>[
return <RangeAnnotationSegment<int?>>[
for (int index = 0; index < laps.length; index++)
RangeAnnotationSegment<int>(
RangeAnnotationSegment<int?>(
laps
.sublist(0, index + 1)
.map((Lap lap) => lap.totalDistance)
.reduce((int a, int b) => a + b) -
laps[index].totalDistance,
.reduce((int? a, int? b) => a! + b!)! -
laps[index].totalDistance!,
laps
.sublist(0, index + 1)
.map((Lap lap) => lap.totalDistance)
.reduce((int a, int b) => a + b),
.reduce((int? a, int? b) => a! + b!),
RangeAnnotationAxisType.domain,
color: colorArray[index % 2],
endLabel: 'Lap ${laps[index].index}',
@ -41,12 +41,12 @@ class GraphUtils {
bottomMarginSpec: MarginSpec.fixedPixel(40),
);
static Container loadingContainer = Container(
static SizedBox loadingContainer = const SizedBox(
height: 100,
child: const Center(child: Text('Loading')),
child: Center(child: Text('Loading')),
);
static List<ChartTitle<num>> axis({String measureTitle}) {
static List<ChartTitle<num>> axis({required String measureTitle}) {
return <ChartTitle<num>>[
ChartTitle<num>(
measureTitle,
@ -69,47 +69,47 @@ class GraphUtils {
];
}
static List<RangeAnnotationSegment<int>> powerZoneAnnotations(
{List<PowerZone> powerZones}) {
List<RangeAnnotationSegment<int>> rangeAnnotationSegmentList =
static List<RangeAnnotationSegment<int?>> powerZoneAnnotations(
{List<PowerZone>? powerZones}) {
List<RangeAnnotationSegment<int?>> rangeAnnotationSegmentList =
<RangeAnnotationSegment<int>>[];
if (powerZones != null) {
rangeAnnotationSegmentList = <RangeAnnotationSegment<int>>[
rangeAnnotationSegmentList = <RangeAnnotationSegment<int?>>[
for (PowerZone powerZone in powerZones)
RangeAnnotationSegment<int>(
RangeAnnotationSegment<int?>(
powerZone.lowerLimit,
powerZone.upperLimit,
RangeAnnotationAxisType.measure,
startLabel: powerZone.name,
color: convertedColor(dbColor: powerZone.color),
color: convertedColor(dbColor: powerZone.color!),
)
];
}
return rangeAnnotationSegmentList;
}
static List<RangeAnnotationSegment<int>> heartRateZoneAnnotations(
{List<HeartRateZone> heartRateZones}) {
List<RangeAnnotationSegment<int>> rangeAnnotationSegmentList =
static List<RangeAnnotationSegment<int?>> heartRateZoneAnnotations(
{List<HeartRateZone>? heartRateZones}) {
List<RangeAnnotationSegment<int?>> rangeAnnotationSegmentList =
<RangeAnnotationSegment<int>>[];
if (heartRateZones != null) {
rangeAnnotationSegmentList = <RangeAnnotationSegment<int>>[
rangeAnnotationSegmentList = <RangeAnnotationSegment<int?>>[
for (HeartRateZone heartRateZone in heartRateZones)
RangeAnnotationSegment<int>(
RangeAnnotationSegment<int?>(
heartRateZone.lowerLimit,
heartRateZone.upperLimit,
RangeAnnotationAxisType.measure,
startLabel: heartRateZone.name,
color: convertedColor(dbColor: heartRateZone.color),
color: convertedColor(dbColor: heartRateZone.color!),
)
];
}
return rangeAnnotationSegmentList;
}
static Color convertedColor({int dbColor}) {
static Color convertedColor({required int dbColor}) {
return Color(
r: ui.Color(dbColor).red,
g: ui.Color(dbColor).green,

View File

@ -6,18 +6,18 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';
Future<void> capturePng({GlobalKey widgetKey}) async {
Future<void> capturePng({required GlobalKey widgetKey}) async {
final RenderRepaintBoundary boundary =
widgetKey.currentContext.findRenderObject() as RenderRepaintBoundary;
widgetKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
final ui.Image image = await boundary.toImage(pixelRatio: 3.0);
final ByteData byteData =
await image.toByteData(format: ui.ImageByteFormat.png);
await (image.toByteData(format: ui.ImageByteFormat.png) as Future<ByteData>);
await writeByteToImageFile(byteData);
}
Future<String> writeByteToImageFile(ByteData byteData) async {
final Directory dir = Platform.isAndroid
? await getExternalStorageDirectory()
? await (getExternalStorageDirectory() as Future<Directory>)
: await getApplicationDocumentsDirectory();
final File imageFile = File('${dir.path}/screenshot.png');
// ignore: avoid_slow_async_io

View File

@ -1,15 +1,15 @@
extension StatisticFunctions on Map<DateTime, double> {
extension StatisticFunctions on Map<DateTime?, double?> {
double meanWeightedOverTime() {
double sumOfValues = 0;
double sumOfWeights = 0;
DateTime lastTimeStamp;
DateTime? lastTimeStamp;
forEach((DateTime timeStamp, double speed) {
forEach((DateTime? timeStamp, double? speed) {
final int timeEvolved = lastTimeStamp != null
? timeStamp.difference(lastTimeStamp).inSeconds
? timeStamp!.difference(lastTimeStamp!).inSeconds
: 0;
sumOfValues += timeEvolved * speed;
sumOfValues += timeEvolved * speed!;
sumOfWeights += timeEvolved;
lastTimeStamp = timeStamp;
});
@ -21,13 +21,13 @@ extension StatisticFunctions on Map<DateTime, double> {
double sumOfValues = 0;
double sumOfWeights = 0;
DateTime lastTimeStamp;
DateTime? lastTimeStamp;
forEach((DateTime timeStamp, double speed) {
forEach((DateTime? timeStamp, double? speed) {
final double distanceEvolved = (lastTimeStamp != null
? timeStamp.difference(lastTimeStamp).inSeconds
? timeStamp!.difference(lastTimeStamp!).inSeconds
: 0) *
speed;
speed!;
sumOfValues += distanceEvolved * speed;
sumOfWeights += distanceEvolved;
lastTimeStamp = timeStamp;
@ -40,15 +40,15 @@ extension StatisticFunctions on Map<DateTime, double> {
double sumOfValues = 0;
double sumOfWeights = 0;
DateTime lastTimeStamp;
double lastDistance;
DateTime? lastTimeStamp;
double? lastDistance;
forEach((DateTime timeStamp, double distance) {
forEach((DateTime? timeStamp, double? distance) {
final int timeEvolved = lastTimeStamp != null
? timeStamp.difference(lastTimeStamp).inSeconds
? timeStamp!.difference(lastTimeStamp!).inSeconds
: 0;
final double distanceEvolved = lastDistance != null
? distance - lastDistance
? distance! - lastDistance!
: 0;
sumOfValues += distanceEvolved;
sumOfWeights += timeEvolved;
@ -63,11 +63,11 @@ extension StatisticFunctions on Map<DateTime, double> {
double sumOfValues = 0;
double sumOfWeights = 0;
DateTime lastTimeStamp;
DateTime? lastTimeStamp;
forEach((DateTime timeStamp, double speed) {
forEach((DateTime? timeStamp, double? speed) {
final int timeEvolved = lastTimeStamp != null
? timeStamp.difference(lastTimeStamp).inSeconds
? timeStamp!.difference(lastTimeStamp!).inSeconds
: 0;
sumOfValues += (speed ?? 0) * timeEvolved;
sumOfWeights += timeEvolved;

View File

@ -8,15 +8,15 @@ import '/models/power_zone.dart';
import 'bar_chart_painter.dart';
class MyBarChart extends StatelessWidget {
MyBarChart({
int width,
int height,
@required num value,
num maximum,
num minimum,
List<PowerZone> powerZones,
List<HeartRateZone> heartRateZones,
bool showPercentage,
MyBarChart({Key? key,
int? width,
int? height,
required num value,
num? maximum,
num? minimum,
List<PowerZone>? powerZones,
List<HeartRateZone>? heartRateZones,
bool? showPercentage,
}) : _width = width?.toDouble() ?? 200.0,
_height = height?.toDouble() ?? 30.0,
_value = value.toDouble(),
@ -34,17 +34,17 @@ class MyBarChart extends StatelessWidget {
powerZones: powerZones,
heartRateZones: heartRateZones,
),
_showPercentage = showPercentage;
_showPercentage = showPercentage, super(key: key);
MyBarChart.visualizeDistributions(
{int width, int height, List<BarZone> distributions})
{Key? key, int? width, int? height, required List<BarZone> distributions})
: _width = width?.toDouble() ?? 200.0,
_height = height?.toDouble() ?? 30.0,
_minimum = 0,
_maximum = distributions.last.upper.toDouble(),
_value = distributions.last.upper.toDouble(),
_maximum = distributions.last.upper!.toDouble(),
_value = distributions.last.upper!.toDouble(),
_barZones = distributions,
_showPercentage = true;
_showPercentage = true, super(key: key);
final double _width;
final double _height;
@ -52,13 +52,13 @@ class MyBarChart extends StatelessWidget {
final double _maximum;
final double _minimum;
final List<BarZone> _barZones;
final bool _showPercentage;
final bool? _showPercentage;
@override
Widget build(BuildContext context) {
if (_barZones.isEmpty && _value == null || _value <= 0)
if (_barZones.isEmpty && _value == null || _value <= 0) {
return const Text('no data');
else
} else {
return SizedBox(
width: _width,
height: _height,
@ -74,55 +74,59 @@ class MyBarChart extends StatelessWidget {
),
),
);
}
}
static List<BarZone> toBarZones({
List<PowerZone> powerZones,
List<HeartRateZone> heartRateZones,
List<PowerZone>? powerZones,
List<HeartRateZone>? heartRateZones,
}) {
if (powerZones != null)
if (powerZones != null) {
return BarZone.fromPowerZones(powerZones);
else if (heartRateZones != null)
} else if (heartRateZones != null) {
return BarZone.fromHeartRateZones(heartRateZones);
else
} else {
return <BarZone>[];
}
}
static double maxFromZones(
{List<PowerZone> powerZones,
List<HeartRateZone> heartRateZones,
num maximum}) {
if (maximum != null)
{List<PowerZone>? powerZones,
List<HeartRateZone>? heartRateZones,
num? maximum}) {
if (maximum != null) {
return maximum.toDouble();
else if (powerZones != null)
} else if (powerZones != null) {
return powerZones
.map((PowerZone powerZone) => powerZone.upperLimit.toDouble())
.map((PowerZone powerZone) => powerZone.upperLimit!.toDouble())
.reduce(math.max);
else if (heartRateZones != null)
} else if (heartRateZones != null) {
return heartRateZones
.map((HeartRateZone heartRateZone) =>
heartRateZone.upperLimit.toDouble())
heartRateZone.upperLimit!.toDouble())
.reduce(math.max);
else
} else {
return 100.0;
}
}
static double minFromZones(
{List<PowerZone> powerZones,
List<HeartRateZone> heartRateZones,
num minimum}) {
if (minimum != null)
{List<PowerZone>? powerZones,
List<HeartRateZone>? heartRateZones,
num? minimum}) {
if (minimum != null) {
return minimum.toDouble();
else if (powerZones != null)
} else if (powerZones != null) {
return powerZones
.map((PowerZone powerZone) => powerZone.lowerLimit.toDouble())
.map((PowerZone powerZone) => powerZone.lowerLimit!.toDouble())
.reduce(math.min);
else if (heartRateZones != null)
} else if (heartRateZones != null) {
return heartRateZones
.map((HeartRateZone heartRateZone) =>
heartRateZone.lowerLimit.toDouble())
heartRateZone.lowerLimit!.toDouble())
.reduce(math.min);
else
} else {
return 0.0;
}
}
}

View File

@ -5,74 +5,74 @@ import 'my_button_style.dart';
import 'my_color.dart';
class MyButton extends ElevatedButton {
MyButton.delete({Widget child, VoidCallback onPressed})
: super(
MyButton.delete({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.delete, textColor: Colors.white),
child: child ?? const Text('Delete'),
onPressed: onPressed,
);
MyButton.cancel({Widget child, VoidCallback onPressed})
: super(
MyButton.cancel({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(color: MyColor.cancel),
child: child ?? const Text('Cancel'),
onPressed: onPressed,
);
MyButton.edit({Widget child, VoidCallback onPressed})
: super(
MyButton.edit({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(color: MyColor.edit),
child: child ?? const Text('Edit'),
onPressed: onPressed,
);
MyButton.save({Widget child, VoidCallback onPressed})
: super(
MyButton.save({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(color: MyColor.save),
child: child ?? const Text('Save'),
onPressed: onPressed,
);
MyButton.add({Widget child, VoidCallback onPressed})
: super(
MyButton.add({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(color: MyColor.add),
child: child ?? const Text('Add'),
onPressed: onPressed,
);
MyButton.copy({Widget child, VoidCallback onPressed})
: super(
MyButton.copy({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(color: MyColor.copy),
child: child ?? MyIcon.copy,
onPressed: onPressed,
);
MyButton.navigate({Widget child, VoidCallback onPressed})
: super(
MyButton.navigate({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(color: MyColor.navigate),
child: child ?? const Text('Navigate'),
onPressed: onPressed,
);
MyButton.detail({Widget child, VoidCallback onPressed})
: super(
MyButton.detail({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.detail, textColor: Colors.white),
child: child ?? const Text('Detail'),
onPressed: onPressed,
);
MyButton.log({Widget child, VoidCallback onPressed})
: super(
MyButton.log({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.log, textColor: Colors.white),
child: child ?? const Text('Log Entries'),
onPressed: onPressed,
);
MyButton.activity({Widget child, VoidCallback onPressed})
: super(
MyButton.activity({Key? key, Widget? child, VoidCallback? onPressed})
: super(key: key,
style: MyButtonStyle.raisedButtonStyle(
color: MyColor.activity, textColor: Colors.white),
child: child ?? const Text('Activity'),

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
class MyButtonStyle extends ButtonStyle {
static ButtonStyle raisedButtonStyle({Color color, Color textColor}) {
static ButtonStyle raisedButtonStyle({Color? color, Color? textColor}) {
return ElevatedButton.styleFrom(
onPrimary: textColor ?? Colors.black,
primary: color ?? Colors.grey[300],

View File

@ -71,16 +71,18 @@ class MyColor {
static Color interval = pinkRose;
static Color textColor({
@required Color backgroundColor,
required Color backgroundColor,
bool selected = true,
}) {
if (selected) {
if (ThemeData.estimateBrightnessForColor(backgroundColor) ==
Brightness.light)
Brightness.light) {
return black;
else
} else {
return white;
} else
}
} else {
return black;
}
}
}

View File

@ -2,8 +2,6 @@ import 'dart:math';
import 'package:charts_common/common.dart' as common show Series;
import 'package:charts_flutter/flutter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import '/models/heart_rate_zone.dart';
import '/models/lap.dart';
@ -12,20 +10,20 @@ import '/utils/graph_utils.dart';
class MyLineChart extends LineChart {
MyLineChart({
@required List<common.Series<dynamic, num>> data,
@required double maxDomain,
@required List<Lap> laps,
List<PowerZone> powerZones,
List<HeartRateZone> heartRateZones,
@required String domainTitle,
String measureTitle,
NumericTickProviderSpec measureTickProviderSpec,
NumericTickProviderSpec domainTickProviderSpec,
double minimum,
double maximum,
bool flipVerticalAxis,
required List<common.Series<dynamic, num?>> data,
required double maxDomain,
required List<Lap> laps,
List<PowerZone>? powerZones,
List<HeartRateZone>? heartRateZones,
required String domainTitle,
String? measureTitle,
NumericTickProviderSpec? measureTickProviderSpec,
NumericTickProviderSpec? domainTickProviderSpec,
double? minimum,
double? maximum,
bool? flipVerticalAxis,
}) : super(
data,
data as List<Series<dynamic, num>>,
defaultRenderer: LineRendererConfig<num>(
includeArea: true,
strokeWidthPx: 1,
@ -54,7 +52,7 @@ class MyLineChart extends LineChart {
) +
GraphUtils.heartRateZoneAnnotations(
heartRateZones: heartRateZones,
),
) as List<AnnotationSegment<Object>>,
),
ChartTitle<num>(
domainTitle,
@ -77,37 +75,38 @@ class MyLineChart extends LineChart {
],
);
static NumericExtents determineViewport({
List<PowerZone> powerZones,
List<HeartRateZone> heartRateZones,
double minimum,
double maximum,
static NumericExtents? determineViewport({
List<PowerZone>? powerZones,
List<HeartRateZone>? heartRateZones,
double? minimum,
double? maximum,
}) {
if (powerZones != null)
if (powerZones != null) {
return NumericExtents(
powerZones
.map((PowerZone powerZone) => powerZone.lowerLimit)
.reduce(min) *
.reduce(min)! *
0.9,
powerZones
.map((PowerZone powerZone) => powerZone.upperLimit)
.reduce(max) *
.reduce(max)! *
1.1);
else if (heartRateZones != null)
} else if (heartRateZones != null) {
return NumericExtents(
heartRateZones
.map(
(HeartRateZone heartRateZone) => heartRateZone.lowerLimit)
.reduce(min) *
.reduce(min)! *
0.9,
heartRateZones
.map(
(HeartRateZone heartRateZone) => heartRateZone.upperLimit)
.reduce(max) *
.reduce(max)! *
1.1);
else if (minimum != null)
return NumericExtents(minimum, maximum);
else
} else if (minimum != null) {
return NumericExtents(minimum, maximum!);
} else {
return null;
}
}
}

View File

@ -6,19 +6,19 @@ import '/models/record_list.dart';
import '/utils/path_painter.dart';
class MyPath extends StatelessWidget {
MyPath({
int width,
int height,
@required Activity activity,
@required RecordList<Event> records,
MyPath({Key? key,
int? width,
int? height,
required Activity? activity,
required RecordList<Event> records,
}) : _width = width?.toDouble() ?? 300.0,
_height = height?.toDouble() ?? 300.0,
_activity = activity,
_records = records;
_records = records, super(key: key);
final double _width;
final double _height;
final Activity _activity;
final Activity? _activity;
final RecordList<Event> _records;
@override

View File

@ -10,17 +10,17 @@ import '/utils/my_color.dart';
class PathPainter extends CustomPainter {
PathPainter({
@required this.width,
@required this.height,
@required this.records,
@required this.activity,
required this.width,
required this.height,
required this.records,
required this.activity,
});
final double width;
final double height;
final RecordList<Event> records;
final double strokeWidth = 2;
final Activity activity;
final Activity? activity;
@override
void paint(Canvas canvas, Size size) {
@ -35,8 +35,8 @@ class PathPainter extends CustomPainter {
..strokeWidth = strokeWidth,
);
final double scaleX = width / (activity.necLong - activity.swcLong);
final double scaleY = height / (activity.necLat - activity.swcLat);
final double scaleX = width / (activity!.necLong! - activity!.swcLong!);
final double scaleY = height / (activity!.necLat! - activity!.swcLat!);
final double scale = min(scaleX, scaleY);
canvas.drawPoints(
PointMode.points,
@ -45,14 +45,14 @@ class PathPainter extends CustomPainter {
(Event record) => Offset(
width / 2 +
scale *
(record.positionLong -
activity.swcLong / 2 -
activity.necLong / 2),
(record.positionLong! -
activity!.swcLong! / 2 -
activity!.necLong! / 2),
height / 2 +
scale *
(activity.necLat / 2 +
activity.swcLat / 2 -
record.positionLat),
(activity!.necLat! / 2 +
activity!.swcLat! / 2 -
record.positionLat!),
),
)
.toList(),

View File

@ -6,11 +6,11 @@ import 'enums.dart';
@immutable
class PQText extends StatelessWidget {
const PQText({
@required this.pq,
const PQText({Key? key,
required this.pq,
this.value,
this.format,
});
this.format = DateTimeFormat.longDateTime,
}) : super(key: key);
final dynamic value;
final DateTimeFormat format;
@ -50,9 +50,9 @@ class PQText extends StatelessWidget {
case PQ.powerPerHeartRate:
return Text((value as num).toStringAsFixed(2) + ' W/bpm');
case PQ.calories:
return Text((value as num).toString() + ' kcal');
return Text((value as num?).toString() + ' kcal');
case PQ.elevation:
return Text((value as num).toString() + ' m');
return Text((value as num?).toString() + ' m');
case PQ.cadence:
return Text(((value as num) * 2).toStringAsPrecision(3) + ' spm');
case PQ.duration:
@ -60,17 +60,17 @@ class PQText extends StatelessWidget {
case PQ.shortDuration:
return Text(Duration(seconds: value as int).asShortString());
case PQ.trainingEffect:
return Text((value as num).toString());
return Text((value as num?).toString());
case PQ.text:
return Text(value as String);
case PQ.temperature:
return Text((value as num).toString() + '°C');
return Text((value as num?).toString() + '°C');
case PQ.verticalOscillation:
return Text((value as num).toStringAsFixed(2) + ' cm');
case PQ.cycles:
return Text((value as num).toString() + ' cycles');
return Text((value as num?).toString() + ' cycles');
case PQ.integer:
return Text((value as num).toString());
return Text((value as num?).toString());
case PQ.fractionalCadence:
return Text((value as num).toStringAsFixed(2));
case PQ.percentage:
@ -79,9 +79,9 @@ class PQText extends StatelessWidget {
case PQ.groundTime:
return Text((value as num).toStringAsPrecision(4) + ' ms');
case PQ.longitude:
return Text((value as double).semicirclesToString() + ' E');
return Text((value as double?)!.semicirclesToString() + ' E');
case PQ.latitude:
return Text((value as double).semicirclesToString() + ' N');
return Text((value as double?)!.semicirclesToString() + ' N');
case PQ.speed:
return Text(((value as num) * 3.6).toStringAsFixed(2) + ' km/h');
case PQ.speedPerHeartRate:
@ -93,8 +93,6 @@ class PQText extends StatelessWidget {
case PQ.double:
return Text((value as double).toStringAsPrecision(3));
}
return const Text(
'the pq Parameter was not provided.'); // just to silence the dart analyzer
}
String get formatString {
@ -112,7 +110,6 @@ class PQText extends StatelessWidget {
case DateTimeFormat.compact:
return 'dd.MM.yyyy\nH:mm:ss';
}
return 'E d MMM yy, H:mm:ss';
}
bool get validValue {

View File

@ -3,5 +3,5 @@ import 'package:fit_parser/src/values/sport_values.dart';
// ignore: avoid_classes_with_only_static_members
class Sport {
static Map<int, String> sports = sport_values as Map<int, String>;
static Map<int, String>? sports = sportValues as Map<int, String>?;
}

View File

@ -8,15 +8,15 @@ import '/models/athlete.dart';
import '/models/tag.dart';
import '/models/tag_group.dart';
import '/screens/show_activity_screen.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/icon_utils.dart';
import '/utils/my_color.dart';
class ActivitiesFeedWidget extends StatefulWidget {
const ActivitiesFeedWidget({Key key, this.athlete}) : super(key: key);
const ActivitiesFeedWidget({Key? key, this.athlete}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_ActivitiesFeedWidgetState createState() => _ActivitiesFeedWidgetState();
@ -25,13 +25,13 @@ class ActivitiesFeedWidget extends StatefulWidget {
class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
List<Activity> activities = <Activity>[];
List<TagGroup> tagGroups = <TagGroup>[];
Flushbar<Object> flushbar;
Flushbar<Object>? flushbar;
bool disposed = false;
@override
void initState() {
getData();
WidgetsBinding.instance.addPostFrameCallback((_) => showMyFlushbar());
WidgetsBinding.instance!.addPostFrameCallback((_) => showMyFlushbar());
super.initState();
}
@ -56,7 +56,7 @@ class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
itemCount: activities.length,
itemBuilder: (BuildContext context, int index) {
final Activity activity = activities[index];
if (activity.nonParsable == true)
if (activity.nonParsable == true) {
return ListTile(
leading: sportsIcon(sport: activity.sport),
title: Text(activity.name ?? 'Activity'),
@ -75,7 +75,7 @@ class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
getData();
},
);
else
} else {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
@ -148,11 +148,11 @@ class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
Chip(
avatar: CircleAvatar(
foregroundColor: MyColor.textColor(
backgroundColor: Color(tagGroup(tag).color)),
backgroundColor: Color(tagGroup(tag).color),
backgroundColor: Color(tagGroup(tag).color!)),
backgroundColor: Color(tagGroup(tag).color!),
child: Text(capitals(tag))),
label: Text(
tag.name,
tag.name!,
style: TextStyle(
color: MyColor.textColor(
selected: true,
@ -167,11 +167,12 @@ class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
),
)
]);
}
},
);
}
Icon sportsIcon({String sport}) {
Icon sportsIcon({String? sport}) {
switch (sport) {
case 'running':
return MyIcon.running;
@ -183,9 +184,9 @@ class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
}
Future<void> getData() async {
activities = await widget.athlete.activities;
activities = await widget.athlete!.activities;
setState(() {});
tagGroups = await TagGroup.allByAthlete(athlete: widget.athlete);
tagGroups = await TagGroup.allByAthlete(athlete: widget.athlete!);
for (final Activity activity in activities) {
await activity.tags;
await activity.ecor;
@ -197,14 +198,14 @@ class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
}
void showMyFlushbar() {
if (widget.athlete.stravaId != null) {
if (widget.athlete.email == null) {
if (widget.athlete!.stravaId != null) {
if (widget.athlete!.email == null) {
flushbar = Flushbar<Object>(
message: 'Strava email not provided yet!',
duration: const Duration(seconds: 3),
backgroundColor: Colors.yellow[900],
backgroundColor: Colors.yellow[900]!,
)..show(context);
} else if (widget.athlete.password == null) {
} else if (widget.athlete!.password == null) {
flushbar = Flushbar<Object>(
message: 'Strava password not provided yet!',
duration: const Duration(seconds: 3),
@ -219,7 +220,7 @@ class _ActivitiesFeedWidgetState extends State<ActivitiesFeedWidget> {
String capitals(Tag tag) {
final String capitals =
tagGroup(tag).name.split(' ').map((String word) => word[0]).join();
tagGroup(tag).name!.split(' ').map((String word) => word[0]).join();
return capitals.substring(0, min(capitals.length, 2));
}
}

View File

@ -4,14 +4,14 @@ import 'package:flutter/material.dart';
import '/models/activity.dart';
import '/models/athlete.dart';
import '/screens/show_activity_screen.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/icon_utils.dart';
class ActivitiesListWidget extends StatefulWidget {
const ActivitiesListWidget({Key key, this.athlete}) : super(key: key);
const ActivitiesListWidget({Key? key, this.athlete}) : super(key: key);
final Athlete athlete;
final Athlete? athlete;
@override
_ActivitiesListWidgetState createState() => _ActivitiesListWidgetState();
@ -19,12 +19,12 @@ class ActivitiesListWidget extends StatefulWidget {
class _ActivitiesListWidgetState extends State<ActivitiesListWidget> {
List<Activity> activities = <Activity>[];
Flushbar<Object> flushbar;
Flushbar<Object>? flushbar;
@override
void initState() {
getActivities();
WidgetsBinding.instance.addPostFrameCallback((_) => showMyFlushbar());
WidgetsBinding.instance!.addPostFrameCallback((_) => showMyFlushbar());
super.initState();
}
@ -84,7 +84,7 @@ class _ActivitiesListWidgetState extends State<ActivitiesListWidget> {
]);
}
Icon sportsIcon({String sport}) {
Icon sportsIcon({String? sport}) {
switch (sport) {
case 'running':
return MyIcon.running;
@ -95,12 +95,12 @@ class _ActivitiesListWidgetState extends State<ActivitiesListWidget> {
}
}
Future<void> delete({Activity activity}) async {
Future<void> delete({required Activity activity}) async {
await activity.delete();
getActivities();
}
Future<void> download({Activity activity}) async {
Future<void> download({required Activity activity}) async {
flushbar = Flushbar<Object>(
message: 'Download .fit-File for »${activity.name}«',
duration: const Duration(seconds: 10),
@ -118,7 +118,7 @@ class _ActivitiesListWidgetState extends State<ActivitiesListWidget> {
setState(() {});
}
Future<void> parse({Activity activity}) async {
Future<void> parse({required Activity activity}) async {
Flushbar<Object> flushbar = Flushbar<Object>(
message: '0% of storing »${activity.name}«',
duration: const Duration(seconds: 10),
@ -141,19 +141,19 @@ class _ActivitiesListWidgetState extends State<ActivitiesListWidget> {
}
Future<void> getActivities() async {
activities = await widget.athlete.activities;
activities = await widget.athlete!.activities;
setState(() {});
}
void showMyFlushbar() {
if (widget.athlete.stravaId != null) {
if (widget.athlete.email == null) {
if (widget.athlete!.stravaId != null) {
if (widget.athlete!.email == null) {
flushbar = Flushbar<Object>(
message: 'Strava email not provided yet!',
duration: const Duration(seconds: 3),
backgroundColor: Colors.yellow[900],
backgroundColor: Colors.yellow[900]!,
)..show(context);
} else if (widget.athlete.password == null) {
} else if (widget.athlete!.password == null) {
flushbar = Flushbar<Object>(
message: 'Strava password not provided yet!',
duration: const Duration(seconds: 3),

View File

@ -4,7 +4,7 @@ import '/models/activity.dart';
import '/models/athlete.dart';
import '/models/event.dart';
import '/models/record_list.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/icon_utils.dart';
import '/utils/image_utils.dart' as image_utils;
@ -12,13 +12,13 @@ import '/utils/my_button.dart';
import '/widgets/charts/activity_charts/activity_altitude_chart.dart';
class ActivityAltitudeWidget extends StatefulWidget {
const ActivityAltitudeWidget({
@required this.activity,
@required this.athlete,
});
const ActivityAltitudeWidget({Key? key,
required this.activity,
required this.athlete,
}) : super(key: key);
final Activity activity;
final Athlete athlete;
final Activity? activity;
final Athlete? athlete;
@override
_ActivityAltitudeWidgetState createState() => _ActivityAltitudeWidgetState();
@ -56,7 +56,7 @@ class _ActivityAltitudeWidgetState extends State<ActivityAltitudeWidget> {
athlete: widget.athlete,
),
),
Text('${widget.athlete.recordAggregationCount} records are '
Text('${widget.athlete!.recordAggregationCount} records are '
'aggregated into one point in the plot. Only records with '
'altitude measurements are shown.'),
Row(children: <Widget>[
@ -92,7 +92,7 @@ class _ActivityAltitudeWidgetState extends State<ActivityAltitudeWidget> {
}
Future<void> getData() async {
final Activity activity = widget.activity;
final Activity activity = widget.activity!;
records = RecordList<Event>(await activity.records);
setState(() => loading = false);
}

View File

@ -10,26 +10,26 @@ import '/models/heart_rate_zone_schema.dart';
import '/models/lap.dart';
import '/models/power_zone.dart';
import '/models/power_zone_schema.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/my_bar_chart.dart';
class ActivityBarGraphWidget extends StatefulWidget {
const ActivityBarGraphWidget({
@required this.activity,
@required this.athlete,
});
const ActivityBarGraphWidget({Key? key,
required this.activity,
required this.athlete,
}) : super(key: key);
final Activity activity;
final Athlete athlete;
final Activity? activity;
final Athlete? athlete;
@override
_ActivityBarGraphWidgetState createState() => _ActivityBarGraphWidgetState();
}
class _ActivityBarGraphWidgetState extends State<ActivityBarGraphWidget> {
PowerZoneSchema _powerZoneSchema;
HeartRateZoneSchema _heartRateZoneSchema;
PowerZoneSchema? _powerZoneSchema;
HeartRateZoneSchema? _heartRateZoneSchema;
List<PowerZone> _powerZones = <PowerZone>[];
List<HeartRateZone> _heartRateZones = <HeartRateZone>[];
List<Lap> _laps = <Lap>[];
@ -48,7 +48,7 @@ class _ActivityBarGraphWidgetState extends State<ActivityBarGraphWidget> {
if (_powerZones.isNotEmpty && _laps.isNotEmpty) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
child: SizedBox(
width: 500,
child: ListView(padding: const EdgeInsets.all(20), children: <Widget>[
Table(columnWidths: const <int, TableColumnWidth>{
@ -70,19 +70,19 @@ class _ActivityBarGraphWidgetState extends State<ActivityBarGraphWidget> {
MyBarChart(
width: 150,
height: 20,
value: widget.activity.avgPower,
value: widget.activity!.avgPower!,
powerZones: _powerZones,
),
Text((widget.activity.avgPower > 0)
? widget.activity.avgPower.toStringAsFixed(1)
Text((widget.activity!.avgPower! > 0)
? widget.activity!.avgPower!.toStringAsFixed(1)
: ''),
MyBarChart(
width: 150,
height: 20,
value: widget.activity.avgHeartRate,
value: widget.activity!.avgHeartRate!,
heartRateZones: _heartRateZones,
),
Text(widget.activity.avgHeartRate.toString()),
Text(widget.activity!.avgHeartRate.toString()),
]),
for (Lap lap in _laps)
TableRow(children: <Widget>[
@ -90,16 +90,16 @@ class _ActivityBarGraphWidgetState extends State<ActivityBarGraphWidget> {
MyBarChart(
width: 150,
height: 20,
value: lap.avgPower,
value: lap.avgPower!,
powerZones: _powerZones,
),
Text((lap.avgPower > 0)
? lap.avgPower.toStringAsFixed(1)
Text((lap.avgPower! > 0)
? lap.avgPower!.toStringAsFixed(1)
: ''),
MyBarChart(
width: 150,
height: 20,
value: lap.avgHeartRate,
value: lap.avgHeartRate!,
heartRateZones: _heartRateZones,
),
Text(lap.avgHeartRate.toString()),
@ -155,17 +155,17 @@ class _ActivityBarGraphWidgetState extends State<ActivityBarGraphWidget> {
const Text('Activity'),
MyBarChart(
height: 20,
value: widget.activity.avgSpeed,
value: widget.activity!.avgSpeed!,
maximum: _laps.map((Lap lap) => lap.avgSpeed).reduce(max),
),
PQText(value: widget.activity.avgSpeed, pq: PQ.paceFromSpeed),
PQText(value: widget.activity!.avgSpeed, pq: PQ.paceFromSpeed),
]),
for (Lap lap in _laps)
TableRow(children: <Widget>[
Text('Lap ' + lap.index.toString()),
MyBarChart(
height: 20,
value: lap.avgSpeed,
value: lap.avgSpeed!,
maximum: _laps.map((Lap lap) => lap.avgSpeed).reduce(max),
),
PQText(value: lap.avgSpeed, pq: PQ.paceFromSpeed),
@ -182,7 +182,7 @@ class _ActivityBarGraphWidgetState extends State<ActivityBarGraphWidget> {
}
Future<void> getData() async {
final Activity activity = widget.activity;
final Activity activity = widget.activity!;
_laps = await activity.laps;
for (final Lap _lap in _laps) {
_lap.powerDistributions = await _lap.powerZoneCounts();
@ -190,15 +190,17 @@ class _ActivityBarGraphWidgetState extends State<ActivityBarGraphWidget> {
}
_powerZoneSchema = await activity.powerZoneSchema;
if (_powerZoneSchema != null)
_powerZones = await _powerZoneSchema.powerZones;
if (_powerZoneSchema != null) {
_powerZones = await _powerZoneSchema!.powerZones;
}
_heartRateDistributions = await activity.powerZoneCounts();
_powerDistributions = await activity.heartRateZoneCounts();
_heartRateZoneSchema = await activity.heartRateZoneSchema;
if (_heartRateZoneSchema != null)
_heartRateZones = await _heartRateZoneSchema.heartRateZones;
if (_heartRateZoneSchema != null) {
_heartRateZones = await _heartRateZoneSchema!.heartRateZones;
}
setState(() => loading = false);
}

View File

@ -5,7 +5,7 @@ import '/models/athlete.dart';
import '/models/event.dart';
import '/models/record_list.dart';
import '/models/weight.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/icon_utils.dart';
import '/utils/image_utils.dart' as image_utils;
@ -13,13 +13,13 @@ import '/utils/my_button.dart';
import '/widgets/charts/activity_charts/activity_ecor_chart.dart';
class ActivityEcorWidget extends StatefulWidget {
const ActivityEcorWidget({
@required this.activity,
@required this.athlete,
});
const ActivityEcorWidget({Key? key,
required this.activity,
required this.athlete,
}) : super(key: key);
final Activity activity;
final Athlete athlete;
final Activity? activity;
final Athlete? athlete;
@override
_ActivityEcorWidgetState createState() => _ActivityEcorWidgetState();
@ -27,7 +27,7 @@ class ActivityEcorWidget extends StatefulWidget {
class _ActivityEcorWidgetState extends State<ActivityEcorWidget> {
RecordList<Event> records = RecordList<Event>(<Event>[]);
Weight weight;
Weight? weight;
bool loading = true;
String screenShotButtonText = 'Save as .png-Image';
GlobalKey widgetKey = GlobalKey();
@ -44,9 +44,9 @@ class _ActivityEcorWidgetState extends State<ActivityEcorWidget> {
final List<Event> ecorRecords = records
.where((Event value) =>
value.power != null &&
value.power > 100 &&
value.power! > 100 &&
value.speed != null &&
value.speed >= 1)
value.speed! >= 1)
.toList();
if (ecorRecords.isNotEmpty && ecorRecords != null) {
@ -61,10 +61,10 @@ class _ActivityEcorWidgetState extends State<ActivityEcorWidget> {
records: RecordList<Event>(ecorRecords),
activity: widget.activity,
athlete: widget.athlete,
weight: widget.activity.cachedWeight,
weight: widget.activity!.cachedWeight,
),
),
Text('${widget.athlete.recordAggregationCount} records are '
Text('${widget.athlete!.recordAggregationCount} records are '
'aggregated into one point in the plot. Only records where '
'power > 0 W and speed > 1 m/s are shown.'),
Row(children: <Widget>[
@ -81,13 +81,13 @@ class _ActivityEcorWidgetState extends State<ActivityEcorWidget> {
]),
ListTile(
leading: MyIcon.power,
title: PQText(value: widget.activity.cachedEcor, pq: PQ.ecor),
title: PQText(value: widget.activity!.cachedEcor, pq: PQ.ecor),
subtitle: const Text('ecor (Energy cost of running)'),
),
ListTile(
leading: MyIcon.weight,
title:
PQText(value: widget.activity.cachedWeight, pq: PQ.weight),
PQText(value: widget.activity!.cachedWeight, pq: PQ.weight),
subtitle: const Text('weight'),
),
ListTile(
@ -111,8 +111,8 @@ class _ActivityEcorWidgetState extends State<ActivityEcorWidget> {
}
Future<void> getData() async {
records = RecordList<Event>(await widget.activity.records);
await widget.activity.ecor;
records = RecordList<Event>(await widget.activity!.records);
await widget.activity!.ecor;
setState(() => loading = false);
}
}

View File

@ -5,19 +5,19 @@ import '/models/athlete.dart';
import '/models/event.dart';
import '/models/record_list.dart';
import '/screens/show_event_screen.dart';
import '/utils/PQText.dart';
import '/utils/pg_text.dart';
import '/utils/enums.dart';
import '/utils/icon_utils.dart';
import '/utils/my_button.dart';
class ActivityEventListWidget extends StatefulWidget {
const ActivityEventListWidget({
@required this.activity,
@required this.athlete,
});
const ActivityEventListWidget({Key? key,
required this.activity,
required this.athlete,
}) : super(key: key);
final Activity activity;
final Athlete athlete;
final Activity? activity;
final Athlete? athlete;
@override
_ActivityEventListWidgetState createState() =>
@ -28,7 +28,7 @@ class _ActivityEventListWidgetState extends State<ActivityEventListWidget> {
RecordList<Event> events = RecordList<Event>(<Event>[]);
bool loading = true;
int offset = 0;
int rows;
late int rows;
@override
void initState() {
@ -40,7 +40,7 @@ class _ActivityEventListWidgetState extends State<ActivityEventListWidget> {
Widget build(BuildContext context) {
if (events.isNotEmpty) {
rows = (events.length < 8) ? events.length : 8;
final DateTime startingTime = events.first.timeStamp;
final DateTime? startingTime = events.first.timeStamp;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
@ -60,7 +60,7 @@ class _ActivityEventListWidgetState extends State<ActivityEventListWidget> {
],
rows: events.sublist(offset, offset + rows).map((Event event) {
return DataRow(
key: ValueKey<int>(event.id),
key: ValueKey<int?>(event.id),
cells: <DataCell>[
DataCell(PQText(
value: event.timeStamp,
@ -69,7 +69,7 @@ class _ActivityEventListWidgetState extends State<ActivityEventListWidget> {
)),
DataCell(PQText(
value:
event.timeStamp.difference(startingTime).inSeconds,
event.timeStamp!.difference(startingTime!).inSeconds,
pq: PQ.duration,
)),
DataCell(PQText(value: event.eventType, pq: PQ.text)),
@ -198,7 +198,7 @@ class _ActivityEventListWidgetState extends State<ActivityEventListWidget> {
}
Future<void> getData() async {
final Activity activity = widget.activity;
final Activity activity = widget.activity!;
events = RecordList<Event>(await activity.events);
setState(() {});
}

Some files were not shown because too many files have changed in this diff Show More