Merge branch 'upgrade-2021-project' of gitea.mittenin.at:encrateia.informatom.com/encrateia into upgrade-2021-project
commit
b5fc31ae70
File diff suppressed because one or more lines are too long
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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}«',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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();
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 >';
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(() {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
));
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(() {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(() {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -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(() {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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')),
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 {
|
|
@ -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>?;
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Reference in New Issue