diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml index 22934e1..cc067ce 100644 --- a/.github/workflows/pr_title.yml +++ b/.github/workflows/pr_title.yml @@ -7,7 +7,7 @@ on: - synchronize branches: - main - - main-design-system + - main-design-system # Remove this once the design system is merged into main concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -21,13 +21,13 @@ jobs: with: scopes: | llc + ui repo requireScope: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} semantic_changelog_update: - if: ${{ false }} # TODO: Enable after the first release needs: conventional_pr_title # Trigger after the [conventional_pr_title] completes runs-on: ubuntu-latest steps: diff --git a/all_lint_rules.yaml b/all_lint_rules.yaml index 8ed068a..0fb9e4b 100644 --- a/all_lint_rules.yaml +++ b/all_lint_rules.yaml @@ -3,10 +3,10 @@ linter: - always_declare_return_types - always_put_control_body_on_new_line - always_put_required_named_parameters_first - - always_require_non_null_named_parameters - always_specify_types - always_use_package_imports - annotate_overrides + - annotate_redeclares - avoid_annotating_with_dynamic - avoid_bool_literals_in_conditional_expressions - avoid_catches_without_on_clauses @@ -20,6 +20,7 @@ linter: - avoid_field_initializers_in_const_classes - avoid_final_parameters - avoid_function_literals_in_foreach_calls + - avoid_futureor_void - avoid_implementing_value_types - avoid_init_to_null - avoid_js_rounded_ints @@ -32,8 +33,6 @@ linter: - avoid_relative_lib_imports - avoid_renaming_method_parameters - avoid_return_types_on_setters - - avoid_returning_null - - avoid_returning_null_for_future - avoid_returning_null_for_void - avoid_returning_this - avoid_setters_without_getters @@ -61,12 +60,15 @@ linter: - constant_identifier_names - control_flow_in_finally - curly_braces_in_flow_control_structures + - dangling_library_doc_comments - depend_on_referenced_packages - deprecated_consistency + - deprecated_member_use_from_same_package - diagnostic_describe_all_properties - directives_ordering - discarded_futures - do_not_use_environment + - document_ignores - empty_catches - empty_constructor_bodies - empty_statements @@ -76,32 +78,41 @@ linter: - flutter_style_todos - hash_and_equals - implementation_imports - - iterable_contains_unrelated_type + - implicit_call_tearoffs + - implicit_reopen + - invalid_case_patterns + - invalid_runtime_check_with_js_interop_types - join_return_with_assignment - leading_newlines_in_multiline_strings + - library_annotations - library_names - library_prefixes - library_private_types_in_public_api - lines_longer_than_80_chars - - list_remove_unrelated_type - literal_only_boolean_expressions + - matching_super_parameters + - missing_code_block_language_in_doc_comment - missing_whitespace_between_adjacent_strings - no_adjacent_strings_in_list - no_default_cases - no_duplicate_case_values - no_leading_underscores_for_library_prefixes - no_leading_underscores_for_local_identifiers + - no_literal_bool_comparisons - no_logic_in_create_state - no_runtimeType_toString + - no_self_assignments + - no_wildcard_variable_uses - non_constant_identifier_names - noop_primitive_operations - null_check_on_nullable_type_parameter - null_closures - omit_local_variable_types + - omit_obvious_local_variable_types + - omit_obvious_property_types - one_member_abstracts - only_throw_errors - overridden_fields - - package_api_docs - package_names - package_prefixed_library_names - parameter_assignments @@ -117,7 +128,6 @@ linter: - prefer_constructors_over_static_methods - prefer_contains - prefer_double_quotes - - prefer_equal_for_default_values - prefer_expression_function_bodies - prefer_final_fields - prefer_final_in_for_each @@ -148,8 +158,10 @@ linter: - provide_deprecation_message - public_member_api_docs - recursive_getters + - remove_deprecations_in_breaking_versions - require_trailing_commas - secure_pubspec_urls + - simplify_variable_pattern - sized_box_for_whitespace - sized_box_shrink_expand - slash_for_doc_comments @@ -157,20 +169,31 @@ linter: - sort_constructors_first - sort_pub_dependencies - sort_unnamed_constructors_first + - specify_nonobvious_local_variable_types + - specify_nonobvious_property_types + - strict_top_level_inference + - switch_on_type - test_types_in_equals - throw_in_finally - tighten_type_of_initializing_formals - type_annotate_public_apis - type_init_formals + - type_literal_in_constant_pattern - unawaited_futures + - unintended_html_in_doc_comment + - unnecessary_async - unnecessary_await_in_return - unnecessary_brace_in_string_interps + - unnecessary_breaks - unnecessary_const - unnecessary_constructor_name - unnecessary_final - unnecessary_getters_setters + - unnecessary_ignore - unnecessary_lambdas - unnecessary_late + - unnecessary_library_directive + - unnecessary_library_name - unnecessary_new - unnecessary_null_aware_assignments - unnecessary_null_aware_operator_on_extension_on_nullable @@ -185,9 +208,11 @@ linter: - unnecessary_string_interpolations - unnecessary_this - unnecessary_to_list_in_spreads + - unnecessary_unawaited + - unnecessary_underscores - unreachable_from_main - unrelated_type_equality_checks - - unsafe_html + - unsafe_variance - use_build_context_synchronously - use_colored_box - use_decorated_box @@ -199,6 +224,7 @@ linter: - use_key_in_widget_constructors - use_late_for_private_fields_and_variables - use_named_constants + - use_null_aware_elements - use_raw_strings - use_rethrow_when_possible - use_setters_to_change_properties @@ -207,5 +233,6 @@ linter: - use_super_parameters - use_test_throws_matchers - use_to_and_as_if_applicable + - use_truncating_division - valid_regexps - - void_checks \ No newline at end of file + - void_checks diff --git a/analysis_options.yaml b/analysis_options.yaml index b873dbc..df6701f 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -10,12 +10,14 @@ analyzer: # We explicitly enabled even conflicting rules and are fixing the conflict # in this file. included_file_warning: ignore - - todo: ignore exclude: # exclude all the generated files - packages/*/lib/**/*.*.dart +formatter: + page_width: 100 + trailing_commas: preserve + linter: rules: ## Disabled rules because the repository doesn't respect them (yet) @@ -93,6 +95,19 @@ linter: # There are situations where we use default in enums on purpose no_default_cases: false + # Sometimes static methods are more readable + prefer_constructors_over_static_methods: false + + # Conflicts with `omit_local_variable_types` + specify_nonobvious_local_variable_types: false + specify_nonobvious_property_types: false + + # Makes the code more verbose without adding much value + document_ignores: false + + # False positives + unsafe_variance: false + # Temporarily disabled to find more important issues public_member_api_docs: false avoid_print: false diff --git a/apps/design_system_gallery/.gitignore b/apps/design_system_gallery/.gitignore deleted file mode 100644 index 3820a95..0000000 --- a/apps/design_system_gallery/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ -/coverage/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/apps/design_system_gallery/analysis_options.yaml b/apps/design_system_gallery/analysis_options.yaml deleted file mode 100644 index 0d29021..0000000 --- a/apps/design_system_gallery/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# 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`. - -# 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.dev/lints. - # - # 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: - # 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 diff --git a/apps/design_system_gallery/lib/components/button.dart b/apps/design_system_gallery/lib/components/button.dart index 1d102d1..d9d2175 100644 --- a/apps/design_system_gallery/lib/components/button.dart +++ b/apps/design_system_gallery/lib/components/button.dart @@ -13,7 +13,7 @@ Widget buildCoolButtonUseCase(BuildContext context) { onTap: () { ScaffoldMessenger.of( context, - ).showSnackBar(SnackBar(content: Text('Button clicked'))); + ).showSnackBar(const SnackBar(content: Text('Button clicked'))); }, type: context.knobs.object.dropdown( label: 'Type', diff --git a/apps/design_system_gallery/lib/main.dart b/apps/design_system_gallery/lib/main.dart index 25c25f3..4cdefa7 100644 --- a/apps/design_system_gallery/lib/main.dart +++ b/apps/design_system_gallery/lib/main.dart @@ -1,4 +1,3 @@ -import 'package:design_system_gallery/theme_config.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:widgetbook/widgetbook.dart'; @@ -7,6 +6,7 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; // This file does not exist yet, // it will be generated in the next step import 'main.directories.g.dart'; +import 'theme_config.dart'; void main() { runApp(const WidgetbookApp()); diff --git a/apps/design_system_gallery/lib/theme_config.dart b/apps/design_system_gallery/lib/theme_config.dart index c0422f1..e8af065 100644 --- a/apps/design_system_gallery/lib/theme_config.dart +++ b/apps/design_system_gallery/lib/theme_config.dart @@ -6,7 +6,7 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; @widgetbook.UseCase(name: 'Default', type: ThemeConfig) Widget buildCoolButtonUseCase(BuildContext context) { - return ThemeConfig(); + return const ThemeConfig(); } class ThemeConfig extends StatelessWidget { @@ -18,7 +18,7 @@ class ThemeConfig extends StatelessWidget { return Column( children: [ - Text('Theme config'), + const Text('Theme config'), Row( spacing: 16, children: [ @@ -27,16 +27,13 @@ class ThemeConfig extends StatelessWidget { height: 25, color: themeConfiguration.themeData.primaryColor, ), - Text('Primary color'), + const Text('Primary color'), StreamButton( label: 'Pick color', onTap: () => pickColor( context, - themeConfiguration.themeData.primaryColor ?? - Theme.of(context).colorScheme.primary, - (color) { - themeConfiguration.setPrimaryColor(color); - }, + themeConfiguration.themeData.primaryColor ?? Theme.of(context).colorScheme.primary, + themeConfiguration.setPrimaryColor, ), ), ], @@ -45,15 +42,15 @@ class ThemeConfig extends StatelessWidget { ); } - void pickColor( + Future pickColor( BuildContext context, Color pickerColor, ValueChanged onColorChanged, ) { - showDialog( + return showDialog( context: context, builder: (context) => AlertDialog( - title: Text('Pick a color'), + title: const Text('Pick a color'), content: SingleChildScrollView( child: MaterialPicker( pickerColor: pickerColor, @@ -66,11 +63,9 @@ class ThemeConfig extends StatelessWidget { } class ThemeConfiguration extends ChangeNotifier { - StreamTheme themeData; - ThemeConfiguration({required this.themeData}); - ThemeConfiguration.empty() : themeData = StreamTheme(); + StreamTheme themeData; void setPrimaryColor(Color color) { themeData = themeData.copyWith(primaryColor: color); diff --git a/apps/design_system_gallery/macos/.gitignore b/apps/design_system_gallery/macos/.gitignore deleted file mode 100644 index 746adbb..0000000 --- a/apps/design_system_gallery/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/apps/design_system_gallery/pubspec.yaml b/apps/design_system_gallery/pubspec.yaml index 02e787c..b3dd78d 100644 --- a/apps/design_system_gallery/pubspec.yaml +++ b/apps/design_system_gallery/pubspec.yaml @@ -4,25 +4,24 @@ publish_to: 'none' version: 1.0.0+1 environment: - sdk: ^3.9.0 + sdk: ^3.10.0 dependencies: + cupertino_icons: ^1.0.8 flutter: sdk: flutter - cupertino_icons: ^1.0.8 flutter_colorpicker: ^1.1.0 provider: ^6.1.5+1 - widgetbook: ^3.20.2 - widgetbook_annotation: ^3.9.0 stream_core_flutter: path: ../../packages/stream_core_flutter + widgetbook: ^3.20.2 + widgetbook_annotation: ^3.9.0 dev_dependencies: + build_runner: ^2.10.5 flutter_test: sdk: flutter - flutter_lints: ^5.0.0 widgetbook_generator: ^3.20.1 - build_runner: ^2.10.4 flutter: uses-material-design: true \ No newline at end of file diff --git a/melos.yaml b/melos.yaml index 0be9381..b87e969 100644 --- a/melos.yaml +++ b/melos.yaml @@ -5,15 +5,16 @@ versioning: mode: independent packages: + - apps/** - packages/** command: bootstrap: # Dart and Flutter environment used in the project. environment: - sdk: ^3.6.2 + sdk: ^3.10.0 # We are not using carat '^' syntax here because flutter don't follow semantic versioning. - flutter: ">=3.27.4" + flutter: ">=3.38.1" # List of all the dependencies used in the project. dependencies: @@ -35,7 +36,7 @@ command: # List of all the dev_dependencies used in the project. dev_dependencies: - build_runner: ^2.4.15 + build_runner: ^2.10.5 json_serializable: ^6.9.5 melos: ^6.2.0 mocktail: ^1.0.4 diff --git a/packages/stream_core/lib/src/api/interceptors/logging_interceptor.dart b/packages/stream_core/lib/src/api/interceptors/logging_interceptor.dart index 61694bd..0c507a0 100644 --- a/packages/stream_core/lib/src/api/interceptors/logging_interceptor.dart +++ b/packages/stream_core/lib/src/api/interceptors/logging_interceptor.dart @@ -1,4 +1,3 @@ -// ignore_for_file: lines_longer_than_80_chars // coverage:ignore-file import 'dart:math' as math; @@ -56,10 +55,10 @@ class LoggingInterceptor extends Interceptor { final bool error; /// InitialTab count to logPrint json response - static const int initialTab = 1; + static const initialTab = 1; /// 1 tab length - static const String tabStep = ' '; + static const tabStep = ' '; /// Print compact json response final bool compact; @@ -155,8 +154,7 @@ class LoggingInterceptor extends Interceptor { _printResponseHeader(_logPrintResponse, response); if (responseHeader) { final responseHeaders = {}; - response.headers - .forEach((k, list) => responseHeaders[k] = list.toString()); + response.headers.forEach((k, list) => responseHeaders[k] = list.toString()); _printMapAsTable(_logPrintResponse, responseHeaders, header: 'Headers'); } @@ -206,8 +204,7 @@ class LoggingInterceptor extends Interceptor { final method = response.requestOptions.method; _printBoxed( logPrint, - header: - 'Response ║ $method ║ Status: ${response.statusCode} ${response.statusMessage}', + header: 'Response ║ $method ║ Status: ${response.statusCode} ${response.statusMessage}', text: uri.toString(), ); } @@ -225,8 +222,7 @@ class LoggingInterceptor extends Interceptor { void Function(Object) logPrint, [ String pre = '', String suf = '╝', - ]) => - logPrint('$pre${'═' * maxWidth}$suf'); + ]) => logPrint('$pre${'═' * maxWidth}$suf'); void _printKV(void Function(Object) logPrint, String? key, Object? v) { final pre = '╟ $key: '; @@ -299,10 +295,12 @@ class LoggingInterceptor extends Interceptor { if (msg.length + indent.length > linWidth) { final lines = (msg.length / linWidth).ceil(); for (var i = 0; i < lines; ++i) { - logPrint('║${_indent(indentedTabs)} ${msg.substring( - i * linWidth, - math.min(i * linWidth + linWidth, msg.length), - )}'); + logPrint( + '║${_indent(indentedTabs)} ${msg.substring( + i * linWidth, + math.min(i * linWidth + linWidth, msg.length), + )}', + ); } } else { logPrint('║${_indent(indentedTabs)} $key: $msg${!isLast ? ',' : ''}'); @@ -351,11 +349,9 @@ class LoggingInterceptor extends Interceptor { _printLine(logPrint, '╚'); } - void _logPrintRequest(Object object) => - logPrint(InterceptStep.request, object); + void _logPrintRequest(Object object) => logPrint(InterceptStep.request, object); - void _logPrintResponse(Object object) => - logPrint(InterceptStep.response, object); + void _logPrintResponse(Object object) => logPrint(InterceptStep.response, object); void _logPrintError(Object object) => logPrint(InterceptStep.error, object); } diff --git a/packages/stream_core/lib/src/api/stream_core_dio_error.dart b/packages/stream_core/lib/src/api/stream_core_dio_error.dart index 33cf78b..fb0d345 100644 --- a/packages/stream_core/lib/src/api/stream_core_dio_error.dart +++ b/packages/stream_core/lib/src/api/stream_core_dio_error.dart @@ -13,9 +13,9 @@ class StreamDioException extends DioException { StackTrace? stackTrace, super.message, }) : super( - error: exception, - stackTrace: stackTrace ?? StackTrace.current, - ); + error: exception, + stackTrace: stackTrace ?? StackTrace.current, + ); final ClientException exception; } diff --git a/packages/stream_core/lib/src/attachment/uploader/attachment_uploader.dart b/packages/stream_core/lib/src/attachment/uploader/attachment_uploader.dart index 73eeaf9..a660306 100644 --- a/packages/stream_core/lib/src/attachment/uploader/attachment_uploader.dart +++ b/packages/stream_core/lib/src/attachment/uploader/attachment_uploader.dart @@ -112,10 +112,7 @@ class StreamAttachmentUploader { /// /// Receives the [attachmentId] and upload [progress] as a value between 0.0 and 1.0 /// for individual attachments during batch upload. -typedef OnBatchUploadProgress = void Function( - String attachmentId, - double progress, -); +typedef OnBatchUploadProgress = void Function(String attachmentId, double progress); /// Extension providing batch upload functionality for [StreamAttachmentUploader]. /// @@ -150,7 +147,8 @@ extension StreamAttachmentUploaderBatch on StreamAttachmentUploader { upload( attachment, onProgress: onProgress?.let( - (f) => (progress) => f(attachment.id, progress), + (f) => + (progress) => f(attachment.id, progress), ), ), ), diff --git a/packages/stream_core/lib/src/errors/stream_api_error.dart b/packages/stream_core/lib/src/errors/stream_api_error.dart index 4d33bcb..19c2fe0 100644 --- a/packages/stream_core/lib/src/errors/stream_api_error.dart +++ b/packages/stream_core/lib/src/errors/stream_api_error.dart @@ -54,20 +54,19 @@ class StreamApiError extends Equatable { Map toJson() => _$StreamApiErrorToJson(this); /// Creates a [StreamApiError] from a JSON map. - static StreamApiError fromJson(Map json) => - _$StreamApiErrorFromJson(json); + static StreamApiError fromJson(Map json) => _$StreamApiErrorFromJson(json); @override List get props => [ - code, - details, - duration, - exceptionFields, - message, - moreInfo, - statusCode, - unrecoverable, - ]; + code, + details, + duration, + exceptionFields, + message, + moreInfo, + statusCode, + unrecoverable, + ]; } final _tokenInvalidErrorCodes = _range(40, 42); diff --git a/packages/stream_core/lib/src/errors/stream_api_error.g.dart b/packages/stream_core/lib/src/errors/stream_api_error.g.dart index 15ba50e..e3fd613 100644 --- a/packages/stream_core/lib/src/errors/stream_api_error.g.dart +++ b/packages/stream_core/lib/src/errors/stream_api_error.g.dart @@ -6,30 +6,26 @@ part of 'stream_api_error.dart'; // JsonSerializableGenerator // ************************************************************************** -StreamApiError _$StreamApiErrorFromJson(Map json) => - StreamApiError( - code: (json['code'] as num).toInt(), - details: (json['details'] as List) - .map((e) => (e as num).toInt()) - .toList(), - duration: json['duration'] as String, - exceptionFields: (json['exception_fields'] as Map?)?.map( - (k, e) => MapEntry(k, e as String), - ), - message: json['message'] as String, - moreInfo: json['more_info'] as String, - statusCode: (json['StatusCode'] as num).toInt(), - unrecoverable: json['unrecoverable'] as bool?, - ); +StreamApiError _$StreamApiErrorFromJson(Map json) => StreamApiError( + code: (json['code'] as num).toInt(), + details: (json['details'] as List).map((e) => (e as num).toInt()).toList(), + duration: json['duration'] as String, + exceptionFields: (json['exception_fields'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ), + message: json['message'] as String, + moreInfo: json['more_info'] as String, + statusCode: (json['StatusCode'] as num).toInt(), + unrecoverable: json['unrecoverable'] as bool?, +); -Map _$StreamApiErrorToJson(StreamApiError instance) => - { - 'code': instance.code, - 'details': instance.details, - 'duration': instance.duration, - 'exception_fields': instance.exceptionFields, - 'message': instance.message, - 'more_info': instance.moreInfo, - 'StatusCode': instance.statusCode, - 'unrecoverable': instance.unrecoverable, - }; +Map _$StreamApiErrorToJson(StreamApiError instance) => { + 'code': instance.code, + 'details': instance.details, + 'duration': instance.duration, + 'exception_fields': instance.exceptionFields, + 'message': instance.message, + 'more_info': instance.moreInfo, + 'StatusCode': instance.statusCode, + 'unrecoverable': instance.unrecoverable, +}; diff --git a/packages/stream_core/lib/src/logger/impl/external_logger.dart b/packages/stream_core/lib/src/logger/impl/external_logger.dart index 5552e76..56a749f 100644 --- a/packages/stream_core/lib/src/logger/impl/external_logger.dart +++ b/packages/stream_core/lib/src/logger/impl/external_logger.dart @@ -1,12 +1,13 @@ import '../stream_logger.dart'; -typedef ExternalFunction = void Function( - Priority priority, - String tag, - MessageBuilder message, [ - Object? error, - StackTrace? stk, -]); +typedef ExternalFunction = + void Function( + Priority priority, + String tag, + MessageBuilder message, [ + Object? error, + StackTrace? stk, + ]); class ExternalStreamLogger extends StreamLogger { const ExternalStreamLogger(this.external); diff --git a/packages/stream_core/lib/src/logger/impl/file_logger.dart b/packages/stream_core/lib/src/logger/impl/file_logger.dart index 634deb7..27f66db 100644 --- a/packages/stream_core/lib/src/logger/impl/file_logger.dart +++ b/packages/stream_core/lib/src/logger/impl/file_logger.dart @@ -7,12 +7,12 @@ import 'package:intl/intl.dart'; import '../../utils/standard.dart'; import '../stream_logger.dart'; -const String _tag = 'SV:FileLogger'; +const _tag = 'SV:FileLogger'; const int _defaultSize = 12 * 1024 * 1024; -const String _shareableFilePrefix = 'stream_log_'; -const String _internalFile0 = 'internal_0.txt'; -const String _internalFile1 = 'internal_1.txt'; +const _shareableFilePrefix = 'stream_log_'; +const _internalFile0 = 'internal_0.txt'; +const _internalFile1 = 'internal_1.txt'; typedef FileLogSender = Future Function(File); @@ -26,8 +26,7 @@ class FileStreamLogger extends StreamLogger { this.console, }); - static final Finalizer _finalizer = - Finalizer((ioSink) async => ioSink.close()); + static final Finalizer _finalizer = Finalizer((ioSink) => ioSink.close()); final FileLogConfig config; final FileLogSender? sender; @@ -73,9 +72,7 @@ class FileStreamLogger extends StreamLogger { final File currentFile; if (!_file0.existsSync() || !_file1.existsSync()) { currentFile = _file0; - } else if (_file0 - .lastModifiedSync() - .isAfter(_file1.lastModifiedSync())) { + } else if (_file0.lastModifiedSync().isAfter(_file1.lastModifiedSync())) { currentFile = _file0; } else { currentFile = _file1; @@ -120,7 +117,8 @@ class FileStreamLogger extends StreamLogger { Future clear() async { try { _logD( - () => '[clear] before; file0: ${_file0.lengthSync()}, ' + () => + '[clear] before; file0: ${_file0.lengthSync()}, ' 'file1: ${_file1.lengthSync()}', ); final currentIO = _currentIO; @@ -139,7 +137,8 @@ class FileStreamLogger extends StreamLogger { _finalizer.attach(this, it, detach: this); }); _logV( - () => '[clear] after; file0: ${_file0.lengthSync()}, ' + () => + '[clear] after; file0: ${_file0.lengthSync()}, ' 'file1: ${_file1.lengthSync()}', ); } catch (e, stk) { @@ -166,19 +165,20 @@ class FileStreamLogger extends StreamLogger { } Future prepareShareable() async { - final filename = '$_shareableFilePrefix' + final filename = + '$_shareableFilePrefix' '${_dateFormat.format(DateTime.now())}.txt'; - final out = File('${_tempsDir.path}$pathSeparator$filename') - ..createSync(recursive: true); + final out = File('${_tempsDir.path}$pathSeparator$filename')..createSync(recursive: true); _logD(() => '[prepareShareable] out: $out'); IOSink? writer; try { writer = out.openWrite(mode: FileMode.append); writer.writeln(await _buildHeader()); - final filtered = [_file0, _file1] - .where((file) => file.existsSync()) - .sortedBy((file) => file.lastModifiedSync()); + final filtered = [ + _file0, + _file1, + ].where((file) => file.existsSync()).sortedBy((file) => file.lastModifiedSync()); for (final file in filtered) { if (file.existsSync()) { await writer.addStream(file.openRead()); diff --git a/packages/stream_core/lib/src/logger/stream_log.dart b/packages/stream_core/lib/src/logger/stream_log.dart index 9862603..f4709d1 100644 --- a/packages/stream_core/lib/src/logger/stream_log.dart +++ b/packages/stream_core/lib/src/logger/stream_log.dart @@ -1,3 +1,5 @@ +// ignore_for_file: omit_obvious_property_types + import 'stream_logger.dart'; StreamLog get streamLog => StreamLog(); @@ -9,7 +11,7 @@ class StreamLog { StreamLog._(); - static final StreamLog _instance = StreamLog._(); + static final _instance = StreamLog._(); StreamLogger _logger = const SilentStreamLogger(); IsLoggableValidator _validator = (Priority priority, Tag tag) => false; diff --git a/packages/stream_core/lib/src/logger/stream_logger.dart b/packages/stream_core/lib/src/logger/stream_logger.dart index e0c9f4f..730f578 100644 --- a/packages/stream_core/lib/src/logger/stream_logger.dart +++ b/packages/stream_core/lib/src/logger/stream_logger.dart @@ -41,7 +41,8 @@ enum Priority implements Comparable { info(level: 4), warning(level: 5), error(level: 6), - none(level: 7); + none(level: 7) + ; const Priority({required this.level}); diff --git a/packages/stream_core/lib/src/platform/current_platform.dart b/packages/stream_core/lib/src/platform/current_platform.dart index 7e0d133..8cb934a 100644 --- a/packages/stream_core/lib/src/platform/current_platform.dart +++ b/packages/stream_core/lib/src/platform/current_platform.dart @@ -1,5 +1,4 @@ -import 'detector/platform_detector.dart' - if (dart.library.io) 'detector/platform_detector_io.dart'; +import 'detector/platform_detector.dart' if (dart.library.io) 'detector/platform_detector_io.dart'; /// Platform detection utility for identifying the current runtime environment. /// @@ -87,7 +86,8 @@ enum PlatformType { linux('linux'), /// Fuchsia: - fuchsia('fuchsia'); + fuchsia('fuchsia') + ; /// Creates a [PlatformType] with the specified [operatingSystem] identifier. const PlatformType(this.operatingSystem); diff --git a/packages/stream_core/lib/src/query/filter/filter.dart b/packages/stream_core/lib/src/query/filter/filter.dart index af7d10d..fd9bef3 100644 --- a/packages/stream_core/lib/src/query/filter/filter.dart +++ b/packages/stream_core/lib/src/query/filter/filter.dart @@ -1,3 +1,5 @@ +// ignore_for_file: matching_super_parameters + import '../../utils.dart'; import 'filter_operation_utils.dart'; import 'filter_operator.dart'; @@ -241,8 +243,7 @@ sealed class ComparisonOperator extends Filter { /// **Supported with**: `.equal` factory method final class EqualOperator extends ComparisonOperator { /// Creates an equality filter for the specified [field] and [value]. - const EqualOperator(super.field, super.value) - : super._(operator: FilterOperator.equal); + const EqualOperator(super.field, super.value) : super._(operator: FilterOperator.equal); @override bool matches(T other) { @@ -273,8 +274,7 @@ final class EqualOperator extends ComparisonOperator { /// **Supported with**: `.greater` factory method final class GreaterOperator extends ComparisonOperator { /// Creates a greater-than filter for the specified [field] and [value]. - const GreaterOperator(super.field, super.value) - : super._(operator: FilterOperator.greater); + const GreaterOperator(super.field, super.value) : super._(operator: FilterOperator.greater); @override bool matches(T other) { @@ -293,11 +293,10 @@ final class GreaterOperator extends ComparisonOperator { /// Greater-than-or-equal comparison filter. /// /// Primarily used with numeric values and dates. -final class GreaterOrEqualOperator - extends ComparisonOperator { +final class GreaterOrEqualOperator extends ComparisonOperator { /// Creates a greater-than-or-equal filter for the specified [field] and [value]. const GreaterOrEqualOperator(super.field, super.value) - : super._(operator: FilterOperator.greaterOrEqual); + : super._(operator: FilterOperator.greaterOrEqual); @override bool matches(T other) { @@ -318,8 +317,7 @@ final class GreaterOrEqualOperator /// Primarily used with numeric values and dates. final class LessOperator extends ComparisonOperator { /// Creates a less-than filter for the specified [field] and [value]. - const LessOperator(super.field, super.value) - : super._(operator: FilterOperator.less); + const LessOperator(super.field, super.value) : super._(operator: FilterOperator.less); @override bool matches(T other) { @@ -338,11 +336,10 @@ final class LessOperator extends ComparisonOperator { /// Less-than-or-equal comparison filter. /// /// Primarily used with numeric values and dates. -final class LessOrEqualOperator - extends ComparisonOperator { +final class LessOrEqualOperator extends ComparisonOperator { /// Creates a less-than-or-equal filter for the specified [field] and [value]. const LessOrEqualOperator(super.field, super.value) - : super._(operator: FilterOperator.lessOrEqual); + : super._(operator: FilterOperator.lessOrEqual); @override bool matches(T other) { @@ -398,7 +395,7 @@ sealed class ListOperator extends Filter { final class InOperator extends ListOperator { /// Creates an 'in' filter for the specified [field] and [values] iterable. const InOperator(super.field, Iterable super.values) - : super._(operator: FilterOperator.in_); + : super._(operator: FilterOperator.in_); @override bool matches(T other) { @@ -422,8 +419,7 @@ final class InOperator extends ListOperator { /// **Supported with**: `.contains` factory method final class ContainsOperator extends ListOperator { /// Creates a contains filter for the specified [field] and [value]. - const ContainsOperator(super.field, super.value) - : super._(operator: FilterOperator.contains_); + const ContainsOperator(super.field, super.value) : super._(operator: FilterOperator.contains_); @override bool matches(T other) { @@ -511,8 +507,7 @@ sealed class EvaluationOperator extends Filter { /// **Supported with**: `.query` factory method final class QueryOperator extends EvaluationOperator { /// Creates a text search filter for the specified [field] and search [query]. - const QueryOperator(super.field, super.query) - : super._(operator: FilterOperator.query); + const QueryOperator(super.field, super.query) : super._(operator: FilterOperator.query); @override bool matches(T other) { @@ -529,11 +524,10 @@ final class QueryOperator extends EvaluationOperator { /// Word prefix matching filter for autocomplete. /// /// Matches field values where any word starts with the provided prefix. -final class AutoCompleteOperator - extends EvaluationOperator { +final class AutoCompleteOperator extends EvaluationOperator { /// Creates an autocomplete filter for the specified [field] and prefix [query]. const AutoCompleteOperator(super.field, super.query) - : super._(operator: FilterOperator.autoComplete); + : super._(operator: FilterOperator.autoComplete); @override bool matches(T other) { diff --git a/packages/stream_core/lib/src/query/filter/location/bounding_box.g.dart b/packages/stream_core/lib/src/query/filter/location/bounding_box.g.dart index 90bb530..ecb84e5 100644 --- a/packages/stream_core/lib/src/query/filter/location/bounding_box.g.dart +++ b/packages/stream_core/lib/src/query/filter/location/bounding_box.g.dart @@ -6,10 +6,9 @@ part of 'bounding_box.dart'; // JsonSerializableGenerator // ************************************************************************** -Map _$BoundingBoxToJson(BoundingBox instance) => - { - 'ne_lat': instance.neLat, - 'ne_lng': instance.neLng, - 'sw_lat': instance.swLat, - 'sw_lng': instance.swLng, - }; +Map _$BoundingBoxToJson(BoundingBox instance) => { + 'ne_lat': instance.neLat, + 'ne_lng': instance.neLng, + 'sw_lat': instance.swLat, + 'sw_lng': instance.swLng, +}; diff --git a/packages/stream_core/lib/src/query/filter/location/circular_region.g.dart b/packages/stream_core/lib/src/query/filter/location/circular_region.g.dart index 66a08e0..2690c73 100644 --- a/packages/stream_core/lib/src/query/filter/location/circular_region.g.dart +++ b/packages/stream_core/lib/src/query/filter/location/circular_region.g.dart @@ -6,9 +6,8 @@ part of 'circular_region.dart'; // JsonSerializableGenerator // ************************************************************************** -Map _$CircularRegionToJson(CircularRegion instance) => - { - 'lat': instance.lat, - 'lng': instance.lng, - 'distance': instance.distance, - }; +Map _$CircularRegionToJson(CircularRegion instance) => { + 'lat': instance.lat, + 'lng': instance.lng, + 'distance': instance.distance, +}; diff --git a/packages/stream_core/lib/src/query/filter/location/location_coordinate.dart b/packages/stream_core/lib/src/query/filter/location/location_coordinate.dart index 2164904..cb67d04 100644 --- a/packages/stream_core/lib/src/query/filter/location/location_coordinate.dart +++ b/packages/stream_core/lib/src/query/filter/location/location_coordinate.dart @@ -79,9 +79,8 @@ class LocationCoordinate { final latComponent = _square(sinDLat); // Calculate longitude component: sin²(Δlon/2) * cos(lat1) * cos(lat2) - final lonComponent = _square(sinDLon) * - math.cos(_degToRad(latitude)) * - math.cos(_degToRad(other.latitude)); + final lonComponent = + _square(sinDLon) * math.cos(_degToRad(latitude)) * math.cos(_degToRad(other.latitude)); // Combine components final a = latComponent + lonComponent; diff --git a/packages/stream_core/lib/src/query/sort.dart b/packages/stream_core/lib/src/query/sort.dart index 164fbc4..67afa67 100644 --- a/packages/stream_core/lib/src/query/sort.dart +++ b/packages/stream_core/lib/src/query/sort.dart @@ -15,7 +15,8 @@ enum SortDirection { /// Sort in descending order (Z to A, 9 to 1, etc.). @JsonValue(-1) - desc(-1); + desc(-1) + ; /// Creates a new [SortDirection] instance with the specified direction. const SortDirection(this.value); @@ -32,7 +33,7 @@ enum NullOrdering { /// Null values appear at the end of the sorted list, /// regardless of sort direction (ASC or DESC). - nullsLast; + nullsLast, } /// Signature for a function that retrieves a sortable field value of type [V] from @@ -44,12 +45,13 @@ typedef SortFieldValueGetter = V? Function(T); /// A comparator function that compares two instances of type [T] based on /// a specified field, sort direction, and null ordering. -typedef SortFieldComparator = int Function( - T? a, - T? b, - SortDirection direction, - NullOrdering nullOrdering, -); +typedef SortFieldComparator = + int Function( + T? a, + T? b, + SortDirection direction, + NullOrdering nullOrdering, + ); /// A sort specification that defines how to order a collection of objects. /// diff --git a/packages/stream_core/lib/src/query/sort.g.dart b/packages/stream_core/lib/src/query/sort.g.dart index 3036cd4..2d8de5f 100644 --- a/packages/stream_core/lib/src/query/sort.g.dart +++ b/packages/stream_core/lib/src/query/sort.g.dart @@ -6,13 +6,9 @@ part of 'sort.dart'; // JsonSerializableGenerator // ************************************************************************** -Map _$SortToJson(Sort instance) => - { - 'field': Sort._fieldToJson(instance.field), - 'direction': _$SortDirectionEnumMap[instance.direction]!, - }; - -const _$SortDirectionEnumMap = { - SortDirection.asc: 1, - SortDirection.desc: -1, +Map _$SortToJson(Sort instance) => { + 'field': Sort._fieldToJson(instance.field), + 'direction': _$SortDirectionEnumMap[instance.direction]!, }; + +const _$SortDirectionEnumMap = {SortDirection.asc: 1, SortDirection.desc: -1}; diff --git a/packages/stream_core/lib/src/user/connect_user_details_request.g.dart b/packages/stream_core/lib/src/user/connect_user_details_request.g.dart index 3b4fe26..1d97036 100644 --- a/packages/stream_core/lib/src/user/connect_user_details_request.g.dart +++ b/packages/stream_core/lib/src/user/connect_user_details_request.g.dart @@ -7,12 +7,12 @@ part of 'connect_user_details_request.dart'; // ************************************************************************** Map _$ConnectUserDetailsRequestToJson( - ConnectUserDetailsRequest instance) => - { - 'id': instance.id, - 'image': instance.image, - 'invisible': instance.invisible, - 'language': instance.language, - 'name': instance.name, - 'custom': instance.custom, - }; + ConnectUserDetailsRequest instance, +) => { + 'id': instance.id, + 'image': instance.image, + 'invisible': instance.invisible, + 'language': instance.language, + 'name': instance.name, + 'custom': instance.custom, +}; diff --git a/packages/stream_core/lib/src/user/token_manager.dart b/packages/stream_core/lib/src/user/token_manager.dart index aa9c6dc..288f0d4 100644 --- a/packages/stream_core/lib/src/user/token_manager.dart +++ b/packages/stream_core/lib/src/user/token_manager.dart @@ -68,7 +68,7 @@ class TokenManager { /// at a time. /// /// Returns a [Future] that resolves to a [UserToken] for the user. - Future getToken() async { + Future getToken() { final snapshot = _cachedToken; return synchronized(() async { // If the snapshot is no longer equal to the cached token, it means diff --git a/packages/stream_core/lib/src/user/user.dart b/packages/stream_core/lib/src/user/user.dart index 9b0fcd5..606ea46 100644 --- a/packages/stream_core/lib/src/user/user.dart +++ b/packages/stream_core/lib/src/user/user.dart @@ -16,14 +16,13 @@ class User extends Equatable { this.role = 'user', this.type = UserType.regular, Map? custom, - }) : originalName = name, - custom = custom ?? const {}; + }) : originalName = name, + custom = custom ?? const {}; /// Creates a guest user with the provided id. /// - Parameter userId: the id of the user. /// - Returns: a guest `User`. - const User.guest(String userId) - : this(id: userId, name: userId, type: UserType.guest); + const User.guest(String userId) : this(id: userId, name: userId, type: UserType.guest); /// Creates an anonymous user. /// - Returns: an anonymous `User`. @@ -54,14 +53,7 @@ class User extends Equatable { String get name => originalName ?? id; @override - List get props => [ - id, - image, - role, - type, - originalName, - custom, - ]; + List get props => [id, image, role, type, originalName, custom]; } /// The user authorization type. diff --git a/packages/stream_core/lib/src/user/user_token.dart b/packages/stream_core/lib/src/user/user_token.dart index 63fe1c6..bdb7cd3 100644 --- a/packages/stream_core/lib/src/user/user_token.dart +++ b/packages/stream_core/lib/src/user/user_token.dart @@ -112,7 +112,8 @@ enum AuthType { /// /// Allows unauthenticated access with limited permissions. /// Used for public content access or guest user scenarios. - anonymous('anonymous'); + anonymous('anonymous') + ; /// Constructs an [AuthType] with the associated header value. const AuthType(this.headerValue); diff --git a/packages/stream_core/lib/src/user/ws_auth_message_request.g.dart b/packages/stream_core/lib/src/user/ws_auth_message_request.g.dart index 9e4f2ae..b32bada 100644 --- a/packages/stream_core/lib/src/user/ws_auth_message_request.g.dart +++ b/packages/stream_core/lib/src/user/ws_auth_message_request.g.dart @@ -7,12 +7,12 @@ part of 'ws_auth_message_request.dart'; // ************************************************************************** Map _$WsAuthMessageRequestToJson( - WsAuthMessageRequest instance) => - { - 'stringify': instance.stringify, - 'hash_code': instance.hashCode, - 'products': instance.products, - 'token': instance.token, - 'user_details': instance.userDetails?.toJson(), - 'props': instance.props, - }; + WsAuthMessageRequest instance, +) => { + 'stringify': instance.stringify, + 'hash_code': instance.hashCode, + 'products': instance.products, + 'token': instance.token, + 'user_details': instance.userDetails?.toJson(), + 'props': instance.props, +}; diff --git a/packages/stream_core/lib/src/utils/comparable_field.dart b/packages/stream_core/lib/src/utils/comparable_field.dart index 00c1310..692ad7c 100644 --- a/packages/stream_core/lib/src/utils/comparable_field.dart +++ b/packages/stream_core/lib/src/utils/comparable_field.dart @@ -41,8 +41,7 @@ import 'package:meta/meta.dart'; /// print(intField?.compareTo(doubleField!)); // 0 (equal) /// ``` @immutable -class ComparableField - implements Comparable> { +class ComparableField implements Comparable> { const ComparableField._(this.value); /// Creates a [ComparableField] from [value]. @@ -84,8 +83,8 @@ class ComparableField (final bool a, final bool b) when a == b => 0, (final bool a, final bool b) => a && !b ? 1 : -1, _ => throw ArgumentError( - 'Incompatible types: ${value.runtimeType} vs ${other.value.runtimeType}', - ), + 'Incompatible types: ${value.runtimeType} vs ${other.value.runtimeType}', + ), }; } } diff --git a/packages/stream_core/lib/src/utils/disposable.dart b/packages/stream_core/lib/src/utils/disposable.dart index 1ef2462..be10176 100644 --- a/packages/stream_core/lib/src/utils/disposable.dart +++ b/packages/stream_core/lib/src/utils/disposable.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_futureor_void, unnecessary_async + import 'dart:async'; import 'package:meta/meta.dart'; @@ -6,7 +8,7 @@ import 'package:meta/meta.dart'; mixin class Disposable { /// Returns `true` if this object has been disposed. bool get isDisposed => _disposed; - bool _disposed = false; + var _disposed = false; /// Disposes of this object. @mustCallSuper diff --git a/packages/stream_core/lib/src/utils/event_emitter.dart b/packages/stream_core/lib/src/utils/event_emitter.dart index 0bda35c..11d20b7 100644 --- a/packages/stream_core/lib/src/utils/event_emitter.dart +++ b/packages/stream_core/lib/src/utils/event_emitter.dart @@ -57,8 +57,8 @@ typedef EventEmitter = SharedEmitter; /// See also: /// - [EventEmitter] for the read-only interface. /// - [EventResolver] for the resolver function signature. -final class MutableEventEmitter - extends SharedEmitterImpl implements MutableSharedEmitter { +final class MutableEventEmitter extends SharedEmitterImpl + implements MutableSharedEmitter { /// Creates a [MutableEventEmitter] with optional event [resolvers]. /// /// Resolvers are applied in order to each emitted event until one returns diff --git a/packages/stream_core/lib/src/utils/result.dart b/packages/stream_core/lib/src/utils/result.dart index 034f809..07c66ca 100644 --- a/packages/stream_core/lib/src/utils/result.dart +++ b/packages/stream_core/lib/src/utils/result.dart @@ -94,8 +94,10 @@ extension PatternMatching on Result { T getOrThrow() { return switch (this) { Success(:final data) => data, - Failure(:final error, :final stackTrace) => - Error.throwWithStackTrace(error, stackTrace ?? StackTrace.current), + Failure(:final error, :final stackTrace) => Error.throwWithStackTrace( + error, + stackTrace ?? StackTrace.current, + ), }; } @@ -184,8 +186,8 @@ extension PatternMatching on Result { return switch (this) { Success(:final data) => Result.success(data as R), Failure(:final error, :final stackTrace) => Result.success( - transform(error, stackTrace), - ), + transform(error, stackTrace), + ), }; } @@ -200,8 +202,8 @@ extension PatternMatching on Result { return switch (this) { Success(:final data) => Result.success(data as R), Failure(:final error, :final stackTrace) => runSafelySync( - () => transform(error, stackTrace), - ), + () => transform(error, stackTrace), + ), }; } diff --git a/packages/stream_core/lib/src/utils/shared_emitter.dart b/packages/stream_core/lib/src/utils/shared_emitter.dart index 0c52b06..c3005c9 100644 --- a/packages/stream_core/lib/src/utils/shared_emitter.dart +++ b/packages/stream_core/lib/src/utils/shared_emitter.dart @@ -98,8 +98,7 @@ abstract interface class MutableSharedEmitter extends SharedEmitter { /// /// See also: /// - [MutableSharedEmitter] for the interface. -class SharedEmitterImpl extends StreamView - implements MutableSharedEmitter { +class SharedEmitterImpl extends StreamView implements MutableSharedEmitter { /// Creates a [SharedEmitterImpl]. /// /// Supports synchronous or asynchronous event emission via [sync], and diff --git a/packages/stream_core/lib/src/utils/state_emitter.dart b/packages/stream_core/lib/src/utils/state_emitter.dart index 5bb0799..8494142 100644 --- a/packages/stream_core/lib/src/utils/state_emitter.dart +++ b/packages/stream_core/lib/src/utils/state_emitter.dart @@ -71,8 +71,7 @@ abstract interface class MutableStateEmitter extends StateEmitter /// /// See also: /// - [MutableStateEmitter] for the interface. -class StateEmitterImpl extends StreamView - implements MutableStateEmitter { +class StateEmitterImpl extends StreamView implements MutableStateEmitter { /// Creates a [StateEmitterImpl] with the given [initialValue]. /// /// Supports synchronous or asynchronous state emission via [sync]. diff --git a/packages/stream_core/lib/src/ws/client/engine/stream_web_socket_engine.dart b/packages/stream_core/lib/src/ws/client/engine/stream_web_socket_engine.dart index 5f5194c..7a70596 100644 --- a/packages/stream_core/lib/src/ws/client/engine/stream_web_socket_engine.dart +++ b/packages/stream_core/lib/src/ws/client/engine/stream_web_socket_engine.dart @@ -36,9 +36,9 @@ class StreamWebSocketEngine implements WebSocketEngine { WebSocketProvider? wsProvider, WebSocketEngineListener? listener, required WebSocketMessageCodec messageCodec, - }) : _wsProvider = wsProvider ?? _createWebSocket, - _messageCodec = messageCodec, - _listener = listener; + }) : _wsProvider = wsProvider ?? _createWebSocket, + _messageCodec = messageCodec, + _listener = listener; final WebSocketProvider _wsProvider; final WebSocketMessageCodec _messageCodec; diff --git a/packages/stream_core/lib/src/ws/client/engine/web_socket_engine.dart b/packages/stream_core/lib/src/ws/client/engine/web_socket_engine.dart index 9553267..29acf58 100644 --- a/packages/stream_core/lib/src/ws/client/engine/web_socket_engine.dart +++ b/packages/stream_core/lib/src/ws/client/engine/web_socket_engine.dart @@ -181,8 +181,8 @@ class WebSocketEngineException with EquatableMixin implements Exception { String? reason, int? code = 0, this.error, - }) : reason = reason ?? 'Unknown', - code = code ?? 0; + }) : reason = reason ?? 'Unknown', + code = code ?? 0; final String reason; final int code; diff --git a/packages/stream_core/lib/src/ws/client/reconnect/automatic_reconnection_policy.dart b/packages/stream_core/lib/src/ws/client/reconnect/automatic_reconnection_policy.dart index 6481c3a..e26ee52 100644 --- a/packages/stream_core/lib/src/ws/client/reconnect/automatic_reconnection_policy.dart +++ b/packages/stream_core/lib/src/ws/client/reconnect/automatic_reconnection_policy.dart @@ -12,8 +12,7 @@ abstract interface class AutomaticReconnectionPolicy { /// A reconnection policy that checks if automatic reconnection is enabled /// based on the current state of the WebSocket connection. -class WebSocketAutomaticReconnectionPolicy - implements AutomaticReconnectionPolicy { +class WebSocketAutomaticReconnectionPolicy implements AutomaticReconnectionPolicy { /// Creates a [WebSocketAutomaticReconnectionPolicy]. WebSocketAutomaticReconnectionPolicy({required this.connectionState}); @@ -30,8 +29,7 @@ class WebSocketAutomaticReconnectionPolicy /// A reconnection policy that checks for internet connectivity before allowing /// reconnection. This prevents unnecessary reconnection attempts when there's no /// network available. -class InternetAvailabilityReconnectionPolicy - implements AutomaticReconnectionPolicy { +class InternetAvailabilityReconnectionPolicy implements AutomaticReconnectionPolicy { /// Creates an [InternetAvailabilityReconnectionPolicy]. InternetAvailabilityReconnectionPolicy({required this.networkState}); @@ -69,7 +67,7 @@ enum Operator { /// Requires ANY policy to return `true` for reconnection to be allowed. /// If at least one policy returns `true`, reconnection will be attempted. - or; + or, } /// A composite reconnection policy that combines multiple [policies] using a diff --git a/packages/stream_core/lib/src/ws/client/reconnect/connection_recovery_handler.dart b/packages/stream_core/lib/src/ws/client/reconnect/connection_recovery_handler.dart index 3dc70c1..3cbfcd3 100644 --- a/packages/stream_core/lib/src/ws/client/reconnect/connection_recovery_handler.dart +++ b/packages/stream_core/lib/src/ws/client/reconnect/connection_recovery_handler.dart @@ -42,23 +42,23 @@ class ConnectionRecoveryHandler extends Disposable { bool keepConnectionAliveInBackground = false, List? policies, RetryStrategy? retryStrategy, - }) : _client = client, - _reconnectStrategy = retryStrategy ?? RetryStrategy(), - _keepConnectionAliveInBackground = keepConnectionAliveInBackground, - _policies = [ - if (policies != null) ...policies, - WebSocketAutomaticReconnectionPolicy( - connectionState: client.connectionState, - ), - if (networkStateProvider case final provider?) - InternetAvailabilityReconnectionPolicy( - networkState: provider.state, - ), - if (lifecycleStateProvider case final provider?) - BackgroundStateReconnectionPolicy( - appLifecycleState: provider.state, - ), - ] { + }) : _client = client, + _reconnectStrategy = retryStrategy ?? RetryStrategy(), + _keepConnectionAliveInBackground = keepConnectionAliveInBackground, + _policies = [ + if (policies != null) ...policies, + WebSocketAutomaticReconnectionPolicy( + connectionState: client.connectionState, + ), + if (networkStateProvider case final provider?) + InternetAvailabilityReconnectionPolicy( + networkState: provider.state, + ), + if (lifecycleStateProvider case final provider?) + BackgroundStateReconnectionPolicy( + appLifecycleState: provider.state, + ), + ] { // Listen to connection state changes. _client.connectionState.on(_onConnectionStateChanged).addTo(_subscriptions); diff --git a/packages/stream_core/lib/src/ws/client/reconnect/retry_strategy.dart b/packages/stream_core/lib/src/ws/client/reconnect/retry_strategy.dart index 43e6256..84278d0 100644 --- a/packages/stream_core/lib/src/ws/client/reconnect/retry_strategy.dart +++ b/packages/stream_core/lib/src/ws/client/reconnect/retry_strategy.dart @@ -65,13 +65,14 @@ class DefaultRetryStrategy implements RetryStrategy { static const maximumReconnectionDelayInSeconds = 25; @override - int consecutiveFailuresCount = 0; + int get consecutiveFailuresCount => _consecutiveFailuresCount; + var _consecutiveFailuresCount = 0; @override - void incrementConsecutiveFailures() => consecutiveFailuresCount++; + void incrementConsecutiveFailures() => _consecutiveFailuresCount++; @override - void resetConsecutiveFailures() => consecutiveFailuresCount = 0; + void resetConsecutiveFailures() => _consecutiveFailuresCount = 0; @override Duration getNextRetryDelay() { diff --git a/packages/stream_core/lib/src/ws/client/stream_web_socket_client.dart b/packages/stream_core/lib/src/ws/client/stream_web_socket_client.dart index 5022433..3e6c4ec 100644 --- a/packages/stream_core/lib/src/ws/client/stream_web_socket_client.dart +++ b/packages/stream_core/lib/src/ws/client/stream_web_socket_client.dart @@ -40,8 +40,7 @@ WsRequest _defaultPingRequestBuilder([HealthCheckInfo? info]) { /// /// await client.connect(); /// ``` -class StreamWebSocketClient - implements WebSocketHealthListener, WebSocketEngineListener { +class StreamWebSocketClient implements WebSocketHealthListener, WebSocketEngineListener { /// Creates a new instance of [StreamWebSocketClient]. StreamWebSocketClient({ required this.options, @@ -121,7 +120,7 @@ class StreamWebSocketClient final result = await _engine.open(options); // If some failure occurs, disconnect and rethrow the error. - return result.recover((_, __) => onClose()).getOrThrow(); + return result.recover((_, _) => onClose()).getOrThrow(); } /// Closes the WebSocket connection. @@ -162,11 +161,11 @@ class StreamWebSocketClient // Any active state that wasn’t user/system initiated becomes server initiated. Connecting() || Authenticating() || Connected() => ServerInitiated( - error: WebSocketEngineException( - code: closeCode, - reason: closeReason, - ), + error: WebSocketEngineException( + code: closeCode, + reason: closeReason, ), + ), // Not meaningful to transition from these; just log and bail. Initialized() || Disconnected() => null, diff --git a/packages/stream_core/lib/src/ws/client/web_socket_connection_state.dart b/packages/stream_core/lib/src/ws/client/web_socket_connection_state.dart index 4eff935..87a6cac 100644 --- a/packages/stream_core/lib/src/ws/client/web_socket_connection_state.dart +++ b/packages/stream_core/lib/src/ws/client/web_socket_connection_state.dart @@ -16,8 +16,7 @@ typedef ConnectionStateEmitter = StateEmitter; /// /// Extends [ConnectionStateEmitter] with the ability to update the current state. /// Used internally by WebSocket client implementations to manage state transitions. -typedef MutableConnectionStateEmitter - = MutableStateEmitter; +typedef MutableConnectionStateEmitter = MutableStateEmitter; /// Represents the current state of a WebSocket connection. /// @@ -107,16 +106,16 @@ sealed class WebSocketConnectionState extends Equatable { bool get isAutomaticReconnectionEnabled { return switch (this) { Disconnected(:final source) => switch (source) { - ServerInitiated() => switch (source.error?.apiError) { - final error? when error.code == 1000 => false, - final error? when error.isTokenExpiredError => false, - final error? when error.isClientError => false, - _ => true, // Reconnect on other server initiated disconnections - }, - UnHealthyConnection() => true, - SystemInitiated() => true, - UserInitiated() => false, + ServerInitiated() => switch (source.error?.apiError) { + final error? when error.code == 1000 => false, + final error? when error.isTokenExpiredError => false, + final error? when error.isClientError => false, + _ => true, // Reconnect on other server initiated disconnections }, + UnHealthyConnection() => true, + SystemInitiated() => true, + UserInitiated() => false, + }, _ => false, // No automatic reconnection for other states }; } diff --git a/packages/stream_core/lib/src/ws/events/ws_request.dart b/packages/stream_core/lib/src/ws/events/ws_request.dart index 2feb688..3fdc65e 100644 --- a/packages/stream_core/lib/src/ws/events/ws_request.dart +++ b/packages/stream_core/lib/src/ws/events/ws_request.dart @@ -18,7 +18,7 @@ final class HealthCheckPingEvent extends WsRequest { Map toJson() { return { 'type': 'health.check', - if (connectionId case final id?) 'client_id': id, + 'client_id': ?connectionId, }; } } diff --git a/packages/stream_core/pubspec.yaml b/packages/stream_core/pubspec.yaml index f9d556f..aaf6294 100644 --- a/packages/stream_core/pubspec.yaml +++ b/packages/stream_core/pubspec.yaml @@ -16,7 +16,7 @@ repository: https://github.com/GetStream/stream-core-flutter # 2. Add it to the melos.yaml file for future updates. environment: - sdk: ^3.6.2 + sdk: ^3.10.0 dependencies: collection: ^1.19.0 @@ -36,7 +36,7 @@ dependencies: web_socket_channel: ^3.0.1 dev_dependencies: - build_runner: ^2.4.15 + build_runner: ^2.10.5 json_serializable: ^6.9.5 mocktail: ^1.0.4 test: ^1.26.2 diff --git a/packages/stream_core/test/query/filter_test.dart b/packages/stream_core/test/query/filter_test.dart index 86c3f3e..a949ca3 100644 --- a/packages/stream_core/test/query/filter_test.dart +++ b/packages/stream_core/test/query/filter_test.dart @@ -743,8 +743,7 @@ void main() { final model = TestModel(metadata: {'a': 1, 'b': 2}); expect( - Filter.equal(TestFilterField.metadata, {'b': 2, 'a': 1}) - .matches(model), + Filter.equal(TestFilterField.metadata, {'b': 2, 'a': 1}).matches(model), isTrue, ); }); @@ -796,23 +795,19 @@ void main() { final modelWithoutDiacritic = TestModel(name: 'Jose'); expect( - Filter.equal(TestFilterField.name, 'José') - .matches(modelWithDiacritic), + Filter.equal(TestFilterField.name, 'José').matches(modelWithDiacritic), isTrue, ); expect( - Filter.equal(TestFilterField.name, 'José') - .matches(modelWithoutDiacritic), + Filter.equal(TestFilterField.name, 'José').matches(modelWithoutDiacritic), isFalse, ); expect( - Filter.equal(TestFilterField.name, 'Jose') - .matches(modelWithDiacritic), + Filter.equal(TestFilterField.name, 'Jose').matches(modelWithDiacritic), isFalse, ); expect( - Filter.equal(TestFilterField.name, 'jose') - .matches(modelWithDiacritic), + Filter.equal(TestFilterField.name, 'jose').matches(modelWithDiacritic), isFalse, ); }); @@ -873,18 +868,15 @@ void main() { final model = TestModel(name: 'John'); expect( - Filter.in_(TestFilterField.name, ['John', 'Jane', 'Bob']) - .matches(model), + Filter.in_(TestFilterField.name, ['John', 'Jane', 'Bob']).matches(model), isTrue, ); expect( - Filter.in_(TestFilterField.name, ['john', 'Jane', 'Bob']) - .matches(model), + Filter.in_(TestFilterField.name, ['john', 'Jane', 'Bob']).matches(model), isFalse, ); expect( - Filter.in_(TestFilterField.name, ['JOHN', 'Jane', 'Bob']) - .matches(model), + Filter.in_(TestFilterField.name, ['JOHN', 'Jane', 'Bob']).matches(model), isFalse, ); }); @@ -894,23 +886,27 @@ void main() { final modelWithoutDiacritic = TestModel(name: 'Jose'); expect( - Filter.in_(TestFilterField.name, ['José', 'François', 'Müller']) - .matches(modelWithDiacritic), + Filter.in_(TestFilterField.name, [ + 'José', + 'François', + 'Müller', + ]).matches(modelWithDiacritic), isTrue, ); expect( - Filter.in_(TestFilterField.name, ['José', 'François', 'Müller']) - .matches(modelWithoutDiacritic), + Filter.in_(TestFilterField.name, [ + 'José', + 'François', + 'Müller', + ]).matches(modelWithoutDiacritic), isFalse, ); expect( - Filter.in_(TestFilterField.name, ['Jose', 'Francois']) - .matches(modelWithDiacritic), + Filter.in_(TestFilterField.name, ['Jose', 'Francois']).matches(modelWithDiacritic), isFalse, ); expect( - Filter.in_(TestFilterField.name, ['jose', 'françois']) - .matches(modelWithDiacritic), + Filter.in_(TestFilterField.name, ['jose', 'françois']).matches(modelWithDiacritic), isFalse, ); }); @@ -921,8 +917,7 @@ void main() { final model = TestModel(metadata: {'a': 1, 'b': 2, 'c': 3}); expect( - Filter.contains(TestFilterField.metadata, {'a': 1, 'b': 2}) - .matches(model), + Filter.contains(TestFilterField.metadata, {'a': 1, 'b': 2}).matches(model), isTrue, ); expect( @@ -935,8 +930,7 @@ void main() { final modelWithNull = TestModel(metadata: {'status': null}); final modelWithoutKey = TestModel(metadata: {'name': 'John'}); - final filter = - Filter.contains(TestFilterField.metadata, {'status': null}); + final filter = Filter.contains(TestFilterField.metadata, {'status': null}); expect(filter.matches(modelWithNull), isTrue); expect(filter.matches(modelWithoutKey), isFalse); @@ -1008,14 +1002,12 @@ void main() { // Filter with duplicates should match (duplicates ignored) expect( - Filter.contains(TestFilterField.tags, ['a', 'a', 'a']) - .matches(model), + Filter.contains(TestFilterField.tags, ['a', 'a', 'a']).matches(model), isTrue, // Should be TRUE, not FALSE ); expect( - Filter.contains(TestFilterField.tags, ['a', 'b', 'a']) - .matches(model), + Filter.contains(TestFilterField.tags, ['a', 'b', 'a']).matches(model), isTrue, ); }, @@ -1067,18 +1059,15 @@ void main() { final model = TestModel(createdAt: DateTime(2023, 6, 15)); expect( - Filter.greater(TestFilterField.createdAt, DateTime(2023, 1, 1)) - .matches(model), + Filter.greater(TestFilterField.createdAt, DateTime(2023, 1, 1)).matches(model), isTrue, ); expect( - Filter.greater(TestFilterField.createdAt, DateTime(2023, 6, 15)) - .matches(model), + Filter.greater(TestFilterField.createdAt, DateTime(2023, 6, 15)).matches(model), isFalse, ); expect( - Filter.greater(TestFilterField.createdAt, DateTime(2024, 1, 1)) - .matches(model), + Filter.greater(TestFilterField.createdAt, DateTime(2024, 1, 1)).matches(model), isFalse, ); }); @@ -1086,67 +1075,55 @@ void main() { test('Greater should use lexicographic comparison for strings', () { // Lexicographic: uppercase < lowercase expect( - Filter.greater(TestFilterField.name, 'John') - .matches(TestModel(name: 'Johnny')), + Filter.greater(TestFilterField.name, 'John').matches(TestModel(name: 'Johnny')), isTrue, ); expect( - Filter.greater(TestFilterField.name, 'John') - .matches(TestModel(name: 'Mike')), + Filter.greater(TestFilterField.name, 'John').matches(TestModel(name: 'Mike')), isTrue, ); expect( - Filter.greater(TestFilterField.name, 'John') - .matches(TestModel(name: 'john')), + Filter.greater(TestFilterField.name, 'John').matches(TestModel(name: 'john')), isTrue, ); expect( - Filter.greater(TestFilterField.name, 'John') - .matches(TestModel(name: 'John')), + Filter.greater(TestFilterField.name, 'John').matches(TestModel(name: 'John')), isFalse, ); expect( - Filter.greater(TestFilterField.name, 'John') - .matches(TestModel(name: 'JOHN')), + Filter.greater(TestFilterField.name, 'John').matches(TestModel(name: 'JOHN')), isFalse, ); expect( - Filter.greater(TestFilterField.name, 'John') - .matches(TestModel(name: 'Alice')), + Filter.greater(TestFilterField.name, 'John').matches(TestModel(name: 'Alice')), isFalse, ); }); test('Greater should handle diacritics lexicographically', () { expect( - Filter.greater(TestFilterField.name, 'José') - .matches(TestModel(name: 'Joséa')), + Filter.greater(TestFilterField.name, 'José').matches(TestModel(name: 'Joséa')), isTrue, ); expect( - Filter.greater(TestFilterField.name, 'José') - .matches(TestModel(name: 'joséa')), + Filter.greater(TestFilterField.name, 'José').matches(TestModel(name: 'joséa')), isTrue, ); expect( - Filter.greater(TestFilterField.name, 'José') - .matches(TestModel(name: 'José')), + Filter.greater(TestFilterField.name, 'José').matches(TestModel(name: 'José')), isFalse, ); expect( - Filter.greater(TestFilterField.name, 'José') - .matches(TestModel(name: 'Jose')), + Filter.greater(TestFilterField.name, 'José').matches(TestModel(name: 'Jose')), isFalse, ); expect( - Filter.greater(TestFilterField.name, 'José') - .matches(TestModel(name: 'jose')), + Filter.greater(TestFilterField.name, 'José').matches(TestModel(name: 'jose')), isTrue, ); }); - test('GreaterOrEqual should match when field value is greater or equal', - () { + test('GreaterOrEqual should match when field value is greater or equal', () { final model = TestModel(id: '50'); expect( @@ -1163,36 +1140,29 @@ void main() { ); }); - test('GreaterOrEqual should use lexicographic comparison for strings', - () { + test('GreaterOrEqual should use lexicographic comparison for strings', () { expect( - Filter.greaterOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'Johnny')), + Filter.greaterOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'Johnny')), isTrue, ); expect( - Filter.greaterOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'Mike')), + Filter.greaterOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'Mike')), isTrue, ); expect( - Filter.greaterOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'john')), + Filter.greaterOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'john')), isTrue, ); expect( - Filter.greaterOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'John')), + Filter.greaterOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'John')), isTrue, ); expect( - Filter.greaterOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'JOHN')), + Filter.greaterOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'JOHN')), isFalse, ); expect( - Filter.greaterOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'Alice')), + Filter.greaterOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'Alice')), isFalse, ); }); @@ -1201,51 +1171,42 @@ void main() { final model = TestModel(createdAt: DateTime(2023, 6, 15)); expect( - Filter.less(TestFilterField.createdAt, DateTime(2024, 1, 1)) - .matches(model), + Filter.less(TestFilterField.createdAt, DateTime(2024, 1, 1)).matches(model), isTrue, ); expect( - Filter.less(TestFilterField.createdAt, DateTime(2023, 6, 15)) - .matches(model), + Filter.less(TestFilterField.createdAt, DateTime(2023, 6, 15)).matches(model), isFalse, ); expect( - Filter.less(TestFilterField.createdAt, DateTime(2023, 1, 1)) - .matches(model), + Filter.less(TestFilterField.createdAt, DateTime(2023, 1, 1)).matches(model), isFalse, ); }); test('Less should use lexicographic comparison for strings', () { expect( - Filter.less(TestFilterField.name, 'John') - .matches(TestModel(name: 'Johnny')), + Filter.less(TestFilterField.name, 'John').matches(TestModel(name: 'Johnny')), isFalse, ); expect( - Filter.less(TestFilterField.name, 'John') - .matches(TestModel(name: 'Mike')), + Filter.less(TestFilterField.name, 'John').matches(TestModel(name: 'Mike')), isFalse, ); expect( - Filter.less(TestFilterField.name, 'John') - .matches(TestModel(name: 'john')), + Filter.less(TestFilterField.name, 'John').matches(TestModel(name: 'john')), isFalse, ); expect( - Filter.less(TestFilterField.name, 'John') - .matches(TestModel(name: 'John')), + Filter.less(TestFilterField.name, 'John').matches(TestModel(name: 'John')), isFalse, ); expect( - Filter.less(TestFilterField.name, 'John') - .matches(TestModel(name: 'JOHN')), + Filter.less(TestFilterField.name, 'John').matches(TestModel(name: 'JOHN')), isTrue, ); expect( - Filter.less(TestFilterField.name, 'John') - .matches(TestModel(name: 'Alice')), + Filter.less(TestFilterField.name, 'John').matches(TestModel(name: 'Alice')), isTrue, ); }); @@ -1269,33 +1230,27 @@ void main() { test('LessOrEqual should use lexicographic comparison for strings', () { expect( - Filter.lessOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'Johnny')), + Filter.lessOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'Johnny')), isFalse, ); expect( - Filter.lessOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'Mike')), + Filter.lessOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'Mike')), isFalse, ); expect( - Filter.lessOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'john')), + Filter.lessOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'john')), isFalse, ); expect( - Filter.lessOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'John')), + Filter.lessOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'John')), isTrue, ); expect( - Filter.lessOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'JOHN')), + Filter.lessOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'JOHN')), isTrue, ); expect( - Filter.lessOrEqual(TestFilterField.name, 'John') - .matches(TestModel(name: 'Alice')), + Filter.lessOrEqual(TestFilterField.name, 'John').matches(TestModel(name: 'Alice')), isTrue, ); }); @@ -1321,8 +1276,7 @@ void main() { ); }); - test('should return false for NULL comparisons (PostgreSQL semantics)', - () { + test('should return false for NULL comparisons (PostgreSQL semantics)', () { final modelWithNull = TestModel(id: null); final modelWithValue = TestModel(id: '50'); @@ -1344,20 +1298,17 @@ void main() { // GreaterOrEqual: NULL >= value → false expect( - Filter.greaterOrEqual(TestFilterField.id, '30') - .matches(modelWithNull), + Filter.greaterOrEqual(TestFilterField.id, '30').matches(modelWithNull), isFalse, ); // GreaterOrEqual: value >= NULL → false expect( - Filter.greaterOrEqual(TestFilterField.id, null) - .matches(modelWithValue), + Filter.greaterOrEqual(TestFilterField.id, null).matches(modelWithValue), isFalse, ); // GreaterOrEqual: NULL >= NULL → false expect( - Filter.greaterOrEqual(TestFilterField.id, null) - .matches(modelWithNull), + Filter.greaterOrEqual(TestFilterField.id, null).matches(modelWithNull), isFalse, ); @@ -1473,8 +1424,7 @@ void main() { final filter = Filter.query(TestFilterField.name, 'PROD'); final itemWithLowercase = TestModel(name: 'production server'); - final itemWithMixedCase = - TestModel(name: 'Development Production Environment'); + final itemWithMixedCase = TestModel(name: 'Development Production Environment'); final itemWithPartialMatch = TestModel(name: 'reproduced issue'); final itemWithoutMatch = TestModel(name: 'staging server'); @@ -1495,46 +1445,38 @@ void main() { test('should handle diacritics case-insensitively', () { expect( - Filter.query(TestFilterField.name, 'josé') - .matches(TestModel(name: 'José')), + Filter.query(TestFilterField.name, 'josé').matches(TestModel(name: 'José')), isTrue, ); expect( - Filter.query(TestFilterField.name, 'josé') - .matches(TestModel(name: 'JOSÉ')), + Filter.query(TestFilterField.name, 'josé').matches(TestModel(name: 'JOSÉ')), isTrue, ); expect( - Filter.query(TestFilterField.name, 'josé') - .matches(TestModel(name: 'josé')), + Filter.query(TestFilterField.name, 'josé').matches(TestModel(name: 'josé')), isTrue, ); expect( - Filter.query(TestFilterField.name, 'josé') - .matches(TestModel(name: 'Jose')), + Filter.query(TestFilterField.name, 'josé').matches(TestModel(name: 'Jose')), isFalse, ); expect( - Filter.query(TestFilterField.name, 'josé') - .matches(TestModel(name: 'jose')), + Filter.query(TestFilterField.name, 'josé').matches(TestModel(name: 'jose')), isFalse, ); }); test('should match middle and end substrings', () { expect( - Filter.query(TestFilterField.name, 'hn') - .matches(TestModel(name: 'John')), + Filter.query(TestFilterField.name, 'hn').matches(TestModel(name: 'John')), isTrue, ); expect( - Filter.query(TestFilterField.name, 'hn') - .matches(TestModel(name: 'JOHN')), + Filter.query(TestFilterField.name, 'hn').matches(TestModel(name: 'JOHN')), isTrue, ); expect( - Filter.query(TestFilterField.name, 'hn') - .matches(TestModel(name: 'Jane')), + Filter.query(TestFilterField.name, 'hn').matches(TestModel(name: 'Jane')), isFalse, ); }); @@ -1563,13 +1505,11 @@ void main() { final modelWithEmptyName = TestModel(name: ''); expect( - Filter.autoComplete(TestFilterField.name, '') - .matches(modelWithContent), + Filter.autoComplete(TestFilterField.name, '').matches(modelWithContent), isFalse, ); expect( - Filter.autoComplete(TestFilterField.name, '') - .matches(modelWithEmptyName), + Filter.autoComplete(TestFilterField.name, '').matches(modelWithEmptyName), isFalse, ); }); @@ -1578,10 +1518,8 @@ void main() { final filter = Filter.autoComplete(TestFilterField.name, 'con'); final itemWithDotSeparation = TestModel(name: 'app.config.json'); - final itemWithDashSeparation = - TestModel(name: 'user-configuration-file'); - final itemWithMixedPunctuation = - TestModel(name: 'system/container,settings.xml'); + final itemWithDashSeparation = TestModel(name: 'user-configuration-file'); + final itemWithMixedPunctuation = TestModel(name: 'system/container,settings.xml'); final itemWithoutWordPrefix = TestModel(name: 'application'); final itemWithInWordMatch = TestModel(name: 'reconstruction'); @@ -1603,88 +1541,77 @@ void main() { test('should handle diacritics case-insensitively', () { expect( - Filter.autoComplete(TestFilterField.name, 'jos') - .matches(TestModel(name: 'José')), + Filter.autoComplete(TestFilterField.name, 'jos').matches(TestModel(name: 'José')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'jos') - .matches(TestModel(name: 'JOSÉ')), + Filter.autoComplete(TestFilterField.name, 'jos').matches(TestModel(name: 'JOSÉ')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'jos') - .matches(TestModel(name: 'josé')), + Filter.autoComplete(TestFilterField.name, 'jos').matches(TestModel(name: 'josé')), isTrue, ); }); test('should match word boundaries in multi-word text', () { expect( - Filter.autoComplete(TestFilterField.name, 'john') - .matches(TestModel(name: 'John Smith')), + Filter.autoComplete(TestFilterField.name, 'john').matches(TestModel(name: 'John Smith')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'john') - .matches(TestModel(name: 'JOHN DOE')), + Filter.autoComplete(TestFilterField.name, 'john').matches(TestModel(name: 'JOHN DOE')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'john') - .matches(TestModel(name: 'Smith John')), + Filter.autoComplete(TestFilterField.name, 'john').matches(TestModel(name: 'Smith John')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'smi') - .matches(TestModel(name: 'John Smith')), + Filter.autoComplete(TestFilterField.name, 'smi').matches(TestModel(name: 'John Smith')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'smi') - .matches(TestModel(name: 'Johnson')), + Filter.autoComplete(TestFilterField.name, 'smi').matches(TestModel(name: 'Johnson')), isFalse, ); }); test('should handle punctuation as word boundaries', () { expect( - Filter.autoComplete(TestFilterField.name, 'john') - .matches(TestModel(name: 'john-doe')), + Filter.autoComplete(TestFilterField.name, 'john').matches(TestModel(name: 'john-doe')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'john') - .matches(TestModel(name: 'john.doe')), + Filter.autoComplete(TestFilterField.name, 'john').matches(TestModel(name: 'john.doe')), isTrue, ); expect( - Filter.autoComplete(TestFilterField.name, 'john') - .matches(TestModel(name: 'Johnson')), + Filter.autoComplete(TestFilterField.name, 'john').matches(TestModel(name: 'Johnson')), isTrue, ); }); test('should not match when query is longer than word', () { expect( - Filter.autoComplete(TestFilterField.name, 'johnathan') - .matches(TestModel(name: 'John')), + Filter.autoComplete(TestFilterField.name, 'johnathan').matches(TestModel(name: 'John')), isFalse, ); }); test('should return false for non-string fields', () { expect( - Filter.autoComplete(TestFilterField.metadata, 'test') - .matches(TestModel(metadata: {'key': 'value'})), + Filter.autoComplete( + TestFilterField.metadata, + 'test', + ).matches(TestModel(metadata: {'key': 'value'})), isFalse, ); }); test('should return false for fields with only punctuation', () { expect( - Filter.autoComplete(TestFilterField.name, 'test') - .matches(TestModel(name: '...')), + Filter.autoComplete(TestFilterField.name, 'test').matches(TestModel(name: '...')), isFalse, ); }); @@ -1701,13 +1628,11 @@ void main() { ); expect( - Filter.pathExists(TestFilterField.metadata, 'user.profile.name') - .matches(model), + Filter.pathExists(TestFilterField.metadata, 'user.profile.name').matches(model), isTrue, ); expect( - Filter.pathExists(TestFilterField.metadata, 'user.profile.age') - .matches(model), + Filter.pathExists(TestFilterField.metadata, 'user.profile.age').matches(model), isFalse, ); }); @@ -1738,8 +1663,7 @@ void main() { final model = TestModel(metadata: null); expect( - Filter.pathExists(TestFilterField.metadata, 'user.name') - .matches(model), + Filter.pathExists(TestFilterField.metadata, 'user.name').matches(model), isFalse, ); }); @@ -1761,8 +1685,7 @@ void main() { ); expect( - Filter.pathExists(TestFilterField.metadata, 'user.name') - .matches(model), + Filter.pathExists(TestFilterField.metadata, 'user.name').matches(model), isFalse, ); }); @@ -1773,15 +1696,13 @@ void main() { // Path exists but value is null - should match (key exists) expect( - Filter.pathExists(TestFilterField.metadata, 'user') - .matches(modelWithNull), + Filter.pathExists(TestFilterField.metadata, 'user').matches(modelWithNull), isTrue, ); // Path doesn't exist - should not match expect( - Filter.pathExists(TestFilterField.metadata, 'user') - .matches(modelWithoutKey), + Filter.pathExists(TestFilterField.metadata, 'user').matches(modelWithoutKey), isFalse, ); }); @@ -1876,9 +1797,7 @@ void main() { ); }); - test( - 'should handle null values in optional fields (PostgreSQL semantics)', - () { + test('should handle null values in optional fields (PostgreSQL semantics)', () { final modelWithNull = TestModel(name: null); final modelWithValue = TestModel(name: 'John'); @@ -1935,8 +1854,7 @@ void main() { isTrue, ); expect( - Filter.contains(TestFilterField.metadata, {}) - .matches(modelWithValues), + Filter.contains(TestFilterField.metadata, {}).matches(modelWithValues), isTrue, ); }); diff --git a/packages/stream_core/test/query/list_extensions_test.dart b/packages/stream_core/test/query/list_extensions_test.dart index 4bd5da4..0e261a5 100644 --- a/packages/stream_core/test/query/list_extensions_test.dart +++ b/packages/stream_core/test/query/list_extensions_test.dart @@ -265,8 +265,7 @@ void main() { final result = users.updateWhere( (user) => user.id == '2', - update: (user) => - _TestUser(id: user.id, name: '${user.name} Updated'), + update: (user) => _TestUser(id: user.id, name: '${user.name} Updated'), ); expect(result.length, 3); @@ -287,8 +286,7 @@ void main() { final result = scores.updateWhere( (score) => score.points < 100, - update: (score) => - _TestScore(userId: score.userId, points: score.points * 2), + update: (score) => _TestScore(userId: score.userId, points: score.points * 2), ); expect(result.length, 4); @@ -322,8 +320,7 @@ void main() { final result = users.updateWhere( (user) => true, - update: (user) => - _TestUser(id: user.id, name: '${user.name} Updated'), + update: (user) => _TestUser(id: user.id, name: '${user.name} Updated'), ); expect(result.length, 2); @@ -374,8 +371,7 @@ void main() { final result = scores.updateWhere( (score) => score.points >= 150 && score.points <= 200, - update: (score) => - _TestScore(userId: score.userId, points: score.points + 50), + update: (score) => _TestScore(userId: score.userId, points: score.points + 50), ); expect(result[0].points, 100); // Unchanged @@ -403,8 +399,7 @@ void main() { expect(result[2].points, 150); }); - test('should sort multiple updated elements when compare is provided', - () { + test('should sort multiple updated elements when compare is provided', () { final users = [ const _TestUser(id: '1', name: 'Alice'), const _TestUser(id: '2', name: 'Bob'), @@ -414,8 +409,7 @@ void main() { final result = users.updateWhere( (user) => user.id == '2' || user.id == '4', - update: (user) => - _TestUser(id: user.id, name: 'Z${user.name}'), // Prefix with Z + update: (user) => _TestUser(id: user.id, name: 'Z${user.name}'), // Prefix with Z compare: (a, b) => a.name.compareTo(b.name), // Ascending by name ); @@ -701,8 +695,7 @@ void main() { test('should insert element at correct position in sorted list', () { final numbers = [1, 3, 5, 7]; - final result = - numbers.sortedInsert(4, compare: (a, b) => a.compareTo(b)); + final result = numbers.sortedInsert(4, compare: (a, b) => a.compareTo(b)); expect(result, [1, 3, 4, 5, 7]); // Original list should be unchanged @@ -712,8 +705,7 @@ void main() { test('should insert at beginning when element is smallest', () { final numbers = [3, 5, 7]; - final result = - numbers.sortedInsert(1, compare: (a, b) => a.compareTo(b)); + final result = numbers.sortedInsert(1, compare: (a, b) => a.compareTo(b)); expect(result, [1, 3, 5, 7]); }); @@ -721,8 +713,7 @@ void main() { test('should insert at end when element is largest', () { final numbers = [1, 3, 5]; - final result = - numbers.sortedInsert(7, compare: (a, b) => a.compareTo(b)); + final result = numbers.sortedInsert(7, compare: (a, b) => a.compareTo(b)); expect(result, [1, 3, 5, 7]); }); @@ -730,10 +721,8 @@ void main() { test('should work with single element list', () { final numbers = [5]; - final smaller = - numbers.sortedInsert(3, compare: (a, b) => a.compareTo(b)); - final larger = - numbers.sortedInsert(7, compare: (a, b) => a.compareTo(b)); + final smaller = numbers.sortedInsert(3, compare: (a, b) => a.compareTo(b)); + final larger = numbers.sortedInsert(7, compare: (a, b) => a.compareTo(b)); expect(smaller, [3, 5]); expect(larger, [5, 7]); @@ -742,8 +731,7 @@ void main() { test('should work with empty list', () { final numbers = []; - final result = - numbers.sortedInsert(5, compare: (a, b) => a.compareTo(b)); + final result = numbers.sortedInsert(5, compare: (a, b) => a.compareTo(b)); expect(result, [5]); }); @@ -751,8 +739,7 @@ void main() { test('should work with reverse order comparator', () { final numbers = [7, 5, 3, 1]; // Descending order - final result = - numbers.sortedInsert(4, compare: (a, b) => b.compareTo(a)); + final result = numbers.sortedInsert(4, compare: (a, b) => b.compareTo(a)); expect(result, [7, 5, 4, 3, 1]); }); @@ -760,8 +747,7 @@ void main() { test('should work with string sorting', () { final names = ['Alice', 'Charlie', 'David']; - final result = - names.sortedInsert('Bob', compare: (a, b) => a.compareTo(b)); + final result = names.sortedInsert('Bob', compare: (a, b) => a.compareTo(b)); expect(result, ['Alice', 'Bob', 'Charlie', 'David']); }); @@ -785,8 +771,7 @@ void main() { test('should handle duplicate values', () { final numbers = [1, 3, 5, 7]; - final result = - numbers.sortedInsert(3, compare: (a, b) => a.compareTo(b)); + final result = numbers.sortedInsert(3, compare: (a, b) => a.compareTo(b)); expect(result, [1, 3, 3, 5, 7]); }); @@ -838,8 +823,7 @@ void main() { final result = scores.insertUnique( const _TestScore(userId: 4, points: 175), key: (score) => score.userId, - compare: (a, b) => - b.points.compareTo(a.points), // Descending by points + compare: (a, b) => b.points.compareTo(a.points), // Descending by points ); expect(result.length, 4); @@ -847,8 +831,7 @@ void main() { expect(result.map((s) => s.userId), [2, 4, 3, 1]); }); - test('should replace and sort when key exists and compare is provided', - () { + test('should replace and sort when key exists and compare is provided', () { final scores = [ const _TestScore(userId: 1, points: 100), const _TestScore(userId: 2, points: 200), @@ -858,8 +841,7 @@ void main() { final result = scores.insertUnique( const _TestScore(userId: 2, points: 250), // Update existing key: (score) => score.userId, - compare: (a, b) => - b.points.compareTo(a.points), // Descending by points + compare: (a, b) => b.points.compareTo(a.points), // Descending by points ); expect(result.length, 3); @@ -967,8 +949,7 @@ void main() { final result = users.sortedUpsert( const _TestScore(userId: 1, points: 150), key: (score) => score.userId, - compare: (a, b) => - b.points.compareTo(a.points), // Descending by points + compare: (a, b) => b.points.compareTo(a.points), // Descending by points ); expect(result.length, 3); @@ -985,8 +966,7 @@ void main() { final result = users.sortedUpsert( const _TestScore(userId: 2, points: 80), key: (score) => score.userId, - compare: (a, b) => - b.points.compareTo(a.points), // Descending by points + compare: (a, b) => b.points.compareTo(a.points), // Descending by points ); expect(result.length, 3); @@ -1063,8 +1043,7 @@ void main() { final result = scores.sortedUpsert( const _TestScore(userId: 2, points: 50), key: (score) => score.userId, - compare: (a, b) => - b.points.compareTo(a.points), // Descending by points + compare: (a, b) => b.points.compareTo(a.points), // Descending by points update: (original, updated) => _TestScore( userId: original.userId, points: original.points + updated.points, // Add points together @@ -1077,9 +1056,7 @@ void main() { expect(result.map((s) => s.userId), [2, 3, 1]); }); - test( - 'should use default update behavior when update function is not provided', - () { + test('should use default update behavior when update function is not provided', () { final scores = [ const _TestScore(userId: 1, points: 100), const _TestScore(userId: 2, points: 200), @@ -1413,8 +1390,7 @@ void main() { ); // Should return same instance }); - test('should handle multiple matching elements (removes first found)', - () { + test('should handle multiple matching elements (removes first found)', () { final comments = [ const _TestComment(id: '1', text: 'duplicate', replies: []), const _TestComment(id: '2', text: 'duplicate', replies: []), @@ -1471,8 +1447,9 @@ void main() { final mainComment = result.first; expect(mainComment.replies.length, 2); - final controversialComment = mainComment.replies - .firstWhere((c) => c.text == 'Controversial opinion'); + final controversialComment = mainComment.replies.firstWhere( + (c) => c.text == 'Controversial opinion', + ); expect(controversialComment.replies.length, 1); expect(controversialComment.replies.first.text, 'Valid response'); expect(mainComment.modifiedAt, isNotNull); // Root was updated @@ -1506,10 +1483,8 @@ void main() { final result = comments.updateNested( (comment) => comment.id == updatedComment.id, children: (comment) => comment.replies, - update: (comment) => - updatedComment.copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + update: (comment) => updatedComment.copyWith(modifiedAt: DateTime.now()), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), ); expect(result.length, 2); @@ -1552,10 +1527,8 @@ void main() { final result = comments.updateNested( (comment) => comment.id == updatedComment.id, children: (comment) => comment.replies, - update: (comment) => - updatedComment.copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + update: (comment) => updatedComment.copyWith(modifiedAt: DateTime.now()), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), ); expect(result.length, 1); @@ -1593,12 +1566,9 @@ void main() { final result = comments.updateNested( (comment) => comment.id == updatedComment.id, children: (comment) => comment.replies, - update: (comment) => - updatedComment.copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), - compare: (a, b) => - b.upvotes.compareTo(a.upvotes), // Sort by upvotes desc + update: (comment) => updatedComment.copyWith(modifiedAt: DateTime.now()), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), + compare: (a, b) => b.upvotes.compareTo(a.upvotes), // Sort by upvotes desc ); expect(result.length, 1); @@ -1649,15 +1619,12 @@ void main() { final result = comments.updateNested( (comment) => comment.id == updatedComment.id, children: (comment) => comment.replies, - update: (comment) => - updatedComment.copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + update: (comment) => updatedComment.copyWith(modifiedAt: DateTime.now()), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), ); expect(result.length, 1); - final deepComment = - result.first.replies.first.replies.first.replies.first; + final deepComment = result.first.replies.first.replies.first.replies.first; expect(deepComment.text, 'Updated Level 3'); expect(deepComment.upvotes, 10); expect(deepComment.modifiedAt, isNotNull); @@ -1670,8 +1637,7 @@ void main() { (comment) => comment.id == '1', children: (comment) => comment.replies, update: (comment) => comment.copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), ); expect(result, isEmpty); @@ -1686,8 +1652,7 @@ void main() { (comment) => comment.id == 'nonexistent', children: (comment) => comment.replies, update: (comment) => comment.copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), ); expect( @@ -1737,10 +1702,8 @@ void main() { final result = forumThread.updateNested( (comment) => comment.id == upvotedComment.id, children: (comment) => comment.replies, - update: (comment) => - upvotedComment.copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + update: (comment) => upvotedComment.copyWith(modifiedAt: DateTime.now()), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), compare: (a, b) => b.upvotes.compareTo(a.upvotes), // Sort by upvotes ); @@ -1860,11 +1823,11 @@ void main() { final result = deepComments.updateNested( (comment) => comment.id == 'thread1_0', children: (comment) => comment.replies, - update: (comment) => - const _TestComment(id: 'thread1_0', text: 'Updated leaf') - .copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + update: (comment) => const _TestComment( + id: 'thread1_0', + text: 'Updated leaf', + ).copyWith(modifiedAt: DateTime.now()), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), ); stopwatch.stop(); @@ -1945,8 +1908,7 @@ void main() { }); group('Concurrent Usage Simulation', () { - test('should maintain immutability under simulated concurrent access', - () { + test('should maintain immutability under simulated concurrent access', () { final baseList = [ const _TestUser(id: '1', name: 'Alice'), const _TestUser(id: '2', name: 'Bob'), @@ -1989,11 +1951,12 @@ void main() { currentState = currentState.updateNested( (comment) => comment.id == '2', children: (comment) => comment.replies, - update: (comment) => - _TestComment(id: '2', text: 'Reply 1', upvotes: 5 + i) - .copyWith(modifiedAt: DateTime.now()), - updateChildren: (parent, newReplies) => - parent.copyWith(replies: newReplies), + update: (comment) => _TestComment( + id: '2', + text: 'Reply 1', + upvotes: 5 + i, + ).copyWith(modifiedAt: DateTime.now()), + updateChildren: (parent, newReplies) => parent.copyWith(replies: newReplies), ); } @@ -2031,8 +1994,7 @@ void main() { authorId: 'user1', content: 'Hello Updated', ), - key: (activity) => - '${activity.authorId}_${activity.content.split(' ').first}', + key: (activity) => '${activity.authorId}_${activity.content.split(' ').first}', ); expect(result.length, 2); // Should replace 'Hello' activity diff --git a/packages/stream_core/test/query/sort_test.dart b/packages/stream_core/test/query/sort_test.dart index 2aeec57..2747b2d 100644 --- a/packages/stream_core/test/query/sort_test.dart +++ b/packages/stream_core/test/query/sort_test.dart @@ -120,10 +120,8 @@ void main() { final field = SortField('birthDate', (p) => p.birthDate); final sort = Sort.asc(field); - final person1990 = - Person(name: 'Person1990', age: 34, birthDate: DateTime(1990)); - final person2000 = - Person(name: 'Person2000', age: 24, birthDate: DateTime(2000)); + final person1990 = Person(name: 'Person1990', age: 34, birthDate: DateTime(1990)); + final person2000 = Person(name: 'Person2000', age: 24, birthDate: DateTime(2000)); expect(sort.compare(person1990, person2000), lessThan(0)); // 1990 < 2000 }); @@ -156,8 +154,7 @@ void main() { final field = SortField('birthDate', (p) => p.birthDate); final sort = Sort.asc(field); - final withDate = - Person(name: 'WithDate', age: 30, birthDate: DateTime(1990)); + final withDate = Person(name: 'WithDate', age: 30, birthDate: DateTime(1990)); const withoutDate = Person(name: 'WithoutDate', age: 25); expect( @@ -174,8 +171,7 @@ void main() { final field = SortField('birthDate', (p) => p.birthDate); final sort = Sort.asc(field, nullOrdering: NullOrdering.nullsFirst); - final withDate = - Person(name: 'WithDate', age: 30, birthDate: DateTime(1990)); + final withDate = Person(name: 'WithDate', age: 30, birthDate: DateTime(1990)); const withoutDate = Person(name: 'WithoutDate', age: 25); expect( @@ -443,9 +439,7 @@ void main() { people.sort(sorts.compare); - final result = people - .map((p) => '${p.name}-${p.score?.toString() ?? 'null'}') - .toList(); + final result = people.map((p) => '${p.name}-${p.score?.toString() ?? 'null'}').toList(); expect( result, equals([ diff --git a/packages/stream_core/test/utils/event_emitter_test.dart b/packages/stream_core/test/utils/event_emitter_test.dart index d304a0b..7947791 100644 --- a/packages/stream_core/test/utils/event_emitter_test.dart +++ b/packages/stream_core/test/utils/event_emitter_test.dart @@ -126,8 +126,7 @@ void main() { expect((values.first as AnotherEvent).value, 5); }); - test('resolver can conditionally transform based on event properties', - () async { + test('resolver can conditionally transform based on event properties', () async { final emitter = MutableEventEmitter( resolvers: [ (event) => event.data.startsWith('transform:') diff --git a/packages/stream_core/test/utils/shared_emitter_test.dart b/packages/stream_core/test/utils/shared_emitter_test.dart index c0013dc..aa97293 100644 --- a/packages/stream_core/test/utils/shared_emitter_test.dart +++ b/packages/stream_core/test/utils/shared_emitter_test.dart @@ -84,8 +84,7 @@ void main() { expect(() => emitter.emit(1), throwsStateError); }); - test('tryEmit catches errors and returns false instead of throwing', - () async { + test('tryEmit catches errors and returns false instead of throwing', () async { final emitter = MutableSharedEmitter(); addTearDown(emitter.close); @@ -409,8 +408,7 @@ void main() { }); group('SharedEmitter vs StateEmitter behavior', () { - test('SharedEmitter does not emit to late subscribers by default', - () async { + test('SharedEmitter does not emit to late subscribers by default', () async { final emitter = MutableSharedEmitter(); addTearDown(emitter.close); @@ -428,8 +426,7 @@ void main() { expect(values, [3]); }); - test('StateEmitter always emits current value to new subscribers', - () async { + test('StateEmitter always emits current value to new subscribers', () async { final emitter = MutableStateEmitter(0); addTearDown(emitter.close); diff --git a/packages/stream_core/test/utils/state_emitter_test.dart b/packages/stream_core/test/utils/state_emitter_test.dart index c5803f5..2805f19 100644 --- a/packages/stream_core/test/utils/state_emitter_test.dart +++ b/packages/stream_core/test/utils/state_emitter_test.dart @@ -25,7 +25,7 @@ void main() { expect(values, [42]); }); - test('updates value on emit', () async { + test('updates value on emit', () { final emitter = MutableStateEmitter(0); addTearDown(emitter.close); @@ -34,7 +34,7 @@ void main() { expect(emitter.value, 42); }); - test('value setter works like emit', () async { + test('value setter works like emit', () { final emitter = MutableStateEmitter(0); addTearDown(emitter.close); @@ -115,7 +115,7 @@ void main() { }); group('atomic update methods', () { - test('update applies function to current value', () async { + test('update applies function to current value', () { final emitter = MutableStateEmitter(10); addTearDown(emitter.close); @@ -124,7 +124,7 @@ void main() { expect(emitter.value, 20); }); - test('getAndUpdate returns previous value and updates', () async { + test('getAndUpdate returns previous value and updates', () { final emitter = MutableStateEmitter(10); addTearDown(emitter.close); @@ -134,7 +134,7 @@ void main() { expect(emitter.value, 15); }); - test('updateAndGet returns new value after update', () async { + test('updateAndGet returns new value after update', () { final emitter = MutableStateEmitter(10); addTearDown(emitter.close); diff --git a/packages/stream_core_flutter/.gitignore b/packages/stream_core_flutter/.gitignore deleted file mode 100644 index dd5eb98..0000000 --- a/packages/stream_core_flutter/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock -**/doc/api/ -.dart_tool/ -.flutter-plugins-dependencies -/build/ -/coverage/ diff --git a/packages/stream_core_flutter/analysis_options.yaml b/packages/stream_core_flutter/analysis_options.yaml deleted file mode 100644 index a5744c1..0000000 --- a/packages/stream_core_flutter/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/stream_core_flutter/lib/src/components/stream_button.dart b/packages/stream_core_flutter/lib/src/components/stream_button.dart index 32250d1..21a2b81 100644 --- a/packages/stream_core_flutter/lib/src/components/stream_button.dart +++ b/packages/stream_core_flutter/lib/src/components/stream_button.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:stream_core_flutter/src/theme/stream_component_factory.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; + +import '../../stream_core_flutter.dart'; +import '../theme/stream_component_factory.dart'; class StreamButton extends StatelessWidget { StreamButton({ @@ -12,13 +13,13 @@ class StreamButton extends StatelessWidget { Widget? iconLeft, Widget? iconRight, }) : props = StreamButtonProps( - label: label, - onTap: onTap, - type: type, - size: size, - iconLeft: iconLeft, - iconRight: iconRight, - ); + label: label, + onTap: onTap, + type: type, + size: size, + iconLeft: iconLeft, + iconRight: iconRight, + ); final StreamButtonProps props; @@ -53,10 +54,11 @@ enum StreamButtonType { primary, secondary, destructive } enum StreamButtonSize { small, medium, large } class DefaultStreamButton extends StatelessWidget { + const DefaultStreamButton({super.key, required this.props}); + static StreamComponentBuilder get factory => (context, props) => DefaultStreamButton(props: props); - const DefaultStreamButton({super.key, required this.props}); final StreamButtonProps props; @override @@ -67,20 +69,20 @@ class DefaultStreamButton extends StatelessWidget { final colors = switch (props.type) { StreamButtonType.primary => _primaryColors( - theme, - streamTheme, - buttonTheme, - ), + theme, + streamTheme, + buttonTheme, + ), StreamButtonType.secondary => _secondaryColors( - theme, - streamTheme, - buttonTheme, - ), + theme, + streamTheme, + buttonTheme, + ), StreamButtonType.destructive => _destructiveColors( - theme, - streamTheme, - buttonTheme, - ), + theme, + streamTheme, + buttonTheme, + ), }; return ElevatedButton( @@ -91,17 +93,15 @@ class DefaultStreamButton extends StatelessWidget { side: WidgetStateProperty.resolveWith( (states) => BorderSide( color: colors.borderColor.resolve(states), - width: 1, - style: BorderStyle.solid, ), ), elevation: WidgetStateProperty.all(0), ), child: Row( children: [ - if (props.iconLeft case final iconLeft?) iconLeft, + ?props.iconLeft, if (props.label case final label?) Text(label), - if (props.iconRight case final iconRight?) iconRight, + ?props.iconRight, ], ), ); @@ -111,40 +111,39 @@ class DefaultStreamButton extends StatelessWidget { ThemeData theme, StreamTheme streamTheme, StreamButtonTheme buttonTheme, - ) => - _StreamButtonColors( - bgColor: buttonTheme.primaryColor ?? - (streamTheme.primaryColor != null - ? WidgetStateProperty.all(streamTheme.primaryColor!) - : WidgetStateProperty.all(theme.colorScheme.primary)), - borderColor: buttonTheme.primaryColor ?? - (streamTheme.primaryColor != null - ? WidgetStateProperty.all(streamTheme.primaryColor!) - : WidgetStateProperty.all(theme.colorScheme.primary)), - textColor: WidgetStateProperty.all(Colors.white), - ); + ) => _StreamButtonColors( + bgColor: + buttonTheme.primaryColor ?? + (streamTheme.primaryColor != null + ? WidgetStateProperty.all(streamTheme.primaryColor!) + : WidgetStateProperty.all(theme.colorScheme.primary)), + borderColor: + buttonTheme.primaryColor ?? + (streamTheme.primaryColor != null + ? WidgetStateProperty.all(streamTheme.primaryColor!) + : WidgetStateProperty.all(theme.colorScheme.primary)), + textColor: WidgetStateProperty.all(Colors.white), + ); _StreamButtonColors _secondaryColors( ThemeData theme, StreamTheme streamTheme, StreamButtonTheme buttonTheme, - ) => - _StreamButtonColors( - bgColor: WidgetStateProperty.all(Colors.white), - borderColor: WidgetStateProperty.all(Colors.grey), - textColor: WidgetStateProperty.all(Colors.black), - ); + ) => _StreamButtonColors( + bgColor: WidgetStateProperty.all(Colors.white), + borderColor: WidgetStateProperty.all(Colors.grey), + textColor: WidgetStateProperty.all(Colors.black), + ); _StreamButtonColors _destructiveColors( ThemeData theme, StreamTheme streamTheme, StreamButtonTheme buttonTheme, - ) => - _StreamButtonColors( - bgColor: WidgetStateProperty.all(Colors.red), - borderColor: WidgetStateProperty.all(Colors.red), - textColor: WidgetStateProperty.all(Colors.white), - ); + ) => _StreamButtonColors( + bgColor: WidgetStateProperty.all(Colors.red), + borderColor: WidgetStateProperty.all(Colors.red), + textColor: WidgetStateProperty.all(Colors.white), + ); } class _StreamButtonColors { diff --git a/packages/stream_core_flutter/lib/src/theme/components/stream_button_theme.dart b/packages/stream_core_flutter/lib/src/theme/components/stream_button_theme.dart index fe0d01d..12e8337 100644 --- a/packages/stream_core_flutter/lib/src/theme/components/stream_button_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/components/stream_button_theme.dart @@ -1,5 +1,5 @@ import 'package:flutter/widgets.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; +import '../../../stream_core_flutter.dart'; class StreamButtonTheme { StreamButtonTheme({this.primaryColor}); diff --git a/packages/stream_core_flutter/lib/src/theme/stream_component_factory.dart b/packages/stream_core_flutter/lib/src/theme/stream_component_factory.dart index 17622d8..687ac2a 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_component_factory.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_component_factory.dart @@ -1,10 +1,9 @@ import 'package:flutter/widgets.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; +import '../../stream_core_flutter.dart'; import '../components/stream_button.dart' show DefaultStreamButton; -typedef StreamComponentBuilder = Widget Function( - BuildContext context, T props); +typedef StreamComponentBuilder = Widget Function(BuildContext context, T props); class StreamComponentFactory { StreamComponentFactory({ diff --git a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart index 802599c..fc53183 100644 --- a/packages/stream_core_flutter/lib/src/theme/stream_theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/stream_theme.dart @@ -1,14 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:stream_core_flutter/src/theme/stream_component_factory.dart'; -import 'package:stream_core_flutter/stream_core_flutter.dart'; +import '../../stream_core_flutter.dart'; + +import 'stream_component_factory.dart'; class StreamTheme extends ThemeExtension { StreamTheme({ StreamComponentFactory? componentFactory, this.primaryColor, StreamButtonTheme? buttonTheme, - }) : componentFactory = componentFactory ?? StreamComponentFactory(), - buttonTheme = buttonTheme ?? StreamButtonTheme(); + }) : componentFactory = componentFactory ?? StreamComponentFactory(), + buttonTheme = buttonTheme ?? StreamButtonTheme(); final StreamComponentFactory componentFactory; diff --git a/packages/stream_core_flutter/lib/stream_core_flutter.dart b/packages/stream_core_flutter/lib/stream_core_flutter.dart index 995faad..274a80a 100644 --- a/packages/stream_core_flutter/lib/stream_core_flutter.dart +++ b/packages/stream_core_flutter/lib/stream_core_flutter.dart @@ -1,3 +1,3 @@ export 'src/components.dart'; -export 'src/theme/stream_theme.dart'; export 'src/theme/components.dart'; +export 'src/theme/stream_theme.dart'; diff --git a/packages/stream_core_flutter/pubspec.yaml b/packages/stream_core_flutter/pubspec.yaml index afa5e56..ded9734 100644 --- a/packages/stream_core_flutter/pubspec.yaml +++ b/packages/stream_core_flutter/pubspec.yaml @@ -4,8 +4,8 @@ version: 0.0.1 homepage: environment: - sdk: ^3.9.0 - flutter: ">=1.17.0" + sdk: ^3.10.0 + flutter: ">=3.38.1" dependencies: flutter: @@ -14,7 +14,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/pubspec.lock b/pubspec.lock index 6f5a39f..e2a4ec2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -298,4 +298,4 @@ packages: source: hosted version: "2.2.2" sdks: - dart: ">=3.6.2 <4.0.0" + dart: ">=3.10.0 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index ca55b7e..217ca38 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: stream_core_flutter_workspace environment: - sdk: ^3.6.2 + sdk: ^3.10.0 dev_dependencies: melos: ^6.2.0