From 696817c8879506b5fd517398e5786582635a5a75 Mon Sep 17 00:00:00 2001 From: Vincent Velociter <423393+veloce@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:44:29 +0100 Subject: [PATCH] Riverpod 3 (#2381) --- analysis_options.yaml | 1 + build.yaml | 8 - ios/Podfile.lock | 7 - lib/src/db/database.dart | 19 +- lib/src/db/openings_database.dart | 9 +- lib/src/localizations.dart | 13 +- lib/src/log.dart | 23 +- .../model/account/account_preferences.dart | 46 ++-- lib/src/model/account/account_repository.dart | 6 +- lib/src/model/account/account_service.dart | 11 +- lib/src/model/account/flair_provider.dart | 9 +- lib/src/model/account/home_preferences.dart | 10 +- .../model/analysis/analysis_controller.dart | 21 +- .../model/analysis/analysis_preferences.dart | 10 +- lib/src/model/analysis/opening_service.dart | 9 +- lib/src/model/analysis/retro_controller.dart | 27 ++- .../analysis/server_analysis_service.dart | 18 +- lib/src/model/auth/auth_controller.dart | 15 +- lib/src/model/auth/auth_repository.dart | 9 +- lib/src/model/auth/auth_session.dart | 20 +- lib/src/model/auth/session_storage.dart | 9 +- .../board_editor/board_editor_controller.dart | 19 +- .../broadcast_analysis_controller.dart | 41 ++-- .../broadcast/broadcast_preferences.dart | 11 +- .../model/broadcast/broadcast_providers.dart | 86 +++---- .../broadcast/broadcast_round_controller.dart | 25 ++- .../challenge/challenge_preferences.dart | 10 +- .../model/challenge/challenge_repository.dart | 9 +- .../model/challenge/challenge_service.dart | 9 +- lib/src/model/challenge/challenges.dart | 10 +- lib/src/model/chat/chat_controller.dart | 48 ++-- .../model/clock/clock_tool_controller.dart | 12 +- lib/src/model/common/preloaded_data.dart | 9 +- .../model/common/service/move_feedback.dart | 9 +- .../model/common/service/sound_service.dart | 9 +- .../coordinate_training_controller.dart | 12 +- .../coordinate_training_preferences.dart | 11 +- .../correspondence_game_storage.dart | 46 ++-- .../correspondence_service.dart | 9 +- .../model/engine/evaluation_preferences.dart | 11 +- lib/src/model/engine/evaluation_service.dart | 17 +- .../opening_explorer_preferences.dart | 11 +- .../explorer/opening_explorer_repository.dart | 21 +- .../model/explorer/tablebase_repository.dart | 24 +- lib/src/model/game/game_bookmarks.dart | 12 +- lib/src/model/game/game_controller.dart | 27 ++- lib/src/model/game/game_filter.dart | 19 +- lib/src/model/game/game_history.dart | 81 +++---- lib/src/model/game/game_preferences.dart | 11 +- .../model/game/game_repository_providers.dart | 21 +- lib/src/model/game/game_share_service.dart | 9 +- lib/src/model/game/game_storage.dart | 9 +- .../model/http_log/http_log_paginator.dart | 17 +- lib/src/model/http_log/http_log_storage.dart | 6 +- lib/src/model/lobby/create_game_service.dart | 7 +- lib/src/model/lobby/game_seek.dart | 11 +- .../model/lobby/game_setup_preferences.dart | 10 +- lib/src/model/lobby/lobby_numbers.dart | 13 +- lib/src/model/lobby/lobby_repository.dart | 13 +- .../message/conversation_controller.dart | 17 +- lib/src/model/message/message_repository.dart | 1 - lib/src/model/message/message_service.dart | 9 +- .../notifications/notification_service.dart | 13 +- .../over_the_board/over_the_board_clock.dart | 12 +- .../over_the_board_game_controller.dart | 12 +- lib/src/model/puzzle/puzzle_activity.dart | 12 +- .../model/puzzle/puzzle_batch_storage.dart | 7 +- lib/src/model/puzzle/puzzle_controller.dart | 38 +++- lib/src/model/puzzle/puzzle_opening.dart | 19 +- lib/src/model/puzzle/puzzle_preferences.dart | 10 +- lib/src/model/puzzle/puzzle_providers.dart | 94 ++++---- lib/src/model/puzzle/puzzle_service.dart | 15 +- lib/src/model/puzzle/puzzle_session.dart | 27 ++- lib/src/model/puzzle/puzzle_storage.dart | 9 +- lib/src/model/puzzle/puzzle_streak.dart | 11 +- lib/src/model/puzzle/puzzle_theme.dart | 7 +- lib/src/model/puzzle/storm_controller.dart | 32 ++- lib/src/model/puzzle/streak_storage.dart | 18 +- lib/src/model/relation/online_friends.dart | 12 +- lib/src/model/settings/board_preferences.dart | 10 +- lib/src/model/settings/brightness.dart | 10 +- .../model/settings/general_preferences.dart | 11 +- .../settings/over_the_board_preferences.dart | 11 +- lib/src/model/study/study_controller.dart | 28 ++- lib/src/model/study/study_list_paginator.dart | 32 +-- lib/src/model/study/study_preferences.dart | 10 +- lib/src/model/study/study_repository.dart | 9 +- .../tournament/tournament_controller.dart | 22 +- .../tournament/tournament_providers.dart | 30 +-- .../tournament/tournament_repository.dart | 9 +- lib/src/model/tv/live_tv_channels.dart | 13 +- lib/src/model/tv/tv_controller.dart | 53 +++-- .../model/user/game_history_preferences.dart | 11 +- lib/src/model/user/search_history.dart | 10 +- .../model/user/user_repository_providers.dart | 74 +++--- lib/src/network/connectivity.dart | 17 +- lib/src/network/http.dart | 23 +- lib/src/network/socket.dart | 28 ++- lib/src/quick_actions.dart | 9 +- lib/src/tab_scaffold.dart | 1 + lib/src/utils/riverpod.dart | 1 + lib/src/view/account/account_drawer.dart | 8 +- lib/src/view/account/profile_screen.dart | 2 +- lib/src/view/analysis/analysis_screen.dart | 4 +- lib/src/view/analysis/retro_screen.dart | 4 +- .../view/broadcast/broadcast_game_screen.dart | 57 +++-- .../broadcast_game_screen_providers.dart | 75 ++++--- .../broadcast_game_settings_screen.dart | 2 +- .../broadcast_player_results_screen.dart | 2 +- .../broadcast_player_screen_providers.dart | 11 +- .../view/explorer/opening_explorer_view.dart | 4 +- lib/src/view/explorer/tablebase_view.dart | 2 +- lib/src/view/game/game_body.dart | 17 +- lib/src/view/game/game_screen.dart | 23 +- lib/src/view/game/game_screen_providers.dart | 110 ++++----- lib/src/view/home/home_tab_screen.dart | 10 +- lib/src/view/learn/learn_tab_screen.dart | 7 +- lib/src/view/message/contacts_screen.dart | 1 + lib/src/view/message/conversation_screen.dart | 4 +- lib/src/view/more/more_tab_screen.dart | 2 +- lib/src/view/play/create_game_widget.dart | 6 +- lib/src/view/play/play_menu.dart | 2 +- lib/src/view/play/quick_game_matrix.dart | 4 +- lib/src/view/puzzle/dashboard_screen.dart | 1 + .../view/puzzle/puzzle_history_screen.dart | 2 +- lib/src/view/puzzle/puzzle_screen.dart | 8 +- .../view/puzzle/puzzle_session_widget.dart | 13 +- lib/src/view/puzzle/puzzle_tab_screen.dart | 6 +- lib/src/view/puzzle/puzzle_themes_screen.dart | 2 - lib/src/view/puzzle/storm_screen.dart | 13 +- lib/src/view/puzzle/streak_screen.dart | 8 +- .../settings/account_preferences_screen.dart | 2 +- lib/src/view/settings/http_log_screen.dart | 4 +- lib/src/view/study/study_bottom_bar.dart | 2 +- lib/src/view/study/study_gamebook.dart | 18 +- lib/src/view/study/study_list_screen.dart | 6 +- lib/src/view/study/study_screen.dart | 2 +- .../view/tournament/tournament_screen.dart | 14 +- lib/src/view/user/game_history_screen.dart | 39 ++-- lib/src/view/user/perf_stats_screen.dart | 4 +- lib/src/view/user/recent_games.dart | 2 +- lib/src/view/user/user_context_menu.dart | 2 +- lib/src/view/user/user_screen.dart | 4 +- lib/src/view/watch/tv_screen.dart | 16 +- lib/src/view/watch/watch_tab_screen.dart | 2 +- lib/src/widgets/feedback.dart | 6 +- pubspec.lock | 212 +++++++++++------- pubspec.yaml | 8 +- test/app_test.dart | 8 +- test/model/auth/auth_controller_test.dart | 32 +-- .../challenge/challenge_service_test.dart | 12 +- .../correspondence_service_test.dart | 24 +- .../notification_service_test.dart | 36 +-- test/model/puzzle/puzzle_service_test.dart | 6 +- test/model/puzzle/puzzle_storage_test.dart | 6 +- test/model/study/study_repository_test.dart | 6 +- test/network/aggregator_test.dart | 6 +- test/network/http_test.dart | 64 +++--- test/test_container.dart | 113 +++++----- test/test_provider_scope.dart | 136 ++++++----- test/view/analysis/analysis_screen_test.dart | 30 +-- test/view/analysis/retro_screen_test.dart | 8 +- .../broadcast/broadcast_game_screen_test.dart | 6 +- .../broadcast/broadcast_list_screen_test.dart | 12 +- .../broadcast_round_screen_test.dart | 102 +++++---- .../broadcast_search_screen_test.dart | 12 +- test/view/engine/test_engine_app.dart | 10 +- test/view/explorer/explorer_view_test.dart | 12 +- .../opening_explorer_screen_test.dart | 6 +- test/view/game/game_screen_test.dart | 66 ++++-- test/view/home/home_tab_screen_test.dart | 38 ++-- .../puzzle/puzzle_history_screen_test.dart | 12 +- test/view/puzzle/puzzle_screen_test.dart | 116 ++++++---- test/view/puzzle/puzzle_tab_screen_test.dart | 56 +++-- test/view/puzzle/storm_screen_test.dart | 50 +++-- test/view/puzzle/streak_screen_test.dart | 12 +- test/view/relation/friend_screen_test.dart | 38 ++-- test/view/study/study_list_screen_test.dart | 12 +- test/view/study/study_screen_test.dart | 32 ++- .../tournament_list_screen_test.dart | 6 +- .../tournament/tournament_screen_test.dart | 48 ++-- test/view/user/leaderboard_screen_test.dart | 6 +- test/view/user/perf_stats_screen_test.dart | 12 +- test/view/user/search_screen_test.dart | 12 +- test/view/user/user_screen_test.dart | 6 +- 185 files changed, 2110 insertions(+), 1644 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 82f96796d..96d9c2b2e 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -16,6 +16,7 @@ analyzer: strict-raw-types: true exclude: - "**/*.g.dart" + - "**/*.freezed.dart" - lib/src/styles/lichess_icons.dart - lib/src/styles/social_icons.dart - lib/firebase_options.dart diff --git a/build.yaml b/build.yaml index 1aa92272c..9e617467a 100644 --- a/build.yaml +++ b/build.yaml @@ -13,11 +13,3 @@ targets: options: from_json: false to_json: false - riverpod_generator: - generate_for: - - lib/src/localizations.dart - - lib/src/model/**/*.dart - - lib/src/network/*.dart - - lib/src/db/*.dart - - lib/src/quick_actions.dart - - lib/src/**/*_providers.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 98bc33d9a..637477164 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -129,9 +129,6 @@ PODS: - Flutter - package_info_plus (0.4.5): - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - PromisesObjC (2.4.0) - PromisesSwift (2.4.0): - PromisesObjC (= 2.4.0) @@ -171,7 +168,6 @@ DEPENDENCIES: - multistockfish_variant (from `.symlinks/plugins/multistockfish_variant/ios`) - objective_c (from `.symlinks/plugins/objective_c/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) @@ -235,8 +231,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/objective_c/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" quick_actions_ios: :path: ".symlinks/plugins/quick_actions_ios/ios" share_plus: @@ -284,7 +278,6 @@ SPEC CHECKSUMS: nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 objective_c: 89e720c30d716b036faf9c9684022048eee1eee2 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779 diff --git a/lib/src/db/database.dart b/lib/src/db/database.dart index f955edf5b..99b9cbbb9 100644 --- a/lib/src/db/database.dart +++ b/lib/src/db/database.dart @@ -5,9 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; -part 'database.g.dart'; const kLichessDatabaseName = 'lichess_mobile.db'; @@ -21,14 +19,14 @@ const kStorageAnonId = '**anonymous**'; final _logger = Logger('Database'); -@Riverpod(keepAlive: true) -Future database(Ref ref) async { +/// A provider for the app [Database]. +final databaseProvider = FutureProvider((Ref ref) async { if (Platform.isLinux) { databaseFactory = databaseFactoryFfi; } final dbPath = await _databasePath; return openAppDatabase(databaseFactory, dbPath); -} +}, name: 'DatabaseProvider'); /// Returns the database path including filename. Future get _databasePath async { @@ -41,11 +39,10 @@ Future get _databasePath async { } /// Returns the sqlite version as an integer. -@Riverpod(keepAlive: true) -Future sqliteVersion(Ref ref) async { +final sqliteVersionProvider = FutureProvider((Ref ref) async { final db = await ref.read(databaseProvider.future); return _getDatabaseVersion(db); -} +}, name: 'SqliteVersionProvider'); Future _getDatabaseVersion(Database db) async { try { @@ -57,13 +54,13 @@ Future _getDatabaseVersion(Database db) async { } } -@Riverpod(keepAlive: true) -Future getDbSizeInBytes(Ref ref) async { +/// A provider that returns the size of the database file in bytes. +final getDbSizeInBytesProvider = FutureProvider((Ref ref) async { final dbPath = join(await getDatabasesPath(), kLichessDatabaseName); final dbFile = File(dbPath); return dbFile.length(); -} +}, name: 'GetDbSizeInBytesProvider'); /// Opens the app database. Future openAppDatabase(DatabaseFactory dbFactory, String path) { diff --git a/lib/src/db/openings_database.dart b/lib/src/db/openings_database.dart index af1506cf8..1a9fc7016 100644 --- a/lib/src/db/openings_database.dart +++ b/lib/src/db/openings_database.dart @@ -3,22 +3,19 @@ import 'dart:io'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart' as p; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; -part 'openings_database.g.dart'; - // The dataset is from https://github.com/lichess-org/chess-openings // It can be updated by running the script at scripts/update_openings_db.py const _kDatabaseVersion = 3; const _kDatabaseName = 'chess_openings$_kDatabaseVersion.db'; -@Riverpod(keepAlive: true) -Future openingsDatabase(Ref ref) async { +/// A provider for the openings database. +final openingsDatabaseProvider = FutureProvider((Ref ref) async { final dbPath = p.join(await getDatabasesPath(), _kDatabaseName); return _openDb(dbPath); -} +}, name: 'OpeningsDatabaseProvider'); Future _openDb(String path) async { final exists = await databaseExists(path); diff --git a/lib/src/localizations.dart b/lib/src/localizations.dart index 62767000a..cd83f2f31 100644 --- a/lib/src/localizations.dart +++ b/lib/src/localizations.dart @@ -1,14 +1,17 @@ import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/model/settings/general_preferences.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'localizations.g.dart'; typedef ActiveLocalizations = ({Locale locale, AppLocalizations strings}); -@Riverpod(keepAlive: true) -class Localizations extends _$Localizations { +/// A provider for [Localizations]. +final localizationsProvider = NotifierProvider( + Localizations.new, + name: 'LocalizationsProvider', +); + +class Localizations extends Notifier { @override ActiveLocalizations build() { final generalPrefs = ref.watch(generalPreferencesProvider); diff --git a/lib/src/log.dart b/lib/src/log.dart index 8fdc8074c..1e21c47cd 100644 --- a/lib/src/log.dart +++ b/lib/src/log.dart @@ -27,26 +27,25 @@ void setupLogging() { } } -class ProviderLogger extends ProviderObserver { +final class ProviderLogger extends ProviderObserver { final _logger = Logger('Provider'); @override - void didAddProvider(ProviderBase provider, Object? value, ProviderContainer container) { - _logger.info('${provider.name ?? provider.runtimeType} initialized', value); + void didAddProvider(ProviderObserverContext context, Object? value) { + _logger.info('${context.provider.name ?? context.provider.runtimeType} initialized', value); } @override - void didDisposeProvider(ProviderBase provider, ProviderContainer container) { - _logger.info('${provider.name ?? provider.runtimeType} disposed'); + void didDisposeProvider(ProviderObserverContext context) { + _logger.info('${context.provider.name ?? context.provider.runtimeType} disposed'); } @override - void providerDidFail( - ProviderBase provider, - Object error, - StackTrace stackTrace, - ProviderContainer container, - ) { - _logger.severe('${provider.name ?? provider.runtimeType} error', error, stackTrace); + void providerDidFail(ProviderObserverContext context, Object error, StackTrace stackTrace) { + _logger.severe( + '${context.provider.name ?? context.provider.runtimeType} error', + error, + stackTrace, + ); } } diff --git a/lib/src/model/account/account_preferences.dart b/lib/src/model/account/account_preferences.dart index b86acffc1..f3fef1847 100644 --- a/lib/src/model/account/account_preferences.dart +++ b/lib/src/model/account/account_preferences.dart @@ -4,9 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/model/account/account_repository.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'account_preferences.g.dart'; typedef AccountPrefState = ({ // game display @@ -30,28 +27,22 @@ typedef AccountPrefState = ({ }); /// A provider that tells if the user wants to see ratings in the app. -@Riverpod(keepAlive: true) -Future showRatingsPref(Ref ref) async { - return ref.watch( - accountPreferencesProvider.selectAsync((state) => state?.showRatings ?? ShowRatings.yes), - ); -} +final showRatingsPrefProvider = FutureProvider((Ref ref) async { + final prefs = await ref.watch(accountPreferencesProvider.future); + return prefs?.showRatings ?? defaultAccountPreferences.showRatings; +}); -@Riverpod(keepAlive: true) -Future clockSound(Ref ref) async { - return ref.watch( - accountPreferencesProvider.selectAsync((state) => state?.clockSound.value ?? true), - ); -} +/// A provider that tells if the user wants clock sounds. +final clockSoundProvider = FutureProvider((Ref ref) async { + final prefs = await ref.watch(accountPreferencesProvider.future); + return prefs?.clockSound.value ?? defaultAccountPreferences.clockSound.value; +}); -@Riverpod(keepAlive: true) -Future pieceNotation(Ref ref) async { - return ref.watch( - accountPreferencesProvider.selectAsync( - (state) => state?.pieceNotation ?? defaultAccountPreferences.pieceNotation, - ), - ); -} +/// A provider that gives the user's preferred piece notation. +final pieceNotationProvider = FutureProvider((Ref ref) async { + final prefs = await ref.watch(accountPreferencesProvider.future); + return prefs?.pieceNotation ?? defaultAccountPreferences.pieceNotation; +}); final defaultAccountPreferences = ( zenMode: Zen.no, @@ -70,12 +61,17 @@ final defaultAccountPreferences = ( message: Message.always, ); +/// A provider that gives the account preferences for the current user. +final accountPreferencesProvider = AsyncNotifierProvider( + AccountPreferences.new, + name: 'AccountPreferencesProvider', +); + /// Get the account preferences for the current user. /// /// The result is cached for the lifetime of the app, until refreshed. /// If the server returns an error, default values are returned. -@Riverpod(keepAlive: true) -class AccountPreferences extends _$AccountPreferences { +class AccountPreferences extends AsyncNotifier { @override Future build() async { final session = ref.watch(authSessionProvider); diff --git a/lib/src/model/account/account_repository.dart b/lib/src/model/account/account_repository.dart index 4c21ba820..da40cc219 100644 --- a/lib/src/model/account/account_repository.dart +++ b/lib/src/model/account/account_repository.dart @@ -17,10 +17,12 @@ final accountProvider = FutureProvider.autoDispose((Ref ref) { }, name: 'AccountProvider'); /// A provider that fetches the current user's kid mode status. -final kidModeProvider = FutureProvider.autoDispose((ref) { - return ref.watch(accountProvider.selectAsync((user) => user?.kid ?? false)); +final kidModeProvider = FutureProvider.autoDispose((ref) async { + final account = await ref.watch(accountProvider.future); + return account?.kid ?? false; }, name: 'KidModeProvider'); +/// A provider for the [AccountRepository]. final accountRepositoryProvider = Provider((ref) { final client = ref.read(lichessClientProvider); final aggregator = ref.read(aggregatorProvider); diff --git a/lib/src/model/account/account_service.dart b/lib/src/model/account/account_service.dart index 1551dd664..093c93eaa 100644 --- a/lib/src/model/account/account_service.dart +++ b/lib/src/model/account/account_service.dart @@ -14,18 +14,15 @@ import 'package:lichess_mobile/src/model/user/user.dart' show TemporaryBan, User import 'package:lichess_mobile/src/tab_scaffold.dart' show currentNavigatorKeyProvider; import 'package:lichess_mobile/src/view/play/playban.dart'; import 'package:lichess_mobile/src/widgets/platform_alert_dialog.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'account_service.g.dart'; - -@Riverpod(keepAlive: true) -AccountService accountService(Ref ref) { +/// A provider for [AccountService]. +final accountServiceProvider = Provider((Ref ref) { final service = AccountService(ref); ref.onDispose(() { service.dispose(); }); return service; -} +}, name: 'AccountServiceProvider'); class AccountService { AccountService(this._ref); @@ -48,7 +45,7 @@ class AccountService { final prefs = LichessBinding.instance.sharedPreferences; _accountProviderSubscription = _ref.listen(accountProvider, (_, account) { - final playban = account.valueOrNull?.playban; + final playban = account.value?.playban; final storedDate = prefs.getString(_storageKey); final lastPlaybanNotificationDate = storedDate != null ? DateTime.parse(storedDate) : null; diff --git a/lib/src/model/account/flair_provider.dart b/lib/src/model/account/flair_provider.dart index 705f78611..5bef1292b 100644 --- a/lib/src/model/account/flair_provider.dart +++ b/lib/src/model/account/flair_provider.dart @@ -2,18 +2,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/utils/lichess_assets.dart'; import 'package:lichess_mobile/src/widgets/emoji_picker/emoji_picker_models.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'flair_provider.g.dart'; - -@Riverpod(keepAlive: true) -Future flairList(Ref ref) async { +/// A provider that fetches the list of available flairs. +final flairListProvider = FutureProvider((Ref ref) async { final list = await ref .read(defaultClientProvider) .read(Uri.parse(lichessAssetUrl('flair/list.txt'))); final data = _makeEmojiData(list); return EmojiData.fromJson(data); -} +}, name: 'FlairListProvider'); const categories = [ ['smileys', 'Smileys'], diff --git a/lib/src/model/account/home_preferences.dart b/lib/src/model/account/home_preferences.dart index c9ee1c226..ff9f551e5 100644 --- a/lib/src/model/account/home_preferences.dart +++ b/lib/src/model/account/home_preferences.dart @@ -1,15 +1,19 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/account/home_widgets.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'home_preferences.freezed.dart'; part 'home_preferences.g.dart'; -@Riverpod(keepAlive: true) -class HomePreferences extends _$HomePreferences with SessionPreferencesStorage { +final homePreferencesProvider = NotifierProvider( + HomePreferences.new, + name: 'HomePreferencesProvider', +); + +class HomePreferences extends Notifier with SessionPreferencesStorage { @override @protected PrefCategory get prefCategory => PrefCategory.home; diff --git a/lib/src/model/analysis/analysis_controller.dart b/lib/src/model/analysis/analysis_controller.dart index b7ce23283..b567850c5 100644 --- a/lib/src/model/analysis/analysis_controller.dart +++ b/lib/src/model/analysis/analysis_controller.dart @@ -4,6 +4,7 @@ import 'package:collection/collection.dart'; import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:intl/intl.dart'; import 'package:lichess_mobile/src/model/account/account_service.dart'; @@ -34,10 +35,8 @@ import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/network/socket.dart'; import 'package:lichess_mobile/src/view/engine/engine_gauge.dart'; import 'package:lichess_mobile/src/widgets/pgn.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'analysis_controller.freezed.dart'; -part 'analysis_controller.g.dart'; final _dateFormat = DateFormat('yyyy.MM.dd'); @@ -104,10 +103,20 @@ enum AnalysisGameResult { }; } -@riverpod -class AnalysisController extends _$AnalysisController +/// A provider for [AnalysisController]. +final analysisControllerProvider = AsyncNotifierProvider.autoDispose + .family( + AnalysisController.new, + name: 'AnalysisControllerProvider', + ); + +class AnalysisController extends AsyncNotifier with EngineEvaluationMixin implements PgnTreeNotifier { + AnalysisController(this.options); + + final AnalysisOptions options; + static final Uri socketUri = Uri(path: '/analysis/socket/v5'); StreamSubscription? _socketSubscription; @@ -143,7 +152,7 @@ class AnalysisController extends _$AnalysisController GameRepository get _gameRepository => ref.read(gameRepositoryProvider); @override - Future build(AnalysisOptions options) async { + Future build() async { final serverAnalysisService = ref.watch(serverAnalysisServiceProvider); ref.onDispose(() { @@ -173,7 +182,7 @@ class AnalysisController extends _$AnalysisController switch (options) { case ArchivedGame(:final gameId): { - archivedGame = await ref.read(archivedGameProvider(id: gameId).future); + archivedGame = await ref.read(archivedGameProvider(gameId).future); _variant = archivedGame!.meta.variant; if (!_variant.isReadSupported) { throw UnsupportedVariantException(_variant, gameId); diff --git a/lib/src/model/analysis/analysis_preferences.dart b/lib/src/model/analysis/analysis_preferences.dart index 1a7acd456..1800886d3 100644 --- a/lib/src/model/analysis/analysis_preferences.dart +++ b/lib/src/model/analysis/analysis_preferences.dart @@ -1,13 +1,17 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/analysis/common_analysis_prefs.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'analysis_preferences.freezed.dart'; part 'analysis_preferences.g.dart'; -@Riverpod(keepAlive: true) -class AnalysisPreferences extends _$AnalysisPreferences with PreferencesStorage { +final analysisPreferencesProvider = NotifierProvider( + AnalysisPreferences.new, + name: 'AnalysisPreferencesProvider', +); + +class AnalysisPreferences extends Notifier with PreferencesStorage { @override @protected final prefCategory = PrefCategory.analysis; diff --git a/lib/src/model/analysis/opening_service.dart b/lib/src/model/analysis/opening_service.dart index 4ddaa366d..96479c9a9 100644 --- a/lib/src/model/analysis/opening_service.dart +++ b/lib/src/model/analysis/opening_service.dart @@ -2,11 +2,8 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/db/openings_database.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; -part 'opening_service.g.dart'; - const kOpeningAllowedVariants = ISetConst({ Variant.standard, Variant.kingOfTheHill, @@ -14,10 +11,10 @@ const kOpeningAllowedVariants = ISetConst({ Variant.crazyhouse, }); -@Riverpod(keepAlive: true) -OpeningService openingService(Ref ref) { +/// A provider for [OpeningService]. +final openingServiceProvider = Provider((Ref ref) { return OpeningService(ref); -} +}, name: 'OpeningServiceProvider'); class OpeningService { OpeningService(this._ref); diff --git a/lib/src/model/analysis/retro_controller.dart b/lib/src/model/analysis/retro_controller.dart index ecb700494..d8669829e 100644 --- a/lib/src/model/analysis/retro_controller.dart +++ b/lib/src/model/analysis/retro_controller.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/analysis/analysis_controller.dart'; import 'package:lichess_mobile/src/model/analysis/common_analysis_state.dart'; @@ -25,10 +26,8 @@ import 'package:lichess_mobile/src/model/game/game_repository_providers.dart'; import 'package:lichess_mobile/src/network/socket.dart'; import 'package:lichess_mobile/src/view/engine/engine_gauge.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'retro_controller.freezed.dart'; -part 'retro_controller.g.dart'; typedef RetroOptions = ({GameId id, Side initialSide}); @@ -74,8 +73,18 @@ const double _kCorrectMovePovDiffThreshold = -0.04; /// Threshold for considering a move a mistake due to how it affected the evaluation. const double _kEvalSwingThreshold = 0.1; -@riverpod -class RetroController extends _$RetroController with EngineEvaluationMixin { +/// A provider for [RetroController]. +final retroControllerProvider = AsyncNotifierProvider.autoDispose + .family( + RetroController.new, + name: 'RetroControllerProvider', + ); + +class RetroController extends AsyncNotifier with EngineEvaluationMixin { + RetroController(this.options); + + final RetroOptions options; + late Root _root; late ExportedGame _game; @@ -109,7 +118,7 @@ class RetroController extends _$RetroController with EngineEvaluationMixin { Node get positionTree => _root; @override - Future build(RetroOptions options) async { + Future build() async { final serverAnalysisService = ref.watch(serverAnalysisServiceProvider); ref.onDispose(() { @@ -119,7 +128,7 @@ class RetroController extends _$RetroController with EngineEvaluationMixin { socketClient = ref.watch(socketPoolProvider).open(AnalysisController.socketUri); - _game = await ref.read(archivedGameProvider(id: options.id).future); + _game = await ref.read(archivedGameProvider(options.id).future); if (engineSupportedVariants.contains(_game.meta.variant) == false) { throw Exception('Variant ${_game.meta.variant} is not supported for retro mode'); @@ -270,7 +279,7 @@ class RetroController extends _$RetroController with EngineEvaluationMixin { } void onPromotionSelection(Role? role) { - final state = this.state.valueOrNull; + final state = this.state.value; if (state == null) return; if (role == null) { @@ -297,7 +306,7 @@ class RetroController extends _$RetroController with EngineEvaluationMixin { } void viewSolution() { - final currentMistake = state.valueOrNull?.currentMistake; + final currentMistake = state.value?.currentMistake; if (currentMistake != null) { onUserMove(currentMistake.serverMove); state = AsyncValue.data(state.requireValue.copyWith(feedback: RetroFeedback.viewingSolution)); @@ -352,7 +361,7 @@ class RetroController extends _$RetroController with EngineEvaluationMixin { /// Whether the user is navigating through the moves (as opposed to playing a move). bool isNavigating = false, }) { - final state = this.state.valueOrNull; + final state = this.state.value; if (state == null) return; final pathChange = state.currentPath != path; diff --git a/lib/src/model/analysis/server_analysis_service.dart b/lib/src/model/analysis/server_analysis_service.dart index 95cd731af..a509a8c52 100644 --- a/lib/src/model/analysis/server_analysis_service.dart +++ b/lib/src/model/analysis/server_analysis_service.dart @@ -15,16 +15,13 @@ import 'package:lichess_mobile/src/model/game/game_repository.dart'; import 'package:lichess_mobile/src/model/game/game_socket_events.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'server_analysis_service.g.dart'; const Duration kMaxWaitForServerAnalysis = Duration(minutes: 1); -@Riverpod(keepAlive: true) -ServerAnalysisService serverAnalysisService(Ref ref) { +/// A provider for [ServerAnalysisService]. +final serverAnalysisServiceProvider = Provider((Ref ref) { return ServerAnalysisService(ref); -} +}, name: 'ServerAnalysisServiceProvider'); class ServerAnalysisService { ServerAnalysisService(this.ref); @@ -177,8 +174,13 @@ class ServerAnalysisService { } } -@riverpod -class CurrentAnalysis extends _$CurrentAnalysis { +/// A provider that exposes the current game being analyzed by the server. +final currentAnalysisProvider = NotifierProvider.autoDispose( + CurrentAnalysis.new, + name: 'CurrentAnalysisProvider', +); + +class CurrentAnalysis extends Notifier { @override GameId? build() { final listenable = ref.watch(serverAnalysisServiceProvider).currentAnalysis; diff --git a/lib/src/model/auth/auth_controller.dart b/lib/src/model/auth/auth_controller.dart index 958d09ecc..c015f9d0f 100644 --- a/lib/src/model/auth/auth_controller.dart +++ b/lib/src/model/auth/auth_controller.dart @@ -1,17 +1,20 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/auth/auth_repository.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/notifications/notification_service.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'auth_controller.g.dart'; +/// A provider for [AuthController]. +final authControllerProvider = AsyncNotifierProvider.autoDispose( + AuthController.new, + name: 'AuthControllerProvider', +); -@riverpod -class AuthController extends _$AuthController { +class AuthController extends AsyncNotifier { @override - AsyncValue build() { - return const AsyncValue.data(null); + Future build() { + return Future.value(); } Future signIn() async { diff --git a/lib/src/model/auth/auth_repository.dart b/lib/src/model/auth/auth_repository.dart index b0b923dc7..68694a77f 100644 --- a/lib/src/model/auth/auth_repository.dart +++ b/lib/src/model/auth/auth_repository.dart @@ -7,17 +7,14 @@ import 'package:lichess_mobile/src/model/auth/bearer.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'auth_repository.g.dart'; const redirectUri = 'org.lichess.mobile://login-callback'; const oauthScopes = ['web:mobile']; -@Riverpod(keepAlive: true) -FlutterAppAuth appAuth(Ref ref) { +/// A provider for [FlutterAppAuth]. +final appAuthProvider = Provider((Ref ref) { return const FlutterAppAuth(); -} +}, name: 'AppAuthProvider'); class AuthRepository { AuthRepository(LichessClient client, FlutterAppAuth appAuth) diff --git a/lib/src/model/auth/auth_session.dart b/lib/src/model/auth/auth_session.dart index a5dad7562..155d5a807 100644 --- a/lib/src/model/auth/auth_session.dart +++ b/lib/src/model/auth/auth_session.dart @@ -3,13 +3,22 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/auth/session_storage.dart'; import 'package:lichess_mobile/src/model/common/preloaded_data.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'auth_session.freezed.dart'; part 'auth_session.g.dart'; -@Riverpod(keepAlive: true) -class AuthSession extends _$AuthSession { +/// A provider for [AuthSession]. +final authSessionProvider = NotifierProvider( + AuthSession.new, + name: 'AuthSessionProvider', +); + +/// A provider that indicates whether the user is logged in. +final isLoggedInProvider = Provider.autoDispose((Ref ref) { + return ref.watch(authSessionProvider.select((authSession) => authSession != null)); +}, name: 'IsLoggedInProvider'); + +class AuthSession extends Notifier { @override AuthSessionState? build() { return ref.read(preloadedDataProvider).requireValue.userSession; @@ -35,8 +44,3 @@ sealed class AuthSessionState with _$AuthSessionState { factory AuthSessionState.fromJson(Map json) => _$AuthSessionStateFromJson(json); } - -@riverpod -bool isLoggedIn(Ref ref) { - return ref.watch(authSessionProvider.select((authSession) => authSession != null)); -} diff --git a/lib/src/model/auth/session_storage.dart b/lib/src/model/auth/session_storage.dart index 2b33ba16b..7bde6f93c 100644 --- a/lib/src/model/auth/session_storage.dart +++ b/lib/src/model/auth/session_storage.dart @@ -4,16 +4,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/constants.dart'; import 'package:lichess_mobile/src/db/secure_storage.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'session_storage.g.dart'; const kSessionStorageKey = '$kLichessHost.userSession'; -@Riverpod(keepAlive: true) -SessionStorage sessionStorage(Ref ref) { +/// A provider for [SessionStorage]. +final sessionStorageProvider = Provider((Ref ref) { return const SessionStorage(); -} +}, name: 'SessionStorageProvider'); class SessionStorage { const SessionStorage(); diff --git a/lib/src/model/board_editor/board_editor_controller.dart b/lib/src/model/board_editor/board_editor_controller.dart index c7fd36fea..7535c5aa1 100644 --- a/lib/src/model/board_editor/board_editor_controller.dart +++ b/lib/src/model/board_editor/board_editor_controller.dart @@ -1,16 +1,25 @@ import 'package:chessground/chessground.dart'; import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'board_editor_controller.freezed.dart'; -part 'board_editor_controller.g.dart'; -@riverpod -class BoardEditorController extends _$BoardEditorController { +/// A provider for [BoardEditorController]. +final boardEditorControllerProvider = NotifierProvider.autoDispose + .family( + BoardEditorController.new, + name: 'BoardEditorControllerProvider', + ); + +class BoardEditorController extends Notifier { + BoardEditorController(this.initialFen); + + final String? initialFen; + @override - BoardEditorState build(String? initialFen) { + BoardEditorState build() { final setup = Setup.parseFen(initialFen ?? kInitialFEN); final position = Chess.fromSetup(setup, ignoreImpossibleCheck: true); final pieces = readFen(initialFen ?? kInitialFEN).lock; diff --git a/lib/src/model/broadcast/broadcast_analysis_controller.dart b/lib/src/model/broadcast/broadcast_analysis_controller.dart index 512dde706..7d03ca809 100644 --- a/lib/src/model/broadcast/broadcast_analysis_controller.dart +++ b/lib/src/model/broadcast/broadcast_analysis_controller.dart @@ -4,6 +4,7 @@ import 'package:dartchess/dartchess.dart'; import 'package:deep_pick/deep_pick.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/analysis/analysis_controller.dart'; import 'package:lichess_mobile/src/model/analysis/common_analysis_state.dart'; @@ -24,15 +25,25 @@ import 'package:lichess_mobile/src/utils/json.dart'; import 'package:lichess_mobile/src/utils/rate_limit.dart'; import 'package:lichess_mobile/src/view/engine/engine_gauge.dart'; import 'package:lichess_mobile/src/widgets/pgn.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'broadcast_analysis_controller.freezed.dart'; -part 'broadcast_analysis_controller.g.dart'; -@riverpod -class BroadcastAnalysisController extends _$BroadcastAnalysisController +typedef BroadcastAnalysisControllerParams = ({BroadcastRoundId roundId, BroadcastGameId gameId}); + +/// A provider for [BroadcastAnalysisController]. +final broadcastAnalysisControllerProvider = AsyncNotifierProvider.autoDispose + .family( + BroadcastAnalysisController.new, + name: 'BroadcastAnalysisControllerProvider', + ); + +class BroadcastAnalysisController extends AsyncNotifier with EngineEvaluationMixin implements PgnTreeNotifier { + BroadcastAnalysisController(this.params); + + final BroadcastAnalysisControllerParams params; + static Uri broadcastSocketUri(BroadcastRoundId broadcastRoundId) => Uri(path: 'study/$broadcastRoundId/socket/v6'); @@ -75,7 +86,7 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController Root get positionTree => _root; @override - Future build(BroadcastRoundId roundId, BroadcastGameId gameId) async { + Future build() async { ref.onDispose(() { _key = null; _subscription?.cancel(); @@ -88,14 +99,14 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController _socketClient = ref .watch(socketPoolProvider) - .open(BroadcastAnalysisController.broadcastSocketUri(roundId)); + .open(BroadcastAnalysisController.broadcastSocketUri(params.roundId)); _subscription = _socketClient.stream.listen(_handleSocketEvent); await _socketClient.firstConnection; _socketOpenSubscription = _socketClient.connectedStream.listen((_) { - if (state.valueOrNull?.isNewOrOngoing == true) { + if (state.value?.isNewOrOngoing == true) { _syncDebouncer(() { _reloadPgn(); }); @@ -104,7 +115,7 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController _appLifecycleListener = AppLifecycleListener( onResume: () { - if (state.valueOrNull?.isNewOrOngoing == true) { + if (state.value?.isNewOrOngoing == true) { _syncDebouncer(() { _reloadPgn(); }); @@ -112,7 +123,9 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController }, ); - final pgn = await ref.read(broadcastRepositoryProvider).getGamePgn(roundId, gameId); + final pgn = await ref + .read(broadcastRepositoryProvider) + .getGamePgn(params.roundId, params.gameId); final game = PgnGame.parsePgn(pgn); final pgnHeaders = IMap(game.headers); @@ -128,7 +141,7 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController final prefs = ref.read(broadcastPreferencesProvider); final broadcastState = BroadcastAnalysisState( - id: gameId, + id: params.gameId, currentPath: currentPath, broadcastPath: currentPath, isOnMainline: _root.isOnMainline(currentPath), @@ -163,7 +176,9 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController if (!state.hasValue) return; final key = _key; - final pgn = await ref.read(broadcastRepositoryProvider).getGamePgn(roundId, gameId); + final pgn = await ref + .read(broadcastRepositoryProvider) + .getGamePgn(params.roundId, params.gameId); // check provider is still mounted if (key == _key) { @@ -235,7 +250,7 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController final broadcastGameId = pick(event.data, 'p', 'chapterId').asBroadcastGameIdOrThrow(); // We check if the event is for this game - if (broadcastGameId != gameId) return; + if (broadcastGameId != params.gameId) return; // The path of the last and current move of the broadcasted game // Its value is "!" if the path is identical to one of the node that was received @@ -276,7 +291,7 @@ class BroadcastAnalysisController extends _$BroadcastAnalysisController final broadcastGameId = pick(event.data, 'chapterId').asBroadcastGameIdOrThrow(); // We check if the event is for this game - if (broadcastGameId != gameId) return; + if (broadcastGameId != params.gameId) return; final pgnHeadersEntries = pick( event.data, diff --git a/lib/src/model/broadcast/broadcast_preferences.dart b/lib/src/model/broadcast/broadcast_preferences.dart index 536fe283c..1e7614107 100644 --- a/lib/src/model/broadcast/broadcast_preferences.dart +++ b/lib/src/model/broadcast/broadcast_preferences.dart @@ -1,14 +1,19 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/analysis/common_analysis_prefs.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'broadcast_preferences.freezed.dart'; part 'broadcast_preferences.g.dart'; -@Riverpod(keepAlive: true) -class BroadcastPreferences extends _$BroadcastPreferences with PreferencesStorage { +final broadcastPreferencesProvider = NotifierProvider( + BroadcastPreferences.new, + name: 'BroadcastPreferencesProvider', +); + +class BroadcastPreferences extends Notifier + with PreferencesStorage { @override @protected PrefCategory get prefCategory => PrefCategory.broadcast; diff --git a/lib/src/model/broadcast/broadcast_providers.dart b/lib/src/model/broadcast/broadcast_providers.dart index f1304a9d2..7d1de6cf5 100644 --- a/lib/src/model/broadcast/broadcast_providers.dart +++ b/lib/src/model/broadcast/broadcast_providers.dart @@ -3,13 +3,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/broadcast/broadcast.dart'; import 'package:lichess_mobile/src/model/broadcast/broadcast_repository.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'broadcast_providers.g.dart'; /// A provider that fetches a paginated list of broadcasts. -@riverpod -class BroadcastsPaginator extends _$BroadcastsPaginator { +final broadcastsPaginatorProvider = + AsyncNotifierProvider.autoDispose( + BroadcastsPaginator.new, + name: 'BroadcastsPaginatorProvider', + ); + +class BroadcastsPaginator extends AsyncNotifier { @override Future build() { return ref.read(broadcastRepositoryProvider).getBroadcasts(); @@ -35,10 +37,19 @@ class BroadcastsPaginator extends _$BroadcastsPaginator { } /// A provider that fetches a paginated list of broadcasts matching the [searchTerm]. -@riverpod -class BroadcastsSearchPaginator extends _$BroadcastsSearchPaginator { +final broadcastsSearchPaginatorProvider = AsyncNotifierProvider.autoDispose + .family( + BroadcastsSearchPaginator.new, + name: 'BroadcastsSearchPaginatorProvider', + ); + +class BroadcastsSearchPaginator extends AsyncNotifier { + BroadcastsSearchPaginator(this.searchTerm); + + final String searchTerm; + @override - Future build(String searchTerm) { + Future build() { return ref.read(broadcastRepositoryProvider).searchBroadcasts(searchTerm: searchTerm); } @@ -60,37 +71,36 @@ class BroadcastsSearchPaginator extends _$BroadcastsSearchPaginator { } } -@riverpod -Future broadcastTournament( - Ref ref, - BroadcastTournamentId broadcastTournamentId, -) { - return ref.read(broadcastRepositoryProvider).getTournament(broadcastTournamentId); -} +final broadcastTournamentProvider = FutureProvider.autoDispose + .family(( + Ref ref, + BroadcastTournamentId broadcastTournamentId, + ) { + return ref.read(broadcastRepositoryProvider).getTournament(broadcastTournamentId); + }, name: 'BroadcastTournamentProvider'); -@riverpod -Future broadcastRound(Ref ref, BroadcastRoundId roundId) { - return ref.read(broadcastRepositoryProvider).getRound(roundId); -} +final broadcastRoundProvider = FutureProvider.autoDispose + .family((Ref ref, BroadcastRoundId roundId) { + return ref.read(broadcastRepositoryProvider).getRound(roundId); + }, name: 'BroadcastRoundProvider'); -@riverpod -Future> broadcastPlayers( - Ref ref, - BroadcastTournamentId tournamentId, -) { - return ref.read(broadcastRepositoryProvider).getPlayers(tournamentId); -} +final broadcastPlayersProvider = FutureProvider.autoDispose + .family, BroadcastTournamentId>(( + Ref ref, + BroadcastTournamentId tournamentId, + ) { + return ref.read(broadcastRepositoryProvider).getPlayers(tournamentId); + }, name: 'BroadcastPlayersProvider'); -@riverpod -Future broadcastPlayer( - Ref ref, - BroadcastTournamentId broadcastTournamentId, - String playerId, -) { - return ref.read(broadcastRepositoryProvider).getPlayerResults(broadcastTournamentId, playerId); -} +final broadcastPlayerProvider = FutureProvider.autoDispose + .family(( + Ref ref, + (BroadcastTournamentId, String) params, + ) { + return ref.read(broadcastRepositoryProvider).getPlayerResults(params.$1, params.$2); + }, name: 'BroadcastPlayerProvider'); -@riverpod -Future> broadcastTeamMatches(Ref ref, BroadcastRoundId roundId) { - return ref.read(broadcastRepositoryProvider).getTeamMatches(roundId); -} +final broadcastTeamMatchesProvider = FutureProvider.autoDispose + .family, BroadcastRoundId>((Ref ref, BroadcastRoundId roundId) { + return ref.read(broadcastRepositoryProvider).getTeamMatches(roundId); + }, name: 'BroadcastTeamMatchesProvider'); diff --git a/lib/src/model/broadcast/broadcast_round_controller.dart b/lib/src/model/broadcast/broadcast_round_controller.dart index bf8e2495a..3e7ff3f76 100644 --- a/lib/src/model/broadcast/broadcast_round_controller.dart +++ b/lib/src/model/broadcast/broadcast_round_controller.dart @@ -4,6 +4,7 @@ import 'package:dartchess/dartchess.dart'; import 'package:deep_pick/deep_pick.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/broadcast/broadcast.dart'; import 'package:lichess_mobile/src/model/broadcast/broadcast_preferences.dart'; @@ -15,13 +16,21 @@ import 'package:lichess_mobile/src/model/common/socket.dart'; import 'package:lichess_mobile/src/network/socket.dart'; import 'package:lichess_mobile/src/utils/json.dart'; import 'package:lichess_mobile/src/utils/rate_limit.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'broadcast_round_controller.freezed.dart'; -part 'broadcast_round_controller.g.dart'; -@riverpod -class BroadcastRoundController extends _$BroadcastRoundController { +/// A provider for [BroadcastRoundController]. +final broadcastRoundControllerProvider = AsyncNotifierProvider.autoDispose + .family( + BroadcastRoundController.new, + name: 'BroadcastRoundControllerProvider', + ); + +class BroadcastRoundController extends AsyncNotifier { + BroadcastRoundController(this.broadcastRoundId); + + final BroadcastRoundId broadcastRoundId; + static Uri broadcastSocketUri(BroadcastRoundId broadcastRoundId) => Uri(path: 'study/$broadcastRoundId/socket/v6'); @@ -37,7 +46,7 @@ class BroadcastRoundController extends _$BroadcastRoundController { Object? _key = Object(); @override - Future build(BroadcastRoundId broadcastRoundId) async { + Future build() async { ref.onDispose(() { _key = null; _subscription?.cancel(); @@ -56,7 +65,7 @@ class BroadcastRoundController extends _$BroadcastRoundController { await _socketClient.firstConnection; _socketOpenSubscription = _socketClient.connectedStream.listen((_) { - if (state.valueOrNull?.round.status == RoundStatus.live) { + if (state.value?.round.status == RoundStatus.live) { _syncRoundDebouncer(() { _syncRound(); }); @@ -65,7 +74,7 @@ class BroadcastRoundController extends _$BroadcastRoundController { _appLifecycleListener = AppLifecycleListener( onResume: () { - if (state.valueOrNull?.round.status == RoundStatus.live) { + if (state.value?.round.status == RoundStatus.live) { _syncRoundDebouncer(() { _syncRound(); }); @@ -254,7 +263,7 @@ class BroadcastRoundController extends _$BroadcastRoundController { } void addObservedGame(BroadcastGameId gameId) { - if (state.valueOrNull?.games.containsKey(gameId) != true) return; + if (state.value?.games.containsKey(gameId) != true) return; state = AsyncData( state.requireValue.copyWith(observedGames: state.requireValue.observedGames.add(gameId)), diff --git a/lib/src/model/challenge/challenge_preferences.dart b/lib/src/model/challenge/challenge_preferences.dart index 2c024c990..69ee6daaa 100644 --- a/lib/src/model/challenge/challenge_preferences.dart +++ b/lib/src/model/challenge/challenge_preferences.dart @@ -1,3 +1,4 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/challenge/challenge.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; @@ -6,13 +7,16 @@ import 'package:lichess_mobile/src/model/common/speed.dart'; import 'package:lichess_mobile/src/model/common/time_increment.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'challenge_preferences.freezed.dart'; part 'challenge_preferences.g.dart'; -@Riverpod(keepAlive: true) -class ChallengePreferences extends _$ChallengePreferences +final challengePreferencesProvider = NotifierProvider( + ChallengePreferences.new, + name: 'ChallengePreferencesProvider', +); + +class ChallengePreferences extends Notifier with SessionPreferencesStorage { @override @protected diff --git a/lib/src/model/challenge/challenge_repository.dart b/lib/src/model/challenge/challenge_repository.dart index 35ebb1679..33762c128 100644 --- a/lib/src/model/challenge/challenge_repository.dart +++ b/lib/src/model/challenge/challenge_repository.dart @@ -7,14 +7,11 @@ import 'package:lichess_mobile/src/model/challenge/challenge.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/network/aggregator.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'challenge_repository.g.dart'; - -@Riverpod(keepAlive: true) -ChallengeRepository challengeRepository(Ref ref) { +/// A provider for [ChallengeRepository]. +final challengeRepositoryProvider = Provider((Ref ref) { return ChallengeRepository(ref.read(lichessClientProvider), ref.read(aggregatorProvider)); -} +}, name: 'ChallengeRepositoryProvider'); typedef ChallengesList = ({IList inward, IList outward}); diff --git a/lib/src/model/challenge/challenge_service.dart b/lib/src/model/challenge/challenge_service.dart index 984f461e4..46438d297 100644 --- a/lib/src/model/challenge/challenge_service.dart +++ b/lib/src/model/challenge/challenge_service.dart @@ -20,17 +20,14 @@ import 'package:lichess_mobile/src/view/game/game_screen_providers.dart'; import 'package:lichess_mobile/src/view/user/challenge_requests_screen.dart'; import 'package:lichess_mobile/src/widgets/adaptive_action_sheet.dart'; import 'package:lichess_mobile/src/widgets/feedback.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:stream_transform/stream_transform.dart'; -part 'challenge_service.g.dart'; - -@Riverpod(keepAlive: true) -ChallengeService challengeService(Ref ref) { +/// A provider for [ChallengeService]. +final challengeServiceProvider = Provider((Ref ref) { final service = ChallengeService(ref); ref.onDispose(() => service.dispose()); return service; -} +}, name: 'ChallengeServiceProvider'); /// A service that listens to challenge events and shows notifications. class ChallengeService { diff --git a/lib/src/model/challenge/challenges.dart b/lib/src/model/challenge/challenges.dart index 9f81f0439..b7c8ee465 100644 --- a/lib/src/model/challenge/challenges.dart +++ b/lib/src/model/challenge/challenges.dart @@ -1,16 +1,18 @@ import 'dart:async'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/challenge/challenge.dart'; import 'package:lichess_mobile/src/model/challenge/challenge_repository.dart'; import 'package:lichess_mobile/src/model/challenge/challenge_service.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'challenges.g.dart'; +final challengesProvider = AsyncNotifierProvider.autoDispose( + Challenges.new, + name: 'ChallengesProvider', +); -@riverpod -class Challenges extends _$Challenges { +class Challenges extends AsyncNotifier { StreamSubscription? _subscription; @override diff --git a/lib/src/model/chat/chat_controller.dart b/lib/src/model/chat/chat_controller.dart index 46f26c2ef..df8b8b1fd 100644 --- a/lib/src/model/chat/chat_controller.dart +++ b/lib/src/model/chat/chat_controller.dart @@ -16,11 +16,9 @@ import 'package:lichess_mobile/src/model/tournament/tournament_controller.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; part 'chat_controller.freezed.dart'; -part 'chat_controller.g.dart'; const _tableName = 'chat_read_messages'; String _storeKey(StringId id) => 'chat.$id'; @@ -79,21 +77,33 @@ abstract class StudyChatOptions extends ChatOptions with _$StudyChatOptions { } /// A provider that gets the chat unread messages -@riverpod -Future chatUnread(Ref ref, ChatOptions options) async { - return ref.watch(chatControllerProvider(options).selectAsync((s) => s.unreadMessages)); -} +final chatUnreadProvider = FutureProvider.autoDispose.family(( + Ref ref, + ChatOptions options, +) async { + return (await ref.watch(chatControllerProvider(options).future)).unreadMessages; +}, name: 'ChatUnreadProvider'); const IList _kEmptyMessages = IListConst([]); -@riverpod -class ChatController extends _$ChatController { +/// A provider for [ChatController]. +final chatControllerProvider = AsyncNotifierProvider.autoDispose + .family( + ChatController.new, + name: 'ChatControllerProvider', + ); + +class ChatController extends AsyncNotifier { + ChatController(this.options); + + final ChatOptions options; + StreamSubscription? _subscription; LightUser? get _me => ref.read(authSessionProvider)?.user; @override - Future build(ChatOptions options) async { + Future build() async { _subscription?.cancel(); _subscription = socketGlobalStream.listen(_handleSocketEvent); @@ -101,16 +111,16 @@ class ChatController extends _$ChatController { _subscription?.cancel(); }); - final initialMessages = await switch (options) { - GameChatOptions(:final id) => ref.watch( - gameControllerProvider(id).selectAsync((s) => s.game.chat?.lines), - ), - TournamentChatOptions(:final id) => ref.watch( - tournamentControllerProvider(id).selectAsync((s) => s.tournament.chat?.lines), - ), - StudyChatOptions(:final id) => ref.watch( - studyControllerProvider(id).selectAsync((s) => s.study.chat?.lines), - ), + final initialMessages = switch (options) { + GameChatOptions(:final id) => (await ref.watch( + gameControllerProvider(id).future, + )).game.chat?.lines, + TournamentChatOptions(:final id) => (await ref.watch( + tournamentControllerProvider(id).future, + )).tournament.chat?.lines, + StudyChatOptions(:final id) => (await ref.watch( + studyControllerProvider(id).future, + )).study.chat?.lines, }; final filteredMessages = _selectMessages(initialMessages ?? _kEmptyMessages); diff --git a/lib/src/model/clock/clock_tool_controller.dart b/lib/src/model/clock/clock_tool_controller.dart index f1c0f9bea..a3d83e4ab 100755 --- a/lib/src/model/clock/clock_tool_controller.dart +++ b/lib/src/model/clock/clock_tool_controller.dart @@ -1,13 +1,12 @@ import 'package:dartchess/dartchess.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/clock/chess_clock.dart'; import 'package:lichess_mobile/src/model/common/service/sound_service.dart'; import 'package:lichess_mobile/src/model/common/time_increment.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'clock_tool_controller.freezed.dart'; -part 'clock_tool_controller.g.dart'; enum ClockSide { top, @@ -18,8 +17,13 @@ enum ClockSide { Side get chessClockSide => this == ClockSide.top ? Side.black : Side.white; } -@riverpod -class ClockToolController extends _$ClockToolController { +/// A provider for [ClockToolController]. +final clockToolControllerProvider = NotifierProvider.autoDispose( + ClockToolController.new, + name: 'ClockToolControllerProvider', +); + +class ClockToolController extends Notifier { late ChessClock _clock; final Map _hasPlayedLowTimeSound = { ClockSide.top: false, diff --git a/lib/src/model/common/preloaded_data.dart b/lib/src/model/common/preloaded_data.dart index e2c6ddf52..72246abbc 100644 --- a/lib/src/model/common/preloaded_data.dart +++ b/lib/src/model/common/preloaded_data.dart @@ -12,9 +12,6 @@ import 'package:lichess_mobile/src/utils/system.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:path_provider/path_provider.dart' show getApplicationDocumentsDirectory, getApplicationSupportDirectory; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'preloaded_data.g.dart'; typedef PreloadedData = ({ PackageInfo packageInfo, @@ -26,8 +23,8 @@ typedef PreloadedData = ({ Directory? appSupportDirectory, }); -@Riverpod(keepAlive: true) -Future preloadedData(Ref ref) async { +/// A provider that preloads various data needed throughout the app. +final preloadedDataProvider = FutureProvider((Ref ref) async { final sessionStorage = ref.watch(sessionStorageProvider); final pInfo = await PackageInfo.fromPlatform(); @@ -74,4 +71,4 @@ Future preloadedData(Ref ref) async { appDocumentsDirectory: appDocumentsDirectory, appSupportDirectory: appSupportDirectory, ); -} +}, name: 'PreloadedDataProvider'); diff --git a/lib/src/model/common/service/move_feedback.dart b/lib/src/model/common/service/move_feedback.dart index ff11f5d50..db3464402 100644 --- a/lib/src/model/common/service/move_feedback.dart +++ b/lib/src/model/common/service/move_feedback.dart @@ -2,15 +2,12 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/common/service/sound_service.dart'; import 'package:lichess_mobile/src/model/settings/board_preferences.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'move_feedback.g.dart'; - -@Riverpod(keepAlive: true) -MoveFeedbackService moveFeedbackService(Ref ref) { +/// A provider for [MoveFeedbackService]. +final moveFeedbackServiceProvider = Provider((Ref ref) { final soundService = ref.watch(soundServiceProvider); return MoveFeedbackService(soundService, ref); -} +}, name: 'MoveFeedbackServiceProvider'); class MoveFeedbackService { MoveFeedbackService(this._soundService, this._ref); diff --git a/lib/src/model/common/service/sound_service.dart b/lib/src/model/common/service/sound_service.dart index 48740685c..7fe5a9162 100644 --- a/lib/src/model/common/service/sound_service.dart +++ b/lib/src/model/common/service/sound_service.dart @@ -7,11 +7,8 @@ import 'package:lichess_mobile/src/binding.dart'; import 'package:lichess_mobile/src/model/settings/general_preferences.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sound_effect/sound_effect.dart'; -part 'sound_service.g.dart'; - /// Maximum number of concurrent sounds that can be played. const _kMaxConcurrentStreams = 2; @@ -22,12 +19,12 @@ final _logger = Logger('SoundService'); // Must match name of files in assets/sounds/standard enum Sound { move, capture, lowTime, dong, error, confirmation, puzzleStormEnd, clock, berserk } -@Riverpod(keepAlive: true) -SoundService soundService(Ref ref) { +/// A provider for [SoundService]. +final soundServiceProvider = Provider((Ref ref) { final service = SoundService(ref); ref.onDispose(() => service.release()); return service; -} +}, name: 'SoundServiceProvider'); final _extension = defaultTargetPlatform == TargetPlatform.iOS ? 'aifc' : 'mp3'; diff --git a/lib/src/model/coordinate_training/coordinate_training_controller.dart b/lib/src/model/coordinate_training/coordinate_training_controller.dart index 2d949bdd9..0afa9bbb6 100644 --- a/lib/src/model/coordinate_training/coordinate_training_controller.dart +++ b/lib/src/model/coordinate_training/coordinate_training_controller.dart @@ -2,18 +2,22 @@ import 'dart:async'; import 'dart:math'; import 'package:dartchess/dartchess.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/game.dart'; import 'package:lichess_mobile/src/model/coordinate_training/coordinate_training_preferences.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'coordinate_training_controller.freezed.dart'; -part 'coordinate_training_controller.g.dart'; enum Guess { correct, incorrect } -@riverpod -class CoordinateTrainingController extends _$CoordinateTrainingController { +final coordinateTrainingControllerProvider = + NotifierProvider.autoDispose( + CoordinateTrainingController.new, + name: 'CoordinateTrainingControllerProvider', + ); + +class CoordinateTrainingController extends Notifier { final _random = Random(DateTime.now().millisecondsSinceEpoch); final _stopwatch = Stopwatch(); diff --git a/lib/src/model/coordinate_training/coordinate_training_preferences.dart b/lib/src/model/coordinate_training/coordinate_training_preferences.dart index d22236208..68c7e30d6 100644 --- a/lib/src/model/coordinate_training/coordinate_training_preferences.dart +++ b/lib/src/model/coordinate_training/coordinate_training_preferences.dart @@ -1,15 +1,20 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/model/common/game.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'coordinate_training_preferences.freezed.dart'; part 'coordinate_training_preferences.g.dart'; -@Riverpod(keepAlive: true) -class CoordinateTrainingPreferences extends _$CoordinateTrainingPreferences +final coordinateTrainingPreferencesProvider = + NotifierProvider( + CoordinateTrainingPreferences.new, + name: 'CoordinateTrainingPreferencesProvider', + ); + +class CoordinateTrainingPreferences extends Notifier with PreferencesStorage { @override @protected diff --git a/lib/src/model/correspondence/correspondence_game_storage.dart b/lib/src/model/correspondence/correspondence_game_storage.dart index 991e17a92..dd62c3546 100644 --- a/lib/src/model/correspondence/correspondence_game_storage.dart +++ b/lib/src/model/correspondence/correspondence_game_storage.dart @@ -7,34 +7,32 @@ import 'package:lichess_mobile/src/db/database.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/correspondence/offline_correspondence_game.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; -part 'correspondence_game_storage.g.dart'; - -@Riverpod(keepAlive: true) -Future correspondenceGameStorage(Ref ref) async { - final db = await ref.watch(databaseProvider.future); - return CorrespondenceGameStorage(db, ref); -} - -@riverpod -Future> offlineOngoingCorrespondenceGames( +/// A provider for [CorrespondenceGameStorage]. +final correspondenceGameStorageProvider = FutureProvider(( Ref ref, ) async { - final session = ref.watch(authSessionProvider); - // cannot use ref.watch because it would create a circular dependency - // as we invalidate this provider in the storage save and delete methods - final storage = await ref.read(correspondenceGameStorageProvider.future); - final data = await storage.fetchOngoingGames(session?.user.id); - return data.sort((a, b) { - final aIsMyTurn = a.$2.isMyTurn; - final bIsMyTurn = b.$2.isMyTurn; - if (aIsMyTurn && !bIsMyTurn) return -1; - if (!aIsMyTurn && bIsMyTurn) return 1; - return b.$1.compareTo(a.$1); - }); -} + final db = await ref.watch(databaseProvider.future); + return CorrespondenceGameStorage(db, ref); +}, name: 'CorrespondenceGameStorageProvider'); + +/// Fetches all ongoing offline correspondence games, sorted by whose turn it is and last modified time. +final offlineOngoingCorrespondenceGamesProvider = + FutureProvider.autoDispose>((Ref ref) async { + final session = ref.watch(authSessionProvider); + // cannot use ref.watch because it would create a circular dependency + // as we invalidate this provider in the storage save and delete methods + final storage = await ref.read(correspondenceGameStorageProvider.future); + final data = await storage.fetchOngoingGames(session?.user.id); + return data.sort((a, b) { + final aIsMyTurn = a.$2.isMyTurn; + final bIsMyTurn = b.$2.isMyTurn; + if (aIsMyTurn && !bIsMyTurn) return -1; + if (!aIsMyTurn && bIsMyTurn) return 1; + return b.$1.compareTo(a.$1); + }); + }, name: 'OfflineOngoingCorrespondenceGamesProvider'); const kCorrespondenceStorageTable = 'correspondence_game'; diff --git a/lib/src/model/correspondence/correspondence_service.dart b/lib/src/model/correspondence/correspondence_service.dart index b5764897e..b2f5b0487 100644 --- a/lib/src/model/correspondence/correspondence_service.dart +++ b/lib/src/model/correspondence/correspondence_service.dart @@ -24,16 +24,13 @@ import 'package:lichess_mobile/src/tab_scaffold.dart' show currentNavigatorKeyPr import 'package:lichess_mobile/src/view/game/game_screen.dart'; import 'package:lichess_mobile/src/view/game/game_screen_providers.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'correspondence_service.g.dart'; - -@Riverpod(keepAlive: true) -CorrespondenceService correspondenceService(Ref ref) { +/// A provider for [CorrespondenceService]. +final correspondenceServiceProvider = Provider((Ref ref) { final service = CorrespondenceService(Logger('CorrespondenceService'), ref: ref); ref.onDispose(() => service.dispose()); return service; -} +}, name: 'CorrespondenceServiceProvider'); /// Service that manages correspondence games. class CorrespondenceService { diff --git a/lib/src/model/engine/evaluation_preferences.dart b/lib/src/model/engine/evaluation_preferences.dart index bcc6b8092..2d4e11d40 100644 --- a/lib/src/model/engine/evaluation_preferences.dart +++ b/lib/src/model/engine/evaluation_preferences.dart @@ -1,19 +1,24 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/engine/evaluation_service.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'evaluation_preferences.freezed.dart'; part 'evaluation_preferences.g.dart'; +final engineEvaluationPreferencesProvider = + NotifierProvider( + EngineEvaluationPreferences.new, + name: 'EngineEvaluationPreferencesProvider', + ); + /// Preferences for engine evaluation. /// /// Same preferences are used in various screens where engine evaluation is used: /// - Analysis screen /// - Study screen /// - Broadcast game screen -@Riverpod(keepAlive: true) -class EngineEvaluationPreferences extends _$EngineEvaluationPreferences +class EngineEvaluationPreferences extends Notifier with PreferencesStorage { @override @protected diff --git a/lib/src/model/engine/evaluation_service.dart b/lib/src/model/engine/evaluation_service.dart index 0bbe0fa6d..09c7e4706 100644 --- a/lib/src/model/engine/evaluation_service.dart +++ b/lib/src/model/engine/evaluation_service.dart @@ -25,11 +25,9 @@ import 'package:lichess_mobile/src/utils/l10n_context.dart'; import 'package:lichess_mobile/src/widgets/platform_alert_dialog.dart'; import 'package:logging/logging.dart'; import 'package:multistockfish/multistockfish.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:stream_transform/stream_transform.dart'; part 'evaluation_service.freezed.dart'; -part 'evaluation_service.g.dart'; final _logger = Logger('EvaluationService'); @@ -47,8 +45,8 @@ typedef ShouldEmitEvalFilter = bool Function(Work work); typedef NNUEFiles = ({File bigNet, File smallNet}); -@Riverpod(keepAlive: true) -EvaluationService evaluationService(Ref ref) { +/// A provider for [EvaluationService]. +final evaluationServiceProvider = Provider((Ref ref) { final maxMemory = ref.read(preloadedDataProvider).requireValue.engineMaxMemoryInMb; final service = EvaluationService(ref, maxMemory: maxMemory); @@ -57,7 +55,7 @@ EvaluationService evaluationService(Ref ref) { }); return service; -} +}, name: 'EvaluationServiceProvider'); /// A service to evaluate chess positions using an engine. class EvaluationService { @@ -387,8 +385,13 @@ typedef EngineEvaluationState = ({ }); /// A provider that holds the state of the engine and the current evaluation. -@riverpod -class EngineEvaluation extends _$EngineEvaluation { +final engineEvaluationProvider = + NotifierProvider.autoDispose( + EngineEvaluation.new, + name: 'EngineEvaluationProvider', + ); + +class EngineEvaluation extends Notifier { @override EngineEvaluationState build() { final listenable = ref.watch(evaluationServiceProvider).state; diff --git a/lib/src/model/explorer/opening_explorer_preferences.dart b/lib/src/model/explorer/opening_explorer_preferences.dart index fd15863de..0b65fd58f 100644 --- a/lib/src/model/explorer/opening_explorer_preferences.dart +++ b/lib/src/model/explorer/opening_explorer_preferences.dart @@ -1,17 +1,22 @@ import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/speed.dart'; import 'package:lichess_mobile/src/model/explorer/opening_explorer.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'opening_explorer_preferences.freezed.dart'; part 'opening_explorer_preferences.g.dart'; -@Riverpod(keepAlive: true) -class OpeningExplorerPreferences extends _$OpeningExplorerPreferences +final openingExplorerPreferencesProvider = + NotifierProvider( + OpeningExplorerPreferences.new, + name: 'OpeningExplorerPreferencesProvider', + ); + +class OpeningExplorerPreferences extends Notifier with SessionPreferencesStorage { @override @protected diff --git a/lib/src/model/explorer/opening_explorer_repository.dart b/lib/src/model/explorer/opening_explorer_repository.dart index 76ff7ef47..8ad937c41 100644 --- a/lib/src/model/explorer/opening_explorer_repository.dart +++ b/lib/src/model/explorer/opening_explorer_repository.dart @@ -10,16 +10,21 @@ import 'package:lichess_mobile/src/model/explorer/opening_explorer.dart'; import 'package:lichess_mobile/src/model/explorer/opening_explorer_preferences.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/utils/riverpod.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'opening_explorer_repository.g.dart'; +final openingExplorerProvider = AsyncNotifierProvider.autoDispose + .family( + OpeningExplorer.new, + name: 'OpeningExplorerProvider', + ); + +class OpeningExplorer extends AsyncNotifier<({OpeningExplorerEntry entry, bool isIndexing})?> { + OpeningExplorer(this.fen); + final String fen; -@riverpod -class OpeningExplorer extends _$OpeningExplorer { StreamSubscription? _openingExplorerSubscription; @override - Future<({OpeningExplorerEntry entry, bool isIndexing})?> build({required String fen}) async { + Future<({OpeningExplorerEntry entry, bool isIndexing})?> build() async { ref.onDispose(() { _openingExplorerSubscription?.cancel(); }); @@ -67,10 +72,10 @@ class OpeningExplorer extends _$OpeningExplorer { } } -@Riverpod(keepAlive: true) -OpeningExplorerRepository openingExplorerRepository(Ref ref) { +/// A provider for [OpeningExplorerRepository]. +final openingExplorerRepositoryProvider = Provider((Ref ref) { return OpeningExplorerRepository(ref.read(defaultClientProvider)); -} +}, name: 'OpeningExplorerRepositoryProvider'); class OpeningExplorerRepository { const OpeningExplorerRepository(this.client); diff --git a/lib/src/model/explorer/tablebase_repository.dart b/lib/src/model/explorer/tablebase_repository.dart index cb388e177..11f4c920f 100644 --- a/lib/src/model/explorer/tablebase_repository.dart +++ b/lib/src/model/explorer/tablebase_repository.dart @@ -1,26 +1,24 @@ import 'dart:async'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart'; import 'package:lichess_mobile/src/constants.dart'; import 'package:lichess_mobile/src/model/explorer/tablebase.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/utils/riverpod.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'tablebase_repository.g.dart'; +/// A provider for fetching tablebase entries. +final tablebaseProvider = FutureProvider.autoDispose.family(( + ref, + fen, +) async { + await ref.debounce(const Duration(milliseconds: 300)); -@riverpod -class Tablebase extends _$Tablebase { - @override - Future build({required String fen}) async { - await ref.debounce(const Duration(milliseconds: 300)); + final client = ref.read(defaultClientProvider); - final client = ref.read(defaultClientProvider); - - final tablebaseEntry = await TablebaseRepository(client).getTablebaseEntry(fen); - return tablebaseEntry; - } -} + final tablebaseEntry = await TablebaseRepository(client).getTablebaseEntry(fen); + return tablebaseEntry; +}, name: 'TablebaseProvider'); class TablebaseRepository { const TablebaseRepository(this.client); diff --git a/lib/src/model/game/game_bookmarks.dart b/lib/src/model/game/game_bookmarks.dart index b50d108a2..d3cacb827 100644 --- a/lib/src/model/game/game_bookmarks.dart +++ b/lib/src/model/game/game_bookmarks.dart @@ -2,21 +2,25 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/game/exported_game.dart'; import 'package:lichess_mobile/src/model/game/game_repository.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_bookmarks.freezed.dart'; -part 'game_bookmarks.g.dart'; const _nbPerPage = 20; /// A provider that paginates the game bookmarks for the current app user. -@riverpod -class GameBookmarksPaginator extends _$GameBookmarksPaginator { +final gameBookmarksPaginatorProvider = + AsyncNotifierProvider.autoDispose( + GameBookmarksPaginator.new, + name: 'GameBookmarksPaginatorProvider', + ); + +class GameBookmarksPaginator extends AsyncNotifier { final _list = []; GameRepository get _gameRepository => ref.read(gameRepositoryProvider); diff --git a/lib/src/model/game/game_controller.dart b/lib/src/model/game/game_controller.dart index a7096fd6b..7887a3521 100644 --- a/lib/src/model/game/game_controller.dart +++ b/lib/src/model/game/game_controller.dart @@ -6,6 +6,7 @@ import 'package:deep_pick/deep_pick.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/binding.dart'; import 'package:lichess_mobile/src/model/account/account_preferences.dart'; @@ -33,13 +34,21 @@ import 'package:lichess_mobile/src/model/settings/board_preferences.dart'; import 'package:lichess_mobile/src/network/socket.dart'; import 'package:lichess_mobile/src/utils/rate_limit.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_controller.freezed.dart'; -part 'game_controller.g.dart'; -@riverpod -class GameController extends _$GameController { +/// A provider for [GameController]. +final gameControllerProvider = AsyncNotifierProvider.autoDispose + .family( + GameController.new, + name: 'GameControllerProvider', + ); + +class GameController extends AsyncNotifier { + GameController(this.gameFullId); + + final GameFullId gameFullId; + final _logger = Logger('GameController'); StreamSubscription? _socketSubscription; @@ -67,7 +76,7 @@ class GameController extends _$GameController { GameRepository get _gameRepository => ref.read(gameRepositoryProvider); @override - Future build(GameFullId gameFullId) { + Future build() { _socketClient = _openSocket(); _onFullReload = () { @@ -374,7 +383,7 @@ class GameController extends _$GameController { /// Play a sound when the clock is about to run out Future onClockEmergency(Side activeSide) async { - if (activeSide != state.valueOrNull?.game.youAre) return; + if (activeSide != state.value?.game.youAre) return; final shouldPlay = await ref.read(clockSoundProvider.future); if (shouldPlay) { ref.read(soundServiceProvider).play(Sound.lowTime); @@ -394,7 +403,7 @@ class GameController extends _$GameController { } void berserk() { - if (state.valueOrNull?.canBerserk == true && state.valueOrNull?.hasBerserked == false) { + if (state.value?.canBerserk == true && state.value?.hasBerserked == false) { _socketClient.send('berserk', null); } } @@ -702,8 +711,8 @@ class GameController extends _$GameController { playedSide == curState.game.youAre?.opposite && curState.premove != null) { scheduleMicrotask(() { - final postMovePremove = state.valueOrNull?.premove; - final postMovePosition = state.valueOrNull?.game.lastPosition; + final postMovePremove = state.value?.premove; + final postMovePosition = state.value?.game.lastPosition; if (postMovePremove != null && postMovePosition?.isLegal(postMovePremove) == true) { userMove(postMovePremove, isPremove: true); } diff --git a/lib/src/model/game/game_filter.dart b/lib/src/model/game/game_filter.dart index a36a258d6..80396abba 100644 --- a/lib/src/model/game/game_filter.dart +++ b/lib/src/model/game/game_filter.dart @@ -1,18 +1,27 @@ import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/model/common/perf.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_filter.freezed.dart'; -part 'game_filter.g.dart'; -@riverpod -class GameFilter extends _$GameFilter { +/// A provider for [GameFilter]. +final gameFilterProvider = NotifierProvider.autoDispose + .family( + GameFilter.new, + name: 'GameFilterProvider', + ); + +class GameFilter extends Notifier { + GameFilter(this.filter); + + final GameFilterState? filter; + @override - GameFilterState build({GameFilterState? filter}) { + GameFilterState build() { return filter ?? const GameFilterState(); } diff --git a/lib/src/model/game/game_history.dart b/lib/src/model/game/game_history.dart index 35f867153..0974ae195 100644 --- a/lib/src/model/game/game_history.dart +++ b/lib/src/model/game/game_history.dart @@ -18,10 +18,8 @@ import 'package:lichess_mobile/src/model/user/user.dart'; import 'package:lichess_mobile/src/model/user/user_repository_providers.dart'; import 'package:lichess_mobile/src/network/connectivity.dart'; import 'package:lichess_mobile/src/utils/riverpod.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_history.freezed.dart'; -part 'game_history.g.dart'; const kNumberOfRecentGames = 10; @@ -32,9 +30,10 @@ const _nbPerPage = 20; /// If the user is logged in, the recent games are fetched from the server. /// If the user is not logged in, or there is no connectivity, the recent games /// stored locally are fetched instead. -@riverpod -Future> myRecentGames(Ref ref) async { - final online = await ref.watch(connectivityChangesProvider.selectAsync((c) => c.isOnline)); +final myRecentGamesProvider = FutureProvider.autoDispose>(( + Ref ref, +) async { + final online = (await ref.watch(connectivityChangesProvider.future)).isOnline; final session = ref.watch(authSessionProvider); if (session != null && online) { return ref @@ -52,38 +51,51 @@ Future> myRecentGames(Ref ref) async { .toIList(), ); } -} +}, name: 'MyRecentGamesProvider'); /// A provider that fetches the recent games from the server for a given user. -@riverpod -Future> userRecentGames(Ref ref, {required UserId userId}) { - return ref - .read(gameRepositoryProvider) - .getUserGames(userId, withBookmarked: true, max: kNumberOfRecentGames); -} +final userRecentGamesProvider = FutureProvider.autoDispose + .family, UserId>((Ref ref, UserId userId) { + return ref + .read(gameRepositoryProvider) + .getUserGames(userId, withBookmarked: true, max: kNumberOfRecentGames); + }, name: 'UserRecentGamesProvider'); /// A provider that fetches the total number of games played by given user, or the current app user if no user is provided. /// /// If the user is logged in, the number of games is fetched from the server. /// If the user is not logged in, or there is no connectivity, the number of games /// stored locally are fetched instead. -@riverpod -Future userNumberOfGames(Ref ref, LightUser? user) async { +final userNumberOfGamesProvider = FutureProvider.autoDispose.family(( + Ref ref, + LightUser? user, +) async { final session = ref.watch(authSessionProvider); - final online = await ref.watch(connectivityChangesProvider.selectAsync((c) => c.isOnline)); + final online = (await ref.watch(connectivityChangesProvider.future)).isOnline; return user != null - ? ref.watch(userProvider(id: user.id).selectAsync((u) => u.count?.all ?? 0)) + ? (await ref.watch(userProvider(user.id).future)).count?.all ?? 0 : session != null && online - ? ref.watch(accountProvider.selectAsync((u) => u?.count?.all ?? 0)) + ? (await ref.watch(accountProvider.future))?.count?.all ?? 0 : (await ref.watch(gameStorageProvider.future)).count(userId: user?.id); -} +}, name: 'UserNumberOfGamesProvider'); + +typedef UserGameHistoryNotifierParams = ({UserId? userId, GameFilterState filter}); /// A provider that paginates the game history for a given user, or the current app user if no user is provided. /// /// The game history is fetched from the server if the user is logged in and app is online. /// Otherwise, the game history is fetched from the local storage. -@riverpod -class UserGameHistory extends _$UserGameHistory { +final userGameHistoryProvider = AsyncNotifierProvider.autoDispose + .family( + UserGameHistoryNotifier.new, + name: 'UserGameHistoryProvider', + ); + +class UserGameHistoryNotifier extends AsyncNotifier { + UserGameHistoryNotifier(this.params); + + final UserGameHistoryNotifierParams params; + final _list = []; StreamSubscription<(GameId, bool)>? _bookmarkChangesSubscription; @@ -91,18 +103,7 @@ class UserGameHistory extends _$UserGameHistory { GameRepository get _gameRepository => ref.read(gameRepositoryProvider); @override - Future build( - UserId? userId, { - - /// Whether the history is requested in an online context. Applicable only - /// when [userId] is null. - /// - /// If this is true, the provider will attempt to fetch the games from the - /// server. If this is false, the provider will fetch the games from the - /// local storage. - required bool isOnline, - GameFilterState filter = const GameFilterState(), - }) async { + Future build() async { _bookmarkChangesSubscription?.cancel(); _bookmarkChangesSubscription = ref.read(accountServiceProvider).bookmarkChanges.listen((data) { final (id, bookmarked) = data; @@ -119,19 +120,19 @@ class UserGameHistory extends _$UserGameHistory { final session = ref.watch(authSessionProvider); final prefs = ref.watch(gameHistoryPreferencesProvider); - final online = await ref.watch(connectivityChangesProvider.selectAsync((c) => c.isOnline)); + final online = (await ref.watch(connectivityChangesProvider.future)).isOnline; final storage = await ref.watch(gameStorageProvider.future); - final id = userId ?? session?.user.id; + final id = params.userId ?? session?.user.id; final recentGames = id != null && online ? _gameRepository.getUserGames( id, - filter: filter, + filter: params.filter, withBookmarked: true, withMoves: prefs.displayMode == GameHistoryDisplayMode.detail, ) : storage - .page(userId: id, filter: filter) + .page(userId: id, filter: params.filter) .then( (value) => value // we can assume that `youAre` is not null either for logged @@ -147,8 +148,8 @@ class UserGameHistory extends _$UserGameHistory { isLoading: false, hasMore: true, hasError: false, - online: isOnline, - filter: filter, + online: online, + filter: params.filter, session: session, ); } @@ -161,9 +162,9 @@ class UserGameHistory extends _$UserGameHistory { final currentVal = state.requireValue; state = AsyncData(currentVal.copyWith(isLoading: true)); try { - final value = await (userId != null + final value = await (params.userId != null ? _gameRepository.getUserGames( - userId!, + params.userId!, max: _nbPerPage, until: _list.last.game.createdAt, filter: currentVal.filter, diff --git a/lib/src/model/game/game_preferences.dart b/lib/src/model/game/game_preferences.dart index 1790d7c99..fa010b625 100644 --- a/lib/src/model/game/game_preferences.dart +++ b/lib/src/model/game/game_preferences.dart @@ -1,13 +1,18 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_preferences.freezed.dart'; part 'game_preferences.g.dart'; +/// Provider for [GamePreferences]. +final gamePreferencesProvider = NotifierProvider( + GamePreferences.new, + name: 'GamePreferencesProvider', +); + /// Local game preferences, defined client-side only. -@Riverpod(keepAlive: true) -class GamePreferences extends _$GamePreferences with PreferencesStorage { +class GamePreferences extends Notifier with PreferencesStorage { @override @protected final prefCategory = PrefCategory.game; diff --git a/lib/src/model/game/game_repository_providers.dart b/lib/src/model/game/game_repository_providers.dart index d93f50569..9301ebf36 100644 --- a/lib/src/model/game/game_repository_providers.dart +++ b/lib/src/model/game/game_repository_providers.dart @@ -5,13 +5,12 @@ import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/game/exported_game.dart'; import 'package:lichess_mobile/src/model/game/game_repository.dart'; import 'package:lichess_mobile/src/model/game/game_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'game_repository_providers.g.dart'; /// Fetches a game from the server or from the local storage if not available online. -@riverpod -Future archivedGame(Ref ref, {required GameId id}) async { +final archivedGameProvider = FutureProvider.autoDispose.family(( + Ref ref, + GameId id, +) async { ExportedGame game; try { final isLoggedIn = ref.watch(isLoggedInProvider); @@ -26,9 +25,11 @@ Future archivedGame(Ref ref, {required GameId id}) async { } } return game; -} +}, name: 'ArchivedGameProvider'); -@riverpod -Future> gamesById(Ref ref, {required ISet ids}) { - return ref.read(gameRepositoryProvider).getGamesByIds(ids); -} +final gamesByIdProvider = FutureProvider.autoDispose.family, ISet>( + (Ref ref, ISet ids) { + return ref.read(gameRepositoryProvider).getGamesByIds(ids); + }, + name: 'GamesByIdProvider', +); diff --git a/lib/src/model/game/game_share_service.dart b/lib/src/model/game/game_share_service.dart index c79956b66..9471163ef 100644 --- a/lib/src/model/game/game_share_service.dart +++ b/lib/src/model/game/game_share_service.dart @@ -9,15 +9,12 @@ import 'package:lichess_mobile/src/model/game/exported_game.dart'; import 'package:lichess_mobile/src/model/game/game_repository.dart'; import 'package:lichess_mobile/src/model/settings/board_preferences.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:share_plus/share_plus.dart'; -part 'game_share_service.g.dart'; - -@Riverpod(keepAlive: true) -GameShareService gameShareService(Ref ref) { +/// A provider for [GameShareService]. +final gameShareServiceProvider = Provider((Ref ref) { return GameShareService(ref); -} +}, name: 'GameShareServiceProvider'); class GameShareService { GameShareService(this._ref); diff --git a/lib/src/model/game/game_storage.dart b/lib/src/model/game/game_storage.dart index 18e17b2c5..6d76c59b9 100644 --- a/lib/src/model/game/game_storage.dart +++ b/lib/src/model/game/game_storage.dart @@ -6,16 +6,13 @@ import 'package:lichess_mobile/src/db/database.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/game/exported_game.dart'; import 'package:lichess_mobile/src/model/game/game_filter.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; -part 'game_storage.g.dart'; - -@Riverpod(keepAlive: true) -Future gameStorage(Ref ref) async { +/// A provider for [GameStorage]. +final gameStorageProvider = FutureProvider((Ref ref) async { final db = await ref.watch(databaseProvider.future); return GameStorage(db); -} +}, name: 'GameStorageProvider'); const kGameStorageTable = 'game'; diff --git a/lib/src/model/http_log/http_log_paginator.dart b/lib/src/model/http_log/http_log_paginator.dart index e5356bad3..f561ad758 100644 --- a/lib/src/model/http_log/http_log_paginator.dart +++ b/lib/src/model/http_log/http_log_paginator.dart @@ -1,21 +1,25 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/http_log/http_log_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'http_log_paginator.freezed.dart'; -part 'http_log_paginator.g.dart'; /// The number of HTTP logs to fetch per page. const _pageSize = 20; +/// A provider for [HttpLogPaginator]. +final httpLogPaginatorProvider = AsyncNotifierProvider.autoDispose( + HttpLogPaginator.new, + name: 'HttpLogPaginatorProvider', +); + /// A Riverpod controller for managing HTTP logs. /// /// The `HttpLogController` class is responsible for fetching and managing /// paginated HTTP log entries from the storage. It uses a throttler to limit /// the rate of fetching new pages. -@riverpod -class HttpLogPaginator extends _$HttpLogPaginator { +class HttpLogPaginator extends AsyncNotifier { @override Future build() async { final storage = await ref.read(httpLogStorageProvider.future); @@ -68,9 +72,8 @@ sealed class HttpLogState with _$HttpLogState { const factory HttpLogState({required IList> data}) = _HttpLogState; bool get initialized => data.isNotEmpty; - List get logs => - data.expand((e) => e.valueOrNull?.items ?? []).toList(); - int? get nextPage => data.lastOrNull?.valueOrNull?.next; + List get logs => data.expand((e) => e.value?.items ?? []).toList(); + int? get nextPage => data.lastOrNull?.value?.next; bool get hasMore => initialized && nextPage != null; bool get isLoading => data.lastOrNull?.isLoading == true; bool get isDeleteButtonVisible => logs.isNotEmpty; diff --git a/lib/src/model/http_log/http_log_storage.dart b/lib/src/model/http_log/http_log_storage.dart index 0a2b1dc63..c0ff2abcc 100644 --- a/lib/src/model/http_log/http_log_storage.dart +++ b/lib/src/model/http_log/http_log_storage.dart @@ -3,18 +3,16 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/db/database.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; part 'http_log_storage.g.dart'; part 'http_log_storage.freezed.dart'; /// Provides an instance of [HttpLogStorage] using Riverpod. -@Riverpod(keepAlive: true) -Future httpLogStorage(Ref ref) async { +final httpLogStorageProvider = FutureProvider((Ref ref) async { final db = await ref.watch(databaseProvider.future); return HttpLogStorage(db); -} +}, name: 'HttpLogStorageProvider'); const kHttpLogStorageTable = 'http_log'; diff --git a/lib/src/model/lobby/create_game_service.dart b/lib/src/model/lobby/create_game_service.dart index 83d8d86c6..dcc50f3fa 100644 --- a/lib/src/model/lobby/create_game_service.dart +++ b/lib/src/model/lobby/create_game_service.dart @@ -14,9 +14,7 @@ import 'package:lichess_mobile/src/model/lobby/lobby_repository.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/network/socket.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'create_game_service.g.dart'; part 'create_game_service.freezed.dart'; /// The user response of a challenge request. @@ -47,14 +45,13 @@ sealed class ChallengeResponseDeclined } /// A provider for the [CreateGameService]. -@riverpod -CreateGameService createGameService(Ref ref) { +final createGameServiceProvider = Provider.autoDispose((Ref ref) { final service = CreateGameService(Logger('CreateGameService'), ref: ref); ref.onDispose(() { service.dispose(); }); return service; -} +}, name: 'CreateGameServiceProvider'); /// A service to create a new game from the lobby or from a challenge. class CreateGameService { diff --git a/lib/src/model/lobby/game_seek.dart b/lib/src/model/lobby/game_seek.dart index 296a833f9..d38fced4e 100644 --- a/lib/src/model/lobby/game_seek.dart +++ b/lib/src/model/lobby/game_seek.dart @@ -1,6 +1,7 @@ import 'dart:math' as math; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/binding.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; @@ -13,7 +14,6 @@ import 'package:lichess_mobile/src/model/game/playable_game.dart'; import 'package:lichess_mobile/src/model/lobby/game_setup_preferences.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_seek.freezed.dart'; part 'game_seek.g.dart'; @@ -139,8 +139,13 @@ sealed class RecentGameSeekPrefs with _$RecentGameSeekPrefs implements Serializa } } -@Riverpod(keepAlive: true) -class RecentGameSeek extends _$RecentGameSeek with PreferencesStorage { +final recentGameSeekProvider = NotifierProvider( + RecentGameSeek.new, + name: 'RecentGameSeekProvider', +); + +class RecentGameSeek extends Notifier + with PreferencesStorage { @override @protected final prefCategory = PrefCategory.gameSeeks; diff --git a/lib/src/model/lobby/game_setup_preferences.dart b/lib/src/model/lobby/game_setup_preferences.dart index 49351a65b..1de693535 100644 --- a/lib/src/model/lobby/game_setup_preferences.dart +++ b/lib/src/model/lobby/game_setup_preferences.dart @@ -1,4 +1,5 @@ import 'dart:math' as math; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; import 'package:lichess_mobile/src/model/common/perf.dart'; @@ -6,13 +7,16 @@ import 'package:lichess_mobile/src/model/common/speed.dart'; import 'package:lichess_mobile/src/model/common/time_increment.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_setup_preferences.freezed.dart'; part 'game_setup_preferences.g.dart'; -@Riverpod(keepAlive: true) -class GameSetupPreferences extends _$GameSetupPreferences +final gameSetupPreferencesProvider = NotifierProvider( + GameSetupPreferences.new, + name: 'GameSetupPreferencesProvider', +); + +class GameSetupPreferences extends Notifier with SessionPreferencesStorage { @override @protected diff --git a/lib/src/model/lobby/lobby_numbers.dart b/lib/src/model/lobby/lobby_numbers.dart index 88b1fea70..8970a031f 100644 --- a/lib/src/model/lobby/lobby_numbers.dart +++ b/lib/src/model/lobby/lobby_numbers.dart @@ -1,15 +1,18 @@ import 'dart:async'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/common/socket.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'lobby_numbers.g.dart'; /// The [LobbyNumbers] provider is used to display the number of players and /// games on lichess in real time. -@riverpod -class LobbyNumbers extends _$LobbyNumbers { +final lobbyNumbersProvider = + NotifierProvider.autoDispose( + LobbyNumbers.new, + name: 'LobbyNumbersProvider', + ); + +class LobbyNumbers extends Notifier<({int nbPlayers, int nbGames})?> { StreamSubscription? _socketSubscription; @override diff --git a/lib/src/model/lobby/lobby_repository.dart b/lib/src/model/lobby/lobby_repository.dart index d5c24adec..0be27abd6 100644 --- a/lib/src/model/lobby/lobby_repository.dart +++ b/lib/src/model/lobby/lobby_repository.dart @@ -7,14 +7,13 @@ import 'package:lichess_mobile/src/model/common/perf.dart'; import 'package:lichess_mobile/src/model/lobby/correspondence_challenge.dart'; import 'package:lichess_mobile/src/model/lobby/game_seek.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'lobby_repository.g.dart'; - -@riverpod -Future> correspondenceChallenges(Ref ref) { - return ref.withClient((client) => LobbyRepository(client).getCorrespondenceChallenges()); -} +final correspondenceChallengesProvider = FutureProvider.autoDispose>( + (Ref ref) { + return ref.withClient((client) => LobbyRepository(client).getCorrespondenceChallenges()); + }, + name: 'CorrespondenceChallengesProvider', +); class LobbyRepository { LobbyRepository(this.client); diff --git a/lib/src/model/message/conversation_controller.dart b/lib/src/model/message/conversation_controller.dart index 7b54ea93c..914b92563 100644 --- a/lib/src/model/message/conversation_controller.dart +++ b/lib/src/model/message/conversation_controller.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; @@ -8,15 +9,21 @@ import 'package:lichess_mobile/src/model/message/message_repository.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; import 'package:lichess_mobile/src/network/socket.dart'; import 'package:lichess_mobile/src/utils/rate_limit.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'conversation_controller.g.dart'; part 'conversation_controller.freezed.dart'; const kMessagesPerPage = 100; -@riverpod -class ConversationController extends _$ConversationController { +final conversationControllerProvider = AsyncNotifierProvider.autoDispose + .family( + ConversationController.new, + name: 'ConversationControllerProvider', + ); + +class ConversationController extends AsyncNotifier { + ConversationController(this.userId); + final UserId userId; + late SocketClient _client; StreamSubscription? _socketSubscription; Timer? _setReadTimer; @@ -27,7 +34,7 @@ class ConversationController extends _$ConversationController { LightUser? get _me => ref.read(authSessionProvider)?.user; @override - Future build(UserId userId) async { + Future build() async { _connectSocket(); ref.onDispose(() { diff --git a/lib/src/model/message/message_repository.dart b/lib/src/model/message/message_repository.dart index 1ac89e5fd..4868b6ab8 100644 --- a/lib/src/model/message/message_repository.dart +++ b/lib/src/model/message/message_repository.dart @@ -4,7 +4,6 @@ import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/message/message.dart'; import 'package:lichess_mobile/src/network/aggregator.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; /// A provider that gets the conversation data for the current user. final contactsProvider = FutureProvider.autoDispose((ref) { diff --git a/lib/src/model/message/message_service.dart b/lib/src/model/message/message_service.dart index 15cd0e989..d39f33f44 100644 --- a/lib/src/model/message/message_service.dart +++ b/lib/src/model/message/message_service.dart @@ -9,16 +9,13 @@ import 'package:lichess_mobile/src/model/notifications/notifications.dart'; import 'package:lichess_mobile/src/model/user/user_repository.dart'; import 'package:lichess_mobile/src/tab_scaffold.dart'; import 'package:lichess_mobile/src/view/message/conversation_screen.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'message_service.g.dart'; - -@Riverpod(keepAlive: true) -MessageService messageService(Ref ref) { +/// A provider for [MessageService]. +final messageServiceProvider = Provider((Ref ref) { final service = MessageService(ref); ref.onDispose(service.dispose); return service; -} +}, name: 'MessageServiceProvider'); class MessageService { MessageService(this.ref); diff --git a/lib/src/model/notifications/notification_service.dart b/lib/src/model/notifications/notification_service.dart index 3e7dea710..c92a25219 100644 --- a/lib/src/model/notifications/notification_service.dart +++ b/lib/src/model/notifications/notification_service.dart @@ -15,25 +15,22 @@ import 'package:lichess_mobile/src/network/connectivity.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/utils/badge_service.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'notification_service.g.dart'; final _logger = Logger('NotificationService'); /// A provider instance of the [FlutterLocalNotificationsPlugin]. -@Riverpod(keepAlive: true) -FlutterLocalNotificationsPlugin notificationDisplay(Ref _) => FlutterLocalNotificationsPlugin(); +final notificationDisplayProvider = Provider( + (Ref _) => FlutterLocalNotificationsPlugin(), +); /// A provider instance of the [NotificationService]. -@Riverpod(keepAlive: true) -NotificationService notificationService(Ref ref) { +final notificationServiceProvider = Provider((Ref ref) { final service = NotificationService(ref); ref.onDispose(() => service._dispose()); return service; -} +}); /// Received FCM message and whether it was from the background. typedef ReceivedFcmMessage = ({FcmMessage message, bool fromBackground}); diff --git a/lib/src/model/over_the_board/over_the_board_clock.dart b/lib/src/model/over_the_board/over_the_board_clock.dart index 248f7dc38..1ca94f105 100644 --- a/lib/src/model/over_the_board/over_the_board_clock.dart +++ b/lib/src/model/over_the_board/over_the_board_clock.dart @@ -2,15 +2,19 @@ import 'dart:async'; import 'dart:math'; import 'package:dartchess/dartchess.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/time_increment.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'over_the_board_clock.freezed.dart'; -part 'over_the_board_clock.g.dart'; -@riverpod -class OverTheBoardClock extends _$OverTheBoardClock { +final overTheBoardClockProvider = + NotifierProvider.autoDispose( + OverTheBoardClock.new, + name: 'OverTheBoardClockProvider', + ); + +class OverTheBoardClock extends Notifier { final Stopwatch _stopwatch = Stopwatch(); Timer? _updateTimer; diff --git a/lib/src/model/over_the_board/over_the_board_game_controller.dart b/lib/src/model/over_the_board/over_the_board_game_controller.dart index 73571f63e..bba7fcd20 100644 --- a/lib/src/model/over_the_board/over_the_board_game_controller.dart +++ b/lib/src/model/over_the_board/over_the_board_game_controller.dart @@ -1,5 +1,6 @@ import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; import 'package:lichess_mobile/src/model/common/chess960.dart'; @@ -11,13 +12,16 @@ import 'package:lichess_mobile/src/model/game/game.dart'; import 'package:lichess_mobile/src/model/game/game_status.dart'; import 'package:lichess_mobile/src/model/game/material_diff.dart'; import 'package:lichess_mobile/src/model/game/over_the_board_game.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'over_the_board_game_controller.freezed.dart'; -part 'over_the_board_game_controller.g.dart'; -@riverpod -class OverTheBoardGameController extends _$OverTheBoardGameController { +final overTheBoardGameControllerProvider = + NotifierProvider.autoDispose( + OverTheBoardGameController.new, + name: 'OverTheBoardGameControllerProvider', + ); + +class OverTheBoardGameController extends Notifier { @override OverTheBoardGameState build() => OverTheBoardGameState.fromVariant( Variant.standard, diff --git a/lib/src/model/puzzle/puzzle_activity.dart b/lib/src/model/puzzle/puzzle_activity.dart index 8a2bf387e..a544bcdf4 100644 --- a/lib/src/model/puzzle/puzzle_activity.dart +++ b/lib/src/model/puzzle/puzzle_activity.dart @@ -1,22 +1,26 @@ import 'dart:async'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_providers.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_repository.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/utils/riverpod.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'puzzle_activity.freezed.dart'; -part 'puzzle_activity.g.dart'; const _nbPerPage = 50; const _maxPuzzles = 500; -@riverpod -class PuzzleActivity extends _$PuzzleActivity { +final puzzleActivityProvider = + AsyncNotifierProvider.autoDispose( + PuzzleActivity.new, + name: 'PuzzleActivityProvider', + ); + +class PuzzleActivity extends AsyncNotifier { final _list = []; @override diff --git a/lib/src/model/puzzle/puzzle_batch_storage.dart b/lib/src/model/puzzle/puzzle_batch_storage.dart index 26aef420a..2449550a5 100644 --- a/lib/src/model/puzzle/puzzle_batch_storage.dart +++ b/lib/src/model/puzzle/puzzle_batch_storage.dart @@ -9,17 +9,16 @@ import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_angle.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_theme.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; part 'puzzle_batch_storage.freezed.dart'; part 'puzzle_batch_storage.g.dart'; -@Riverpod(keepAlive: true) -Future puzzleBatchStorage(Ref ref) async { +/// A provider for [PuzzleBatchStorage]. +final puzzleBatchStorageProvider = FutureProvider((Ref ref) async { final database = await ref.watch(databaseProvider.future); return PuzzleBatchStorage(database, ref); -} +}, name: 'PuzzleBatchStorageProvider'); const _anonUserKey = '**anon**'; const _tableName = 'puzzle_batchs'; diff --git a/lib/src/model/puzzle/puzzle_controller.dart b/lib/src/model/puzzle/puzzle_controller.dart index d6b765d6f..f02fafa00 100644 --- a/lib/src/model/puzzle/puzzle_controller.dart +++ b/lib/src/model/puzzle/puzzle_controller.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:collection/collection.dart' show IterableExtension; import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; import 'package:lichess_mobile/src/model/common/node.dart'; @@ -20,13 +21,20 @@ import 'package:lichess_mobile/src/model/puzzle/puzzle_service.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_session.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'puzzle_controller.freezed.dart'; -part 'puzzle_controller.g.dart'; -@riverpod -class PuzzleController extends _$PuzzleController with EngineEvaluationMixin { +final puzzleControllerProvider = NotifierProvider.autoDispose + .family( + PuzzleController.new, + name: 'PuzzleControllerProvider', + ); + +class PuzzleController extends Notifier with EngineEvaluationMixin { + PuzzleController(this.initialContext); + + final PuzzleContext initialContext; + static final Uri socketUri = Uri(path: '/analysis/socket/v5'); late Branch _gameTree; @@ -62,7 +70,7 @@ class PuzzleController extends _$PuzzleController with EngineEvaluationMixin { ref.read(puzzleServiceFactoryProvider)(queueLength: kPuzzleLocalQueueLength); @override - PuzzleState build(PuzzleContext initialContext, {bool isPuzzleStreak = false}) { + PuzzleState build() { initEngineEvaluation(); ref.onDispose(() { @@ -165,7 +173,7 @@ class PuzzleController extends _$PuzzleController with EngineEvaluationMixin { } else { state = state.copyWith(feedback: PuzzleFeedback.bad); _onFailOrWin(PuzzleResult.lose); - if (!isPuzzleStreak) { + if (initialContext.isPuzzleStreak != true) { await Future.delayed(const Duration(milliseconds: 500)); _setPath(state.currentPath.penultimate); } @@ -224,7 +232,7 @@ class PuzzleController extends _$PuzzleController with EngineEvaluationMixin { } void skipMove() { - if (isPuzzleStreak && state._nextSolutionMove != null) { + if (initialContext.isPuzzleStreak == true && state._nextSolutionMove != null) { onUserMove(state._nextSolutionMove!); } } @@ -271,7 +279,7 @@ class PuzzleController extends _$PuzzleController with EngineEvaluationMixin { final soundService = ref.read(soundServiceProvider); - if (isPuzzleStreak) { + if (initialContext.isPuzzleStreak == true) { // one fail and streak is over if (result == PuzzleResult.lose) { soundService.play(Sound.error); @@ -307,13 +315,23 @@ class PuzzleController extends _$PuzzleController with EngineEvaluationMixin { state = state.copyWith(nextContext: next); ref - .read(puzzleSessionProvider(initialContext.userId, initialContext.angle).notifier) + .read( + puzzleSessionProvider(( + userId: initialContext.userId, + angle: initialContext.angle, + )).notifier, + ) .addAttempt(state.puzzle.puzzle.id, win: result == PuzzleResult.win); final rounds = next?.rounds; if (rounds != null) { ref - .read(puzzleSessionProvider(initialContext.userId, initialContext.angle).notifier) + .read( + puzzleSessionProvider(( + userId: initialContext.userId, + angle: initialContext.angle, + )).notifier, + ) .setRatingDiffs(rounds); } diff --git a/lib/src/model/puzzle/puzzle_opening.dart b/lib/src/model/puzzle/puzzle_opening.dart index 3a7b1d7cd..e06543749 100644 --- a/lib/src/model/puzzle/puzzle_opening.dart +++ b/lib/src/model/puzzle/puzzle_opening.dart @@ -1,9 +1,6 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_providers.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'puzzle_opening.g.dart'; typedef PuzzleOpeningFamily = ({ String key, @@ -15,8 +12,9 @@ typedef PuzzleOpeningFamily = ({ typedef PuzzleOpeningData = ({String key, String name, int count}); /// Returns a flattened list of openings with their respective counts. -@riverpod -Future> flatOpeningsList(Ref ref) async { +final flatOpeningsListProvider = FutureProvider.autoDispose>(( + Ref ref, +) async { final families = await ref.watch(puzzleOpeningsProvider.future); return families .map( @@ -27,10 +25,13 @@ Future> flatOpeningsList(Ref ref) async { ) .expand((e) => e) .toIList(); -} +}, name: 'FlatOpeningsListProvider'); -@riverpod -Future puzzleOpeningName(Ref ref, String key) async { +/// Provides the name of a puzzle opening given its key. +final puzzleOpeningNameProvider = FutureProvider.autoDispose.family(( + Ref ref, + String key, +) async { final openings = await ref.watch(flatOpeningsListProvider.future); return openings.firstWhere((element) => element.key == key).name; -} +}, name: 'PuzzleOpeningNameProvider'); diff --git a/lib/src/model/puzzle/puzzle_preferences.dart b/lib/src/model/puzzle/puzzle_preferences.dart index b90d2530b..988d3563d 100644 --- a/lib/src/model/puzzle/puzzle_preferences.dart +++ b/lib/src/model/puzzle/puzzle_preferences.dart @@ -1,15 +1,19 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_difficulty.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'puzzle_preferences.freezed.dart'; part 'puzzle_preferences.g.dart'; -@Riverpod(keepAlive: true) -class PuzzlePreferences extends _$PuzzlePreferences with SessionPreferencesStorage { +final puzzlePreferencesProvider = NotifierProvider( + PuzzlePreferences.new, + name: 'PuzzlePreferencesProvider', +); + +class PuzzlePreferences extends Notifier with SessionPreferencesStorage { @override @protected final prefCategory = PrefCategory.puzzle; diff --git a/lib/src/model/puzzle/puzzle_providers.dart b/lib/src/model/puzzle/puzzle_providers.dart index 27cb48637..59103c5ff 100644 --- a/lib/src/model/puzzle/puzzle_providers.dart +++ b/lib/src/model/puzzle/puzzle_providers.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; @@ -15,12 +13,12 @@ import 'package:lichess_mobile/src/model/puzzle/puzzle_theme.dart'; import 'package:lichess_mobile/src/model/puzzle/storm.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/utils/riverpod.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'puzzle_providers.g.dart'; - -@riverpod -Future nextPuzzle(Ref ref, PuzzleAngle angle) async { +/// Fetches the next puzzle for the given [PuzzleAngle]. +final nextPuzzleProvider = FutureProvider.autoDispose.family(( + Ref ref, + PuzzleAngle angle, +) async { final session = ref.watch(authSessionProvider); final puzzleService = await ref.read(puzzleServiceFactoryProvider)( queueLength: kPuzzleLocalQueueLength, @@ -30,88 +28,102 @@ Future nextPuzzle(Ref ref, PuzzleAngle angle) async { ref.cacheFor(const Duration(minutes: 1)); return puzzleService.nextPuzzle(userId: session?.user.id, angle: angle); -} +}, name: 'NextPuzzleProvider'); -@riverpod -Future storm(Ref ref) { +/// Fetches a storm of puzzles. +final stormProvider = FutureProvider.autoDispose((Ref ref) { return ref.withClient((client) => PuzzleRepository(client).storm()); -} +}, name: 'StormProvider'); /// Fetches a puzzle from the local storage if available, otherwise fetches it from the server. -@riverpod -Future puzzle(Ref ref, PuzzleId id) async { +final puzzleProvider = FutureProvider.autoDispose.family(( + Ref ref, + PuzzleId id, +) async { final puzzleStorage = await ref.watch(puzzleStorageProvider.future); final puzzle = await puzzleStorage.fetch(puzzleId: id); if (puzzle != null) return puzzle; return ref.withClient((client) => PuzzleRepository(client).fetch(id)); -} +}, name: 'PuzzleProvider'); -@riverpod -Future dailyPuzzle(Ref ref) { +/// Fetches the daily puzzle. +final dailyPuzzleProvider = FutureProvider.autoDispose((Ref ref) { return ref.withClientCacheFor( (client) => PuzzleRepository(client).daily(), const Duration(hours: 6), ); -} +}, name: 'DailyPuzzleProvider'); -@riverpod -Future> savedBatches(Ref ref) async { +/// Fetches all saved puzzle batches for the current user. +final savedBatchesProvider = FutureProvider.autoDispose>((Ref ref) async { final session = ref.watch(authSessionProvider); final storage = await ref.watch(puzzleBatchStorageProvider.future); return storage.fetchAll(userId: session?.user.id); -} +}, name: 'SavedBatchesProvider'); -@riverpod -Future> savedThemeBatches(Ref ref) async { +/// Fetches saved puzzle theme batches for the current user. +final savedThemeBatchesProvider = FutureProvider.autoDispose>(( + Ref ref, +) async { final session = ref.watch(authSessionProvider); final storage = await ref.watch(puzzleBatchStorageProvider.future); return storage.fetchSavedThemes(userId: session?.user.id); -} +}, name: 'SavedThemeBatchesProvider'); -@riverpod -Future> savedOpeningBatches(Ref ref) async { +/// Fetches saved puzzle opening batches for the current user. +final savedOpeningBatchesProvider = FutureProvider.autoDispose>((Ref ref) async { final session = ref.watch(authSessionProvider); final storage = await ref.watch(puzzleBatchStorageProvider.future); return storage.fetchSavedOpenings(userId: session?.user.id); -} +}, name: 'SavedOpeningBatchesProvider'); -@riverpod -Future puzzleDashboard(Ref ref, int days) async { +/// Fetches the puzzle dashboard for the current user for the given number of [days]. +final puzzleDashboardProvider = FutureProvider.autoDispose.family(( + Ref ref, + int days, +) { final session = ref.watch(authSessionProvider); if (session == null) return null; return ref.withClientCacheFor( (client) => PuzzleRepository(client).puzzleDashboard(days), const Duration(hours: 3), ); -} +}, name: 'PuzzleDashboardProvider'); -@riverpod -Future?> puzzleRecentActivity(Ref ref) async { +/// Fetches recent puzzle activity for the current user. +final puzzleRecentActivityProvider = FutureProvider.autoDispose?>(( + Ref ref, +) { final session = ref.watch(authSessionProvider); if (session == null) return null; return ref.withClientCacheFor( (client) => PuzzleRepository(client).puzzleActivity(20), const Duration(hours: 3), ); -} +}, name: 'PuzzleRecentActivityProvider'); -@riverpod -Future stormDashboard(Ref ref, UserId id) { +/// Fetches the storm dashboard for a given user [UserId]. +final stormDashboardProvider = FutureProvider.autoDispose.family(( + Ref ref, + UserId id, +) { return ref.withClient((client) => PuzzleRepository(client).stormDashboard(id)); -} +}, name: 'StormDashboardProvider'); -@riverpod -Future> puzzleThemes(Ref ref) { +/// Fetches available puzzle themes. +final puzzleThemesProvider = FutureProvider.autoDispose>(( + Ref ref, +) { return ref.withClientCacheFor( (client) => PuzzleRepository(client).puzzleThemes(), const Duration(days: 1), ); -} +}, name: 'PuzzleThemesProvider'); -@riverpod -Future> puzzleOpenings(Ref ref) { +/// Fetches available puzzle openings. +final puzzleOpeningsProvider = FutureProvider.autoDispose>((Ref ref) { return ref.withClientCacheFor( (client) => PuzzleRepository(client).puzzleOpenings(), const Duration(days: 1), ); -} +}, name: 'PuzzleOpeningsProvider'); diff --git a/lib/src/model/puzzle/puzzle_service.dart b/lib/src/model/puzzle/puzzle_service.dart index 8c94f6ef9..723aa8b80 100644 --- a/lib/src/model/puzzle/puzzle_service.dart +++ b/lib/src/model/puzzle/puzzle_service.dart @@ -15,23 +15,21 @@ import 'package:lichess_mobile/src/model/puzzle/puzzle_theme.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:logging/logging.dart'; import 'package:result_extensions/result_extensions.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'puzzle_service.freezed.dart'; -part 'puzzle_service.g.dart'; /// Size of puzzle local cache const kPuzzleLocalQueueLength = 50; -@Riverpod(keepAlive: true) -Future puzzleService(Ref ref) { +/// A provider for [PuzzleService]. +final puzzleServiceProvider = FutureProvider((Ref ref) { return ref.read(puzzleServiceFactoryProvider)(queueLength: kPuzzleLocalQueueLength); -} +}, name: 'PuzzleServiceProvider'); -@Riverpod(keepAlive: true) -PuzzleServiceFactory puzzleServiceFactory(Ref ref) { +/// A provider for [PuzzleServiceFactory]. +final puzzleServiceFactoryProvider = Provider((Ref ref) { return PuzzleServiceFactory(ref); -} +}, name: 'PuzzleServiceFactoryProvider'); class PuzzleServiceFactory { PuzzleServiceFactory(this._ref); @@ -63,6 +61,7 @@ sealed class PuzzleContext with _$PuzzleContext { /// If true, the result won't be recorded on the server for this puzzle. bool? casual, + bool? isPuzzleStreak, }) = _PuzzleContext; } diff --git a/lib/src/model/puzzle/puzzle_session.dart b/lib/src/model/puzzle/puzzle_session.dart index 3ae0b813a..10dc34bd7 100644 --- a/lib/src/model/puzzle/puzzle_session.dart +++ b/lib/src/model/puzzle/puzzle_session.dart @@ -2,32 +2,43 @@ import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/binding.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_angle.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_theme.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:shared_preferences/shared_preferences.dart'; part 'puzzle_session.freezed.dart'; part 'puzzle_session.g.dart'; -@riverpod -class PuzzleSession extends _$PuzzleSession { +final puzzleSessionProvider = + NotifierProvider.family( + PuzzleSession.new, + name: 'PuzzleSessionProvider', + ); + +typedef PuzzleSessionParams = ({UserId? userId, PuzzleAngle angle}); + +class PuzzleSession extends Notifier { + PuzzleSession(this.params); + + final PuzzleSessionParams params; + static const maxAge = Duration(hours: 1); static const maxSize = 150; @override - PuzzleSessionData build(UserId? userId, PuzzleAngle angle) { + PuzzleSessionData build() { final data = _stored; if (data != null && - data.angle == angle && + data.angle == params.angle && data.lastUpdatedAt.isAfter(DateTime.now().subtract(maxAge))) { return data; } - return PuzzleSessionData.initial(angle: angle); + return PuzzleSessionData.initial(angle: params.angle); } Future addAttempt(PuzzleId id, {required bool win}) async { @@ -66,14 +77,14 @@ class PuzzleSession extends _$PuzzleSession { PuzzleSessionData? get _stored { final stored = _store.getString(_storageKey); if (stored == null) { - return PuzzleSessionData.initial(angle: angle); + return PuzzleSessionData.initial(angle: params.angle); } return PuzzleSessionData.fromJson(jsonDecode(stored) as Map); } SharedPreferencesWithCache get _store => LichessBinding.instance.sharedPreferences; - String get _storageKey => 'puzzle_session.${userId ?? '**anon**'}'; + String get _storageKey => 'puzzle_session.${params.userId ?? '**anon**'}'; } @Freezed(fromJson: true, toJson: true) diff --git a/lib/src/model/puzzle/puzzle_storage.dart b/lib/src/model/puzzle/puzzle_storage.dart index c11fc70ae..82fd1d565 100644 --- a/lib/src/model/puzzle/puzzle_storage.dart +++ b/lib/src/model/puzzle/puzzle_storage.dart @@ -4,16 +4,13 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/db/database.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:sqflite/sqflite.dart'; -part 'puzzle_storage.g.dart'; - -@Riverpod(keepAlive: true) -Future puzzleStorage(Ref ref) async { +/// A provider for [PuzzleStorage]. +final puzzleStorageProvider = FutureProvider((Ref ref) async { final db = await ref.watch(databaseProvider.future); return PuzzleStorage(db); -} +}, name: 'PuzzleStorageProvider'); const _tableName = 'puzzle'; diff --git a/lib/src/model/puzzle/puzzle_streak.dart b/lib/src/model/puzzle/puzzle_streak.dart index 465159c86..037da6d70 100644 --- a/lib/src/model/puzzle/puzzle_streak.dart +++ b/lib/src/model/puzzle/puzzle_streak.dart @@ -1,4 +1,5 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; @@ -10,7 +11,6 @@ import 'package:lichess_mobile/src/model/puzzle/streak_storage.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/tab_scaffold.dart' show currentNavigatorKeyProvider; import 'package:lichess_mobile/src/widgets/feedback.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'puzzle_streak.freezed.dart'; part 'puzzle_streak.g.dart'; @@ -37,8 +37,13 @@ sealed class PuzzleStreak with _$PuzzleStreak { /// [PuzzleStreak] with its current [Puzzle]. typedef StreakState = ({PuzzleStreak streak, Puzzle puzzle, Puzzle? nextPuzzle}); -@riverpod -class PuzzleStreakController extends _$PuzzleStreakController { +final puzzleStreakControllerProvider = + AsyncNotifierProvider.autoDispose( + PuzzleStreakController.new, + name: 'PuzzleStreakControllerProvider', + ); + +class PuzzleStreakController extends AsyncNotifier { @override Future build() async { final session = ref.watch(authSessionProvider); diff --git a/lib/src/model/puzzle/puzzle_theme.dart b/lib/src/model/puzzle/puzzle_theme.dart index b259601a2..fe7080999 100644 --- a/lib/src/model/puzzle/puzzle_theme.dart +++ b/lib/src/model/puzzle/puzzle_theme.dart @@ -5,10 +5,8 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/localizations.dart'; import 'package:lichess_mobile/src/styles/puzzle_icons.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'puzzle_theme.freezed.dart'; -part 'puzzle_theme.g.dart'; @freezed sealed class PuzzleThemeData with _$PuzzleThemeData { @@ -412,8 +410,7 @@ final IMap puzzleThemeNameMap = IMap(PuzzleThemeKey.valu typedef PuzzleThemeCategory = (String, List); -@Riverpod(keepAlive: true) -IList puzzleThemeCategories(Ref ref) { +final puzzleThemeCategoriesProvider = Provider>((Ref ref) { final l10n = ref.watch(localizationsProvider); return IList([ @@ -512,7 +509,7 @@ IList puzzleThemeCategories(Ref ref) { [PuzzleThemeKey.master, PuzzleThemeKey.masterVsMaster, PuzzleThemeKey.superGM], ), ]); -} +}, name: 'PuzzleThemeCategoriesProvider'); class PuzzleThemeL10n { const PuzzleThemeL10n({required this.name, required this.description}); diff --git a/lib/src/model/puzzle/storm_controller.dart b/lib/src/model/puzzle/storm_controller.dart index 2edf9b4af..05d646978 100644 --- a/lib/src/model/puzzle/storm_controller.dart +++ b/lib/src/model/puzzle/storm_controller.dart @@ -6,6 +6,7 @@ import 'package:async/async.dart'; import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; @@ -16,22 +17,33 @@ import 'package:lichess_mobile/src/model/puzzle/puzzle_repository.dart'; import 'package:lichess_mobile/src/model/puzzle/storm.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:result_extensions/result_extensions.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'storm_controller.freezed.dart'; -part 'storm_controller.g.dart'; const malus = Duration(seconds: 10); const moveDelay = Duration(milliseconds: 200); const startTime = Duration(minutes: 3); -@riverpod -class StormController extends _$StormController { +typedef StormControllerParams = (IList puzzles, DateTime timestamp); + +final stormControllerProvider = NotifierProvider.autoDispose + .family( + StormController.new, + name: 'StormControllerProvider', + ); + +class StormController extends Notifier { + StormController(this.params); + + final StormControllerParams params; + Timer? _firstMoveTimer; + IList get _puzzles => params.$1; + @override - StormState build(IList puzzles, DateTime timestamp) { - final pov = Chess.fromSetup(Setup.parseFen(puzzles.first.fen)); + StormState build() { + final pov = Chess.fromSetup(Setup.parseFen(_puzzles.first.fen)); final clock = StormClock(); ref.onDispose(() { @@ -43,7 +55,7 @@ class StormController extends _$StormController { firstMovePlayed: false, mode: StormMode.initial, puzzleIndex: 0, - puzzle: puzzles.first, + puzzle: _puzzles.first, moves: 0, errors: 0, history: const IList.empty(), @@ -181,8 +193,8 @@ class StormController extends _$StormController { state = state.copyWith( puzzleIndex: newPuzzleIndex, - puzzle: puzzles[newPuzzleIndex], - position: Chess.fromSetup(Setup.parseFen(puzzles[newPuzzleIndex].fen)), + puzzle: _puzzles[newPuzzleIndex], + position: Chess.fromSetup(Setup.parseFen(_puzzles[newPuzzleIndex].fen)), moveIndex: -1, numSolved: result ? state.numSolved + 1 : state.numSolved, lastSolvedTime: DateTime.now(), @@ -269,7 +281,7 @@ class StormController extends _$StormController { } bool _isNextPuzzleAvailable() { - return state.puzzleIndex + 1 < puzzles.length; + return state.puzzleIndex + 1 < _puzzles.length; } } diff --git a/lib/src/model/puzzle/streak_storage.dart b/lib/src/model/puzzle/streak_storage.dart index 949c8a687..aa9a85739 100644 --- a/lib/src/model/puzzle/streak_storage.dart +++ b/lib/src/model/puzzle/streak_storage.dart @@ -1,31 +1,29 @@ import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/binding.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle_streak.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:shared_preferences/shared_preferences.dart'; -part 'streak_storage.g.dart'; - -@riverpod -StreakStorage streakStorage(Ref ref, UserId? userId) { +/// Provider for the streak storage for a given user. +final streakStorageProvider = Provider.autoDispose.family(( + Ref ref, + UserId? userId, +) { return StreakStorage(ref, userId); -} +}); /// Fetches the current streak score from the local storage if available, returns null otherwise. -@riverpod -Future savedStreakScore(Ref ref) async { +final savedStreakScoreProvider = FutureProvider.autoDispose((Ref ref) async { final session = ref.watch(authSessionProvider); // cannot use ref.watch because it would create a circular dependency // as we invalidate this provider in the storage saveActiveStreak and clearActiveStreak methods final streakStorage = ref.read(streakStorageProvider(session?.user.id)); final streak = await streakStorage.loadActiveStreak(); return streak?.index; -} +}); /// Local storage for the current puzzle streak. class StreakStorage { diff --git a/lib/src/model/relation/online_friends.dart b/lib/src/model/relation/online_friends.dart index b108fdda1..5e59ff903 100644 --- a/lib/src/model/relation/online_friends.dart +++ b/lib/src/model/relation/online_friends.dart @@ -2,18 +2,20 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/common/socket.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'online_friends.g.dart'; typedef OnlineFriend = ({LightUser user, bool playing}); -@riverpod -class OnlineFriends extends _$OnlineFriends { +final onlineFriendsProvider = AsyncNotifierProvider.autoDispose>( + OnlineFriends.new, + name: 'OnlineFriendsProvider', +); + +class OnlineFriends extends AsyncNotifier> { StreamSubscription? _socketSubscription; StreamSubscription? _socketOpenSubscription; diff --git a/lib/src/model/settings/board_preferences.dart b/lib/src/model/settings/board_preferences.dart index d40d9393b..904ede3a1 100644 --- a/lib/src/model/settings/board_preferences.dart +++ b/lib/src/model/settings/board_preferences.dart @@ -2,13 +2,13 @@ import 'package:chessground/chessground.dart'; import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/styles/styles.dart'; import 'package:lichess_mobile/src/utils/color_palette.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'board_preferences.freezed.dart'; part 'board_preferences.g.dart'; @@ -16,8 +16,12 @@ part 'board_preferences.g.dart'; const kBoardDefaultBrightnessFilter = 1.0; const kBoardDefaultHueFilter = 0.0; -@Riverpod(keepAlive: true) -class BoardPreferences extends _$BoardPreferences with PreferencesStorage { +final boardPreferencesProvider = NotifierProvider( + BoardPreferences.new, + name: 'BoardPreferencesProvider', +); + +class BoardPreferences extends Notifier with PreferencesStorage { @override @protected PrefCategory get prefCategory => PrefCategory.board; diff --git a/lib/src/model/settings/brightness.dart b/lib/src/model/settings/brightness.dart index 6cc6f93b6..0f1bed6c0 100644 --- a/lib/src/model/settings/brightness.dart +++ b/lib/src/model/settings/brightness.dart @@ -1,12 +1,14 @@ import 'package:flutter/foundation.dart' show Brightness; import 'package:flutter/widgets.dart' show WidgetsBinding; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/settings/general_preferences.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'brightness.g.dart'; +final currentBrightnessProvider = NotifierProvider( + CurrentBrightness.new, + name: 'CurrentBrightnessProvider', +); -@riverpod -class CurrentBrightness extends _$CurrentBrightness { +class CurrentBrightness extends Notifier { @override Brightness build() { final themeMode = ref.watch(generalPreferencesProvider.select((state) => state.themeMode)); diff --git a/lib/src/model/settings/general_preferences.dart b/lib/src/model/settings/general_preferences.dart index 8a8ca4213..e806c56e0 100644 --- a/lib/src/model/settings/general_preferences.dart +++ b/lib/src/model/settings/general_preferences.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/model/settings/board_preferences.dart' @@ -7,13 +8,17 @@ import 'package:lichess_mobile/src/model/settings/board_preferences.dart' import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; import 'package:lichess_mobile/src/theme.dart'; import 'package:lichess_mobile/src/utils/json.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'general_preferences.freezed.dart'; part 'general_preferences.g.dart'; -@Riverpod(keepAlive: true) -class GeneralPreferences extends _$GeneralPreferences with PreferencesStorage { +final generalPreferencesProvider = NotifierProvider( + GeneralPreferencesNotifier.new, + name: 'GeneralPreferencesProvider', +); + +class GeneralPreferencesNotifier extends Notifier + with PreferencesStorage { @override @protected final prefCategory = PrefCategory.general; diff --git a/lib/src/model/settings/over_the_board_preferences.dart b/lib/src/model/settings/over_the_board_preferences.dart index 2b5042a2a..1122782aa 100644 --- a/lib/src/model/settings/over_the_board_preferences.dart +++ b/lib/src/model/settings/over_the_board_preferences.dart @@ -1,12 +1,17 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'over_the_board_preferences.freezed.dart'; part 'over_the_board_preferences.g.dart'; -@Riverpod(keepAlive: true) -class OverTheBoardPreferences extends _$OverTheBoardPreferences +final overTheBoardPreferencesProvider = + NotifierProvider( + OverTheBoardPreferencesNotifier.new, + name: 'OverTheBoardPreferencesProvider', + ); + +class OverTheBoardPreferencesNotifier extends Notifier with PreferencesStorage { @override @protected diff --git a/lib/src/model/study/study_controller.dart b/lib/src/model/study/study_controller.dart index 0fe9bc22f..7ff50b0de 100644 --- a/lib/src/model/study/study_controller.dart +++ b/lib/src/model/study/study_controller.dart @@ -4,6 +4,7 @@ import 'package:chessground/chessground.dart'; import 'package:collection/collection.dart'; import 'package:dartchess/dartchess.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/analysis/common_analysis_state.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; @@ -25,15 +26,22 @@ import 'package:lichess_mobile/src/network/socket.dart'; import 'package:lichess_mobile/src/utils/rate_limit.dart'; import 'package:lichess_mobile/src/view/engine/engine_gauge.dart'; import 'package:lichess_mobile/src/widgets/pgn.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'study_controller.freezed.dart'; -part 'study_controller.g.dart'; -@riverpod -class StudyController extends _$StudyController +final studyControllerProvider = AsyncNotifierProvider.autoDispose + .family( + StudyController.new, + name: 'StudyControllerProvider', + ); + +class StudyController extends AsyncNotifier with EngineEvaluationMixin implements PgnTreeNotifier { + StudyController(this.id); + + final StudyId id; + late Root _root; Timer? _opponentFirstMoveTimer; @@ -69,7 +77,7 @@ class StudyController extends _$StudyController StudyState get evaluationState => state.requireValue; @override - Future build(StudyId id) async { + Future build() async { ref.onDispose(() { _opponentFirstMoveTimer?.cancel(); _sendMoveToSocketTimer?.cancel(); @@ -275,7 +283,7 @@ class StudyController extends _$StudyController } void onPromotionSelection(Role? role) { - final state = this.state.valueOrNull; + final state = this.state.value; if (state == null) return; if (role == null) { @@ -300,7 +308,7 @@ class StudyController extends _$StudyController } void userNext() { - final state = this.state.valueOrNull; + final state = this.state.value; if (state!.currentNode.children.isEmpty) return; _setPath( state.currentPath + _root.nodeAt(state.currentPath).children.first.id, @@ -332,7 +340,7 @@ class StudyController extends _$StudyController } void toggleBoard() { - final state = this.state.valueOrNull; + final state = this.state.value; if (state != null) { this.state = AsyncValue.data(state.copyWith(pov: state.pov.opposite)); } @@ -382,7 +390,7 @@ class StudyController extends _$StudyController @override void promoteVariation(UciPath path, bool toMainline) { - final state = this.state.valueOrNull; + final state = this.state.value; if (state == null) return; _root.promoteAt(path, toMainline: toMainline); this.state = AsyncValue.data( @@ -440,7 +448,7 @@ class StudyController extends _$StudyController /// Whether the user is navigating through the moves (as opposed to playing a move). bool isNavigating = false, }) { - final state = this.state.valueOrNull; + final state = this.state.value; if (state == null) return; final pathChange = state.currentPath != path; diff --git a/lib/src/model/study/study_list_paginator.dart b/lib/src/model/study/study_list_paginator.dart index 57d0672fb..d698115a9 100644 --- a/lib/src/model/study/study_list_paginator.dart +++ b/lib/src/model/study/study_list_paginator.dart @@ -1,22 +1,26 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/study/study.dart'; import 'package:lichess_mobile/src/model/study/study_filter.dart'; import 'package:lichess_mobile/src/model/study/study_repository.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'study_list_paginator.g.dart'; typedef StudyList = ({IList studies, int? nextPage}); +typedef StudyListNotifierParams = ({StudyCategory category, StudyListOrder order, String? search}); + +/// A provider that gets a list of studies from the paginated API. +final studyListPaginatorProvider = AsyncNotifierProvider.autoDispose + .family( + StudyListPaginatorNotifier.new, + name: 'StudyListPaginatorProvider', + ); + +class StudyListPaginatorNotifier extends AsyncNotifier { + StudyListPaginatorNotifier(this.params); + + final StudyListNotifierParams params; -/// Gets a list of studies from the paginated API. -@riverpod -class StudyListPaginator extends _$StudyListPaginator { @override - Future build({ - required StudyCategory category, - required StudyListOrder order, - String? search, - }) { + Future build() { return _nextPage(); } @@ -36,8 +40,8 @@ class StudyListPaginator extends _$StudyListPaginator { final nextPage = state.value?.nextPage ?? 1; final repo = ref.read(studyRepositoryProvider); - return search == null - ? repo.getStudies(category: category, order: order, page: nextPage) - : repo.searchStudies(query: search!, page: nextPage); + return params.search == null + ? repo.getStudies(category: params.category, order: params.order, page: nextPage) + : repo.searchStudies(query: params.search!, page: nextPage); } } diff --git a/lib/src/model/study/study_preferences.dart b/lib/src/model/study/study_preferences.dart index f2acd8edf..abb914489 100644 --- a/lib/src/model/study/study_preferences.dart +++ b/lib/src/model/study/study_preferences.dart @@ -1,13 +1,17 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/analysis/common_analysis_prefs.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'study_preferences.freezed.dart'; part 'study_preferences.g.dart'; -@Riverpod(keepAlive: true) -class StudyPreferences extends _$StudyPreferences with PreferencesStorage { +final studyPreferencesProvider = NotifierProvider( + StudyPreferencesNotifier.new, + name: 'StudyPreferencesProvider', +); + +class StudyPreferencesNotifier extends Notifier with PreferencesStorage { @override @protected final prefCategory = PrefCategory.study; diff --git a/lib/src/model/study/study_repository.dart b/lib/src/model/study/study_repository.dart index 5777065a6..1747c7a10 100644 --- a/lib/src/model/study/study_repository.dart +++ b/lib/src/model/study/study_repository.dart @@ -9,14 +9,11 @@ import 'package:lichess_mobile/src/model/study/study.dart'; import 'package:lichess_mobile/src/model/study/study_filter.dart'; import 'package:lichess_mobile/src/model/study/study_list_paginator.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'study_repository.g.dart'; - -@Riverpod(keepAlive: true) -StudyRepository studyRepository(Ref ref) { +/// A provider for [StudyRepository]. +final studyRepositoryProvider = Provider((Ref ref) { return StudyRepository(ref, ref.read(lichessClientProvider)); -} +}, name: 'StudyRepositoryProvider'); class StudyRepository { StudyRepository(this.ref, this.client); diff --git a/lib/src/model/tournament/tournament_controller.dart b/lib/src/model/tournament/tournament_controller.dart index ddbfa7aa1..c2c77503b 100644 --- a/lib/src/model/tournament/tournament_controller.dart +++ b/lib/src/model/tournament/tournament_controller.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/chat/chat_controller.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; @@ -9,15 +10,22 @@ import 'package:lichess_mobile/src/model/tournament/tournament_repository.dart'; import 'package:lichess_mobile/src/model/tv/tv_socket_events.dart'; import 'package:lichess_mobile/src/network/socket.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'tournament_controller.freezed.dart'; -part 'tournament_controller.g.dart'; final _logger = Logger('TournamentController'); -@riverpod -class TournamentController extends _$TournamentController { +final tournamentControllerProvider = AsyncNotifierProvider.autoDispose + .family( + TournamentController.new, + name: 'TournamentControllerProvider', + ); + +class TournamentController extends AsyncNotifier { + TournamentController(this.id); + + final TournamentId id; + StreamSubscription? _socketSubscription; SocketClient? _socketClient; @@ -34,7 +42,7 @@ class TournamentController extends _$TournamentController { SocketPool get _socketPool => ref.read(socketPoolProvider); @override - Future build(TournamentId id) async { + Future build() async { ref.onDispose(() { _socketSubscription?.cancel(); _pauseDelayTimer?.cancel(); @@ -105,7 +113,7 @@ class TournamentController extends _$TournamentController { } void jumpToMyPage() { - if (state.valueOrNull?.tournament.me != null) { + if (state.value?.tournament.me != null) { _loadPage(_pageOf(state.requireValue.tournament.me!.rank)); } } @@ -200,7 +208,7 @@ class TournamentController extends _$TournamentController { } void joinOrPause() { - final state = this.state.valueOrNull; + final state = this.state.value; if (state == null) { return; } diff --git a/lib/src/model/tournament/tournament_providers.dart b/lib/src/model/tournament/tournament_providers.dart index 058e9a585..90762e73f 100644 --- a/lib/src/model/tournament/tournament_providers.dart +++ b/lib/src/model/tournament/tournament_providers.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; @@ -7,26 +5,22 @@ import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/tournament/tournament.dart'; import 'package:lichess_mobile/src/model/tournament/tournament_repository.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'tournament_providers.g.dart'; - -@riverpod -Future> featuredTournaments(Ref ref) { +final featuredTournamentsProvider = FutureProvider.autoDispose>((Ref ref) { // logged in users get personalized featured tournaments ref.watch(authSessionProvider); return ref.read(tournamentRepositoryProvider).featured(); -} +}, name: 'FeaturedTournamentsProvider'); -@riverpod -Future tournaments(Ref ref) { +final tournamentsProvider = FutureProvider.autoDispose((Ref ref) { return ref.read(tournamentRepositoryProvider).getTournaments(); -} +}, name: 'TournamentsProvider'); -@riverpod -Future tournamentPlayer(Ref ref, TournamentId tournamentId, UserId userId) { - return ref.withClientCacheFor( - (client) => ref.read(tournamentRepositoryProvider).getTournamentPlayer(tournamentId, userId), - const Duration(seconds: 10), - ); -} +final tournamentPlayerProvider = FutureProvider.autoDispose + .family((Ref ref, (TournamentId, UserId) params) { + return ref.withClientCacheFor( + (client) => + ref.read(tournamentRepositoryProvider).getTournamentPlayer(params.$1, params.$2), + const Duration(seconds: 10), + ); + }, name: 'TournamentPlayerProvider'); diff --git a/lib/src/model/tournament/tournament_repository.dart b/lib/src/model/tournament/tournament_repository.dart index 54966b90a..ec56d76e4 100644 --- a/lib/src/model/tournament/tournament_repository.dart +++ b/lib/src/model/tournament/tournament_repository.dart @@ -8,14 +8,11 @@ import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/tournament/tournament.dart'; import 'package:lichess_mobile/src/network/aggregator.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'tournament_repository.g.dart'; - -@Riverpod(keepAlive: true) -TournamentRepository tournamentRepository(Ref ref) { +/// A provider for [TournamentRepository]. +final tournamentRepositoryProvider = Provider((Ref ref) { return TournamentRepository(ref.read(lichessClientProvider), ref.read(aggregatorProvider), ref); -} +}, name: 'TournamentRepositoryProvider'); class TournamentRepository { TournamentRepository(this.client, this.aggregator, Ref ref) : _ref = ref; diff --git a/lib/src/model/tv/live_tv_channels.dart b/lib/src/model/tv/live_tv_channels.dart index 6b2d35282..a60fd1d95 100644 --- a/lib/src/model/tv/live_tv_channels.dart +++ b/lib/src/model/tv/live_tv_channels.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:dartchess/dartchess.dart'; import 'package:deep_pick/deep_pick.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/common/socket.dart'; import 'package:lichess_mobile/src/model/tv/featured_player.dart'; import 'package:lichess_mobile/src/model/tv/tv_channel.dart'; @@ -10,14 +11,16 @@ import 'package:lichess_mobile/src/model/tv/tv_game.dart'; import 'package:lichess_mobile/src/model/tv/tv_repository.dart'; import 'package:lichess_mobile/src/model/tv/tv_socket_events.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'live_tv_channels.g.dart'; typedef LiveTvChannelsState = IMap; -@riverpod -class LiveTvChannels extends _$LiveTvChannels { +final liveTvChannelsProvider = + AsyncNotifierProvider.autoDispose( + LiveTvChannels.new, + name: 'LiveTvChannelsProvider', + ); + +class LiveTvChannels extends AsyncNotifier { StreamSubscription? _socketSubscription; StreamSubscription? _socketReadySubscription; diff --git a/lib/src/model/tv/tv_controller.dart b/lib/src/model/tv/tv_controller.dart index 03b3e9992..3599a62db 100644 --- a/lib/src/model/tv/tv_controller.dart +++ b/lib/src/model/tv/tv_controller.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:dartchess/dartchess.dart'; import 'package:deep_pick/deep_pick.dart'; import 'package:flutter/foundation.dart' show VoidCallback; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/common/chess.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; @@ -18,24 +19,36 @@ import 'package:lichess_mobile/src/model/tv/tv_repository.dart'; import 'package:lichess_mobile/src/model/tv/tv_socket_events.dart'; import 'package:lichess_mobile/src/model/user/user_repository.dart'; import 'package:lichess_mobile/src/network/socket.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'tv_controller.freezed.dart'; -part 'tv_controller.g.dart'; -@riverpod -class TvController extends _$TvController { +typedef TvControllerParams = ({ + TvChannel? channel, + (GameId id, Side orientation)? initialGame, + UserId? userId, +}); + +final tvControllerProvider = AsyncNotifierProvider.autoDispose + .family( + TvController.new, + name: 'TvControllerProvider', + ); + +class TvController extends AsyncNotifier { + TvController(this.params); + + final TvControllerParams params; + StreamSubscription? _socketSubscription; VoidCallback? _onReload; @override - Future build( - TvChannel? channel, { - (GameId id, Side orientation)? initialGame, - UserId? userId, - }) { - assert(channel != null || userId != null, 'Either a channel or a userId must be provided'); + Future build() { + assert( + params.channel != null || params.userId != null, + 'Either a channel or a userId must be provided', + ); _onReload = ref.invalidateSelf; @@ -44,7 +57,7 @@ class TvController extends _$TvController { _onReload = null; }); - return _connectWebsocket(initialGame); + return _connectWebsocket(params.initialGame); } SoundService get _soundService => ref.read(soundServiceProvider); @@ -65,18 +78,18 @@ class TvController extends _$TvController { if (game != null) { id = game.$1; orientation = game.$2; - } else if (channel != null) { + } else if (params.channel != null) { final channels = await ref.read(tvRepositoryProvider).channels(); - final channelGame = channels[channel!]!; + final channelGame = channels[params.channel!]!; id = channelGame.id; orientation = channelGame.side ?? Side.white; - } else if (userId != null) { - final game = await ref.read(userRepositoryProvider).getCurrentGame(userId!); + } else if (params.userId != null) { + final game = await ref.read(userRepositoryProvider).getCurrentGame(params.userId!); id = game.id; - orientation = game.playerSideOf(userId!) ?? Side.white; + orientation = game.playerSideOf(params.userId!) ?? Side.white; } else { - id = state.valueOrNull?.game.id ?? initialGame!.$1; - orientation = state.valueOrNull?.orientation ?? initialGame!.$2; + id = state.value?.game.id ?? params.initialGame!.$1; + orientation = state.value?.orientation ?? params.initialGame!.$2; } final socketClient = ref @@ -84,7 +97,7 @@ class TvController extends _$TvController { .open( Uri( path: '/watch/$id/${orientation.name}/v6', - queryParameters: userId != null ? {'userTv': userId.toString()} : null, + queryParameters: params.userId != null ? {'userTv': params.userId.toString()} : null, ), forceReconnect: true, onEventGapFailure: () { @@ -245,7 +258,7 @@ class TvController extends _$TvController { case 'tvSelect': final json = event.data as Map; final eventChannel = pick(json, 'channel').asTvChannelOrNull(); - if (eventChannel != null && eventChannel == channel) { + if (eventChannel != null && eventChannel == params.channel) { final data = TvSelectEvent.fromJson(json); _moveToNextGame((data.id, data.orientation)); } diff --git a/lib/src/model/user/game_history_preferences.dart b/lib/src/model/user/game_history_preferences.dart index 4a6d88251..d389a44f8 100644 --- a/lib/src/model/user/game_history_preferences.dart +++ b/lib/src/model/user/game_history_preferences.dart @@ -1,12 +1,17 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/settings/preferences_storage.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'game_history_preferences.freezed.dart'; part 'game_history_preferences.g.dart'; -@Riverpod(keepAlive: true) -class GameHistoryPreferences extends _$GameHistoryPreferences +final gameHistoryPreferencesProvider = + NotifierProvider( + GameHistoryPreferencesNotifier.new, + name: 'GameHistoryPreferencesProvider', + ); + +class GameHistoryPreferencesNotifier extends Notifier with PreferencesStorage { @override @protected diff --git a/lib/src/model/user/search_history.dart b/lib/src/model/user/search_history.dart index 83ea2e3a9..b65c4ae8a 100644 --- a/lib/src/model/user/search_history.dart +++ b/lib/src/model/user/search_history.dart @@ -1,17 +1,21 @@ import 'dart:convert'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/binding.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:shared_preferences/shared_preferences.dart'; part 'search_history.g.dart'; part 'search_history.freezed.dart'; -@riverpod -class SearchHistory extends _$SearchHistory { +final searchHistoryProvider = NotifierProvider( + SearchHistory.new, + name: 'SearchHistoryProvider', +); + +class SearchHistory extends Notifier { static const maxHistory = 10; String _storageKey(AuthSessionState? session) => diff --git a/lib/src/model/user/user_repository_providers.dart b/lib/src/model/user/user_repository_providers.dart index ef7be3a7f..383e47508 100644 --- a/lib/src/model/user/user_repository_providers.dart +++ b/lib/src/model/user/user_repository_providers.dart @@ -7,57 +7,53 @@ import 'package:lichess_mobile/src/model/user/streamer.dart'; import 'package:lichess_mobile/src/model/user/user.dart'; import 'package:lichess_mobile/src/model/user/user_repository.dart'; import 'package:lichess_mobile/src/network/http.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'user_repository_providers.g.dart'; const _kAutoCompleteDebounceTimer = Duration(milliseconds: 300); -@riverpod -Future user(Ref ref, {required UserId id}) { +final userProvider = FutureProvider.autoDispose.family((Ref ref, UserId id) { return ref.read(userRepositoryProvider).getUser(id, withCanChallenge: true); -} +}, name: 'UserProvider'); -@riverpod -Future userPerfStats(Ref ref, {required UserId id, required Perf perf}) { - return ref.read(userRepositoryProvider).getPerfStats(id, perf); -} +final userPerfStatsProvider = FutureProvider.autoDispose.family(( + Ref ref, + (UserId, Perf) params, +) { + return ref.read(userRepositoryProvider).getPerfStats(params.$1, params.$2); +}, name: 'UserPerfStatsProvider'); -@riverpod -Future> liveStreamers(Ref ref) { +final liveStreamersProvider = FutureProvider.autoDispose>((Ref ref) { return ref.withAggregatorCacheFor( (client, aggregator) => UserRepository(client, aggregator).getLiveStreamers(), const Duration(minutes: 1), ); -} +}, name: 'LiveStreamersProvider'); -@riverpod -Future top1(Ref ref) { +final top1Provider = FutureProvider.autoDispose((Ref ref) { return ref.withAggregatorCacheFor( (client, aggregator) => UserRepository(client, aggregator).getTop1(), const Duration(hours: 12), ); -} +}, name: 'Top1Provider'); -@riverpod -Future leaderboard(Ref ref) { +final leaderboardProvider = FutureProvider.autoDispose((Ref ref) { return ref.withAggregatorCacheFor( (client, aggregator) => UserRepository(client, aggregator).getLeaderboard(), const Duration(hours: 2), ); -} +}, name: 'LeaderboardProvider'); -@riverpod -Future> onlineBots(Ref ref) { +final onlineBotsProvider = FutureProvider.autoDispose>((Ref ref) { return ref.withAggregatorCacheFor( (client, aggregator) => UserRepository(client, aggregator).getOnlineBots().then((bots) => bots.toIList()), const Duration(hours: 5), ); -} +}, name: 'OnlineBotsProvider'); -@riverpod -Future> autoCompleteUser(Ref ref, String term) async { +final autoCompleteUserProvider = FutureProvider.autoDispose.family, String>(( + Ref ref, + String term, +) async { // debounce calls as user might be typing var didDispose = false; ref.onDispose(() => didDispose = true); @@ -67,17 +63,23 @@ Future> autoCompleteUser(Ref ref, String term) async { } return ref.read(userRepositoryProvider).autocompleteUser(term); -} +}, name: 'AutoCompleteUserProvider'); -@riverpod -Future> userRatingHistory(Ref ref, {required UserId id}) { - return ref.withAggregatorCacheFor( - (client, aggregator) => UserRepository(client, aggregator).getRatingHistory(id), - const Duration(minutes: 1), - ); -} +final userRatingHistoryProvider = FutureProvider.autoDispose + .family, UserId>((Ref ref, UserId id) { + return ref.withAggregatorCacheFor( + (client, aggregator) => UserRepository(client, aggregator).getRatingHistory(id), + const Duration(minutes: 1), + ); + }, name: 'UserRatingHistoryProvider'); -@riverpod -Future crosstable(Ref ref, UserId userId1, UserId userId2, {bool matchup = true}) { - return ref.read(userRepositoryProvider).getCrosstable(userId1, userId2, matchup: matchup); -} +typedef CrosstableProviderParams = ({UserId userId1, UserId userId2, bool matchup}); + +final crosstableProvider = FutureProvider.autoDispose.family(( + Ref ref, + CrosstableProviderParams params, +) { + return ref + .read(userRepositoryProvider) + .getCrosstable(params.userId1, params.userId2, matchup: params.matchup); +}, name: 'CrosstableProvider'); diff --git a/lib/src/network/connectivity.dart b/lib/src/network/connectivity.dart index 0bce91164..06665acdf 100644 --- a/lib/src/network/connectivity.dart +++ b/lib/src/network/connectivity.dart @@ -8,23 +8,24 @@ import 'package:lichess_mobile/src/constants.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:lichess_mobile/src/utils/rate_limit.dart'; import 'package:logging/logging.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'connectivity.g.dart'; final _logger = Logger('Connectivity'); /// A provider that exposes a [Connectivity] instance. -@Riverpod(keepAlive: true) -Connectivity connectivityPlugin(Ref _) => Connectivity(); +final connectivityPluginProvider = Provider((Ref _) => Connectivity()); /// This provider is used to check the device's connectivity status, reacting to /// changes in connectivity and app lifecycle events. /// /// - Uses the [Connectivity] plugin to listen to connectivity changes /// - Uses [AppLifecycleListener] to check connectivity on app resume -@Riverpod(keepAlive: true) -class ConnectivityChanges extends _$ConnectivityChanges { +final connectivityChangesProvider = + AsyncNotifierProvider( + ConnectivityChangesNotifier.new, + name: 'ConnectivityChangesProvider', + ); + +class ConnectivityChangesNotifier extends AsyncNotifier { StreamSubscription>? _connectivitySubscription; AppLifecycleListener? _appLifecycleListener; @@ -83,7 +84,7 @@ class ConnectivityChanges extends _$ConnectivityChanges { if (newIsOnline != wasOnline) { _logger.info('Connectivity status: $result, isOnline: $isOnline'); - state = AsyncValue.data((isOnline: newIsOnline, appState: state.valueOrNull?.appState)); + state = AsyncValue.data((isOnline: newIsOnline, appState: state.value?.appState)); } } diff --git a/lib/src/network/http.dart b/lib/src/network/http.dart index 57bcf5e6a..b3af1c5a0 100644 --- a/lib/src/network/http.dart +++ b/lib/src/network/http.dart @@ -30,9 +30,6 @@ import 'package:lichess_mobile/src/model/user/user.dart'; import 'package:lichess_mobile/src/network/aggregator.dart'; import 'package:logging/logging.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -part 'http.g.dart'; final _logger = Logger('HttpClient'); @@ -82,8 +79,7 @@ class HttpClientFactory { /// The global [HttpClientFactory] provider. /// /// Http clients created by this factory log all requests and responses to the database. -@Riverpod(keepAlive: true) -HttpClientFactory httpClientFactory(Ref ref) { +final httpClientFactoryProvider = Provider((Ref ref) { return HttpClientFactory( wrapper: (client) => _RegisterCallbackClient( client, @@ -123,28 +119,26 @@ HttpClientFactory httpClientFactory(Ref ref) { }, ), ); -} +}); /// The default http client. /// /// This client is used for all requests that don't go to the lichess server, for /// example, requests to lichess CDN, or other APIs. /// Only one instance of this client is created and kept alive for the whole app. -@Riverpod(keepAlive: true) -Client defaultClient(Ref ref) { +final defaultClientProvider = Provider((Ref ref) { final client = _RegisterCallbackClient( ref.read(httpClientFactoryProvider)(), onRequest: (request) => _logger.info('${request.method} ${request.url}'), ); ref.onDispose(() => client.close()); return client; -} +}); /// The http client configured to make requests to the lichess API. /// /// Only one instance of this client is created and kept alive for the whole app. -@Riverpod(keepAlive: true) -LichessClient lichessClient(Ref ref) { +final lichessClientProvider = Provider((Ref ref) { final client = LichessClient( // Retry just once, after 500ms, on 429 Too Many Requests. RetryClient( @@ -157,13 +151,12 @@ LichessClient lichessClient(Ref ref) { ); ref.onDispose(() => client.close()); return client; -} +}); Duration _defaultDelay(int retryCount) => const Duration(milliseconds: 900) * math.pow(1.5, retryCount); -@Riverpod(keepAlive: true) -String userAgent(Ref ref) { +final userAgentProvider = Provider((Ref ref) { final session = ref.watch(authSessionProvider); return makeUserAgent( @@ -172,7 +165,7 @@ String userAgent(Ref ref) { ref.read(preloadedDataProvider).requireValue.sri, session?.user, ); -} +}); /// Creates a user-agent string with the app version, build number, and device info and possibly the user ID if a user is logged in. String makeUserAgent(PackageInfo info, BaseDeviceInfo deviceInfo, String sri, LightUser? user) { diff --git a/lib/src/network/socket.dart b/lib/src/network/socket.dart index 936f7c1ef..31ab203bb 100644 --- a/lib/src/network/socket.dart +++ b/lib/src/network/socket.dart @@ -17,12 +17,9 @@ import 'package:lichess_mobile/src/model/common/socket.dart'; import 'package:lichess_mobile/src/network/http.dart'; import 'package:logging/logging.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:web_socket_channel/io.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; -part 'socket.g.dart'; - const kDefaultSocketRoute = '/socket/v5'; const _kDefaultConnectTimeout = Duration(seconds: 10); @@ -624,8 +621,8 @@ class SocketPool { } } -@Riverpod(keepAlive: true) -SocketPool socketPool(Ref ref) { +/// The global socket pool provider. +final socketPoolProvider = Provider((Ref ref) { final pool = SocketPool(ref); Timer? closeInBackgroundTimer; @@ -654,17 +651,26 @@ SocketPool socketPool(Ref ref) { }); return pool; -} +}, name: 'SocketPoolProvider'); typedef SocketPingState = ({Duration averageLag, int rating}); +/// A provider that exposes the average lag and ping rating for a given socket route. +final socketPingProvider = NotifierProvider.autoDispose + .family( + SocketPingNotifier.new, + name: 'SocketPingProvider', + ); + /// Average lag and ping rating computed from WebSocket ping/pong protocol. /// /// If [route] is provided, it will return the average lag for that route only, and if any other route /// is active, it will return [Duration.zero], meaning the socket is not connected. /// If no route is provided, it will return the average lag for the current active route. -@riverpod -class SocketPing extends _$SocketPing { +class SocketPingNotifier extends Notifier { + SocketPingNotifier(this.route); + final Uri? route; + @override SocketPingState build({Uri? route}) { final pool = ref.watch(socketPoolProvider); @@ -708,10 +714,10 @@ class SocketPing extends _$SocketPing { } } -@Riverpod(keepAlive: true) -WebSocketChannelFactory webSocketChannelFactory(Ref ref) { +/// A provider for the [WebSocketChannelFactory]. +final webSocketChannelFactoryProvider = Provider((Ref ref) { return const WebSocketChannelFactory(); -} +}); /// A factory to create a [WebSocketChannel]. /// diff --git a/lib/src/quick_actions.dart b/lib/src/quick_actions.dart index 839ae6093..33f809ae1 100644 --- a/lib/src/quick_actions.dart +++ b/lib/src/quick_actions.dart @@ -15,19 +15,16 @@ import 'package:lichess_mobile/src/view/game/game_screen.dart'; import 'package:lichess_mobile/src/view/game/game_screen_providers.dart'; import 'package:lichess_mobile/src/view/puzzle/puzzle_screen.dart'; import 'package:quick_actions/quick_actions.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'quick_actions.g.dart'; - -@Riverpod(keepAlive: true) -QuickActionService quickActionService(Ref ref) { +/// Provider for the [QuickActionService]. +final quickActionServiceProvider = Provider((Ref ref) { final service = QuickActionService(ref); ref.listen(recentGameSeekProvider, (previous, next) { if (previous?.seeks == next.seeks) return; service.setQuickActions(next.seeks); }); return service; -} +}); class QuickActionService { QuickActionService(this.ref); diff --git a/lib/src/tab_scaffold.dart b/lib/src/tab_scaffold.dart index 8115acca7..d49274fac 100644 --- a/lib/src/tab_scaffold.dart +++ b/lib/src/tab_scaffold.dart @@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/legacy.dart'; import 'package:lichess_mobile/l10n/l10n.dart'; import 'package:lichess_mobile/src/constants.dart'; import 'package:lichess_mobile/src/utils/l10n_context.dart'; diff --git a/lib/src/utils/riverpod.dart b/lib/src/utils/riverpod.dart index a4976c6ea..7be5d8fb4 100644 --- a/lib/src/utils/riverpod.dart +++ b/lib/src/utils/riverpod.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/misc.dart'; extension RefExtension on Ref { /// Keeps the provider alive for [duration] diff --git a/lib/src/view/account/account_drawer.dart b/lib/src/view/account/account_drawer.dart index 6cfc0e6c5..4ecfc4fe1 100644 --- a/lib/src/view/account/account_drawer.dart +++ b/lib/src/view/account/account_drawer.dart @@ -40,7 +40,7 @@ class _AccountIconButtonState extends ConsumerState { @override Widget build(BuildContext context) { final account = ref.watch(accountProvider); - final unreadMessages = ref.watch(unreadMessagesProvider).valueOrNull?.unread ?? 0; + final unreadMessages = ref.watch(unreadMessagesProvider).value?.unread ?? 0; return switch (account) { AsyncData(:final value) => Badge.count( offset: const Offset(-4, 0), @@ -101,10 +101,10 @@ class _AccountDrawerState extends ConsumerState { final authController = ref.watch(authControllerProvider); final account = ref.watch(accountProvider); final userSession = ref.watch(authSessionProvider); - final kidMode = account.valueOrNull?.kid ?? false; - final LightUser? user = account.valueOrNull?.lightUser ?? userSession?.user; + final kidMode = account.value?.kid ?? false; + final LightUser? user = account.value?.lightUser ?? userSession?.user; - final unreadMessages = ref.watch(unreadMessagesProvider).valueOrNull?.unread ?? 0; + final unreadMessages = ref.watch(unreadMessagesProvider).value?.unread ?? 0; return Drawer( shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), diff --git a/lib/src/view/account/profile_screen.dart b/lib/src/view/account/profile_screen.dart index 1331f17b3..d7c9f7d11 100644 --- a/lib/src/view/account/profile_screen.dart +++ b/lib/src/view/account/profile_screen.dart @@ -86,7 +86,7 @@ class _ProfileScreenState extends ConsumerState { } final activity = ref.watch(_accountActivityProvider); final recentGames = ref.watch(myRecentGamesProvider); - final nbOfGames = ref.watch(userNumberOfGamesProvider(null)).valueOrNull ?? 0; + final nbOfGames = ref.watch(userNumberOfGamesProvider(null)).value ?? 0; return HapticRefreshIndicator( edgeOffset: Theme.of(context).platform == TargetPlatform.iOS ? MediaQuery.paddingOf(context).top + kToolbarHeight diff --git a/lib/src/view/analysis/analysis_screen.dart b/lib/src/view/analysis/analysis_screen.dart index 3b6bbef87..a0373cc7b 100644 --- a/lib/src/view/analysis/analysis_screen.dart +++ b/lib/src/view/analysis/analysis_screen.dart @@ -179,9 +179,9 @@ class _AnalysisScreenState extends ConsumerState<_AnalysisScreen> final enginePrefs = ref.watch(engineEvaluationPreferencesProvider); final appBarActions = [ - if (asyncState.valueOrNull?.isEngineAvailable(enginePrefs) == true) + if (asyncState.value?.isEngineAvailable(enginePrefs) == true) EngineDepth( - savedEval: asyncState.valueOrNull?.currentNode.eval, + savedEval: asyncState.value?.currentNode.eval, goDeeper: () => ref.read(ctrlProvider.notifier).requestEval(goDeeper: true), ), AppBarAnalysisTabIndicator(tabs: tabs, controller: _tabController), diff --git a/lib/src/view/analysis/retro_screen.dart b/lib/src/view/analysis/retro_screen.dart index 6d26c0d6d..68d490a93 100644 --- a/lib/src/view/analysis/retro_screen.dart +++ b/lib/src/view/analysis/retro_screen.dart @@ -67,9 +67,9 @@ class RetroScreen extends ConsumerWidget { maxLines: 2, ), actions: [ - if (asyncState.requireValue.isEngineAvailable(enginePrefs) == true) + if (value.isEngineAvailable(enginePrefs) == true) EngineDepth( - savedEval: asyncState.valueOrNull?.currentNode.eval, + savedEval: value.currentNode.eval, goDeeper: () => ref .read(retroControllerProvider(options).notifier) .requestEval(goDeeper: true), diff --git a/lib/src/view/broadcast/broadcast_game_screen.dart b/lib/src/view/broadcast/broadcast_game_screen.dart index 4c3a5e2a4..bb0c82749 100644 --- a/lib/src/view/broadcast/broadcast_game_screen.dart +++ b/lib/src/view/broadcast/broadcast_game_screen.dart @@ -109,17 +109,18 @@ class _BroadcastGameScreenState extends ConsumerState ), _ => const SizedBox.shrink(), }; - final asyncEval = ref.watch(broadcastGameEvalProvider(widget.roundId, widget.gameId)); + final asyncEval = ref.watch( + broadcastGameEvalProvider((roundId: widget.roundId, gameId: widget.gameId)), + ); final asyncIsEngineAvailable = ref.watch( - isBroadcastEngineAvailableProvider(widget.roundId, widget.gameId), + isBroadcastEngineAvailableProvider((roundId: widget.roundId, gameId: widget.gameId)), ); return Scaffold( appBar: AppBar( title: title, actions: [ - if (asyncIsEngineAvailable.valueOrNull == true) - EngineDepth(savedEval: asyncEval.valueOrNull), + if (asyncIsEngineAvailable.value == true) EngineDepth(savedEval: asyncEval.value), AppBarAnalysisTabIndicator(tabs: tabs, controller: _tabController), _BroadcastGameMenu( roundId: widget.roundId, @@ -248,7 +249,7 @@ class _Body extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - switch (ref.watch(broadcastAnalysisControllerProvider(roundId, gameId))) { + switch (ref.watch(broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId)))) { case AsyncValue(value: final state?, hasValue: true): final broadcastPrefs = ref.watch(broadcastPreferencesProvider); final enginePrefs = ref.watch(engineEvaluationPreferencesProvider); @@ -313,7 +314,12 @@ class _Body extends ConsumerWidget { savedEval: currentNode.eval, isGameOver: currentNode.position.isGameOver, onTapMove: ref - .read(broadcastAnalysisControllerProvider(roundId, gameId).notifier) + .read( + broadcastAnalysisControllerProvider(( + roundId: roundId, + gameId: gameId, + )).notifier, + ) .onUserMove, ) : null, @@ -341,7 +347,7 @@ class _BroadcastGameTreeView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final ctrlProvider = broadcastAnalysisControllerProvider(roundId, gameId); + final ctrlProvider = broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId)); final state = ref.watch(ctrlProvider).requireValue; final broadcastPrefs = ref.watch(broadcastPreferencesProvider); @@ -373,7 +379,7 @@ class _OpeningExplorerTab extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final ctrlProvider = broadcastAnalysisControllerProvider(roundId, gameId); + final ctrlProvider = broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId)); final state = ref.watch(ctrlProvider).requireValue; return ExplorerView( @@ -403,8 +409,9 @@ class BroadcastAnalysisBoard extends AnalysisBoard { class _BroadcastAnalysisBoardState extends AnalysisBoardState { @override - BroadcastAnalysisState get analysisState => - ref.watch(broadcastAnalysisControllerProvider(widget.roundId, widget.gameId)).requireValue; + BroadcastAnalysisState get analysisState => ref + .watch(broadcastAnalysisControllerProvider((roundId: widget.roundId, gameId: widget.gameId))) + .requireValue; @override BroadcastPrefs get analysisPrefs => ref.watch(broadcastPreferencesProvider); @@ -415,12 +422,22 @@ class _BroadcastAnalysisBoardState @override void onUserMove(NormalMove move) => ref - .read(broadcastAnalysisControllerProvider(widget.roundId, widget.gameId).notifier) + .read( + broadcastAnalysisControllerProvider(( + roundId: widget.roundId, + gameId: widget.gameId, + )).notifier, + ) .onUserMove(move); @override void onPromotionSelection(Role? role) => ref - .read(broadcastAnalysisControllerProvider(widget.roundId, widget.gameId).notifier) + .read( + broadcastAnalysisControllerProvider(( + roundId: widget.roundId, + gameId: widget.gameId, + )).notifier, + ) .onPromotionSelection(role); } @@ -441,10 +458,10 @@ class _PlayerWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - switch (ref.watch(broadcastRoundGameProvider(roundId, gameId))) { + switch (ref.watch(broadcastRoundGameProvider((roundId: roundId, gameId: gameId)))) { case AsyncValue(value: final game?, hasValue: true): final broadcastAnalysisState = ref - .watch(broadcastAnalysisControllerProvider(roundId, gameId)) + .watch(broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId))) .requireValue; final isCursorOnLiveMove = @@ -583,7 +600,7 @@ class _BroadcastGameBottomBar extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final enginePrefs = ref.watch(engineEvaluationPreferencesProvider); - final ctrlProvider = broadcastAnalysisControllerProvider(roundId, gameId); + final ctrlProvider = broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId)); final broadcastAnalysisState = ref.watch(ctrlProvider).requireValue; return BottomBar( @@ -644,8 +661,10 @@ class _BroadcastGameBottomBar extends ConsumerWidget { ); } - void _moveForward(WidgetRef ref) => - ref.read(broadcastAnalysisControllerProvider(roundId, gameId).notifier).userNext(); - void _moveBackward(WidgetRef ref) => - ref.read(broadcastAnalysisControllerProvider(roundId, gameId).notifier).userPrevious(); + void _moveForward(WidgetRef ref) => ref + .read(broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId)).notifier) + .userNext(); + void _moveBackward(WidgetRef ref) => ref + .read(broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId)).notifier) + .userPrevious(); } diff --git a/lib/src/view/broadcast/broadcast_game_screen_providers.dart b/lib/src/view/broadcast/broadcast_game_screen_providers.dart index 08c4e029a..c50000a6a 100644 --- a/lib/src/view/broadcast/broadcast_game_screen_providers.dart +++ b/lib/src/view/broadcast/broadcast_game_screen_providers.dart @@ -5,45 +5,46 @@ import 'package:lichess_mobile/src/model/broadcast/broadcast_round_controller.da import 'package:lichess_mobile/src/model/common/eval.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; import 'package:lichess_mobile/src/model/engine/evaluation_preferences.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'broadcast_game_screen_providers.g.dart'; +typedef BroadcastRoundGameParam = ({BroadcastRoundId roundId, BroadcastGameId gameId}); -@riverpod -Future broadcastRoundGame( - Ref ref, - BroadcastRoundId roundId, - BroadcastGameId gameId, -) { - return ref.watch( - broadcastRoundControllerProvider(roundId).selectAsync((round) => round.games[gameId]!), - ); -} +/// A provider that exposes the [BroadcastGame] for the given [BroadcastRoundGameParam]. +final broadcastRoundGameProvider = FutureProvider.autoDispose + .family(( + Ref ref, + BroadcastRoundGameParam params, + ) async { + final round = await ref.watch(broadcastRoundControllerProvider(params.roundId).future); + return round.games[params.gameId]!; + }, name: 'BroadcastRoundGameProvider'); -@riverpod -Future broadcastGameEval(Ref ref, BroadcastRoundId roundId, BroadcastGameId gameId) { - return ref.watch( - broadcastAnalysisControllerProvider( - roundId, - gameId, - ).selectAsync((state) => state.currentNode.eval), - ); -} +/// A provider that exposes the current [ClientEval] for the given [BroadcastRoundGameParam]. +final broadcastGameEvalProvider = FutureProvider.autoDispose + .family((Ref ref, BroadcastRoundGameParam params) async { + final state = await ref.watch( + broadcastAnalysisControllerProvider(( + roundId: params.roundId, + gameId: params.gameId, + )).future, + ); + return state.currentNode.eval; + }, name: 'BroadcastGameEvalProvider'); -@riverpod -Future isBroadcastEngineAvailable(Ref ref, BroadcastRoundId roundId, BroadcastGameId gameId) { - final enginePrefs = ref.watch(engineEvaluationPreferencesProvider); - return ref.watch( - broadcastAnalysisControllerProvider( - roundId, - gameId, - ).selectAsync((round) => round.isEngineAvailable(enginePrefs)), - ); -} +/// A provider that indicates whether engine analysis is available for the given +final isBroadcastEngineAvailableProvider = FutureProvider.autoDispose + .family((Ref ref, BroadcastRoundGameParam params) async { + final enginePrefs = ref.watch(engineEvaluationPreferencesProvider); + final state = await ref.watch( + broadcastAnalysisControllerProvider(( + roundId: params.roundId, + gameId: params.gameId, + )).future, + ); + return state.isEngineAvailable(enginePrefs); + }, name: 'IsBroadcastEngineAvailableProvider'); -@riverpod -Future broadcastGameScreenTitle(Ref ref, BroadcastRoundId roundId) { - return ref.watch( - broadcastRoundControllerProvider(roundId).selectAsync((round) => round.round.name), - ); -} +final broadcastGameScreenTitleProvider = FutureProvider.autoDispose + .family((Ref ref, BroadcastRoundId roundId) async { + final round = await ref.watch(broadcastRoundControllerProvider(roundId).future); + return round.round.name; + }, name: 'BroadcastGameScreenTitleProvider'); diff --git a/lib/src/view/broadcast/broadcast_game_settings_screen.dart b/lib/src/view/broadcast/broadcast_game_settings_screen.dart index d94e4bcb6..80932d649 100644 --- a/lib/src/view/broadcast/broadcast_game_settings_screen.dart +++ b/lib/src/view/broadcast/broadcast_game_settings_screen.dart @@ -26,7 +26,7 @@ class BroadcastGameSettingsScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final controller = broadcastAnalysisControllerProvider(roundId, gameId); + final controller = broadcastAnalysisControllerProvider((roundId: roundId, gameId: gameId)); final broadcastPrefs = ref.watch(broadcastPreferencesProvider); diff --git a/lib/src/view/broadcast/broadcast_player_results_screen.dart b/lib/src/view/broadcast/broadcast_player_results_screen.dart index 782295658..b0657ca73 100644 --- a/lib/src/view/broadcast/broadcast_player_results_screen.dart +++ b/lib/src/view/broadcast/broadcast_player_results_screen.dart @@ -114,7 +114,7 @@ class _Body extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final playerWithGameResults = ref.watch(broadcastPlayerProvider(tournamentId, playerId)); + final playerWithGameResults = ref.watch(broadcastPlayerProvider((tournamentId, playerId))); switch (playerWithGameResults) { case AsyncData(value: final playerWithGameResults): diff --git a/lib/src/view/broadcast/broadcast_player_screen_providers.dart b/lib/src/view/broadcast/broadcast_player_screen_providers.dart index c5c26c24d..b76211245 100644 --- a/lib/src/view/broadcast/broadcast_player_screen_providers.dart +++ b/lib/src/view/broadcast/broadcast_player_screen_providers.dart @@ -1,11 +1,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/broadcast/broadcast_providers.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'broadcast_player_screen_providers.g.dart'; - -@riverpod -Future broadcastTournamentId(Ref ref, BroadcastRoundId roundId) { - return ref.watch(broadcastRoundProvider(roundId).selectAsync((round) => round.tournament.id)); -} +final broadcastTournamentIdProvider = FutureProvider.autoDispose + .family((Ref ref, BroadcastRoundId roundId) async { + return (await ref.watch(broadcastRoundProvider(roundId).future)).tournament.id; + }, name: 'BroadcastTournamentIdProvider'); diff --git a/lib/src/view/explorer/opening_explorer_view.dart b/lib/src/view/explorer/opening_explorer_view.dart index 58481ab1f..052fe658f 100644 --- a/lib/src/view/explorer/opening_explorer_view.dart +++ b/lib/src/view/explorer/opening_explorer_view.dart @@ -68,10 +68,10 @@ class _OpeningExplorerState extends ConsumerState { final cacheOpeningExplorer = cache[cacheKey]; final openingExplorerAsync = cacheOpeningExplorer != null ? AsyncValue.data((entry: cacheOpeningExplorer, isIndexing: false)) - : ref.watch(openingExplorerProvider(fen: widget.position.fen)); + : ref.watch(openingExplorerProvider(widget.position.fen)); if (cacheOpeningExplorer == null) { - ref.listen(openingExplorerProvider(fen: widget.position.fen), (_, curAsync) { + ref.listen(openingExplorerProvider(widget.position.fen), (_, curAsync) { curAsync.whenData((cur) { if (cur != null && !cur.isIndexing) { cache[cacheKey] = cur.entry; diff --git a/lib/src/view/explorer/tablebase_view.dart b/lib/src/view/explorer/tablebase_view.dart index f90e23a35..c166b551b 100644 --- a/lib/src/view/explorer/tablebase_view.dart +++ b/lib/src/view/explorer/tablebase_view.dart @@ -17,7 +17,7 @@ class TablebaseView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final tablebaseAsync = ref.watch(tablebaseProvider(fen: position.fen)); + final tablebaseAsync = ref.watch(tablebaseProvider(position.fen)); switch (tablebaseAsync) { case AsyncData(:final value): diff --git a/lib/src/view/game/game_body.dart b/lib/src/view/game/game_body.dart index 5b8b4cf36..1bbb96b5f 100644 --- a/lib/src/view/game/game_body.dart +++ b/lib/src/view/game/game_body.dart @@ -111,14 +111,14 @@ class GameBody extends ConsumerWidget { // If playing against Stockfish, user is null final crosstable = gameState.game.white.user != null && gameState.game.black.user != null ? ref.watch( - crosstableProvider( - gameState.game.white.user!.id, - gameState.game.black.user!.id, + crosstableProvider(( + userId1: gameState.game.white.user!.id, + userId2: gameState.game.black.user!.id, matchup: true, - ), + )), ) : null; - final crosstableData = crosstable?.valueOrNull; + final crosstableData = crosstable?.value; final matchupData = crosstableData?.matchup; final black = GamePlayer( @@ -336,8 +336,7 @@ class GameBody extends ConsumerWidget { if (!state.requireValue.game.playable) { WakelockPlus.disable(); } - if (prev?.valueOrNull?.isZenModeActive == true && - state.requireValue.isZenModeActive == false) { + if (prev?.value?.isZenModeActive == true && state.requireValue.isZenModeActive == false) { if (context.mounted) { // when Zen mode is disabled, reload chat data ref @@ -364,7 +363,7 @@ class GameBody extends ConsumerWidget { } // true when the game was loaded, playable, and just finished - if (prev?.valueOrNull?.game.playable == true && state.requireValue.game.playable == false) { + if (prev?.value?.game.playable == true && state.requireValue.game.playable == false) { clearAndroidBoardGesturesExclusion(); } // true when the game was not loaded: handles rematches @@ -424,7 +423,7 @@ class _GameBottomBar extends ConsumerWidget { final canShowChat = gamePrefs.enableChat == true && gameState.chatOptions != null && - kidModeAsync.valueOrNull == false; + kidModeAsync.value == false; final numPremoveLines = gameState.game.correspondenceForecast?.length; return BottomBar( diff --git a/lib/src/view/game/game_screen.dart b/lib/src/view/game/game_screen.dart index 982438800..9598dcbd4 100644 --- a/lib/src/view/game/game_screen.dart +++ b/lib/src/view/game/game_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import 'package:lichess_mobile/src/model/challenge/challenge.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; +import 'package:lichess_mobile/src/model/common/speed.dart'; import 'package:lichess_mobile/src/model/common/time_increment.dart'; import 'package:lichess_mobile/src/model/game/game.dart'; import 'package:lichess_mobile/src/model/game/game_controller.dart'; @@ -64,6 +65,14 @@ class GameScreen extends ConsumerStatefulWidget { ConsumerState createState() => _GameScreenState(); } +final _isRealTimePlayableGameProvider = FutureProvider.autoDispose.family(( + Ref ref, + GameFullId gameId, +) async { + final state = await ref.watch(gameControllerProvider(gameId).future); + return state.game.meta.speed != Speed.correspondence && state.game.playable; +}, name: 'IsRealTimePlayableGameProvider'); + class _GameScreenState extends ConsumerState { final _whiteClockKey = GlobalKey(debugLabel: 'whiteClockOnGameScreen'); final _blackClockKey = GlobalKey(debugLabel: 'blackClockOnGameScreen'); @@ -95,7 +104,7 @@ class _GameScreenState extends ConsumerState { ); case AsyncData(value: GameCreatedState(:final createdGameId)): final isRealTimePlayingGame = - ref.watch(isRealTimePlayableGameProvider(createdGameId)).valueOrNull ?? false; + ref.watch(_isRealTimePlayableGameProvider(createdGameId)).value ?? false; final socketUri = GameController.socketUri(createdGameId); @@ -241,7 +250,7 @@ class _GameMenu extends ConsumerWidget { ), GameBookmarkContextMenuAction( id: gameId.gameId, - bookmarked: isBookmarkedAsync.valueOrNull ?? false, + bookmarked: isBookmarkedAsync.value ?? false, onToggleBookmark: () => ref.read(gameControllerProvider(gameId).notifier).toggleBookmark(), ), @@ -331,6 +340,14 @@ class _TournamentGameTitle extends ConsumerWidget { } } +final _gameMetaProvider = FutureProvider.autoDispose.family(( + Ref ref, + GameFullId gameId, +) async { + // Using ref.read as an optimization since we know that game meta never changes during the game. + return (await ref.read(gameControllerProvider(gameId).future)).game.meta; +}, name: 'GameMetaProvider'); + class _StandaloneGameTitle extends ConsumerWidget { const _StandaloneGameTitle({required this.id, this.lastMoveAt}); @@ -342,7 +359,7 @@ class _StandaloneGameTitle extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final metaAsync = ref.watch(gameMetaProvider(id)); + final metaAsync = ref.watch(_gameMetaProvider(id)); return metaAsync.when( data: (meta) { if (meta.tournament?.isOngoing == true) { diff --git a/lib/src/view/game/game_screen_providers.dart b/lib/src/view/game/game_screen_providers.dart index 71acfc8e4..c6073bbd8 100644 --- a/lib/src/view/game/game_screen_providers.dart +++ b/lib/src/view/game/game_screen_providers.dart @@ -3,15 +3,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:lichess_mobile/src/model/challenge/challenge.dart'; import 'package:lichess_mobile/src/model/common/id.dart'; -import 'package:lichess_mobile/src/model/common/speed.dart'; import 'package:lichess_mobile/src/model/game/game.dart'; import 'package:lichess_mobile/src/model/game/game_controller.dart'; import 'package:lichess_mobile/src/model/lobby/create_game_service.dart'; import 'package:lichess_mobile/src/model/lobby/game_seek.dart'; import 'package:lichess_mobile/src/view/game/game_screen.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'game_screen_providers.g.dart'; part 'game_screen_providers.freezed.dart'; /// The state of the [GameScreen]. @@ -79,10 +76,19 @@ sealed class UserChallengeSource with _$UserChallengeSource implements GameScree } /// A provider that loads or creates a game for the [GameScreen]. -@riverpod -class GameScreenLoader extends _$GameScreenLoader { +final gameScreenLoaderProvider = AsyncNotifierProvider.autoDispose + .family( + GameScreenLoaderNotifier.new, + name: 'GameScreenLoaderProvider', + ); + +class GameScreenLoaderNotifier extends AsyncNotifier { + GameScreenLoaderNotifier(this.source); + + final GameScreenSource source; + @override - Future build(GameScreenSource source) { + Future build() { final service = ref.watch(createGameServiceProvider); return switch (source) { @@ -115,8 +121,12 @@ class GameScreenLoader extends _$GameScreenLoader { } } -@riverpod -class IsBoardTurned extends _$IsBoardTurned { +final isBoardTurnedProvider = NotifierProvider.autoDispose( + IsBoardTurnedNotifier.new, + name: 'IsBoardTurnedProvider', +); + +class IsBoardTurnedNotifier extends Notifier { @override bool build() { return false; @@ -127,64 +137,32 @@ class IsBoardTurned extends _$IsBoardTurned { } } -@riverpod -Future isGameBookmarked(Ref ref, GameFullId gameId) { - return ref.watch( - gameControllerProvider(gameId).selectAsync((state) => state.game.bookmarked ?? false), - ); -} +/// A provider that indicates whether the game is bookmarked. +final isGameBookmarkedProvider = FutureProvider.autoDispose.family(( + Ref ref, + GameFullId gameId, +) async { + return (await ref.watch(gameControllerProvider(gameId).future)).game.bookmarked ?? false; +}, name: 'IsGameBookmarkedProvider'); -@riverpod -Future<({bool finished, Side? pov})> gameShareData(Ref ref, GameFullId gameId) { - return ref.watch( - gameControllerProvider( - gameId, - ).selectAsync((state) => (finished: state.game.finished, pov: state.game.youAre)), - ); -} - -@riverpod -Future isRealTimePlayableGame(Ref ref, GameFullId gameId) { - return ref.watch( - gameControllerProvider( - gameId, - ).selectAsync((state) => state.game.meta.speed != Speed.correspondence && state.game.playable), - ); -} +/// A provider that exposes data needed for sharing the game. +final gameShareDataProvider = FutureProvider.autoDispose + .family<({bool finished, Side? pov}), GameFullId>((Ref ref, GameFullId gameId) async { + final state = await ref.watch(gameControllerProvider(gameId).future); + return (finished: state.game.finished, pov: state.game.youAre); + }, name: 'GameShareDataProvider'); /// User game preferences, defined server-side. -@riverpod -Future<({ServerGamePrefs? prefs, bool shouldConfirmMove, bool isZenModeEnabled, bool canAutoQueen})> -userGamePrefs(Ref ref, GameFullId gameId) async { - final prefs = await ref.watch( - gameControllerProvider(gameId).selectAsync((state) => state.game.prefs), - ); - final shouldConfirmMove = await ref.watch( - gameControllerProvider(gameId).selectAsync((state) => state.shouldConfirmMove), - ); - final isZenModeEnabled = await ref.watch( - gameControllerProvider(gameId).selectAsync((state) => state.isZenModeEnabled), - ); - final canAutoQueen = await ref.watch( - gameControllerProvider(gameId).selectAsync((state) => state.canAutoQueen), - ); - return ( - prefs: prefs, - shouldConfirmMove: shouldConfirmMove, - isZenModeEnabled: isZenModeEnabled, - canAutoQueen: canAutoQueen, - ); -} - -/// Returns the [PlayableGameMeta]. -/// -/// This is data that won't change during the game. -@riverpod -Future gameMeta(Ref ref, GameFullId gameId) async { - return await ref.watch(gameControllerProvider(gameId).selectAsync((state) => state.game.meta)); -} - -@riverpod -Future gameTournament(Ref ref, GameFullId gameId) async { - return await ref.watch(gameControllerProvider(gameId).selectAsync((state) => state.tournament)); -} +final userGamePrefsProvider = FutureProvider.autoDispose + .family< + ({ServerGamePrefs? prefs, bool shouldConfirmMove, bool isZenModeEnabled, bool canAutoQueen}), + GameFullId + >((Ref ref, GameFullId gameId) async { + final state = await ref.watch(gameControllerProvider(gameId).future); + return ( + prefs: state.game.prefs, + shouldConfirmMove: state.shouldConfirmMove, + isZenModeEnabled: state.isZenModeEnabled, + canAutoQueen: state.canAutoQueen, + ); + }, name: 'UserGamePrefsProvider'); diff --git a/lib/src/view/home/home_tab_screen.dart b/lib/src/view/home/home_tab_screen.dart index 8c6b9b5c4..3b3fb4980 100644 --- a/lib/src/view/home/home_tab_screen.dart +++ b/lib/src/view/home/home_tab_screen.dart @@ -211,11 +211,11 @@ class _HomeScreenState extends ConsumerState { skipLoadingOnReload: true, data: (status) { final session = ref.watch(authSessionProvider); - final unreadLichessMessage = ref.watch(unreadMessagesProvider).valueOrNull?.lichess == true; + final unreadLichessMessage = ref.watch(unreadMessagesProvider).value?.lichess == true; final ongoingGames = ref.watch(ongoingGamesProvider); final offlineCorresGames = ref.watch(offlineOngoingCorrespondenceGamesProvider); final recentGames = ref.watch(myRecentGamesProvider); - final nbOfGames = ref.watch(userNumberOfGamesProvider(null)).valueOrNull ?? 0; + final nbOfGames = ref.watch(userNumberOfGamesProvider(null)).value ?? 0; final isTablet = isTabletOrLarger(context); final featuredTournaments = status.isOnline ? ref.watch(featuredTournamentsProvider) @@ -610,7 +610,7 @@ class _EditableWidget extends ConsumerWidget { } } -class _IsDayTimeNotifier extends AutoDisposeNotifier { +class _IsDayTimeNotifier extends Notifier { Timer? _timer; @override @@ -961,8 +961,8 @@ class _ChallengeScreenButton extends ConsumerWidget { final connectivity = ref.watch(connectivityChangesProvider); final challenges = ref.watch(challengesProvider); - final inwardCount = challenges.valueOrNull?.inward.length ?? 0; - final outwardCount = challenges.valueOrNull?.outward.length ?? 0; + final inwardCount = challenges.value?.inward.length ?? 0; + final outwardCount = challenges.value?.outward.length ?? 0; if (inwardCount == 0 && outwardCount == 0) { return const SizedBox.shrink(); diff --git a/lib/src/view/learn/learn_tab_screen.dart b/lib/src/view/learn/learn_tab_screen.dart index 104c705df..607e4fadb 100644 --- a/lib/src/view/learn/learn_tab_screen.dart +++ b/lib/src/view/learn/learn_tab_screen.dart @@ -81,12 +81,11 @@ class _Body extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? false; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? false; final session = ref.watch(authSessionProvider); - final haveIStudies = - session != null && (ref.watch(_myStudiesLengthProvider).valueOrNull ?? 0) > 0; + final haveIStudies = session != null && (ref.watch(_myStudiesLengthProvider).value ?? 0) > 0; final haveIFavoriteStudies = - session != null && (ref.watch(_myFavoriteStudiesLengthProvider).valueOrNull ?? 0) > 0; + session != null && (ref.watch(_myFavoriteStudiesLengthProvider).value ?? 0) > 0; return ListTileTheme.merge( iconColor: Theme.of(context).colorScheme.primary, diff --git a/lib/src/view/message/contacts_screen.dart b/lib/src/view/message/contacts_screen.dart index f2bc049ae..187d4d571 100644 --- a/lib/src/view/message/contacts_screen.dart +++ b/lib/src/view/message/contacts_screen.dart @@ -1,6 +1,7 @@ import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/legacy.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/message/message.dart'; import 'package:lichess_mobile/src/model/message/message_repository.dart'; diff --git a/lib/src/view/message/conversation_screen.dart b/lib/src/view/message/conversation_screen.dart index 28dc99e80..d348ba274 100644 --- a/lib/src/view/message/conversation_screen.dart +++ b/lib/src/view/message/conversation_screen.dart @@ -231,9 +231,7 @@ class _ContactTyping extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final isTyping = ref.watch( - conversationControllerProvider( - user.id, - ).select((state) => state.valueOrNull?.contactTyping == true), + conversationControllerProvider(user.id).select((state) => state.value?.contactTyping == true), ); return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), diff --git a/lib/src/view/more/more_tab_screen.dart b/lib/src/view/more/more_tab_screen.dart index e39965446..cca1834e5 100644 --- a/lib/src/view/more/more_tab_screen.dart +++ b/lib/src/view/more/more_tab_screen.dart @@ -54,7 +54,7 @@ class _Body extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? false; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? false; final session = ref.watch(authSessionProvider); return ListTileTheme.merge( diff --git a/lib/src/view/play/create_game_widget.dart b/lib/src/view/play/create_game_widget.dart index 95fa341af..a89ad2f1f 100644 --- a/lib/src/view/play/create_game_widget.dart +++ b/lib/src/view/play/create_game_widget.dart @@ -21,8 +21,8 @@ class CreateGameWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final playPrefs = ref.watch(gameSetupPreferencesProvider); - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? false; - final account = ref.watch(accountProvider).valueOrNull; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? false; + final account = ref.watch(accountProvider).value; final userPerf = account?.perfs[playPrefs.realTimePerf]; final canUseRatingRange = userPerf != null && userPerf.provisional != true; @@ -197,7 +197,7 @@ class CreateGameWidget extends ConsumerWidget { // Pops the play bottom sheet Navigator.of(context).popUntil((route) => route is! ModalBottomSheetRoute); - final playban = ref.read(accountProvider).valueOrNull?.playban; + final playban = ref.read(accountProvider).value?.playban; if (playban != null) { ref.read(accountServiceProvider).showPlaybanDialog(playban); return; diff --git a/lib/src/view/play/play_menu.dart b/lib/src/view/play/play_menu.dart index 49a7bd9e1..e5d80792f 100644 --- a/lib/src/view/play/play_menu.dart +++ b/lib/src/view/play/play_menu.dart @@ -15,7 +15,7 @@ class PlayMenu extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? false; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? false; return Column( children: [ diff --git a/lib/src/view/play/quick_game_matrix.dart b/lib/src/view/play/quick_game_matrix.dart index 2e631d7da..39f19bad1 100644 --- a/lib/src/view/play/quick_game_matrix.dart +++ b/lib/src/view/play/quick_game_matrix.dart @@ -21,7 +21,7 @@ class QuickGameMatrix extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final playban = ref.watch(accountProvider).valueOrNull?.playban; + final playban = ref.watch(accountProvider).value?.playban; final brightness = Theme.of(context).brightness; final logoColor = brightness == Brightness.light ? const Color(0x0F000000) @@ -78,7 +78,7 @@ class _SectionChoices extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final session = ref.watch(authSessionProvider); - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? false; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? false; final choiceWidgets = choices .mapIndexed((index, choice) { return [ diff --git a/lib/src/view/puzzle/dashboard_screen.dart b/lib/src/view/puzzle/dashboard_screen.dart index 9648ae359..00a6dfbc0 100644 --- a/lib/src/view/puzzle/dashboard_screen.dart +++ b/lib/src/view/puzzle/dashboard_screen.dart @@ -2,6 +2,7 @@ import 'package:collection/collection.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/legacy.dart'; import 'package:http/http.dart' show ClientException; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; import 'package:lichess_mobile/src/model/puzzle/puzzle.dart'; diff --git a/lib/src/view/puzzle/puzzle_history_screen.dart b/lib/src/view/puzzle/puzzle_history_screen.dart index d576cf56d..7839270a2 100644 --- a/lib/src/view/puzzle/puzzle_history_screen.dart +++ b/lib/src/view/puzzle/puzzle_history_screen.dart @@ -110,7 +110,7 @@ class _BodyState extends ConsumerState<_Body> { void _scrollListener() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 300) { - final currentState = ref.read(puzzleActivityProvider).valueOrNull; + final currentState = ref.read(puzzleActivityProvider).value; if (currentState != null && !currentState.isLoading) { ref.read(puzzleActivityProvider.notifier).getNext(); } diff --git a/lib/src/view/puzzle/puzzle_screen.dart b/lib/src/view/puzzle/puzzle_screen.dart index 6760b98c7..36868f8a4 100644 --- a/lib/src/view/puzzle/puzzle_screen.dart +++ b/lib/src/view/puzzle/puzzle_screen.dart @@ -645,7 +645,7 @@ class _PuzzleStatus extends ConsumerWidget { ), ), ), - PuzzleSessionWidget(initialPuzzleContext: initialPuzzleContext, ctrlProvider: ctrlProvider), + PuzzleSessionWidget(initialPuzzleContext: initialPuzzleContext), ], ); } @@ -847,9 +847,7 @@ class _BottomBarState extends ConsumerState<_BottomBar> { makeLabel: (context) => Text(context.l10n.puzzleFromGameLink(puzzleState.puzzle.game.id.value)), onPressed: () async { - final game = await ref.read( - archivedGameProvider(id: puzzleState.puzzle.game.id).future, - ); + final game = await ref.read(archivedGameProvider(puzzleState.puzzle.game.id).future); if (context.mounted) { Navigator.of(context).push( AnalysisScreen.buildRoute( @@ -911,7 +909,7 @@ class _PuzzleSettingsBottomSheet extends ConsumerWidget { final ctrlProvider = puzzleControllerProvider(initialPuzzleContext); final puzzleState = ref.watch(ctrlProvider); final difficulty = ref.watch(puzzlePreferencesProvider.select((state) => state.difficulty)); - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? false; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? false; return BottomSheetScrollableContainer( padding: const EdgeInsets.only(bottom: 16), children: [ diff --git a/lib/src/view/puzzle/puzzle_session_widget.dart b/lib/src/view/puzzle/puzzle_session_widget.dart index d97d81631..b15067a4d 100644 --- a/lib/src/view/puzzle/puzzle_session_widget.dart +++ b/lib/src/view/puzzle/puzzle_session_widget.dart @@ -12,10 +12,9 @@ import 'package:lichess_mobile/src/utils/screen.dart'; import 'package:lichess_mobile/src/view/account/rating_pref_aware.dart'; class PuzzleSessionWidget extends ConsumerStatefulWidget { - const PuzzleSessionWidget({required this.initialPuzzleContext, required this.ctrlProvider}); + const PuzzleSessionWidget({required this.initialPuzzleContext}); final PuzzleContext initialPuzzleContext; - final PuzzleControllerProvider ctrlProvider; @override ConsumerState createState() => PuzzleSessionWidgetState(); @@ -52,9 +51,13 @@ class PuzzleSessionWidgetState extends ConsumerState { @override Widget build(BuildContext context) { final session = ref.watch( - puzzleSessionProvider(widget.initialPuzzleContext.userId, widget.initialPuzzleContext.angle), + puzzleSessionProvider(( + userId: widget.initialPuzzleContext.userId, + angle: widget.initialPuzzleContext.angle, + )), ); - final puzzleState = ref.watch(widget.ctrlProvider); + final puzzleController = puzzleControllerProvider(widget.initialPuzzleContext); + final puzzleState = ref.watch(puzzleController); final brightness = Theme.of(context).brightness; final currentAttempt = session.attempts.firstWhereOrNull( (a) => a.id == puzzleState.puzzle.puzzle.id, @@ -102,7 +105,7 @@ class PuzzleSessionWidgetState extends ConsumerState { puzzle: puzzle, ); - ref.read(widget.ctrlProvider.notifier).onLoadPuzzle(nextContext); + ref.read(puzzleController.notifier).onLoadPuzzle(nextContext); } finally { if (mounted) { setState(() { diff --git a/lib/src/view/puzzle/puzzle_tab_screen.dart b/lib/src/view/puzzle/puzzle_tab_screen.dart index bf36fde70..af136d9a3 100644 --- a/lib/src/view/puzzle/puzzle_tab_screen.dart +++ b/lib/src/view/puzzle/puzzle_tab_screen.dart @@ -43,7 +43,7 @@ class PuzzleTabScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final savedBatches = ref.watch(savedBatchesProvider).valueOrNull; + final savedBatches = ref.watch(savedBatchesProvider).value; if (savedBatches == null) { return const Center(child: CircularProgressIndicator.adaptive()); @@ -425,7 +425,7 @@ class DailyPuzzle extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? false; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? false; final puzzle = ref.watch(dailyPuzzleProvider); return puzzle.when( @@ -563,7 +563,7 @@ class PuzzleAnglePreview extends ConsumerWidget { ], PuzzleOpening(key: final openingKey) => [ Text( - flatOpenings.valueOrNull + flatOpenings.value ?.firstWhere( (o) => o.key == openingKey, orElse: () => ( diff --git a/lib/src/view/puzzle/puzzle_themes_screen.dart b/lib/src/view/puzzle/puzzle_themes_screen.dart index 2c8eea284..189df4146 100644 --- a/lib/src/view/puzzle/puzzle_themes_screen.dart +++ b/lib/src/view/puzzle/puzzle_themes_screen.dart @@ -12,9 +12,7 @@ import 'package:lichess_mobile/src/view/puzzle/opening_screen.dart'; import 'package:lichess_mobile/src/view/puzzle/puzzle_screen.dart'; import 'package:lichess_mobile/src/widgets/list.dart'; import 'package:lichess_mobile/src/widgets/platform.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -@riverpod final _themesProvider = FutureProvider.autoDispose< (bool, IMap, IMap?, bool) diff --git a/lib/src/view/puzzle/storm_screen.dart b/lib/src/view/puzzle/storm_screen.dart index 908db9175..086faec82 100644 --- a/lib/src/view/puzzle/storm_screen.dart +++ b/lib/src/view/puzzle/storm_screen.dart @@ -94,7 +94,7 @@ class _BodyState extends ConsumerState<_Body> { @override Widget build(BuildContext context) { - final ctrlProvider = stormControllerProvider(widget.data.puzzles, widget.data.timestamp); + final ctrlProvider = stormControllerProvider((widget.data.puzzles, widget.data.timestamp)); final boardPreferences = ref.watch(boardPreferencesProvider); final stormState = ref.watch(ctrlProvider); @@ -279,7 +279,7 @@ class _BodyState extends ConsumerState<_Body> { ), _Combo(stormState.combo), - _BottomBar(ctrlProvider), + _BottomBar(widget.data), ], ), ), @@ -329,7 +329,7 @@ class _BodyState extends ConsumerState<_Body> { child: _Combo(stormState.combo), ), ), - _BottomBar(ctrlProvider), + _BottomBar(widget.data), ], ); } @@ -446,7 +446,7 @@ class _TopTable extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final stormState = ref.watch(stormControllerProvider(data.puzzles, data.timestamp)); + final stormState = ref.watch(stormControllerProvider((data.puzzles, data.timestamp))); return Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Row( @@ -675,12 +675,13 @@ class _ComboState extends ConsumerState<_Combo> with SingleTickerProviderStateMi } class _BottomBar extends ConsumerWidget { - const _BottomBar(this.ctrl); + const _BottomBar(this.data); - final StormControllerProvider ctrl; + final PuzzleStormResponse data; @override Widget build(BuildContext context, WidgetRef ref) { + final ctrl = stormControllerProvider((data.puzzles, data.timestamp)); final stormState = ref.watch(ctrl); return BottomBar( children: [ diff --git a/lib/src/view/puzzle/streak_screen.dart b/lib/src/view/puzzle/streak_screen.dart index 32687c16b..20725a142 100644 --- a/lib/src/view/puzzle/streak_screen.dart +++ b/lib/src/view/puzzle/streak_screen.dart @@ -70,6 +70,7 @@ class _Load extends ConsumerWidget { puzzle: value.puzzle, angle: const PuzzleTheme(PuzzleThemeKey.mix), userId: session?.user.id, + isPuzzleStreak: true, ), streak: value.streak, ); @@ -96,10 +97,7 @@ class _BodyState extends ConsumerState<_Body> { @override Widget build(BuildContext context) { final boardPreferences = ref.watch(boardPreferencesProvider); - final ctrlProvider = puzzleControllerProvider( - widget.initialPuzzleContext, - isPuzzleStreak: true, - ); + final ctrlProvider = puzzleControllerProvider(widget.initialPuzzleContext); final puzzleState = ref.watch(ctrlProvider); ref.listen(puzzleStreakControllerProvider, (previous, next) { @@ -460,7 +458,7 @@ class _BottomBar extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final ctrlProvider = puzzleControllerProvider(initialPuzzleContext, isPuzzleStreak: true); + final ctrlProvider = puzzleControllerProvider(initialPuzzleContext); final puzzleState = ref.watch(ctrlProvider); return BottomBar( diff --git a/lib/src/view/settings/account_preferences_screen.dart b/lib/src/view/settings/account_preferences_screen.dart index 85a6ec734..b5e39e54d 100644 --- a/lib/src/view/settings/account_preferences_screen.dart +++ b/lib/src/view/settings/account_preferences_screen.dart @@ -43,7 +43,7 @@ class _AccountPreferencesScreenState extends ConsumerState { appBar: AppBar( title: const Text('HTTP logs'), actions: [ - if (asyncState.valueOrNull?.isDeleteButtonVisible == true) + if (asyncState.value?.isDeleteButtonVisible == true) IconButton( // TODO localize tooltip: 'Clear all logs', @@ -77,7 +77,7 @@ class _HttpLogScreenState extends ConsumerState { body: _HttpLogList( scrollController: _scrollController, refreshIndicatorKey: _refreshIndicatorKey, - logs: asyncState.valueOrNull?.logs.toList() ?? [], + logs: asyncState.value?.logs.toList() ?? [], onRefresh: _onRefresh, ), ); diff --git a/lib/src/view/study/study_bottom_bar.dart b/lib/src/view/study/study_bottom_bar.dart index 4b0747a88..9fe95e8a9 100644 --- a/lib/src/view/study/study_bottom_bar.dart +++ b/lib/src/view/study/study_bottom_bar.dart @@ -32,7 +32,7 @@ class _AnalysisBottomBar extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final state = ref.watch(studyControllerProvider(id)).valueOrNull; + final state = ref.watch(studyControllerProvider(id)).value; if (state == null) { return const BottomBar(children: []); } diff --git a/lib/src/view/study/study_gamebook.dart b/lib/src/view/study/study_gamebook.dart index dfac1c790..a5b4db579 100644 --- a/lib/src/view/study/study_gamebook.dart +++ b/lib/src/view/study/study_gamebook.dart @@ -98,17 +98,17 @@ class _HintState extends ConsumerState<_Hint> { @override Widget build(BuildContext context) { - ref.listen( - studyControllerProvider(widget.id).select((state) => state.valueOrNull?.gamebookState), - (prev, next) { - if (prev == GamebookState.correctMove && next == GamebookState.findTheMove) { - _hideHint(); - } - }, - ); + ref.listen(studyControllerProvider(widget.id).select((state) => state.value?.gamebookState), ( + prev, + next, + ) { + if (prev == GamebookState.correctMove && next == GamebookState.findTheMove) { + _hideHint(); + } + }); ref.listen( - studyControllerProvider(widget.id).select((state) => state.valueOrNull?.currentChapter.id), + studyControllerProvider(widget.id).select((state) => state.value?.currentChapter.id), (prev, next) { if (prev != next) { _hideHint(); diff --git a/lib/src/view/study/study_list_screen.dart b/lib/src/view/study/study_list_screen.dart index 90fbf8a3d..8e6588d45 100644 --- a/lib/src/view/study/study_list_screen.dart +++ b/lib/src/view/study/study_list_screen.dart @@ -1,4 +1,5 @@ import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lichess_mobile/src/model/auth/auth_session.dart'; @@ -48,8 +49,9 @@ class _StudyListScreenState extends ConsumerState { bool requestedNextPage = false; - StudyListPaginatorProvider get paginatorProvider => - StudyListPaginatorProvider(category: category, order: order, search: search); + AsyncNotifierProvider studies})> + get paginatorProvider => + studyListPaginatorProvider((category: category, order: order, search: search)); @override void initState() { diff --git a/lib/src/view/study/study_screen.dart b/lib/src/view/study/study_screen.dart index b9cf2fc5a..6eebc962a 100644 --- a/lib/src/view/study/study_screen.dart +++ b/lib/src/view/study/study_screen.dart @@ -365,7 +365,7 @@ class _StudyMenu extends ConsumerWidget { ), ), ), - if (state.chatOptions != null && kidModeAsync.valueOrNull == false) + if (state.chatOptions != null && kidModeAsync.value == false) ContextMenuAction( label: context.l10n.chatRoom, onPressed: () { diff --git a/lib/src/view/tournament/tournament_screen.dart b/lib/src/view/tournament/tournament_screen.dart index 965c4a1b6..64af11f85 100644 --- a/lib/src/view/tournament/tournament_screen.dart +++ b/lib/src/view/tournament/tournament_screen.dart @@ -82,7 +82,7 @@ class _TournamentScreenState extends ConsumerState with RouteA @override void didPop() { if (mounted) { - final joined = ref.read(tournamentControllerProvider(widget.id)).valueOrNull?.hasJoined; + final joined = ref.read(tournamentControllerProvider(widget.id)).value?.hasJoined; if (joined == true) { ref.invalidate(myRecentGamesProvider); ref.invalidate(accountProvider); @@ -94,7 +94,7 @@ class _TournamentScreenState extends ConsumerState with RouteA @override Widget build(BuildContext context) { ref.listen( - tournamentControllerProvider(widget.id).select((value) => value.valueOrNull?.currentGame), + tournamentControllerProvider(widget.id).select((value) => value.value?.currentGame), (prevGameId, currentGameId) { if (prevGameId != currentGameId && currentGameId != null) { Navigator.of( @@ -916,7 +916,7 @@ class _BottomBarState extends ConsumerState<_BottomBar> { final kidModeAsync = ref.watch(kidModeProvider); ref.listen( - tournamentControllerProvider(widget.state.id).select((value) => value.valueOrNull?.joined), + tournamentControllerProvider(widget.state.id).select((value) => value.value?.joined), (prevJoined, joined) { if (prevJoined != joined) { setState(() { @@ -929,7 +929,7 @@ class _BottomBarState extends ConsumerState<_BottomBar> { return BottomBar( cupertinoTransparent: true, children: [ - if (widget.state.chatOptions != null && kidModeAsync.valueOrNull == false) + if (widget.state.chatOptions != null && kidModeAsync.value == false) ChatBottomBarButton(options: widget.state.chatOptions!, showLabel: true), if (widget.state.tournament.isFinished != true && session != null) @@ -986,7 +986,7 @@ void _showPlayerDetails( builder: (context, scrollController) { return Consumer( builder: (context, ref, child) { - final playerAsync = ref.watch(tournamentPlayerProvider(tournamentId, userId)); + final playerAsync = ref.watch(tournamentPlayerProvider((tournamentId, userId))); return switch (playerAsync) { AsyncData(value: final player) => _TournamentPlayerDetails( @@ -1038,7 +1038,7 @@ class _TournamentPlayerDetails extends ConsumerWidget { user: player.user, rating: player.rating, style: Styles.title, - onTap: tournamentState.valueOrNull?.isSpectator == true + onTap: tournamentState.value?.isSpectator == true ? () => Navigator.of( context, ).push(UserOrProfileScreen.buildRoute(context, player.user)) @@ -1184,7 +1184,7 @@ class _PairingTile extends ConsumerWidget { contentPadding: const EdgeInsetsDirectional.only(start: 16.0, end: 16.0), visualDensity: VisualDensity.compact, tileColor: index.isEven ? context.lichessTheme.rowEven : context.lichessTheme.rowOdd, - onTap: tournamentState.valueOrNull?.isSpectator == true + onTap: tournamentState.value?.isSpectator == true ? () { // If game is finished (status neither started nor created), go to analysis board if (pairing.status != GameStatus.started && pairing.status != GameStatus.created) { diff --git a/lib/src/view/user/game_history_screen.dart b/lib/src/view/user/game_history_screen.dart index f073ebc87..d2a1f0f36 100644 --- a/lib/src/view/user/game_history_screen.dart +++ b/lib/src/view/user/game_history_screen.dart @@ -62,7 +62,7 @@ class GameHistoryScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final filtersInUse = ref.watch(gameFilterProvider(filter: gameFilter)); + final filtersInUse = ref.watch(gameFilterProvider(gameFilter)); final nbGamesAsync = ref.watch(userNumberOfGamesProvider(user)); final title = user != null && gameFilter.opponent != null ? AppBarTitleText(context.l10n.resVsX(user!.name, gameFilter.opponent!.username)) @@ -90,13 +90,11 @@ class GameHistoryScreen extends ConsumerWidget { context: context, useRootNavigator: true, isScrollControlled: true, - builder: (_) => _FilterGames( - filter: ref.read(gameFilterProvider(filter: gameFilter)), - user: user, - ), + builder: (_) => + _FilterGames(filter: ref.read(gameFilterProvider(gameFilter)), user: user), ).then((value) { if (value != null) { - ref.read(gameFilterProvider(filter: gameFilter).notifier).setFilter(value); + ref.read(gameFilterProvider(gameFilter).notifier).setFilter(value); } }), ); @@ -164,11 +162,10 @@ class _BodyState extends ConsumerState<_Body> { void _scrollListener() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 300) { final state = ref.read( - userGameHistoryProvider( - widget.user?.id, - isOnline: widget.isOnline, - filter: ref.read(gameFilterProvider(filter: widget.gameFilter)), - ), + userGameHistoryProvider(( + userId: widget.user?.id, + filter: ref.read(gameFilterProvider(widget.gameFilter)), + )), ); if (!state.hasValue) { @@ -181,11 +178,10 @@ class _BodyState extends ConsumerState<_Body> { if (hasMore && !isLoading) { ref .read( - userGameHistoryProvider( - widget.user?.id, - isOnline: widget.isOnline, - filter: ref.read(gameFilterProvider(filter: widget.gameFilter)), - ).notifier, + userGameHistoryProvider(( + userId: widget.user?.id, + filter: ref.read(gameFilterProvider(widget.gameFilter)), + )).notifier, ) .getNext(); } @@ -194,12 +190,11 @@ class _BodyState extends ConsumerState<_Body> { @override Widget build(BuildContext context) { - final gameFilterState = ref.watch(gameFilterProvider(filter: widget.gameFilter)); - final gameListProvider = userGameHistoryProvider( - widget.user?.id, - isOnline: widget.isOnline, + final gameFilterState = ref.watch(gameFilterProvider(widget.gameFilter)); + final gameListProvider = userGameHistoryProvider(( + userId: widget.user?.id, filter: gameFilterState, - ); + )); final gameListState = ref.watch(gameListProvider); final isLoggedIn = ref.watch(isLoggedInProvider); @@ -375,7 +370,7 @@ class _FilterGamesState extends ConsumerState<_FilterGames> { final Widget filters = userId != null ? ref - .watch(userProvider(id: userId)) + .watch(userProvider(userId)) .when( data: (user) => perfFilter(availablePerfs(user)), loading: () => const Center(child: CircularProgressIndicator.adaptive()), diff --git a/lib/src/view/user/perf_stats_screen.dart b/lib/src/view/user/perf_stats_screen.dart index 22ad58631..9526965db 100644 --- a/lib/src/view/user/perf_stats_screen.dart +++ b/lib/src/view/user/perf_stats_screen.dart @@ -133,8 +133,8 @@ class _Body extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final perfStats = ref.watch(userPerfStatsProvider(id: user.id, perf: perf)); - final ratingHistory = ref.watch(userRatingHistoryProvider(id: user.id)); + final perfStats = ref.watch(userPerfStatsProvider((user.id, perf))); + final ratingHistory = ref.watch(userRatingHistoryProvider(user.id)); final loggedInUser = ref.watch(authSessionProvider); const statGroupSpace = SizedBox(height: 16.0); const subStatSpace = SizedBox(height: 10); diff --git a/lib/src/view/user/recent_games.dart b/lib/src/view/user/recent_games.dart index f3c858b38..ad6f42f71 100644 --- a/lib/src/view/user/recent_games.dart +++ b/lib/src/view/user/recent_games.dart @@ -49,7 +49,7 @@ class RecentGamesWidget extends ConsumerWidget { GameHistoryScreen.buildRoute( context, user: user, - isOnline: connectivity.valueOrNull?.isOnline == true, + isOnline: connectivity.value?.isOnline == true, ), ); } diff --git a/lib/src/view/user/user_context_menu.dart b/lib/src/view/user/user_context_menu.dart index f4d0e9275..60a886f7c 100644 --- a/lib/src/view/user/user_context_menu.dart +++ b/lib/src/view/user/user_context_menu.dart @@ -29,7 +29,7 @@ class UserContextMenu extends ConsumerWidget { final AsyncValue userAsync = user != null ? AsyncData(user!) - : ref.watch(userProvider(id: userId!)); + : ref.watch(userProvider(userId!)); switch (userAsync) { case AsyncData(:final value): diff --git a/lib/src/view/user/user_screen.dart b/lib/src/view/user/user_screen.dart index f54cdf67b..481f9fa0f 100644 --- a/lib/src/view/user/user_screen.dart +++ b/lib/src/view/user/user_screen.dart @@ -196,7 +196,7 @@ class _UserProfileListView extends ConsumerWidget { GameHistoryScreen.buildRoute( context, user: session.user, - isOnline: connectivity.valueOrNull?.isOnline == true, + isOnline: connectivity.value?.isOnline == true, gameFilter: GameFilterState(opponent: user), ), ); @@ -223,7 +223,7 @@ class _UserProfileListView extends ConsumerWidget { onTap: () => UserScreen.challengeUser(user, context: context, ref: ref), ), - if (user.blocking != true && !user.isBot && kidMode.valueOrNull == false) + if (user.blocking != true && !user.isBot && kidMode.value == false) ListTile( leading: const Icon(Icons.chat_bubble_outline), title: Text(context.l10n.composeMessage), diff --git a/lib/src/view/watch/tv_screen.dart b/lib/src/view/watch/tv_screen.dart index 2bdf8355e..126e78342 100644 --- a/lib/src/view/watch/tv_screen.dart +++ b/lib/src/view/watch/tv_screen.dart @@ -51,11 +51,11 @@ class TvScreen extends ConsumerStatefulWidget { } class _TvScreenState extends ConsumerState { - TvControllerProvider get _tvGameCtrl => tvControllerProvider( - widget.channel, + AsyncNotifierProvider get _tvGameCtrl => tvControllerProvider(( + channel: widget.channel, initialGame: widget.initialGame, userId: widget.user?.id, - ); + )); final _whiteClockKey = GlobalKey(debugLabel: 'whiteClockOnTvScreen'); final _blackClockKey = GlobalKey(debugLabel: 'blackClockOnTvScreen'); @@ -99,15 +99,15 @@ class _TvScreenState extends ConsumerState { // If Stockfish is playing, user is null final crosstable = game.white.user != null && game.black.user != null ? ref.watch( - crosstableProvider( - game.white.user!.id, - game.black.user!.id, + crosstableProvider(( + userId1: game.white.user!.id, + userId2: game.black.user!.id, matchup: true, - ), + )), ) : null; - final crosstableData = crosstable?.valueOrNull; + final crosstableData = crosstable?.value; final matchupData = crosstableData?.matchup; final blackPlayerWidget = GamePlayer( game: game.copyWith(black: game.black.setOnGame(true)), diff --git a/lib/src/view/watch/watch_tab_screen.dart b/lib/src/view/watch/watch_tab_screen.dart index 943fcac95..0f727fdc4 100644 --- a/lib/src/view/watch/watch_tab_screen.dart +++ b/lib/src/view/watch/watch_tab_screen.dart @@ -77,7 +77,7 @@ class _WatchScreenState extends ConsumerState { } }); - final isOnline = ref.watch(connectivityChangesProvider).valueOrNull?.isOnline ?? true; + final isOnline = ref.watch(connectivityChangesProvider).value?.isOnline ?? true; return PopScope( canPop: false, onPopInvokedWithResult: (bool didPop, _) { diff --git a/lib/src/widgets/feedback.dart b/lib/src/widgets/feedback.dart index f533b11c0..896f49810 100644 --- a/lib/src/widgets/feedback.dart +++ b/lib/src/widgets/feedback.dart @@ -23,7 +23,7 @@ class SocketPingRatingIcon extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final ping = ref.watch(socketPingProvider(route: socketUri)); + final ping = ref.watch(socketPingProvider(socketUri)); return SemanticIconButton( semanticsLabel: 'PING: ${ping.averageLag.inMilliseconds}ms', @@ -34,7 +34,7 @@ class SocketPingRatingIcon extends ConsumerWidget { bodyBuilder: (_) { return Consumer( builder: (_, ref, _) { - final p = ref.watch(socketPingProvider(route: socketUri)); + final p = ref.watch(socketPingProvider(socketUri)); return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Text.rich( @@ -77,7 +77,7 @@ class SocketPingRatingListTile extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final ping = ref.watch(socketPingProvider(route: socketUri)); + final ping = ref.watch(socketPingProvider(socketUri)); return ListTile( leading: LagIndicator(lagRating: ping.rating), diff --git a/pubspec.lock b/pubspec.lock index ebe3b06a3..c4d1a3bb6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f + sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d url: "https://pub.dev" source: hosted - version: "85.0.0" + version: "91.0.0" _flutterfire_internals: dependency: transitive description: @@ -21,18 +21,26 @@ packages: dependency: transitive description: name: analyzer - sha256: f4ad0fea5f102201015c9aae9d93bc02f75dd9491529a8c21f88d17a8523d44c + sha256: a40a0cee526a7e1f387c6847bd8a5ccbf510a75952ef8a28338e989558072cb0 url: "https://pub.dev" source: hosted - version: "7.6.0" + version: "8.4.0" + analyzer_buffer: + dependency: transitive + description: + name: analyzer_buffer + sha256: aba2f75e63b3135fd1efaa8b6abefe1aa6e41b6bd9806221620fa48f98156033 + url: "https://pub.dev" + source: hosted + version: "0.1.11" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: a5ab7590c27b779f3d4de67f31c4109dbe13dd7339f86461a6f2a8ab2594d8ce + sha256: "08cfefa90b4f4dd3b447bda831cecf644029f9f8e22820f6ee310213ebe2dd53" url: "https://pub.dev" source: hosted - version: "0.13.4" + version: "0.13.10" ansicolor: dependency: transitive description: @@ -93,18 +101,18 @@ packages: dependency: transitive description: name: build - sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" + sha256: c1668065e9ba04752570ad7e038288559d1e2ca5c6d0131c0f5f55e39e777413 url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "4.0.3" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" build_daemon: dependency: transitive description: @@ -113,30 +121,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.1" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 - url: "https://pub.dev" - source: hosted - version: "2.5.4" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" + sha256: "110c56ef29b5eb367b4d17fc79375fa8c18a6cd7acd92c05bb3986c17a079057" url: "https://pub.dev" source: hosted - version: "2.5.4" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" - url: "https://pub.dev" - source: hosted - version: "9.1.2" + version: "2.10.4" built_collection: dependency: transitive description: @@ -217,6 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.0" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" cli_util: dependency: transitive description: @@ -281,6 +281,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + url: "https://pub.dev" + source: hosted + version: "1.15.0" cronet_http: dependency: "direct main" description: @@ -333,42 +341,42 @@ packages: dependency: "direct dev" description: name: custom_lint - sha256: "9656925637516c5cf0f5da018b33df94025af2088fe09c8ae2ca54c53f2d9a84" + sha256: "751ee9440920f808266c3ec2553420dea56d3c7837dd2d62af76b11be3fcece5" url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.8.1" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: "6cdc8e87e51baaaba9c43e283ed8d28e59a0c4732279df62f66f7b5984655414" + sha256: "1128db6f58e71d43842f3b9be7465c83f0c47f4dd8918f878dd6ad3b72a32072" url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.8.1" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: "31110af3dde9d29fb10828ca33f1dce24d2798477b167675543ce3d208dee8be" + sha256: "85b339346154d5646952d44d682965dfe9e12cae5febd706f0db3aa5010d6423" url: "https://pub.dev" source: hosted - version: "0.7.5" + version: "0.8.1" custom_lint_visitor: dependency: transitive description: name: custom_lint_visitor - sha256: "4a86a0d8415a91fbb8298d6ef03e9034dc8e323a599ddc4120a0e36c433983a2" + sha256: "91f2a81e9f0abb4b9f3bb529f78b6227ce6050300d1ae5b1e2c69c66c7a566d8" url: "https://pub.dev" source: hosted - version: "1.0.0+7.7.0" + version: "1.0.0+8.4.0" dart_style: dependency: transitive description: name: dart_style - sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.3" dartchess: dependency: "direct main" description: @@ -687,10 +695,10 @@ packages: dependency: "direct main" description: name: flutter_riverpod - sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" + sha256: "9e2d6907f12cc7d23a846847615941bddee8709bf2bfd274acdf5e80bcf22fde" url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "3.0.3" flutter_secure_storage: dependency: "direct main" description: @@ -770,10 +778,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "2d399f823b8849663744d2a9ddcce01c49268fb4170d0442a655bf6a2f47be22" + sha256: "13065f10e135263a4f5a4391b79a8efc5fb8106f8dd555a9e49b750b45393d77" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.3" freezed_annotation: dependency: "direct main" description: @@ -786,10 +794,10 @@ packages: dependency: "direct dev" description: name: freezed_lint - sha256: "389451a2a3d220c4ec7e057dea0ded1757c78af42680f42b3f12391f3188396a" + sha256: "6b2aecc7304d8ecffb7a50fc63f31df0aae748af58184d287e6268c11c3520cd" url: "https://pub.dev" source: hosted - version: "0.0.10" + version: "0.0.12" frontend_server_client: dependency: transitive description: @@ -986,10 +994,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c + sha256: "33a040668b31b320aafa4822b7b1e177e163fc3c1e835c6750319d4ab23aa6fe" url: "https://pub.dev" source: hosted - version: "6.9.5" + version: "6.11.1" l10n_esperanto: dependency: "direct main" description: @@ -1158,6 +1166,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" objective_c: dependency: transitive description: @@ -1226,10 +1242,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "97390a0719146c7c3e71b6866c34f1cde92685933165c1c671984390d2aca776" + sha256: "6192e477f34018ef1ea790c56fffc7302e3bc3efede9e798b934c252c8c105ba" url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.5.0" path_provider_linux: dependency: transitive description: @@ -1370,42 +1386,26 @@ packages: dependency: transitive description: name: riverpod - sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" + sha256: c406de02bff19d920b832bddfb8283548bfa05ce41c59afba57ce643e116aa59 url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "3.0.3" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: "03a17170088c63aab6c54c44456f5ab78876a1ddb6032ffde1662ddab4959611" + sha256: a0f68adb078b790faa3c655110a017f9a7b7b079a57bbd40f540e80dce5fcd29 url: "https://pub.dev" source: hosted - version: "0.5.10" - riverpod_annotation: - dependency: "direct main" - description: - name: riverpod_annotation - sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8 - url: "https://pub.dev" - source: hosted - version: "2.6.1" - riverpod_generator: - dependency: "direct dev" - description: - name: riverpod_generator - sha256: "44a0992d54473eb199ede00e2260bd3c262a86560e3c6f6374503d86d0580e36" - url: "https://pub.dev" - source: hosted - version: "2.6.5" + version: "1.0.0-dev.7" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: "89a52b7334210dbff8605c3edf26cfe69b15062beed5cbfeff2c3812c33c9e35" + sha256: "7ef9c43469e9b5ac4e4c3b24d7c30642e47ce1b12cd7dcdd643534db0a72ed13" url: "https://pub.dev" source: hosted - version: "2.6.5" + version: "3.0.3" rxdart: dependency: transitive description: @@ -1494,6 +1494,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" shelf_web_socket: dependency: transitive description: @@ -1527,18 +1543,34 @@ packages: dependency: transitive description: name: source_gen - sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + sha256: "07b277b67e0096c45196cbddddf2d8c6ffc49342e88bf31d460ce04605ddac75" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "4.1.1" source_helper: dependency: transitive description: name: source_helper - sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca + sha256: "6a3c6cc82073a8797f8c4dc4572146114a39652851c157db37e964d9c7038723" url: "https://pub.dev" source: hosted - version: "1.3.7" + version: "1.3.8" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" source_span: dependency: transitive description: @@ -1659,6 +1691,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2" + test: + dependency: transitive + description: + name: test + sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" + url: "https://pub.dev" + source: hosted + version: "1.26.3" test_api: dependency: transitive description: @@ -1667,6 +1707,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.7" + test_core: + dependency: transitive + description: + name: test_core + sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" + url: "https://pub.dev" + source: hosted + version: "0.6.12" timezone: dependency: transitive description: @@ -1675,14 +1723,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.1" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" typed_data: dependency: transitive description: @@ -1843,6 +1883,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 34a0fb9c7..d83963c3d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: sdk: flutter flutter_markdown: ^0.7.3+1 flutter_native_splash: ^2.3.5 - flutter_riverpod: ^2.3.4 + flutter_riverpod: ^3.0.3 flutter_secure_storage: ^10.0.0-beta.4 flutter_slidable: ^4.0.0 flutter_spinkit: ^5.2.0 @@ -65,7 +65,6 @@ dependencies: pub_semver: ^2.1.4 quick_actions: ^1.1.0 result_extensions: ^0.2.0 - riverpod_annotation: ^2.3.0 share_plus: ^12.0.0 shared_preferences: ^2.1.0 signal_strength_indicator: ^0.4.1 @@ -80,7 +79,7 @@ dependencies: dev_dependencies: build_runner: ^2.3.2 - custom_lint: ^0.7.0 + custom_lint: ^0.8.1 fake_async: ^1.3.1 flutter_test: sdk: flutter @@ -90,8 +89,7 @@ dev_dependencies: lint: ^2.0.1 mocktail: ^1.0.0 mocktail_image_network: ^1.2.0 - riverpod_generator: ^2.1.0 - riverpod_lint: ^2.3.3 + riverpod_lint: ^3.0.3 stream_channel: ^2.1.2 wakelock_plus_platform_interface: ^1.3.0 diff --git a/test/app_test.dart b/test/app_test.dart index 6edceae28..8faf55394 100644 --- a/test/app_test.dart +++ b/test/app_test.dart @@ -58,9 +58,11 @@ void main() { tester, child: const Application(), userSession: fakeSession, - overrides: [ - httpClientFactoryProvider.overrideWith((ref) => FakeHttpClientFactory(() => mockClient)), - ], + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( + (ref) => FakeHttpClientFactory(() => mockClient), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/model/auth/auth_controller_test.dart b/test/model/auth/auth_controller_test.dart index 497f44220..795f179da 100644 --- a/test/model/auth/auth_controller_test.dart +++ b/test/model/auth/auth_controller_test.dart @@ -73,11 +73,13 @@ void main() { when(() => mockSessionStorage.write(any())).thenAnswer((_) => Future.value(null)); final container = await makeContainer( - overrides: [ - appAuthProvider.overrideWithValue(mockFlutterAppAuth), - sessionStorageProvider.overrideWithValue(mockSessionStorage), - httpClientFactoryProvider.overrideWith((_) => FakeHttpClientFactory(() => client)), - ], + overrides: { + appAuthProvider: appAuthProvider.overrideWithValue(mockFlutterAppAuth), + sessionStorageProvider: sessionStorageProvider.overrideWithValue(mockSessionStorage), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( + (_) => FakeHttpClientFactory(() => client), + ), + }, ); final listener = Listener>(); @@ -93,9 +95,7 @@ void main() { verifyInOrder([ // init state - () => listener(null, nullData), - // state is loading, waiting for signin logic to complete - () => listener(nullData, loading), + () => listener(null, loading), // signin logic completed () => listener(loading, nullData), ]); @@ -124,11 +124,13 @@ void main() { }); final container = await makeContainer( - overrides: [ - appAuthProvider.overrideWithValue(mockFlutterAppAuth), - sessionStorageProvider.overrideWithValue(mockSessionStorage), - httpClientFactoryProvider.overrideWith((_) => FakeHttpClientFactory(() => client)), - ], + overrides: { + appAuthProvider: appAuthProvider.overrideWithValue(mockFlutterAppAuth), + sessionStorageProvider: sessionStorageProvider.overrideWithValue(mockSessionStorage), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( + (_) => FakeHttpClientFactory(() => client), + ), + }, userSession: testUserSession, ); @@ -145,9 +147,7 @@ void main() { verifyInOrder([ // init state - () => listener(null, nullData), - // state is loading, waiting for signin logic to complete - () => listener(nullData, loading), + () => listener(null, loading), // signOut logic completed () => listener(loading, nullData), ]); diff --git a/test/model/challenge/challenge_service_test.dart b/test/model/challenge/challenge_service_test.dart index 7561b4d48..65a5fd583 100644 --- a/test/model/challenge/challenge_service_test.dart +++ b/test/model/challenge/challenge_service_test.dart @@ -85,7 +85,11 @@ void main() { final container = await makeContainer( userSession: fakeSession, - overrides: [notificationDisplayProvider.overrideWithValue(notificationDisplayMock)], + overrides: { + notificationDisplayProvider: notificationDisplayProvider.overrideWithValue( + notificationDisplayMock, + ), + }, ); final notificationService = container.read(notificationServiceProvider); @@ -163,7 +167,11 @@ void main() { final container = await makeContainer( userSession: fakeSession, - overrides: [notificationDisplayProvider.overrideWithValue(notificationDisplayMock)], + overrides: { + notificationDisplayProvider: notificationDisplayProvider.overrideWithValue( + notificationDisplayMock, + ), + }, ); final notificationService = container.read(notificationServiceProvider); diff --git a/test/model/correspondence/correspondence_service_test.dart b/test/model/correspondence/correspondence_service_test.dart index 94317ac3c..f049e69bb 100644 --- a/test/model/correspondence/correspondence_service_test.dart +++ b/test/model/correspondence/correspondence_service_test.dart @@ -45,10 +45,14 @@ void main() { final container = await makeContainer( userSession: fakeSession, - overrides: [ - correspondenceGameStorageProvider.overrideWith((_) => correspondenceGameStorageMock), - notificationDisplayProvider.overrideWithValue(notificationDisplayMock), - ], + overrides: { + correspondenceGameStorageProvider: correspondenceGameStorageProvider.overrideWith( + (_) => correspondenceGameStorageMock, + ), + notificationDisplayProvider: notificationDisplayProvider.overrideWithValue( + notificationDisplayMock, + ), + }, ); final notificationService = container.read(notificationServiceProvider); @@ -99,10 +103,14 @@ void main() { final container = await makeContainer( userSession: fakeSession, - overrides: [ - correspondenceGameStorageProvider.overrideWith((_) => correspondenceGameStorageMock), - notificationDisplayProvider.overrideWith((_) => notificationDisplayMock), - ], + overrides: { + correspondenceGameStorageProvider: correspondenceGameStorageProvider.overrideWith( + (_) => correspondenceGameStorageMock, + ), + notificationDisplayProvider: notificationDisplayProvider.overrideWith( + (_) => notificationDisplayMock, + ), + }, ); final notificationService = container.read(notificationServiceProvider); diff --git a/test/model/notifications/notification_service_test.dart b/test/model/notifications/notification_service_test.dart index e5e91d991..b43188c6c 100644 --- a/test/model/notifications/notification_service_test.dart +++ b/test/model/notifications/notification_service_test.dart @@ -72,9 +72,11 @@ void main() { () async { final container = await makeContainer( userSession: fakeSession, - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(registerMockClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(registerMockClient, ref), + ), + }, ); final notificationService = container.read(notificationServiceProvider); @@ -92,9 +94,11 @@ void main() { test("don't try to register device when permissions are not granted", () async { final container = await makeContainer( userSession: fakeSession, - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(registerMockClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(registerMockClient, ref), + ), + }, ); final notificationService = container.read(notificationServiceProvider); @@ -112,9 +116,11 @@ void main() { test("don't try to register device when user is not logged in", () async { final container = await makeContainer( - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(registerMockClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(registerMockClient, ref), + ), + }, ); final notificationService = container.read(notificationServiceProvider); @@ -133,10 +139,14 @@ void main() { test('FCM message with associated notification will show it in foreground', () async { final container = await makeContainer( userSession: fakeSession, - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(registerMockClient, ref)), - notificationDisplayProvider.overrideWith((_) => notificationDisplayMock), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(registerMockClient, ref), + ), + notificationDisplayProvider: notificationDisplayProvider.overrideWith( + (_) => notificationDisplayMock, + ), + }, ); final notificationService = container.read(notificationServiceProvider); diff --git a/test/model/puzzle/puzzle_service_test.dart b/test/model/puzzle/puzzle_service_test.dart index 61a51a81d..56677e308 100644 --- a/test/model/puzzle/puzzle_service_test.dart +++ b/test/model/puzzle/puzzle_service_test.dart @@ -20,11 +20,11 @@ import '../../test_helpers.dart'; void main() { Future makeTestContainer(MockClient mockClient) { return makeContainer( - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); } diff --git a/test/model/puzzle/puzzle_storage_test.dart b/test/model/puzzle/puzzle_storage_test.dart index 07bc10bd6..0af6af0c7 100644 --- a/test/model/puzzle/puzzle_storage_test.dart +++ b/test/model/puzzle/puzzle_storage_test.dart @@ -18,12 +18,12 @@ void main() { final db = await openAppDatabase(dbFactory, inMemoryDatabasePath); final container = await makeContainer( - overrides: [ - databaseProvider.overrideWith((ref) { + overrides: { + databaseProvider: databaseProvider.overrideWith((ref) { ref.onDispose(db.close); return db; }), - ], + }, ); final storage = await container.read(puzzleStorageProvider.future); diff --git a/test/model/study/study_repository_test.dart b/test/model/study/study_repository_test.dart index 27226e17e..808cec99c 100644 --- a/test/model/study/study_repository_test.dart +++ b/test/model/study/study_repository_test.dart @@ -16,11 +16,11 @@ import '../../test_helpers.dart'; void main() { Future makeTestContainer(MockClient mockClient) { return makeContainer( - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); } diff --git a/test/network/aggregator_test.dart b/test/network/aggregator_test.dart index e9b02dc44..4332a44b3 100644 --- a/test/network/aggregator_test.dart +++ b/test/network/aggregator_test.dart @@ -29,11 +29,11 @@ void main() { Future fakeClientAggregator() async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, ); return container.read(aggregatorProvider); } diff --git a/test/network/http_test.dart b/test/network/http_test.dart index bbf3e1733..8ecfd967b 100644 --- a/test/network/http_test.dart +++ b/test/network/http_test.dart @@ -22,11 +22,11 @@ void main() { group('LichessClient', () { test('sends requests to lichess host', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, ); final client = container.read(lichessClientProvider); final response = await client.get(Uri(path: '/test')); @@ -43,11 +43,11 @@ void main() { test('sets user agent (no session)', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, ); final client = container.read(lichessClientProvider); await client.get(Uri(path: '/test')); @@ -64,11 +64,11 @@ void main() { test('sets user agent (with session)', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, userSession: const AuthSessionState( token: 'test-token', user: LightUser(id: UserId('test-user-id'), name: 'test-username'), @@ -89,11 +89,11 @@ void main() { test('read methods throw ServerException on status code >= 400', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, ); final client = container.read(lichessClientProvider); for (final method in [ @@ -133,11 +133,11 @@ void main() { test('other methods do not throw on status code >= 400', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, ); final client = container.read(lichessClientProvider); for (final method in [client.get, client.post, client.put, client.patch, client.delete]) { @@ -152,11 +152,11 @@ void main() { test('socket and tls errors do not throw ClientException', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, ); final client = container.read(lichessClientProvider); expect( @@ -171,11 +171,11 @@ void main() { test('failed JSON parsing will throw ClientException', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, ); final client = container.read(lichessClientProvider); expect( @@ -197,11 +197,11 @@ void main() { test('adds a signed bearer token when a session is available the request', () async { final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - ], + }, userSession: const AuthSessionState( token: 'test-token', user: LightUser(id: UserId('test-user-id'), name: 'test-username'), @@ -231,11 +231,11 @@ void main() { () async { int nbTokenTestRequests = 0; final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - defaultClientProvider.overrideWith((ref) { + defaultClientProvider: defaultClientProvider.overrideWith((ref) { return MockClient((request) async { if (request.url.path == '/api/token/test') { nbTokenTestRequests++; @@ -246,7 +246,7 @@ void main() { return http.Response('', 404); }); }), - ], + }, userSession: const AuthSessionState( token: 'test-token', user: LightUser(id: UserId('test-user-id'), name: 'test-username'), @@ -285,11 +285,11 @@ void main() { test('when receiving a 401, will test session token and keep session if still valid', () async { int nbTokenTestRequests = 0; final container = await makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => FakeClient()); }), - defaultClientProvider.overrideWith((ref) { + defaultClientProvider: defaultClientProvider.overrideWith((ref) { return MockClient((request) async { if (request.url.path == '/api/token/test') { nbTokenTestRequests++; @@ -301,7 +301,7 @@ void main() { return http.Response('', 404); }); }), - ], + }, userSession: const AuthSessionState( token: 'test-token', user: LightUser(id: UserId('test-user-id'), name: 'test-username'), diff --git a/test/test_container.dart b/test/test_container.dart index b1e9012cd..7ce1266e4 100644 --- a/test/test_container.dart +++ b/test/test_container.dart @@ -1,5 +1,6 @@ import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/misc.dart' show Override, ProviderOrFamily; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; @@ -32,75 +33,75 @@ final testContainerMockClient = MockClient((request) async { /// with the given [mockClient]. Future lichessClientContainer(MockClient mockClient) { return makeContainer( - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - ], + }, ); } /// Returns a [ProviderContainer] with default mocks, ready for testing. Future makeContainer({ - List? overrides, + Map? overrides, AuthSessionState? userSession, }) async { final binding = TestLichessBinding.ensureInitialized(); FlutterSecureStorage.setMockInitialValues({kSRIStorageKey: 'test'}); - final container = ProviderContainer( - overrides: [ - connectivityPluginProvider.overrideWith((_) { - return FakeConnectivity(); - }), - notificationDisplayProvider.overrideWith((ref) { - return FakeNotificationDisplay(); - }), - databaseProvider.overrideWith((ref) async { - final db = await openAppDatabase(databaseFactoryFfi, inMemoryDatabasePath); - ref.onDispose(db.close); - return db; - }), - webSocketChannelFactoryProvider.overrideWith((ref) { - return defaultFakeWebSocketChannelFactory; - }), - socketPoolProvider.overrideWith((ref) { - final pool = SocketPool(ref); - ref.onDispose(pool.dispose); - return pool; - }), - httpClientFactoryProvider.overrideWith((ref) { - return FakeHttpClientFactory(() => testContainerMockClient); - }), - soundServiceProvider.overrideWithValue(FakeSoundService()), - preloadedDataProvider.overrideWith((ref) { - return ( - sri: 'test-sri', - packageInfo: PackageInfo( - appName: 'lichess_mobile_test', - version: '0.0.0', - buildNumber: '0', - packageName: 'lichess_mobile_test', - ), - deviceInfo: BaseDeviceInfo({ - 'name': 'test', - 'model': 'test', - 'manufacturer': 'test', - 'systemName': 'test', - 'systemVersion': 'test', - 'identifierForVendor': 'test', - 'isPhysicalDevice': true, - }), - userSession: userSession, - engineMaxMemoryInMb: 256, - appDocumentsDirectory: null, - appSupportDirectory: null, - ); - }), - ...overrides ?? [], - ], - ); + final Map overrideMap = { + connectivityPluginProvider: connectivityPluginProvider.overrideWith((_) { + return FakeConnectivity(); + }), + notificationDisplayProvider: notificationDisplayProvider.overrideWith((ref) { + return FakeNotificationDisplay(); + }), + databaseProvider: databaseProvider.overrideWith((ref) async { + final db = await openAppDatabase(databaseFactoryFfi, inMemoryDatabasePath); + ref.onDispose(db.close); + return db; + }), + webSocketChannelFactoryProvider: webSocketChannelFactoryProvider.overrideWith((ref) { + return defaultFakeWebSocketChannelFactory; + }), + socketPoolProvider: socketPoolProvider.overrideWith((ref) { + final pool = SocketPool(ref); + ref.onDispose(pool.dispose); + return pool; + }), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { + return FakeHttpClientFactory(() => testContainerMockClient); + }), + soundServiceProvider: soundServiceProvider.overrideWithValue(FakeSoundService()), + preloadedDataProvider: preloadedDataProvider.overrideWith((ref) { + return ( + sri: 'test-sri', + packageInfo: PackageInfo( + appName: 'lichess_mobile_test', + version: '0.0.0', + buildNumber: '0', + packageName: 'lichess_mobile_test', + ), + deviceInfo: BaseDeviceInfo({ + 'name': 'test', + 'model': 'test', + 'manufacturer': 'test', + 'systemName': 'test', + 'systemVersion': 'test', + 'identifierForVendor': 'test', + 'isPhysicalDevice': true, + }), + userSession: userSession, + engineMaxMemoryInMb: 256, + appDocumentsDirectory: null, + appSupportDirectory: null, + ); + }), + ...?overrides, + }; + + final container = ProviderContainer(overrides: overrideMap.values.toList()); addTearDown(binding.reset); addTearDown(container.dispose); diff --git a/test/test_provider_scope.dart b/test/test_provider_scope.dart index 347c0486c..5da4109b2 100644 --- a/test/test_provider_scope.dart +++ b/test/test_provider_scope.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/misc.dart' show Override, ProviderOrFamily; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; @@ -57,7 +58,7 @@ final offlineClient = MockClient((request) { Future makeTestProviderScopeApp( WidgetTester tester, { required Widget home, - List? overrides, + Map? overrides, AuthSessionState? userSession, Map? defaultPreferences, }) { @@ -102,18 +103,18 @@ class _FakeAppState extends ConsumerState<_FakeApp> { Future makeOfflineTestProviderScope( WidgetTester tester, { required Widget child, - List? overrides, + Map? overrides, AuthSessionState? userSession, Map? defaultPreferences, }) => makeTestProviderScope( tester, child: child, - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => offlineClient); }), - ...overrides ?? [], - ], + ...?overrides, + }, userSession: userSession, defaultPreferences: defaultPreferences, ); @@ -130,7 +131,7 @@ Future makeOfflineTestProviderScope( Future makeTestProviderScope( WidgetTester tester, { required Widget child, - List? overrides, + Map? overrides, AuthSessionState? userSession, Map? defaultPreferences, Size surfaceSize = kTestSurfaceSize, @@ -185,73 +186,64 @@ Future makeTestProviderScope( // TODO consider loading true fonts as well FlutterError.onError = ignoreOverflowErrors; + final Map overrideMap = { + notificationDisplayProvider: notificationDisplayProvider.overrideWith((ref) { + return FakeNotificationDisplay(); + }), + databaseProvider: databaseProvider.overrideWith((ref) async { + final testDb = await openAppDatabase(databaseFactoryFfiNoIsolate, inMemoryDatabasePath); + ref.onDispose(testDb.close); + return testDb; + }), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { + return FakeHttpClientFactory(() => mockClient); + }), + aggregatorProvider: aggregatorProvider.overrideWith((ref) { + // Use a zero aggregation interval to disable aggregation for tests. + return Aggregator(ref.read(lichessClientProvider), aggregationInterval: Duration.zero); + }), + webSocketChannelFactoryProvider: webSocketChannelFactoryProvider.overrideWith((ref) { + return defaultFakeWebSocketChannelFactory; + }), + socketPoolProvider: socketPoolProvider.overrideWith((ref) { + final pool = SocketPool(ref); + ref.onDispose(pool.dispose); + return pool; + }), + connectivityPluginProvider: connectivityPluginProvider.overrideWith((_) => FakeConnectivity()), + showRatingsPrefProvider: showRatingsPrefProvider.overrideWith((ref) => ShowRatings.yes), + soundServiceProvider: soundServiceProvider.overrideWithValue(FakeSoundService()), + openingServiceProvider: openingServiceProvider.overrideWithValue(FakeOpeningService()), + preloadedDataProvider: preloadedDataProvider.overrideWith((ref) { + return ( + sri: 'test-sri', + packageInfo: PackageInfo( + appName: 'lichess_mobile_test', + version: '0.0.0', + buildNumber: '0', + packageName: 'lichess_mobile_test', + ), + deviceInfo: BaseDeviceInfo({ + 'name': 'test', + 'model': 'test', + 'manufacturer': 'test', + 'systemName': 'test', + 'systemVersion': 'test', + 'identifierForVendor': 'test', + 'isPhysicalDevice': true, + }), + userSession: userSession, + engineMaxMemoryInMb: 256, + appDocumentsDirectory: null, + appSupportDirectory: null, + ); + }), + ...?overrides, + }; + return ProviderScope( key: key, - overrides: [ - // ignore: scoped_providers_should_specify_dependencies - notificationDisplayProvider.overrideWith((ref) { - return FakeNotificationDisplay(); - }), - // ignore: scoped_providers_should_specify_dependencies - databaseProvider.overrideWith((ref) async { - final testDb = await openAppDatabase(databaseFactoryFfiNoIsolate, inMemoryDatabasePath); - ref.onDispose(testDb.close); - return testDb; - }), - // ignore: scoped_providers_should_specify_dependencies - httpClientFactoryProvider.overrideWith((ref) { - return FakeHttpClientFactory(() => mockClient); - }), - // ignore: scoped_providers_should_specify_dependencies - aggregatorProvider.overrideWith((ref) { - // Use a zero aggregation interval to disable aggregation for tests. - return Aggregator(ref.read(lichessClientProvider), aggregationInterval: Duration.zero); - }), - // ignore: scoped_providers_should_specify_dependencies - webSocketChannelFactoryProvider.overrideWith((ref) { - return defaultFakeWebSocketChannelFactory; - }), - // ignore: scoped_providers_should_specify_dependencies - socketPoolProvider.overrideWith((ref) { - final pool = SocketPool(ref); - ref.onDispose(pool.dispose); - return pool; - }), - // ignore: scoped_providers_should_specify_dependencies - connectivityPluginProvider.overrideWith((_) => FakeConnectivity()), - // ignore: scoped_providers_should_specify_dependencies - showRatingsPrefProvider.overrideWith((ref) => ShowRatings.yes), - // ignore: scoped_providers_should_specify_dependencies - soundServiceProvider.overrideWithValue(FakeSoundService()), - // ignore: scoped_providers_should_specify_dependencies - openingServiceProvider.overrideWithValue(FakeOpeningService()), - // ignore: scoped_providers_should_specify_dependencies - preloadedDataProvider.overrideWith((ref) { - return ( - sri: 'test-sri', - packageInfo: PackageInfo( - appName: 'lichess_mobile_test', - version: '0.0.0', - buildNumber: '0', - packageName: 'lichess_mobile_test', - ), - deviceInfo: BaseDeviceInfo({ - 'name': 'test', - 'model': 'test', - 'manufacturer': 'test', - 'systemName': 'test', - 'systemVersion': 'test', - 'identifierForVendor': 'test', - 'isPhysicalDevice': true, - }), - userSession: userSession, - engineMaxMemoryInMb: 256, - appDocumentsDirectory: null, - appSupportDirectory: null, - ); - }), - ...overrides ?? [], - ], + overrides: overrideMap.values.toList(), child: TestSurface(size: surfaceSize, child: child), ); } diff --git a/test/view/analysis/analysis_screen_test.dart b/test/view/analysis/analysis_screen_test.dart index 4b472f824..5e5dce56d 100644 --- a/test/view/analysis/analysis_screen_test.dart +++ b/test/view/analysis/analysis_screen_test.dart @@ -131,12 +131,12 @@ void main() { variant: Variant.standard, ), ), - overrides: [ + overrides: { if (mockClient != null) - lichessClientProvider.overrideWith((ref) { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -953,11 +953,11 @@ void main() { gameFullId: kGameFullId, ), ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -1045,11 +1045,11 @@ void main() { gameFullId: kGameFullId, ), ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -1189,11 +1189,11 @@ void main() { gameFullId: kGameFullId, ), ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -1258,11 +1258,11 @@ void main() { gameFullId: kGameFullId, ), ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); diff --git a/test/view/analysis/retro_screen_test.dart b/test/view/analysis/retro_screen_test.dart index c3babc138..ce86eae86 100644 --- a/test/view/analysis/retro_screen_test.dart +++ b/test/view/analysis/retro_screen_test.dart @@ -121,12 +121,12 @@ Future makeTestApp( return await makeTestProviderScopeApp( tester, home: const RetroScreen(options: (id: testId, initialSide: Side.white)), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - defaultClientProvider.overrideWithValue(mockClient), - ], + defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient), + }, defaultPreferences: {}, ); } diff --git a/test/view/broadcast/broadcast_game_screen_test.dart b/test/view/broadcast/broadcast_game_screen_test.dart index 99cf99bf2..802a58cba 100644 --- a/test/view/broadcast/broadcast_game_screen_test.dart +++ b/test/view/broadcast/broadcast_game_screen_test.dart @@ -51,7 +51,11 @@ void main() { roundId: _roundId, gameId: _gameId, ), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/broadcast/broadcast_list_screen_test.dart b/test/view/broadcast/broadcast_list_screen_test.dart index 458449251..1c6ce8550 100644 --- a/test/view/broadcast/broadcast_list_screen_test.dart +++ b/test/view/broadcast/broadcast_list_screen_test.dart @@ -25,7 +25,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const BroadcastListScreen(), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -42,7 +46,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const BroadcastListScreen(), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/broadcast/broadcast_round_screen_test.dart b/test/view/broadcast/broadcast_round_screen_test.dart index 67169738d..e71ef1793 100644 --- a/test/view/broadcast/broadcast_round_screen_test.dart +++ b/test/view/broadcast/broadcast_round_screen_test.dart @@ -21,9 +21,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: BroadcastRoundScreen(broadcast: _finishedBroadcast), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_finishedBroadcastClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_finishedBroadcastClient, ref), + ), + }, ); await tester.pumpWidget(app); @@ -50,9 +52,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const BroadcastRoundScreenLoading(roundId: BroadcastRoundId('S5VCwuVn')), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_finishedBroadcastClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_finishedBroadcastClient, ref), + ), + }, ); await tester.pumpWidget(app); @@ -86,9 +90,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: BroadcastRoundScreen(broadcast: _finishedBroadcast), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_finishedBroadcastClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_finishedBroadcastClient, ref), + ), + }, ); await tester.pumpWidget(app); @@ -117,9 +123,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: BroadcastRoundScreen(broadcast: _liveBroadcast), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveBroadcastClient(), ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveBroadcastClient(), ref), + ), + }, ); await tester.pumpWidget(app); @@ -145,9 +153,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: BroadcastRoundScreen(broadcast: _liveBroadcast), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveBroadcastClient(), ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveBroadcastClient(), ref), + ), + }, ); await tester.pumpWidget(app); @@ -193,9 +203,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: BroadcastRoundScreen(broadcast: _upcomingBroadcast), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_upcomingBroadcastClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_upcomingBroadcastClient, ref), + ), + }, ); await tester.pumpWidget(app); @@ -232,9 +244,11 @@ void main() { broadcast: _liveBroadcast, initialTab: BroadcastRoundTab.players, ), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveBroadcastClient(), ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveBroadcastClient(), ref), + ), + }, ); await tester.pumpWidget(app); @@ -265,9 +279,11 @@ void main() { broadcast: _liveBroadcast, initialTab: BroadcastRoundTab.players, ), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveBroadcastClient(), ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveBroadcastClient(), ref), + ), + }, ); await tester.pumpWidget(app); @@ -312,9 +328,11 @@ void main() { broadcast: _liveBroadcast, initialTab: BroadcastRoundTab.players, ), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveBroadcastClient(), ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveBroadcastClient(), ref), + ), + }, ); await tester.pumpWidget(app); @@ -362,9 +380,11 @@ void main() { broadcast: _liveBroadcast, initialTab: BroadcastRoundTab.players, ), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveBroadcastClient(), ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveBroadcastClient(), ref), + ), + }, ); await tester.pumpWidget(app); @@ -412,11 +432,11 @@ void main() { broadcast: _liveBroadcast, initialTab: BroadcastRoundTab.players, ), - overrides: [ - lichessClientProvider.overrideWith( + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( (ref) => LichessClient(_liveBroadcastClient(withPlayerScores: false), ref), ), - ], + }, ); await tester.pumpWidget(app); @@ -462,9 +482,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: BroadcastRoundScreen(broadcast: _liveTeamBroadcast), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveTeamBroadcastClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveTeamBroadcastClient, ref), + ), + }, ); await tester.pumpWidget(app); @@ -489,9 +511,11 @@ void main() { broadcast: _liveTeamBroadcast, initialTab: BroadcastRoundTab.teams, ), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(_liveTeamBroadcastClient, ref)), - ], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(_liveTeamBroadcastClient, ref), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/broadcast/broadcast_search_screen_test.dart b/test/view/broadcast/broadcast_search_screen_test.dart index 4c7dc6032..76ee582a6 100644 --- a/test/view/broadcast/broadcast_search_screen_test.dart +++ b/test/view/broadcast/broadcast_search_screen_test.dart @@ -29,7 +29,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const BroadcastSearchScreen(), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -53,7 +57,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const BroadcastSearchScreen(), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/engine/test_engine_app.dart b/test/view/engine/test_engine_app.dart index 485f2fd10..2ba1933df 100644 --- a/test/view/engine/test_engine_app.dart +++ b/test/view/engine/test_engine_app.dart @@ -61,9 +61,9 @@ Future makeEngineTestApp( .toJson(), ), }, - overrides: [ + overrides: { if (gameId != null) - lichessClientProvider.overrideWith((ref) { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { final client = MockClient((request) { if (request.url.path == '/game/export/$gameId' && gameResponses.containsKey(gameId)) { return mockResponse(gameResponses[gameId]!, 200); @@ -74,7 +74,7 @@ Future makeEngineTestApp( return LichessClient(client, ref); }) else if (broadcastGame != null) - lichessClientProvider.overrideWith((ref) { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { final client = MockClient((request) { if (request.url.path == '/api/broadcast/-/-/${broadcastGame.$2}') { return mockResponse( @@ -95,7 +95,7 @@ Future makeEngineTestApp( return LichessClient(client, ref); }), - webSocketChannelFactoryProvider.overrideWith( + webSocketChannelFactoryProvider: webSocketChannelFactoryProvider.overrideWith( (_) => FakeWebSocketChannelFactory( (uri) => FakeWebSocketChannel( uri, @@ -122,7 +122,7 @@ Future makeEngineTestApp( ), ), ), - ], + }, home: broadcastGame != null ? BroadcastGameScreen( tournamentId: broadcastGame.$1, diff --git a/test/view/explorer/explorer_view_test.dart b/test/view/explorer/explorer_view_test.dart index f2d86965e..91d768379 100644 --- a/test/view/explorer/explorer_view_test.dart +++ b/test/view/explorer/explorer_view_test.dart @@ -39,7 +39,7 @@ void main() { isComputerAnalysisAllowed: true, ), ), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, ); await tester.pumpWidget(app); @@ -64,7 +64,7 @@ void main() { isComputerAnalysisAllowed: true, ), ), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, ); await tester.pumpWidget(app); @@ -89,7 +89,7 @@ void main() { isComputerAnalysisAllowed: true, ), ), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, ); await tester.pumpWidget(app); @@ -112,7 +112,7 @@ void main() { isComputerAnalysisAllowed: true, ), ), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, ); await tester.pumpWidget(app); @@ -142,7 +142,7 @@ void main() { isComputerAnalysisAllowed: true, ), ), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, ); await tester.pumpWidget(app); @@ -165,7 +165,7 @@ void main() { isComputerAnalysisAllowed: true, ), ), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, ); await tester.pumpWidget(app); diff --git a/test/view/explorer/opening_explorer_screen_test.dart b/test/view/explorer/opening_explorer_screen_test.dart index f50ee0f68..fa46a6b53 100644 --- a/test/view/explorer/opening_explorer_screen_test.dart +++ b/test/view/explorer/opening_explorer_screen_test.dart @@ -57,7 +57,7 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const OpeningExplorerScreen(options: options), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, ); await tester.pumpWidget(app); @@ -92,7 +92,7 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const OpeningExplorerScreen(options: options), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, defaultPreferences: { SessionPreferencesStorage.key(PrefCategory.openingExplorer.storageKey, null): jsonEncode( OpeningExplorerPrefs.defaults().copyWith(db: OpeningDatabase.lichess).toJson(), @@ -129,7 +129,7 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const OpeningExplorerScreen(options: options), - overrides: [defaultClientProvider.overrideWithValue(mockClient)], + overrides: {defaultClientProvider: defaultClientProvider.overrideWithValue(mockClient)}, userSession: session, defaultPreferences: { SessionPreferencesStorage.key( diff --git a/test/view/game/game_screen_test.dart b/test/view/game/game_screen_test.dart index 22c862982..c0347cae0 100644 --- a/test/view/game/game_screen_test.dart +++ b/test/view/game/game_screen_test.dart @@ -5,7 +5,7 @@ import 'package:dartchess/dartchess.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_riverpod/misc.dart' show Override, ProviderOrFamily; import 'package:flutter_test/flutter_test.dart'; import 'package:http/testing.dart'; import 'package:lichess_mobile/src/model/account/account_preferences.dart'; @@ -53,7 +53,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const GameScreen(source: ExistingGameSource(testGameFullId)), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -104,7 +108,11 @@ void main() { GameSeek(clock: (Duration(minutes: 3), Duration(seconds: 2)), rated: true), ), ), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -385,7 +393,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const GameScreen(source: ExistingGameSource(GameFullId('qVChCOTcHSeW'))), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); // Wait for game screen to load @@ -407,7 +419,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const GameScreen(source: ExistingGameSource(GameFullId('qVChCOTcHSeW'))), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); // Wait for game screen to load @@ -621,7 +637,9 @@ void main() { black: Duration(minutes: 3), emerg: Duration(seconds: 30), ), - overrides: [soundServiceProvider.overrideWith((_) => mockSoundService)], + overrides: { + soundServiceProvider: soundServiceProvider.overrideWith((_) => mockSoundService), + }, ); expect( tester.widget(findClockWithTime(Side.white, '0:40')).emergencyThreshold, @@ -741,7 +759,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const GameScreen(source: ExistingGameSource(gameFullId)), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(mockClient, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(mockClient, ref), + ), + }, ); await tester.pumpWidget(app); await tester.pump(const Duration(milliseconds: 10)); @@ -806,7 +828,9 @@ void main() { await createTestGame( tester, pgn: 'e4 e5', - overrides: [soundServiceProvider.overrideWith((_) => mockSoundService)], + overrides: { + soundServiceProvider: soundServiceProvider.overrideWith((_) => mockSoundService), + }, ); sendServerSocketMessages(testGameSocketUri, [ '{"t":"message","d":{"u":"Steven","t":"Hello!"}}', @@ -826,7 +850,9 @@ void main() { tester, pgn: 'e4 e5', defaultPreferences: {PrefCategory.game.storageKey: '{"enableChat": false}'}, - overrides: [soundServiceProvider.overrideWith((_) => mockSoundService)], + overrides: { + soundServiceProvider: soundServiceProvider.overrideWith((_) => mockSoundService), + }, ); sendServerSocketMessages(testGameSocketUri, [ '{"t":"message","d":{"u":"Steven","t":"Hello!"}}', @@ -939,7 +965,7 @@ Future createTestGame( ), FullEventTestCorrespondenceClock? correspondenceClock, Map? defaultPreferences, - List? overrides, + Map? overrides, TournamentMeta? tournament, ServerGamePrefs? serverPrefs, @@ -952,15 +978,17 @@ Future createTestGame( tester, home: const GameScreen(source: ExistingGameSource(gameFullId)), defaultPreferences: defaultPreferences, - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(client, ref)), + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), if (socketFactory != null) - webSocketChannelFactoryProvider.overrideWith((ref) { + webSocketChannelFactoryProvider: webSocketChannelFactoryProvider.overrideWith((ref) { ref.onDispose(socketFactory.dispose); return socketFactory; }), ...?overrides, - ], + }, ); await tester.pumpWidget(app); await tester.pump(const Duration(milliseconds: 10)); @@ -987,7 +1015,7 @@ Future createTestGame( Future loadFinishedTestGame( WidgetTester tester, { String serverFullEvent = _finishedGameFullEvent, - List? overrides, + Map? overrides, }) async { final json = jsonDecode(serverFullEvent) as Map; final gameId = GameFullEvent.fromJson(json['d'] as Map).game.id; @@ -995,10 +1023,12 @@ Future loadFinishedTestGame( final app = await makeTestProviderScopeApp( tester, home: GameScreen(source: ExistingGameSource(gameFullId)), - overrides: [ - lichessClientProvider.overrideWith((ref) => LichessClient(client, ref)), + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), ...?overrides, - ], + }, ); await tester.pumpWidget(app); await tester.pump(const Duration(milliseconds: 10)); diff --git a/test/view/home/home_tab_screen_test.dart b/test/view/home/home_tab_screen_test.dart index 9f3a4ed2b..aaa378704 100644 --- a/test/view/home/home_tab_screen_test.dart +++ b/test/view/home/home_tab_screen_test.dart @@ -58,8 +58,8 @@ void main() { tester, child: const Application(), userSession: fakeSession, - overrides: [ - httpClientFactoryProvider.overrideWith( + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( (ref) => FakeHttpClientFactory( () => MockClient((request) { if (request.url.path == '/api/challenge') { @@ -72,7 +72,7 @@ void main() { }), ), ), - ], + }, ); await tester.pumpWidget(app); @@ -127,9 +127,11 @@ void main() { tester, child: const Application(), userSession: fakeSession, - overrides: [ - httpClientFactoryProvider.overrideWith((ref) => FakeHttpClientFactory(() => mockClient)), - ], + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( + (ref) => FakeHttpClientFactory(() => mockClient), + ), + }, ); await tester.pumpWidget(app); // wait for connectivity @@ -151,9 +153,11 @@ void main() { final app = await makeTestProviderScope( tester, child: const Application(), - overrides: [ - httpClientFactoryProvider.overrideWith((ref) => FakeHttpClientFactory(() => mockClient)), - ], + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( + (ref) => FakeHttpClientFactory(() => mockClient), + ), + }, ); await tester.pumpWidget(app); @@ -189,9 +193,11 @@ void main() { tester, child: const Application(), userSession: fakeSession, - overrides: [ - httpClientFactoryProvider.overrideWith((ref) => FakeHttpClientFactory(() => mockClient)), - ], + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( + (ref) => FakeHttpClientFactory(() => mockClient), + ), + }, ); await tester.pumpWidget(app); // wait for connectivity @@ -221,9 +227,11 @@ void main() { tester, child: const Application(), userSession: fakeSession, - overrides: [ - httpClientFactoryProvider.overrideWith((ref) => FakeHttpClientFactory(() => mockClient)), - ], + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith( + (ref) => FakeHttpClientFactory(() => mockClient), + ), + }, ); await tester.pumpWidget(app); // wait for connectivity diff --git a/test/view/puzzle/puzzle_history_screen_test.dart b/test/view/puzzle/puzzle_history_screen_test.dart index d6e2278a3..b2d9f96ba 100644 --- a/test/view/puzzle/puzzle_history_screen_test.dart +++ b/test/view/puzzle/puzzle_history_screen_test.dart @@ -53,11 +53,11 @@ void main() { tester, home: const PuzzleHistoryScreen(), userSession: fakeSession, - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(makeClient(4), ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -79,11 +79,11 @@ void main() { tester, home: const PuzzleHistoryScreen(), userSession: fakeSession, - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(makeClient(80), ref); }), - ], + }, ); await tester.pumpWidget(app); diff --git a/test/view/puzzle/puzzle_screen_test.dart b/test/view/puzzle/puzzle_screen_test.dart index 2ffb6af86..998af6fb6 100644 --- a/test/view/puzzle/puzzle_screen_test.dart +++ b/test/view/puzzle/puzzle_screen_test.dart @@ -68,10 +68,12 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: puzzle.puzzle.id, ), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - ], + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + }, ); when( @@ -98,10 +100,12 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: puzzle.puzzle.id, ), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - ], + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + }, ); when( @@ -121,10 +125,12 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const PuzzleScreen(angle: PuzzleTheme(PuzzleThemeKey.mix)), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - ], + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + }, ); when( @@ -165,15 +171,15 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: puzzle2.puzzle.id, ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - puzzleBatchStorageProvider.overrideWith((ref) { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith((ref) { return mockBatchStorage; }), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - ], + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + }, ); Future saveDBReq() => mockBatchStorage.save( @@ -270,18 +276,18 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: puzzle2.puzzle.id, ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - puzzleBatchStorageProvider.overrideWith((ref) { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith((ref) { return mockBatchStorage; }), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - showRatingsPrefProvider.overrideWith((ref) { + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + showRatingsPrefProvider: showRatingsPrefProvider.overrideWith((ref) { return showRatings; }), - ], + }, ); when(() => mockHistoryStorage.save(puzzle: any(named: 'puzzle'))).thenAnswer((_) async {}); @@ -368,15 +374,15 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: puzzle2.puzzle.id, ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - puzzleBatchStorageProvider.overrideWith((ref) { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith((ref) { return mockBatchStorage; }), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - ], + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + }, ); when( @@ -466,16 +472,20 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: puzzle2.puzzle.id, ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - puzzlePreferencesProvider.overrideWith( + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + puzzleStorageProvider: puzzleStorageProvider.overrideWith( + (ref) => mockHistoryStorage, + ), + puzzlePreferencesProvider: puzzlePreferencesProvider.overrideWith( () => MockPuzzlePreferences(isRatedPreference), ), - ], + }, userSession: fakeSession, ); @@ -538,14 +548,18 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: puzzle2.puzzle.id, ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - puzzlePreferencesProvider.overrideWith(() => MockPuzzlePreferences(true)), - ], + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + puzzlePreferencesProvider: puzzlePreferencesProvider.overrideWith( + () => MockPuzzlePreferences(true), + ), + }, userSession: fakeSession, ); @@ -639,13 +653,15 @@ void main() { puzzleId: puzzle2.puzzle.id, openCasual: true, ), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - ], + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + }, userSession: fakeSession, ); @@ -738,10 +754,12 @@ void main() { angle: const PuzzleTheme(PuzzleThemeKey.mix), puzzleId: buggyPuzzle.puzzle.id, ), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), - ], + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + puzzleStorageProvider: puzzleStorageProvider.overrideWith((ref) => mockHistoryStorage), + }, ); when( diff --git a/test/view/puzzle/puzzle_tab_screen_test.dart b/test/view/puzzle/puzzle_tab_screen_test.dart index f68ac2b4d..209c31846 100644 --- a/test/view/puzzle/puzzle_tab_screen_test.dart +++ b/test/view/puzzle/puzzle_tab_screen_test.dart @@ -52,7 +52,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const PuzzleTabScreen(), - overrides: [puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage)], + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + }, ); await tester.pumpWidget(app); @@ -80,13 +84,15 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const PuzzleTabScreen(), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - savedStreakScoreProvider.overrideWith((ref) => 123), - ], + savedStreakScoreProvider: savedStreakScoreProvider.overrideWith((ref) => 123), + }, ); await tester.pumpWidget(app); @@ -108,12 +114,14 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const PuzzleTabScreen(), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - ], + }, ); await tester.pumpWidget(app); @@ -140,12 +148,14 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const PuzzleTabScreen(), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - ], + }, ); await tester.pumpWidget(app); @@ -195,12 +205,14 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const PuzzleTabScreen(), - overrides: [ - puzzleBatchStorageProvider.overrideWith((ref) => mockBatchStorage), - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + puzzleBatchStorageProvider: puzzleBatchStorageProvider.overrideWith( + (ref) => mockBatchStorage, + ), + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - ], + }, ); await tester.pumpWidget(app); @@ -237,15 +249,15 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const PuzzleTabScreen(), - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - databaseProvider.overrideWith((ref) { + databaseProvider: databaseProvider.overrideWith((ref) { ref.onDispose(testDb.close); return testDb; }), - ], + }, ); await tester.pumpWidget(app); diff --git a/test/view/puzzle/storm_screen_test.dart b/test/view/puzzle/storm_screen_test.dart index 679eb5ddf..9e43f0267 100644 --- a/test/view/puzzle/storm_screen_test.dart +++ b/test/view/puzzle/storm_screen_test.dart @@ -29,10 +29,12 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StormScreen(), - overrides: [ - stormProvider.overrideWith((ref) => mockStromRun), - lichessClientProvider.overrideWith((ref) => LichessClient(client, ref)), - ], + overrides: { + stormProvider: stormProvider.overrideWith((ref) => mockStromRun), + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -45,10 +47,12 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StormScreen(), - overrides: [ - stormProvider.overrideWith((ref) => mockStromRun), - lichessClientProvider.overrideWith((ref) => LichessClient(client, ref)), - ], + overrides: { + stormProvider: stormProvider.overrideWith((ref) => mockStromRun), + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -61,10 +65,12 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StormScreen(), - overrides: [ - stormProvider.overrideWith((ref) => mockStromRun), - lichessClientProvider.overrideWith((ref) => LichessClient(client, ref)), - ], + overrides: { + stormProvider: stormProvider.overrideWith((ref) => mockStromRun), + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -99,10 +105,12 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StormScreen(), - overrides: [ - stormProvider.overrideWith((ref) => mockStromRun), - lichessClientProvider.overrideWith((ref) => LichessClient(client, ref)), - ], + overrides: { + stormProvider: stormProvider.overrideWith((ref) => mockStromRun), + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -129,10 +137,12 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StormScreen(), - overrides: [ - stormProvider.overrideWith((ref) => mockStromRun), - lichessClientProvider.overrideWith((ref) => LichessClient(client, ref)), - ], + overrides: { + stormProvider: stormProvider.overrideWith((ref) => mockStromRun), + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/puzzle/streak_screen_test.dart b/test/view/puzzle/streak_screen_test.dart index 0d5ce8152..4f00ea879 100644 --- a/test/view/puzzle/streak_screen_test.dart +++ b/test/view/puzzle/streak_screen_test.dart @@ -211,7 +211,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StreakScreen(), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -235,7 +239,11 @@ void main() { ), ), ), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/relation/friend_screen_test.dart b/test/view/relation/friend_screen_test.dart index 9b0bd3618..5c765a7ea 100644 --- a/test/view/relation/friend_screen_test.dart +++ b/test/view/relation/friend_screen_test.dart @@ -97,12 +97,14 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const FriendScreen(), - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - onlineFriendsProvider.overrideWith(() => _MockOnlineFriends(const IList.empty())), - ], + onlineFriendsProvider: onlineFriendsProvider.overrideWith( + () => _MockOnlineFriends(const IList.empty()), + ), + }, ); await tester.pumpWidget(app); @@ -127,12 +129,14 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const FriendScreen(), - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - onlineFriendsProvider.overrideWith(() => _MockOnlineFriends(const IList.empty())), - ], + onlineFriendsProvider: onlineFriendsProvider.overrideWith( + () => _MockOnlineFriends(const IList.empty()), + ), + }, ); await tester.pumpWidget(app); @@ -174,18 +178,18 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const FriendScreen(), - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - onlineFriendsProvider.overrideWith( + onlineFriendsProvider: onlineFriendsProvider.overrideWith( () => _MockOnlineFriends( IList(const [ (user: LightUser(id: UserId('testuser'), name: 'TestUser'), playing: false), ]), ), ), - ], + }, ); await tester.pumpWidget(app); @@ -213,12 +217,14 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const FriendScreen(), - overrides: [ - httpClientFactoryProvider.overrideWith((ref) { + overrides: { + httpClientFactoryProvider: httpClientFactoryProvider.overrideWith((ref) { return FakeHttpClientFactory(() => mockClient); }), - onlineFriendsProvider.overrideWith(() => _MockOnlineFriends(const IList.empty())), - ], + onlineFriendsProvider: onlineFriendsProvider.overrideWith( + () => _MockOnlineFriends(const IList.empty()), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/study/study_list_screen_test.dart b/test/view/study/study_list_screen_test.dart index 028b102fe..1f03e788a 100644 --- a/test/view/study/study_list_screen_test.dart +++ b/test/view/study/study_list_screen_test.dart @@ -28,11 +28,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyListScreen(), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -98,11 +98,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyListScreen(), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); diff --git a/test/view/study/study_screen_test.dart b/test/view/study/study_screen_test.dart index 5f734099c..b9e2079ca 100644 --- a/test/view/study/study_screen_test.dart +++ b/test/view/study/study_screen_test.dart @@ -83,7 +83,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, defaultPreferences: { PrefCategory.study.storageKey: jsonEncode( StudyPrefs.defaults.copyWith(inlineNotation: true).toJson(), @@ -133,7 +135,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, ); await tester.pumpWidget(app); // Wait for study to load @@ -204,7 +208,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, defaultPreferences: { PrefCategory.study.storageKey: jsonEncode( StudyPrefs.defaults.copyWith(inlineNotation: true).toJson(), @@ -266,7 +272,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, ); await tester.pumpWidget(app); // Wait for study to load @@ -397,7 +405,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, ); await tester.pumpWidget(app); // Wait for study to load @@ -506,7 +516,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, ); await tester.pumpWidget(app); @@ -576,7 +588,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, ); await tester.pumpWidget(app); // Wait for study to load @@ -662,7 +676,9 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const StudyScreen(id: testId), - overrides: [studyRepositoryProvider.overrideWith((ref) => mockRepository)], + overrides: { + studyRepositoryProvider: studyRepositoryProvider.overrideWith((ref) => mockRepository), + }, ); await tester.pumpWidget(app); // Wait for study to load diff --git a/test/view/tournament/tournament_list_screen_test.dart b/test/view/tournament/tournament_list_screen_test.dart index 6a1faf231..cb4ef5919 100644 --- a/test/view/tournament/tournament_list_screen_test.dart +++ b/test/view/tournament/tournament_list_screen_test.dart @@ -19,11 +19,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const TournamentListScreen(), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); diff --git a/test/view/tournament/tournament_screen_test.dart b/test/view/tournament/tournament_screen_test.dart index 2fcde2b10..73e8f4980 100644 --- a/test/view/tournament/tournament_screen_test.dart +++ b/test/view/tournament/tournament_screen_test.dart @@ -218,11 +218,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const TournamentScreen(id: TournamentId('82QbxlJb')), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -254,11 +254,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const TournamentScreen(id: TournamentId('82QbxlJb')), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -314,11 +314,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const TournamentScreen(id: tournamentId), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -388,11 +388,11 @@ void main() { tester, home: const TournamentScreen(id: tournamentId), userSession: session, - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -437,11 +437,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const TournamentScreen(id: TournamentId('82QbxlJb')), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -480,11 +480,11 @@ void main() { tester, home: const TournamentScreen(id: tournamentId), userSession: session, - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -541,11 +541,11 @@ void main() { tester, home: const TournamentScreen(id: tournamenId), userSession: session, - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -583,11 +583,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const TournamentScreen(id: TournamentId('82QbxlJb')), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(mockClient, ref); }), - ], + }, ); await tester.pumpWidget(app); diff --git a/test/view/user/leaderboard_screen_test.dart b/test/view/user/leaderboard_screen_test.dart index 70e18efd3..8ff6cd527 100644 --- a/test/view/user/leaderboard_screen_test.dart +++ b/test/view/user/leaderboard_screen_test.dart @@ -21,7 +21,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, home: const LeaderboardScreen(), ); diff --git a/test/view/user/perf_stats_screen_test.dart b/test/view/user/perf_stats_screen_test.dart index eb2606a72..35f7f09ed 100644 --- a/test/view/user/perf_stats_screen_test.dart +++ b/test/view/user/perf_stats_screen_test.dart @@ -28,11 +28,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: PerfStatsScreen(user: fakeUser, perf: testPerf), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(client, ref); }), - ], + }, ); await tester.pumpWidget(app); @@ -53,11 +53,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: PerfStatsScreen(user: fakeUser, perf: testPerf), - overrides: [ - lichessClientProvider.overrideWith((ref) { + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith((ref) { return LichessClient(client, ref); }), - ], + }, ); await tester.pumpWidget(app); diff --git a/test/view/user/search_screen_test.dart b/test/view/user/search_screen_test.dart index cc9f89c71..344219e87 100644 --- a/test/view/user/search_screen_test.dart +++ b/test/view/user/search_screen_test.dart @@ -24,7 +24,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const SearchScreen(), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); @@ -55,7 +59,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const SearchScreen(), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app); diff --git a/test/view/user/user_screen_test.dart b/test/view/user/user_screen_test.dart index d7e8fb94a..d0c184a83 100644 --- a/test/view/user/user_screen_test.dart +++ b/test/view/user/user_screen_test.dart @@ -21,7 +21,11 @@ void main() { final app = await makeTestProviderScopeApp( tester, home: const UserScreen(user: testUser), - overrides: [lichessClientProvider.overrideWith((ref) => LichessClient(client, ref))], + overrides: { + lichessClientProvider: lichessClientProvider.overrideWith( + (ref) => LichessClient(client, ref), + ), + }, ); await tester.pumpWidget(app);