From e2015889ce38f9c030bc9d5bda93818a21c99834 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Fri, 16 Feb 2024 13:57:31 -0500 Subject: [PATCH 01/15] first draft infinite scroll --- lib/core/managers/news_repository.dart | 18 +++++- lib/core/viewmodels/news_viewmodel.dart | 3 + lib/ui/views/news_view.dart | 75 +++++++++++++++++++++---- pubspec.lock | 22 ++++++-- pubspec.yaml | 9 +-- 5 files changed, 105 insertions(+), 22 deletions(-) diff --git a/lib/core/managers/news_repository.dart b/lib/core/managers/news_repository.dart index 2bcfcb5d8..34fca364c 100644 --- a/lib/core/managers/news_repository.dart +++ b/lib/core/managers/news_repository.dart @@ -56,6 +56,14 @@ class NewsRepository { image: "https://picsum.photos/400/200", tags: ["tag1", "tag2"], ), + News( + id: 4, + title: "Test 4", + description: "Test 4 description", + date: DateTime.now(), + image: "https://picsum.photos/400/200", + tags: ["tag1", "tag2"], + ), ]; List? get news => _news; @@ -63,7 +71,11 @@ class NewsRepository { /// Get and update the list of news. /// After fetching the news from the [?] the [CacheManager] /// is updated with the latest version of the news. - Future?> getNews({bool fromCacheOnly = false}) async { + Future?> getNews( + {int pageNumber = 1, + int pageSize = 20, + bool fromCacheOnly = false}) async { + await Future.delayed(const Duration(seconds: 1)); // Force fromCacheOnly mode when user has no connectivity if (!(await _networkingService.hasConnectivity())) { // ignore: parameter_assignments @@ -79,7 +91,7 @@ class NewsRepository { return _news; } - final List fetchedNews = fetchNewsFromAPI(); + final List fetchedNews = fetchNewsFromAPI(pageNumber, pageSize); _news ??= []; @@ -122,7 +134,7 @@ class NewsRepository { } // TODO : Fetch news from the API - List fetchNewsFromAPI() { + List fetchNewsFromAPI(int pageNumber, int pageSize) { final List fetchedNews = []; _logger.d("$tag - getNews: fetched ${fetchedNews.length} news."); diff --git a/lib/core/viewmodels/news_viewmodel.dart b/lib/core/viewmodels/news_viewmodel.dart index 30544e7be..bf9d1735d 100644 --- a/lib/core/viewmodels/news_viewmodel.dart +++ b/lib/core/viewmodels/news_viewmodel.dart @@ -1,6 +1,7 @@ // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:stacked/stacked.dart'; // Project imports: @@ -9,6 +10,8 @@ import 'package:notredame/core/models/news.dart'; import 'package:notredame/locator.dart'; class NewsViewModel extends FutureViewModel> { + static const _pageSize = 20; + /// Load the events final NewsRepository _newsRepository = locator(); diff --git a/lib/ui/views/news_view.dart b/lib/ui/views/news_view.dart index a04297aea..718a05503 100644 --- a/lib/ui/views/news_view.dart +++ b/lib/ui/views/news_view.dart @@ -3,7 +3,11 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:notredame/core/managers/news_repository.dart'; +import 'package:notredame/core/models/news.dart'; +import 'package:notredame/locator.dart'; import 'package:stacked/stacked.dart'; +import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; // Project imports: import 'package:notredame/core/viewmodels/news_viewmodel.dart'; @@ -16,36 +20,87 @@ class NewsView extends StatefulWidget { } class _NewsViewState extends State { - int nbSkeletons = 3; + static const int _nbSkeletons = 3; + static const _pageSize = 3; + + final NewsRepository _newsRepository = locator(); + + final PagingController pagingController = + PagingController(firstPageKey: 1); @override void initState() { + pagingController.addPageRequestListener((pageKey) { + fetchPage(pageKey); + }); + pagingController.addStatusListener((status) { + if (status == PagingStatus.subsequentPageError) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text( + 'Something went wrong while fetching a new page.', + ), + action: SnackBarAction( + label: 'Retry', + onPressed: () => pagingController.retryLastFailedRequest(), + ), + ), + ); + } + }); super.initState(); } + Future fetchPage(int pageNumber) async { + try { + final newItems = await _newsRepository.getNews( + pageNumber: pageNumber, fromCacheOnly: true) ?? + []; + final isLastPage = newItems.length < _pageSize; + if (isLastPage) { + pagingController.appendLastPage(newItems); + } else { + final nextPageKey = pageNumber + newItems.length; + pagingController.appendPage(newItems, nextPageKey); + } + } catch (error) { + pagingController.error = error; + } + } + @override Widget build(BuildContext context) => ViewModelBuilder.reactive( viewModelBuilder: () => NewsViewModel(intl: AppIntl.of(context)!), builder: (context, model, child) { return RefreshIndicator( - onRefresh: model.refresh, + onRefresh: () => Future.sync( + () => pagingController.refresh(), + ), child: Theme( data: Theme.of(context) .copyWith(canvasColor: Colors.transparent), - child: model.isLoadingEvents - ? _buildSkeletonLoader() - : ListView( - padding: const EdgeInsets.fromLTRB(0, 4, 0, 8), - children: - model.news.map((news) => NewsCard(news)).toList(), - ), + child: PagedListView( + pagingController: pagingController, + padding: const EdgeInsets.fromLTRB(0, 4, 0, 8), + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (context, item, index) => NewsCard(item), + firstPageProgressIndicatorBuilder: (context) => + _buildSkeletonLoader(), + newPageProgressIndicatorBuilder: (context) => + NewsCardSkeleton(), + noItemsFoundIndicatorBuilder: (_) => + NoItemsFoundIndicator(), + noMoreItemsIndicatorBuilder: (_) => + NoMoreItemsIndicator(), + ), + ), )); }); Widget _buildSkeletonLoader() { return ListView.builder( - itemCount: nbSkeletons, + itemCount: _nbSkeletons, itemBuilder: (context, index) => NewsCardSkeleton(), ); } diff --git a/pubspec.lock b/pubspec.lock index fa729ac83..6322190ec 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -284,11 +284,9 @@ packages: ets_api_clients: dependency: "direct main" description: - path: "." - ref: "0.5.0" - resolved-ref: cefaa19955323ce4790b64aa45c598925df71109 - url: "https://github.com/ApplETS/ETS-API-Clients.git" - source: git + path: "../ETS-API-Clients" + relative: true + source: path version: "0.5.0" fading_edge_scrollview: dependency: transitive @@ -709,6 +707,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.4" + infinite_scroll_pagination: + dependency: "direct main" + description: + name: infinite_scroll_pagination + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.0" intl: dependency: transitive description: @@ -1134,6 +1139,13 @@ packages: description: flutter source: sdk version: "0.0.99" + sliver_tools: + dependency: transitive + description: + name: sliver_tools + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.12" source_gen: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5910f8ab4..472bc2042 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,10 +42,10 @@ dependencies: # Customs ets_api_clients: - # path: ../ETS-API-Clients/ - git: - url: https://github.com/ApplETS/ETS-API-Clients.git - ref: 0.5.0 + path: ../ETS-API-Clients/ + # git: + # url: https://github.com/ApplETS/ETS-API-Clients.git + # ref: 0.5.0 # Other http: ^0.13.4 @@ -77,6 +77,7 @@ dependencies: import_sorter: ^4.6.0 flutter_keychain: ^2.4.0 shimmer: ^3.0.0 + infinite_scroll_pagination: ^3.2.0 dev_dependencies: flutter_test: From e25369b0c398c977e7a695988694c2f0b037f7de Mon Sep 17 00:00:00 2001 From: Samuel Montambault Date: Sun, 18 Feb 2024 23:50:36 -0500 Subject: [PATCH 02/15] fix infinite scroll --- lib/core/viewmodels/news_viewmodel.dart | 19 +------------------ lib/ui/views/news_view.dart | 12 ++++-------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/lib/core/viewmodels/news_viewmodel.dart b/lib/core/viewmodels/news_viewmodel.dart index bf9d1735d..eeada6c0c 100644 --- a/lib/core/viewmodels/news_viewmodel.dart +++ b/lib/core/viewmodels/news_viewmodel.dart @@ -9,9 +9,7 @@ import 'package:notredame/core/managers/news_repository.dart'; import 'package:notredame/core/models/news.dart'; import 'package:notredame/locator.dart'; -class NewsViewModel extends FutureViewModel> { - static const _pageSize = 20; - +class NewsViewModel extends BaseViewModel { /// Load the events final NewsRepository _newsRepository = locator(); @@ -35,21 +33,6 @@ class NewsViewModel extends FutureViewModel> { bool isLoadingEvents = false; - @override - Future> futureToRun() async { - try { - setBusyForObject(isLoadingEvents, true); - _news = await _newsRepository.getNews(fromCacheOnly: true); - notifyListeners(); - } catch (e) { - onError(e); - } finally { - setBusyForObject(isLoadingEvents, false); - } - - return news; - } - @override // ignore: type_annotate_public_apis void onError(error) { diff --git a/lib/ui/views/news_view.dart b/lib/ui/views/news_view.dart index 718a05503..46e096af8 100644 --- a/lib/ui/views/news_view.dart +++ b/lib/ui/views/news_view.dart @@ -89,19 +89,15 @@ class _NewsViewState extends State { _buildSkeletonLoader(), newPageProgressIndicatorBuilder: (context) => NewsCardSkeleton(), - noItemsFoundIndicatorBuilder: (_) => - NoItemsFoundIndicator(), - noMoreItemsIndicatorBuilder: (_) => - NoMoreItemsIndicator(), ), ), )); }); Widget _buildSkeletonLoader() { - return ListView.builder( - itemCount: _nbSkeletons, - itemBuilder: (context, index) => NewsCardSkeleton(), - ); + final Widget skeleton = NewsCardSkeleton(); + return Column(children: [ + for (var i = 0; i < _nbSkeletons; i++) skeleton, + ]); } } From 3ffb4364b0cacda2b1bc20e26a5ea14c95e52a84 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Mon, 26 Feb 2024 14:01:57 -0500 Subject: [PATCH 03/15] petit fix pour mon bibi pref --- lib/core/managers/news_repository.dart | 65 +++++++++------------ lib/core/models/news.dart | 40 ------------- lib/core/viewmodels/news_viewmodel.dart | 3 +- lib/core/viewmodels/schedule_viewmodel.dart | 4 +- lib/locator.dart | 1 + lib/ui/views/news_view.dart | 2 +- lib/ui/views/schedule_view.dart | 5 +- lib/ui/widgets/news_card.dart | 47 ++++----------- pubspec.yaml | 2 +- 9 files changed, 48 insertions(+), 121 deletions(-) delete mode 100644 lib/core/models/news.dart diff --git a/lib/core/managers/news_repository.dart b/lib/core/managers/news_repository.dart index 34fca364c..be68347f6 100644 --- a/lib/core/managers/news_repository.dart +++ b/lib/core/managers/news_repository.dart @@ -2,14 +2,15 @@ import 'dart:convert'; // Flutter imports: +import 'package:ets_api_clients/clients.dart'; import 'package:flutter/material.dart'; // Package imports: import 'package:logger/logger.dart'; +import 'package:ets_api_clients/models.dart'; // Project imports: import 'package:notredame/core/managers/cache_manager.dart'; -import 'package:notredame/core/models/news.dart'; import 'package:notredame/core/services/networking_service.dart'; import 'package:notredame/core/utils/cache_exception.dart'; import 'package:notredame/locator.dart'; @@ -29,43 +30,31 @@ class NewsRepository { /// Used to verify if the user has connectivity final NetworkingService _networkingService = locator(); - /// List of the news with 3 test news. - List? _news = [ - News( - id: 1, - title: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis.", - description: "Test 1 description", - date: DateTime.now(), - image: "https://picsum.photos/400/200", - tags: ["tag1", "tag2"], - ), - News( - id: 2, - title: "Test 2", - description: "Test 2 description", - date: DateTime.now(), - image: "https://picsum.photos/400/200", - tags: ["tag1", "tag2"], - ), - News( - id: 3, - title: "Test 3", - description: "Test 3 description", - date: DateTime.now(), - image: "https://picsum.photos/400/200", - tags: ["tag1", "tag2"], - ), + final HelloAPIClient _helloApiClient = locator(); + + /// List of the news + List? _news = [ News( - id: 4, - title: "Test 4", - description: "Test 4 description", - date: DateTime.now(), - image: "https://picsum.photos/400/200", - tags: ["tag1", "tag2"], - ), + id: "1", + title: "Annonce #1", + content: "Salut voici un super évènement qui pourrait vous intéressé!", + imageThumbnail: "", + state: 16, + publicationDate: DateTime.now().subtract(const Duration(days: 1)), + eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), + eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), + createdAt: DateTime.now().subtract(const Duration(days: 1)), + updatedAt: DateTime.now().subtract(const Duration(days: 1)), + moderator: NewsUser( + id: "1", + name: "John Doe", + email: "mont.samuel@outlook.com", + type: "moderator", + createdAt: DateTime.now().subtract(const Duration(days: 1)), + updatedAt: DateTime.now().subtract(const Duration(days: 1)), + ), + organizer: organizer) ]; - List? get news => _news; /// Get and update the list of news. @@ -75,7 +64,6 @@ class NewsRepository { {int pageNumber = 1, int pageSize = 20, bool fromCacheOnly = false}) async { - await Future.delayed(const Duration(seconds: 1)); // Force fromCacheOnly mode when user has no connectivity if (!(await _networkingService.hasConnectivity())) { // ignore: parameter_assignments @@ -91,7 +79,8 @@ class NewsRepository { return _news; } - final List fetchedNews = fetchNewsFromAPI(pageNumber, pageSize); + final List fetchedNews = await _helloApiClient.getEvents( + pageNumber: pageNumber, pageSize: pageSize); _news ??= []; diff --git a/lib/core/models/news.dart b/lib/core/models/news.dart deleted file mode 100644 index b535f72af..000000000 --- a/lib/core/models/news.dart +++ /dev/null @@ -1,40 +0,0 @@ -class News { - final int id; - final String title; - final String description; - final String image; - final List tags; - final DateTime date; - - News({ - required this.id, - required this.title, - required this.description, - required this.image, - required this.tags, - required this.date, - }); - - /// Used to create [News] instance from a JSON file - factory News.fromJson(Map map) { - return News( - id: map['id'] as int, - title: map['title'] as String, - description: map['description'] as String, - image: map['image'] as String, - tags: map['tags'] as List, - date: DateTime.parse(map['date'] as String), - ); - } - - Map toJson() { - return { - 'id': id, - 'title': title, - 'description': description, - 'image': image, - 'tags': tags.toList(), - 'date': date.toString(), - }; - } -} diff --git a/lib/core/viewmodels/news_viewmodel.dart b/lib/core/viewmodels/news_viewmodel.dart index eeada6c0c..a6a38c8c7 100644 --- a/lib/core/viewmodels/news_viewmodel.dart +++ b/lib/core/viewmodels/news_viewmodel.dart @@ -1,12 +1,11 @@ // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:fluttertoast/fluttertoast.dart'; -import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:stacked/stacked.dart'; +import 'package:ets_api_clients/models.dart'; // Project imports: import 'package:notredame/core/managers/news_repository.dart'; -import 'package:notredame/core/models/news.dart'; import 'package:notredame/locator.dart'; class NewsViewModel extends BaseViewModel { diff --git a/lib/core/viewmodels/schedule_viewmodel.dart b/lib/core/viewmodels/schedule_viewmodel.dart index 50a319b9f..e91277b4b 100644 --- a/lib/core/viewmodels/schedule_viewmodel.dart +++ b/lib/core/viewmodels/schedule_viewmodel.dart @@ -171,8 +171,8 @@ class ScheduleViewModel extends FutureViewModel> { bool isLoadingEvents = false; - bool get calendarViewSetting => - settings[PreferencesFlag.scheduleListView] as bool; + bool? get calendarViewSetting => + settings[PreferencesFlag.scheduleListView] as bool?; @override Future> futureToRun() async { diff --git a/lib/locator.dart b/lib/locator.dart index 3f2448107..0776db27d 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -53,5 +53,6 @@ void setupLocator() { // Other locator.registerLazySingleton(() => SignetsAPIClient()); locator.registerLazySingleton(() => MonETSAPIClient()); + locator.registerLazySingleton(() => HelloAPIClient()); locator.registerLazySingleton(() => Logger()); } diff --git a/lib/ui/views/news_view.dart b/lib/ui/views/news_view.dart index 46e096af8..668ae7709 100644 --- a/lib/ui/views/news_view.dart +++ b/lib/ui/views/news_view.dart @@ -1,10 +1,10 @@ // Flutter imports: +import 'package:ets_api_clients/models.dart'; import 'package:flutter/material.dart'; // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:notredame/core/managers/news_repository.dart'; -import 'package:notredame/core/models/news.dart'; import 'package:notredame/locator.dart'; import 'package:stacked/stacked.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; diff --git a/lib/ui/views/schedule_view.dart b/lib/ui/views/schedule_view.dart index c8c35b7c8..b0b0742c7 100644 --- a/lib/ui/views/schedule_view.dart +++ b/lib/ui/views/schedule_view.dart @@ -91,7 +91,8 @@ class _ScheduleViewState extends State actions: _buildActionButtons(model), ), body: RefreshIndicator( - child: !model.calendarViewSetting + child: model.calendarViewSetting == null || + !model.calendarViewSetting! ? _buildCalendarView(model, context) : _buildListView(model, context), onRefresh: () => model.refresh(), @@ -470,7 +471,7 @@ class _ScheduleViewState extends State } List _buildActionButtons(ScheduleViewModel model) => [ - if ((model.settings[PreferencesFlag.scheduleShowTodayBtn] as bool) == + if ((model.settings[PreferencesFlag.scheduleShowTodayBtn] as bool?) == true) IconButton( icon: const Icon(Icons.today), diff --git a/lib/ui/widgets/news_card.dart b/lib/ui/widgets/news_card.dart index 12d8bfa4f..fd8cfd62b 100644 --- a/lib/ui/widgets/news_card.dart +++ b/lib/ui/widgets/news_card.dart @@ -1,13 +1,14 @@ // Flutter imports: import 'package:flutter/material.dart'; +import 'dart:convert'; // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:shimmer/shimmer.dart'; import 'package:timeago/timeago.dart' as timeago; +import 'package:ets_api_clients/models.dart'; // Project imports: -import 'package:notredame/core/models/news.dart'; import 'package:notredame/ui/utils/app_theme.dart'; class NewsCard extends StatefulWidget { @@ -37,7 +38,7 @@ class _NewsCardState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildImage(widget.news.image), + _buildImage(widget.news.imageThumbnail), const SizedBox(height: 8), _buildTitleAndTime(widget.news, context) ], @@ -48,18 +49,20 @@ class _NewsCardState extends State { ); } - Widget _buildImage(String image) { - if (image == "") { + Widget _buildImage(String? image) { + if (image == null || image == "") { return const SizedBox(); } return ClipRRect( borderRadius: BorderRadius.circular(16.0), - child: _isImageLoaded - ? Image.network(image, fit: BoxFit.cover) - : _shimmerEffect(), + child: _imageFromBase64String(image), ); } + Image _imageFromBase64String(String base64String) { + return Image.memory(base64Decode(base64String)); + } + Widget _shimmerEffect() { return Shimmer.fromColors( baseColor: Theme.of(context).brightness == Brightness.light @@ -94,37 +97,11 @@ class _NewsCardState extends State { ), const SizedBox(width: 10), Text( - timeago.format(news.date, locale: AppIntl.of(context)!.localeName), + timeago.format(news.createdAt, + locale: AppIntl.of(context)!.localeName), style: textStyle, ), ], ); } - - @override - void initState() { - super.initState(); - _preloadImage(); - } - - void _preloadImage() { - Image.network(widget.news.image) - .image - // ignore: use_named_constants - .resolve(const ImageConfiguration()) - .addListener( - ImageStreamListener( - (ImageInfo image, bool synchronousCall) { - if (mounted) { - setState(() { - _isImageLoaded = true; - }); - } - }, - onError: (exception, stackTrace) { - // Handle image load error - }, - ), - ); - } } diff --git a/pubspec.yaml b/pubspec.yaml index 472bc2042..c8225f97d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,7 +45,7 @@ dependencies: path: ../ETS-API-Clients/ # git: # url: https://github.com/ApplETS/ETS-API-Clients.git - # ref: 0.5.0 + # ref: ftr/add-news # Other http: ^0.13.4 From be130ff2e85475cb1cc09a79e61fb3999bbbc502 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Mon, 26 Feb 2024 14:04:05 -0500 Subject: [PATCH 04/15] fix organizer --- lib/core/managers/news_repository.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/managers/news_repository.dart b/lib/core/managers/news_repository.dart index be68347f6..8384a00c3 100644 --- a/lib/core/managers/news_repository.dart +++ b/lib/core/managers/news_repository.dart @@ -50,8 +50,8 @@ class NewsRepository { name: "John Doe", email: "mont.samuel@outlook.com", type: "moderator", - createdAt: DateTime.now().subtract(const Duration(days: 1)), - updatedAt: DateTime.now().subtract(const Duration(days: 1)), + createdAt: DateTime.now().add(const Duration(days: 1)), + updatedAt: DateTime.now().add(const Duration(days: 1)), ), organizer: organizer) ]; From b81ef191ecf992d2900bb5148c30362cfdad4df1 Mon Sep 17 00:00:00 2001 From: Samuel Montambault Date: Mon, 26 Feb 2024 16:19:23 -0500 Subject: [PATCH 05/15] fix news --- lib/core/managers/news_repository.dart | 40 +++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/core/managers/news_repository.dart b/lib/core/managers/news_repository.dart index be68347f6..95e129c41 100644 --- a/lib/core/managers/news_repository.dart +++ b/lib/core/managers/news_repository.dart @@ -35,25 +35,33 @@ class NewsRepository { /// List of the news List? _news = [ News( + id: "1", + title: "Annonce #1", + content: "Salut voici un super évènement qui pourrait vous intéressé!", + imageThumbnail: "", + state: 16, + publicationDate: DateTime.now().subtract(const Duration(days: 1)), + eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), + eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), + createdAt: DateTime.now().subtract(const Duration(days: 1)), + updatedAt: DateTime.now().subtract(const Duration(days: 1)), + moderator: NewsUser( id: "1", - title: "Annonce #1", - content: "Salut voici un super évènement qui pourrait vous intéressé!", - imageThumbnail: "", - state: 16, - publicationDate: DateTime.now().subtract(const Duration(days: 1)), - eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), - eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), + name: "John Doe", + email: "mont.samuel@outlook.com", + type: "moderator", createdAt: DateTime.now().subtract(const Duration(days: 1)), updatedAt: DateTime.now().subtract(const Duration(days: 1)), - moderator: NewsUser( - id: "1", - name: "John Doe", - email: "mont.samuel@outlook.com", - type: "moderator", - createdAt: DateTime.now().subtract(const Duration(days: 1)), - updatedAt: DateTime.now().subtract(const Duration(days: 1)), - ), - organizer: organizer) + ), + organizer: NewsUser( + id: "1", + name: "ApplETS", + email: "mont.samuel@outlook.com", + type: "organizer", + createdAt: DateTime.now().subtract(const Duration(days: 1)), + updatedAt: DateTime.now().subtract(const Duration(days: 1)), + ), + ) ]; List? get news => _news; From cde3313be64b5bd0f23dc987272323b5362e9a29 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Tue, 27 Feb 2024 15:36:19 -0500 Subject: [PATCH 06/15] news card --- lib/core/managers/news_repository.dart | 75 ++++++++++++++++++++++++-- lib/ui/widgets/news_card.dart | 16 ++++-- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/lib/core/managers/news_repository.dart b/lib/core/managers/news_repository.dart index 8384a00c3..4cbb2107d 100644 --- a/lib/core/managers/news_repository.dart +++ b/lib/core/managers/news_repository.dart @@ -38,7 +38,9 @@ class NewsRepository { id: "1", title: "Annonce #1", content: "Salut voici un super évènement qui pourrait vous intéressé!", - imageThumbnail: "", + imageUrl: + "https://t4.ftcdn.net/jpg/02/16/94/65/360_F_216946587_rmug8FCNgpDCPQlstiCJ0CAXJ2sqPRU7.jpg", + imageThumbnail: null, state: 16, publicationDate: DateTime.now().subtract(const Duration(days: 1)), eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), @@ -50,10 +52,75 @@ class NewsRepository { name: "John Doe", email: "mont.samuel@outlook.com", type: "moderator", - createdAt: DateTime.now().add(const Duration(days: 1)), - updatedAt: DateTime.now().add(const Duration(days: 1)), + createdAt: DateTime.now().subtract(const Duration(days: 100)), + updatedAt: DateTime.now().subtract(const Duration(days: 100)), ), - organizer: organizer) + organizer: NewsUser( + id: "1", + name: "John Doe", + email: "mont.samuel@outlook.com", + type: "organizer", + createdAt: DateTime.now().subtract(const Duration(days: 100)), + updatedAt: DateTime.now().subtract(const Duration(days: 100)), + )), + News( + id: "2", + title: "Annonce #2", + content: "Salut voici un super évènement qui pourrait vous intéressé!", + imageUrl: + "https://t4.ftcdn.net/jpg/02/16/94/65/360_F_216946587_rmug8FCNgpDCPQlstiCJ0CAXJ2sqPRU7.jpg", + imageThumbnail: null, + state: 16, + publicationDate: DateTime.now().subtract(const Duration(days: 1)), + eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), + eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), + createdAt: DateTime.now().subtract(const Duration(days: 1)), + updatedAt: DateTime.now().subtract(const Duration(days: 1)), + moderator: NewsUser( + id: "1", + name: "John Doe", + email: "mont.samuel@outlook.com", + type: "moderator", + createdAt: DateTime.now().subtract(const Duration(days: 100)), + updatedAt: DateTime.now().subtract(const Duration(days: 100)), + ), + organizer: NewsUser( + id: "1", + name: "John Doe", + email: "mont.samuel@outlook.com", + type: "organizer", + createdAt: DateTime.now().subtract(const Duration(days: 100)), + updatedAt: DateTime.now().subtract(const Duration(days: 100)), + )), + News( + id: "3", + title: "Annonce #3", + content: "Salut voici un super évènement qui pourrait vous intéressé!", + imageUrl: + "https://t4.ftcdn.net/jpg/02/16/94/65/360_F_216946587_rmug8FCNgpDCPQlstiCJ0CAXJ2sqPRU7.jpg", + imageThumbnail: null, + state: 16, + publicationDate: DateTime.now().subtract(const Duration(days: 1)), + eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), + eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), + createdAt: DateTime.now().subtract(const Duration(days: 1)), + updatedAt: DateTime.now().subtract(const Duration(days: 1)), + moderator: NewsUser( + id: "1", + name: "John Doe", + email: "mont.samuel@outlook.com", + type: "moderator", + createdAt: DateTime.now().subtract(const Duration(days: 100)), + updatedAt: DateTime.now().subtract(const Duration(days: 100)), + ), + organizer: NewsUser( + id: "1", + name: "John Doe", + email: "mont.samuel@outlook.com", + type: "organizer", + createdAt: DateTime.now().subtract(const Duration(days: 100)), + updatedAt: DateTime.now().subtract(const Duration(days: 100)), + )) ]; List? get news => _news; diff --git a/lib/ui/widgets/news_card.dart b/lib/ui/widgets/news_card.dart index fd8cfd62b..9fb4105a5 100644 --- a/lib/ui/widgets/news_card.dart +++ b/lib/ui/widgets/news_card.dart @@ -38,7 +38,7 @@ class _NewsCardState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildImage(widget.news.imageThumbnail), + _buildImage(widget.news.imageUrl, widget.news.imageThumbnail), const SizedBox(height: 8), _buildTitleAndTime(widget.news, context) ], @@ -49,13 +49,21 @@ class _NewsCardState extends State { ); } - Widget _buildImage(String? image) { - if (image == null || image == "") { + Widget _buildImage(String? imageUrl, String? imageThumbnail) { + if (imageUrl != null && imageUrl != "") { + return ClipRRect( + borderRadius: BorderRadius.circular(16.0), + child: Image.network(imageUrl), + ); + } + + if (imageThumbnail == null || imageThumbnail == "") { return const SizedBox(); } + return ClipRRect( borderRadius: BorderRadius.circular(16.0), - child: _imageFromBase64String(image), + child: _imageFromBase64String(imageThumbnail), ); } From 598a4efc1f527d5639ae28a52f4c2cce86816b97 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Fri, 1 Mar 2024 12:43:24 -0500 Subject: [PATCH 07/15] add first draft of loader for news --- l10n/intl_en.arb | 2 + l10n/intl_fr.arb | 3 + lib/core/managers/news_repository.dart | 177 +----------------------- lib/core/viewmodels/news_viewmodel.dart | 50 ++++--- lib/ui/views/news_view.dart | 165 ++++++++++++++++------ lib/ui/widgets/news_card.dart | 24 ++-- 6 files changed, 164 insertions(+), 257 deletions(-) diff --git a/l10n/intl_en.arb b/l10n/intl_en.arb index 06636a7b5..67a014413 100644 --- a/l10n/intl_en.arb +++ b/l10n/intl_en.arb @@ -171,6 +171,8 @@ "ets_papercut_title":"PaperCut", "news_title" : "News", + "news_error_not_found_title" : "Oh oh!", + "news_error_not_found" : "Something went wrong while trying to retrieve the news. Please try again later.", "more_about_applets_title": "About ApplETS", "more_report_bug": "Report a bug or request a feature", diff --git a/l10n/intl_fr.arb b/l10n/intl_fr.arb index 7892f52f8..3753195c0 100644 --- a/l10n/intl_fr.arb +++ b/l10n/intl_fr.arb @@ -171,6 +171,9 @@ "ets_papercut_title":"PaperCut", "news_title" : "Annonces", + "news_error_not_found_title" : "Oh oh!", + "news_error_not_found" : "Une erreur est survenue lors de la récupération des annonces. Veuillez réessayer plus tard.", + "more_about_applets_title": "À propos d'ApplETS", "more_report_bug": "Rapporter un bogue ou une amélioration", diff --git a/lib/core/managers/news_repository.dart b/lib/core/managers/news_repository.dart index 4cbb2107d..57588e68c 100644 --- a/lib/core/managers/news_repository.dart +++ b/lib/core/managers/news_repository.dart @@ -6,195 +6,24 @@ import 'package:ets_api_clients/clients.dart'; import 'package:flutter/material.dart'; // Package imports: -import 'package:logger/logger.dart'; import 'package:ets_api_clients/models.dart'; // Project imports: import 'package:notredame/core/managers/cache_manager.dart'; -import 'package:notredame/core/services/networking_service.dart'; -import 'package:notredame/core/utils/cache_exception.dart'; import 'package:notredame/locator.dart'; /// Repository to access all the news class NewsRepository { static const String tag = "NewsRepository"; - @visibleForTesting - static const String newsCacheKey = "newsCache"; - - final Logger _logger = locator(); - - /// Cache manager to access and update the cache. - final CacheManager _cacheManager = locator(); - - /// Used to verify if the user has connectivity - final NetworkingService _networkingService = locator(); - final HelloAPIClient _helloApiClient = locator(); - /// List of the news - List? _news = [ - News( - id: "1", - title: "Annonce #1", - content: "Salut voici un super évènement qui pourrait vous intéressé!", - imageUrl: - "https://t4.ftcdn.net/jpg/02/16/94/65/360_F_216946587_rmug8FCNgpDCPQlstiCJ0CAXJ2sqPRU7.jpg", - imageThumbnail: null, - state: 16, - publicationDate: DateTime.now().subtract(const Duration(days: 1)), - eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), - eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), - createdAt: DateTime.now().subtract(const Duration(days: 1)), - updatedAt: DateTime.now().subtract(const Duration(days: 1)), - moderator: NewsUser( - id: "1", - name: "John Doe", - email: "mont.samuel@outlook.com", - type: "moderator", - createdAt: DateTime.now().subtract(const Duration(days: 100)), - updatedAt: DateTime.now().subtract(const Duration(days: 100)), - ), - organizer: NewsUser( - id: "1", - name: "John Doe", - email: "mont.samuel@outlook.com", - type: "organizer", - createdAt: DateTime.now().subtract(const Duration(days: 100)), - updatedAt: DateTime.now().subtract(const Duration(days: 100)), - )), - News( - id: "2", - title: "Annonce #2", - content: "Salut voici un super évènement qui pourrait vous intéressé!", - imageUrl: - "https://t4.ftcdn.net/jpg/02/16/94/65/360_F_216946587_rmug8FCNgpDCPQlstiCJ0CAXJ2sqPRU7.jpg", - imageThumbnail: null, - state: 16, - publicationDate: DateTime.now().subtract(const Duration(days: 1)), - eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), - eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), - createdAt: DateTime.now().subtract(const Duration(days: 1)), - updatedAt: DateTime.now().subtract(const Duration(days: 1)), - moderator: NewsUser( - id: "1", - name: "John Doe", - email: "mont.samuel@outlook.com", - type: "moderator", - createdAt: DateTime.now().subtract(const Duration(days: 100)), - updatedAt: DateTime.now().subtract(const Duration(days: 100)), - ), - organizer: NewsUser( - id: "1", - name: "John Doe", - email: "mont.samuel@outlook.com", - type: "organizer", - createdAt: DateTime.now().subtract(const Duration(days: 100)), - updatedAt: DateTime.now().subtract(const Duration(days: 100)), - )), - News( - id: "3", - title: "Annonce #3", - content: "Salut voici un super évènement qui pourrait vous intéressé!", - imageUrl: - "https://t4.ftcdn.net/jpg/02/16/94/65/360_F_216946587_rmug8FCNgpDCPQlstiCJ0CAXJ2sqPRU7.jpg", - imageThumbnail: null, - state: 16, - publicationDate: DateTime.now().subtract(const Duration(days: 1)), - eventStartDate: DateTime.now().add(const Duration(days: 1, hours: 1)), - eventEndDate: DateTime.now().add(const Duration(days: 1, hours: 2)), - createdAt: DateTime.now().subtract(const Duration(days: 1)), - updatedAt: DateTime.now().subtract(const Duration(days: 1)), - moderator: NewsUser( - id: "1", - name: "John Doe", - email: "mont.samuel@outlook.com", - type: "moderator", - createdAt: DateTime.now().subtract(const Duration(days: 100)), - updatedAt: DateTime.now().subtract(const Duration(days: 100)), - ), - organizer: NewsUser( - id: "1", - name: "John Doe", - email: "mont.samuel@outlook.com", - type: "organizer", - createdAt: DateTime.now().subtract(const Duration(days: 100)), - updatedAt: DateTime.now().subtract(const Duration(days: 100)), - )) - ]; - List? get news => _news; - /// Get and update the list of news. /// After fetching the news from the [?] the [CacheManager] /// is updated with the latest version of the news. - Future?> getNews( - {int pageNumber = 1, - int pageSize = 20, - bool fromCacheOnly = false}) async { - // Force fromCacheOnly mode when user has no connectivity - if (!(await _networkingService.hasConnectivity())) { - // ignore: parameter_assignments - fromCacheOnly = true; - } - - // Load the news from the cache if the list doesn't exist - if (_news == null) { - await getNewsFromCache(); - } - - if (fromCacheOnly) { - return _news; - } - - final List fetchedNews = await _helloApiClient.getEvents( + Future getNews({int pageNumber = 1, int pageSize = 3}) async { + final PaginatedNews pagination = await _helloApiClient.getEvents( pageNumber: pageNumber, pageSize: pageSize); - - _news ??= []; - - // Update the list of news to avoid duplicate news - for (final News news in fetchedNews) { - if (_news?.contains(news) ?? false) { - _news?.add(news); - } - } - - try { - // Update cache - _cacheManager.update(newsCacheKey, jsonEncode(_news)); - } on CacheException catch (_) { - // Do nothing, the caching will retry later and the error has been logged by the [CacheManager] - _logger.e( - "$tag - getNews: exception raised will trying to update the cache."); - } - - return _news; - } - - Future getNewsFromCache() async { - _news = []; - try { - final List responseCache = - jsonDecode(await _cacheManager.get(newsCacheKey)) as List; - - // Build list of news loaded from the cache. - _news = responseCache - .map((e) => News.fromJson(e as Map)) - .toList(); - - _logger.d( - "$tag - getNewsFromCache: ${_news?.length} news loaded from cache"); - } on CacheException catch (_) { - _logger.e( - "$tag - getNewsFromCache: exception raised will trying to load news from cache."); - } - } - - // TODO : Fetch news from the API - List fetchNewsFromAPI(int pageNumber, int pageSize) { - final List fetchedNews = []; - - _logger.d("$tag - getNews: fetched ${fetchedNews.length} news."); - - return fetchedNews; + return pagination; } } diff --git a/lib/core/viewmodels/news_viewmodel.dart b/lib/core/viewmodels/news_viewmodel.dart index a6a38c8c7..405851aab 100644 --- a/lib/core/viewmodels/news_viewmodel.dart +++ b/lib/core/viewmodels/news_viewmodel.dart @@ -1,6 +1,7 @@ // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:stacked/stacked.dart'; import 'package:ets_api_clients/models.dart'; @@ -8,43 +9,46 @@ import 'package:ets_api_clients/models.dart'; import 'package:notredame/core/managers/news_repository.dart'; import 'package:notredame/locator.dart'; -class NewsViewModel extends BaseViewModel { +class NewsViewModel extends BaseViewModel implements Initialisable { /// Load the events final NewsRepository _newsRepository = locator(); + final PagingController pagingController = + PagingController(firstPageKey: 1); + /// Localization class of the application. final AppIntl _appIntl; - /// News list - List? _news = []; - - /// Return the list of all the news. - List get news { - _news = []; - - // Build the list of news - _news?.addAll(_newsRepository.news ?? []); - - return _news ?? []; - } - NewsViewModel({required AppIntl intl}) : _appIntl = intl; bool isLoadingEvents = false; @override - // ignore: type_annotate_public_apis - void onError(error) { - Fluttertoast.showToast(msg: _appIntl.error); + void initialise() { + // This will be called when init state cycle runs + pagingController.addPageRequestListener((pageKey) { + fetchPage(pageKey); + }); } - Future refresh() async { + Future fetchPage(int pageNumber) async { try { - setBusyForObject(isLoadingEvents, true); - _newsRepository.getNews(); - notifyListeners(); - } on Exception catch (error) { - onError(error); + final pagination = await _newsRepository.getNews(pageNumber: pageNumber); + final isLastPage = pagination?.totalPages == pageNumber; + if (isLastPage) { + pagingController.appendLastPage(pagination?.news ?? []); + } else { + final nextPageKey = pageNumber + 1; + pagingController.appendPage(pagination?.news ?? [], nextPageKey); + } + } catch (error) { + pagingController.error = error; } } + + @override + // ignore: type_annotate_public_apis + void onError(error) { + Fluttertoast.showToast(msg: _appIntl.error); + } } diff --git a/lib/ui/views/news_view.dart b/lib/ui/views/news_view.dart index 668ae7709..b112a9388 100644 --- a/lib/ui/views/news_view.dart +++ b/lib/ui/views/news_view.dart @@ -4,8 +4,6 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:notredame/core/managers/news_repository.dart'; -import 'package:notredame/locator.dart'; import 'package:stacked/stacked.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; @@ -21,67 +19,44 @@ class NewsView extends StatefulWidget { class _NewsViewState extends State { static const int _nbSkeletons = 3; - static const _pageSize = 3; - - final NewsRepository _newsRepository = locator(); - - final PagingController pagingController = - PagingController(firstPageKey: 1); @override void initState() { - pagingController.addPageRequestListener((pageKey) { - fetchPage(pageKey); - }); - pagingController.addStatusListener((status) { - if (status == PagingStatus.subsequentPageError) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: const Text( - 'Something went wrong while fetching a new page.', - ), - action: SnackBarAction( - label: 'Retry', - onPressed: () => pagingController.retryLastFailedRequest(), - ), - ), - ); - } - }); super.initState(); } - Future fetchPage(int pageNumber) async { - try { - final newItems = await _newsRepository.getNews( - pageNumber: pageNumber, fromCacheOnly: true) ?? - []; - final isLastPage = newItems.length < _pageSize; - if (isLastPage) { - pagingController.appendLastPage(newItems); - } else { - final nextPageKey = pageNumber + newItems.length; - pagingController.appendPage(newItems, nextPageKey); - } - } catch (error) { - pagingController.error = error; - } - } - @override Widget build(BuildContext context) => ViewModelBuilder.reactive( viewModelBuilder: () => NewsViewModel(intl: AppIntl.of(context)!), + onModelReady: (model) { + model.pagingController.addStatusListener((status) { + if (status == PagingStatus.subsequentPageError) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text( + 'Something went wrong while fetching a new page.', + ), + action: SnackBarAction( + label: 'Retry', + onPressed: () => + model.pagingController.retryLastFailedRequest(), + ), + ), + ); + } + }); + }, builder: (context, model, child) { return RefreshIndicator( onRefresh: () => Future.sync( - () => pagingController.refresh(), + () => model.pagingController.refresh(), ), child: Theme( data: Theme.of(context) .copyWith(canvasColor: Colors.transparent), child: PagedListView( - pagingController: pagingController, + pagingController: model.pagingController, padding: const EdgeInsets.fromLTRB(0, 4, 0, 8), builderDelegate: PagedChildBuilderDelegate( itemBuilder: (context, item, index) => NewsCard(item), @@ -89,6 +64,10 @@ class _NewsViewState extends State { _buildSkeletonLoader(), newPageProgressIndicatorBuilder: (context) => NewsCardSkeleton(), + noMoreItemsIndicatorBuilder: (context) => + _buildNoMoreNewsCard(), + firstPageErrorIndicatorBuilder: (context) => + _buildError(model.pagingController), ), ), )); @@ -100,4 +79,100 @@ class _NewsViewState extends State { for (var i = 0; i < _nbSkeletons; i++) skeleton, ]); } + + Widget _buildNoMoreNewsCard() { + return Column( + children: [ + const SizedBox(height: 16), + const Padding( + padding: EdgeInsets.symmetric(horizontal: 16), + child: Divider(), + ), + const SizedBox(height: 16), + Card( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), + child: Expanded( + child: Row( + children: [ + const Icon(Icons.check, color: Colors.blue, size: 40), + const SizedBox(width: 16), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text("You're all set!", + style: TextStyle(fontSize: 24)), + SizedBox(height: 16), + Text( + 'You have reached the end of the news list. Come back another time for more news!', + textAlign: TextAlign.justify, + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ); + } + + Widget _buildError(PagingController pagingController) { + return Scaffold( + body: SafeArea( + minimum: const EdgeInsets.all(20), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 80, + ), + child: Text( + AppIntl.of(context)!.news_error_not_found_title, + style: const TextStyle( + fontSize: 40, fontWeight: FontWeight.bold), + ), + ), + Padding( + padding: const EdgeInsets.only( + bottom: 70, + ), + child: Text( + AppIntl.of(context)!.news_error_not_found, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 15, + ), + ), + ), + Flexible( + child: ElevatedButton( + onPressed: () { + pagingController.retryLastFailedRequest(); + }, + child: Text(AppIntl.of(context)!.retry), + ), + ), + ], + ), + ), + ), + ); + } } diff --git a/lib/ui/widgets/news_card.dart b/lib/ui/widgets/news_card.dart index 9fb4105a5..d9657b3ab 100644 --- a/lib/ui/widgets/news_card.dart +++ b/lib/ui/widgets/news_card.dart @@ -38,7 +38,7 @@ class _NewsCardState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _buildImage(widget.news.imageUrl, widget.news.imageThumbnail), + _buildImage(widget.news.imageUrl), const SizedBox(height: 8), _buildTitleAndTime(widget.news, context) ], @@ -49,26 +49,20 @@ class _NewsCardState extends State { ); } - Widget _buildImage(String? imageUrl, String? imageThumbnail) { + Widget _buildImage(String? imageUrl) { if (imageUrl != null && imageUrl != "") { return ClipRRect( borderRadius: BorderRadius.circular(16.0), - child: Image.network(imageUrl), + child: Image.network( + imageUrl == "" + ? "https://www.shutterstock.com/image-vector/no-photo-thumbnail-graphic-element-600nw-2311073121.jpg" + : imageUrl, + //loadingBuilder: (context, child, loadingProgress) => _shimmerEffect(), + ), ); } - if (imageThumbnail == null || imageThumbnail == "") { - return const SizedBox(); - } - - return ClipRRect( - borderRadius: BorderRadius.circular(16.0), - child: _imageFromBase64String(imageThumbnail), - ); - } - - Image _imageFromBase64String(String base64String) { - return Image.memory(base64Decode(base64String)); + return const SizedBox(); } Widget _shimmerEffect() { From 73a28be3a7c7b5bc95498a32a5847a04a3f9f004 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Fri, 1 Mar 2024 12:48:02 -0500 Subject: [PATCH 08/15] fix news card loading image effect --- lib/ui/widgets/news_card.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/ui/widgets/news_card.dart b/lib/ui/widgets/news_card.dart index d9657b3ab..453328795 100644 --- a/lib/ui/widgets/news_card.dart +++ b/lib/ui/widgets/news_card.dart @@ -57,7 +57,13 @@ class _NewsCardState extends State { imageUrl == "" ? "https://www.shutterstock.com/image-vector/no-photo-thumbnail-graphic-element-600nw-2311073121.jpg" : imageUrl, - //loadingBuilder: (context, child, loadingProgress) => _shimmerEffect(), + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) { + return child; + } else { + return _shimmerEffect(); + } + }, ), ); } From a1c99b0034c0e21b32aa20d43ff7df789ac5f2f5 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Thu, 7 Mar 2024 22:43:08 -0500 Subject: [PATCH 09/15] Add news tests and fix other that weren't working properly --- lib/core/viewmodels/news_viewmodel.dart | 11 -- lib/ui/views/news_view.dart | 41 +++--- test/managers/news_repository_test.dart | 55 ------- test/mock/managers/news_repository_mock.dart | 19 +-- test/models/news_test.dart | 58 -------- test/ui/views/ets_view_test.dart | 121 +++++++++++---- test/ui/views/goldenFiles/etsView_1.png | Bin 3378 -> 5791 bytes test/ui/views/goldenFiles/newsView_1.png | Bin 1534 -> 1872 bytes test/ui/views/goldenFiles/newsView_2.png | Bin 2461 -> 5989 bytes test/ui/views/news_view_test.dart | 146 ++++++++++++++----- test/viewmodels/news_viewmodel_test.dart | 72 ++++++--- 11 files changed, 281 insertions(+), 242 deletions(-) delete mode 100644 test/managers/news_repository_test.dart delete mode 100644 test/models/news_test.dart diff --git a/lib/core/viewmodels/news_viewmodel.dart b/lib/core/viewmodels/news_viewmodel.dart index 405851aab..df8f05711 100644 --- a/lib/core/viewmodels/news_viewmodel.dart +++ b/lib/core/viewmodels/news_viewmodel.dart @@ -16,11 +16,6 @@ class NewsViewModel extends BaseViewModel implements Initialisable { final PagingController pagingController = PagingController(firstPageKey: 1); - /// Localization class of the application. - final AppIntl _appIntl; - - NewsViewModel({required AppIntl intl}) : _appIntl = intl; - bool isLoadingEvents = false; @override @@ -45,10 +40,4 @@ class NewsViewModel extends BaseViewModel implements Initialisable { pagingController.error = error; } } - - @override - // ignore: type_annotate_public_apis - void onError(error) { - Fluttertoast.showToast(msg: _appIntl.error); - } } diff --git a/lib/ui/views/news_view.dart b/lib/ui/views/news_view.dart index b112a9388..54540ef2f 100644 --- a/lib/ui/views/news_view.dart +++ b/lib/ui/views/news_view.dart @@ -28,7 +28,7 @@ class _NewsViewState extends State { @override Widget build(BuildContext context) => ViewModelBuilder.reactive( - viewModelBuilder: () => NewsViewModel(intl: AppIntl.of(context)!), + viewModelBuilder: () => NewsViewModel(), onModelReady: (model) { model.pagingController.addStatusListener((status) { if (status == PagingStatus.subsequentPageError) { @@ -56,6 +56,7 @@ class _NewsViewState extends State { data: Theme.of(context) .copyWith(canvasColor: Colors.transparent), child: PagedListView( + key: const Key("pagedListView"), pagingController: model.pagingController, padding: const EdgeInsets.fromLTRB(0, 4, 0, 8), builderDelegate: PagedChildBuilderDelegate( @@ -100,27 +101,25 @@ class _NewsViewState extends State { children: [ Container( padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), - child: Expanded( - child: Row( - children: [ - const Icon(Icons.check, color: Colors.blue, size: 40), - const SizedBox(width: 16), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text("You're all set!", - style: TextStyle(fontSize: 24)), - SizedBox(height: 16), - Text( - 'You have reached the end of the news list. Come back another time for more news!', - textAlign: TextAlign.justify, - ), - ], - ), + child: Row( + children: [ + const Icon(Icons.check, color: Colors.blue, size: 40), + const SizedBox(width: 16), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text("You're all set!", + style: TextStyle(fontSize: 24)), + SizedBox(height: 16), + Text( + 'You have reached the end of the news list. Come back another time for more news!', + textAlign: TextAlign.justify, + ), + ], ), - ], - ), + ), + ], ), ), ], diff --git a/test/managers/news_repository_test.dart b/test/managers/news_repository_test.dart deleted file mode 100644 index c749a2c1a..000000000 --- a/test/managers/news_repository_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -// Package imports: -import 'package:flutter_test/flutter_test.dart'; - -// Project imports: -import 'package:notredame/core/managers/news_repository.dart'; -import 'package:notredame/core/models/news.dart'; -import '../helpers.dart'; - -void main() { - group('NewsRepository tests', () { - late NewsRepository repository; - - setUp(() { - setupLogger(); - setupAnalyticsServiceMock(); - setupCacheManagerMock(); - setupNetworkingServiceMock(); - repository = NewsRepository(); - }); - - test('Fetching news updates the news list', () async { - // TODO : remove when the news will be empty by default without test news - //expect(repository.news, isEmpty); - - final List? fetchedNews = - await repository.getNews(fromCacheOnly: true); - - expect(repository.news, isNotEmpty); - expect(repository.news, equals(fetchedNews)); - }); - - test('Fetching news from cache returns the correct data', () async { - // TODO : remove when the news will be empty by default without test news - //expect(repository.news, isEmpty); - - await repository.getNews(fromCacheOnly: true); - - final List? newsFromCache = - await repository.getNews(fromCacheOnly: true); - - expect(newsFromCache, isNotEmpty); - expect(newsFromCache, equals(repository.news)); - }); - - test('Fetching news from API updates the news list', () async { - // TODO : remove when the news will be empty by default without test news - //expect(repository.news, isEmpty); - - final List? fetchedNews = await repository.getNews(); - - expect(repository.news, isNotEmpty); - expect(repository.news, equals(fetchedNews)); - }); - }); -} diff --git a/test/mock/managers/news_repository_mock.dart b/test/mock/managers/news_repository_mock.dart index 9cb4e7a60..1e65059d3 100644 --- a/test/mock/managers/news_repository_mock.dart +++ b/test/mock/managers/news_repository_mock.dart @@ -1,34 +1,29 @@ // Package imports: import 'package:ets_api_clients/exceptions.dart'; +import 'package:ets_api_clients/models.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; // Project imports: import 'package:notredame/core/managers/news_repository.dart'; -import 'package:notredame/core/models/news.dart'; import 'news_repository_mock.mocks.dart'; @GenerateNiceMocks([MockSpec()]) class NewsRepositoryMock extends MockNewsRepository { - /// Stub the getter [news] of [mock] when called will return [toReturn]. - static void stubNews(NewsRepositoryMock mock, - {List toReturn = const []}) { - when(mock.news).thenReturn(toReturn); - } - /// Stub the function [getNews] of [mock] when called will return [toReturn]. static void stubGetNews(NewsRepositoryMock mock, - {List toReturn = const [], bool fromCacheOnly = false}) { - when(mock.getNews(fromCacheOnly: fromCacheOnly)) + {PaginatedNews? toReturn, int pageNumber = 1, int pageSize = 3}) { + when(mock.getNews(pageNumber: pageNumber, pageSize: pageSize)) .thenAnswer((_) async => toReturn); } /// Stub the function [getNews] of [mock] when called will throw [toThrow]. static void stubGetNewsException(NewsRepositoryMock mock, {Exception toThrow = const ApiException(prefix: 'ApiException'), - bool fromCacheOnly = false}) { - when(mock.getNews(fromCacheOnly: fromCacheOnly)).thenAnswer((_) => - Future.delayed(const Duration(milliseconds: 50)) + int pageNumber = 1, + int pageSize = 3}) { + when(mock.getNews(pageNumber: pageNumber, pageSize: pageSize)).thenAnswer( + (_) => Future.delayed(const Duration(milliseconds: 50)) .then((value) => throw toThrow)); } } diff --git a/test/models/news_test.dart b/test/models/news_test.dart deleted file mode 100644 index d64a632ef..000000000 --- a/test/models/news_test.dart +++ /dev/null @@ -1,58 +0,0 @@ -// ignore_for_file: avoid_dynamic_calls - -// Package imports: -import 'package:flutter_test/flutter_test.dart'; - -// Project imports: -import 'package:notredame/core/models/news.dart'; - -void main() { - group('News class tests', () { - test('News.fromJson() should parse JSON correctly', () { - final json = { - 'id': 1, - 'title': 'Test Title', - 'description': 'Test Description', - 'image': 'https://example.com/image.jpg', - 'tags': ['Tag 1', 'Tag 2'], - 'date': '2022-01-01T12:00:00Z', - }; - - final news = News.fromJson(json); - - expect(news.id, equals(1)); - expect(news.title, equals('Test Title')); - expect(news.description, equals('Test Description')); - expect(news.image, equals('https://example.com/image.jpg')); - expect(news.tags.length, equals(2)); - expect(news.tags[0], equals('Tag 1')); - expect(news.tags[1], equals('Tag 2')); - expect(news.date, equals(DateTime.parse('2022-01-01T12:00:00Z'))); - }); - - test('toJson() should convert News to JSON correctly', () { - final news = News( - id: 1, - title: 'Test Title', - description: 'Test Description', - image: 'https://example.com/image.jpg', - tags: [ - 'Tag 1', - 'Tag 2', - ], - date: DateTime.parse('2022-01-01T12:00:00Z'), - ); - - final json = news.toJson(); - - expect(json['id'], equals(1)); - expect(json['title'], equals('Test Title')); - expect(json['description'], equals('Test Description')); - expect(json['image'], equals('https://example.com/image.jpg')); - expect(json['tags'], hasLength(2)); - expect(json['tags'][0], equals('Tag 1')); - expect(json['tags'][1], equals('Tag 2')); - expect(json['date'], equals('2022-01-01 12:00:00.000Z')); - }); - }); -} diff --git a/test/ui/views/ets_view_test.dart b/test/ui/views/ets_view_test.dart index 56652c33c..eeb9b75e6 100644 --- a/test/ui/views/ets_view_test.dart +++ b/test/ui/views/ets_view_test.dart @@ -2,6 +2,7 @@ import 'dart:io'; // Flutter imports: +import 'package:ets_api_clients/models.dart'; import 'package:flutter/material.dart'; // Package imports: @@ -12,7 +13,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:notredame/core/managers/course_repository.dart'; import 'package:notredame/core/managers/news_repository.dart'; import 'package:notredame/core/managers/settings_manager.dart'; -import 'package:notredame/core/models/news.dart'; import 'package:notredame/core/services/analytics_service.dart'; import 'package:notredame/core/services/navigation_service.dart'; import 'package:notredame/core/services/networking_service.dart'; @@ -26,40 +26,104 @@ void main() { final List news = [ News( - id: 1, - title: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis.", - description: "Test 1 description", - date: DateTime.now(), - image: "", - tags: [ - "tag1", - "tag2", + id: "4627a622-f7c7-4ff9-9a01-50c69333ff42", + title: 'Mock News 1', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis. 1', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + tags: [ + NewsTags( + id: 'e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 1", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))), + NewsTags( + id: 'faaaaaaa-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 2", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))) ], + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), News( - id: 2, - title: "Test 2", - description: "Test 2 description", - date: DateTime.now(), - image: "", - tags: [ - "tag1", - "tag2", + id: "4627a622-f7c7-4ff9-9a01-50c69333ff42", + title: 'Mock News 2', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis. 2', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + tags: [ + NewsTags( + id: 'e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 1", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))), + NewsTags( + id: 'faaaaaaa-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 2", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))) ], + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), News( - id: 3, - title: "Test 3", - description: "Test 3 description", - date: DateTime.now(), - image: "", - tags: [ - "tag1", - "tag2", + id: "4627a622-f7c7-4ff9-9a01-50c69333ff42", + title: 'Mock News 3', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis. 3', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + tags: [ + NewsTags( + id: 'e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 1", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))), + NewsTags( + id: 'faaaaaaa-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 2", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))) ], + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), ]; + final PaginatedNews paginatedNews = PaginatedNews( + news: news, pageNumber: 1, pageSize: 3, totalRecords: 3, totalPages: 1); group('ETSView -', () { setUp(() async { @@ -72,8 +136,7 @@ void main() { setupAnalyticsServiceMock(); setupSettingsManagerMock(); - NewsRepositoryMock.stubGetNews(newsRepository, toReturn: news); - NewsRepositoryMock.stubNews(newsRepository, toReturn: news); + NewsRepositoryMock.stubGetNews(newsRepository, toReturn: paginatedNews); }); tearDown(() { @@ -109,6 +172,6 @@ void main() { await expectLater(find.byType(ETSView), matchesGoldenFile(goldenFilePath("etsView_1"))); }); - }, skip: !Platform.isLinux); + }); }); } diff --git a/test/ui/views/goldenFiles/etsView_1.png b/test/ui/views/goldenFiles/etsView_1.png index 8ecc96c1f2cb53b080c4c8fdbd646fab3a204590..33c8821352298f1b42317b4a2d08dfe74ffb8baf 100644 GIT binary patch literal 5791 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 Dp9rXs literal 3378 zcmeHKX;f2577jEj3WyFp(9%L2T(Ad38)Xp)DAFtqf{5&!B1lUVL`aB0h{(9m5oomq zWeG=6G6+f70>~CoAs|b@5ENq)BuXG5KqLu)Z1b?E^~Y$7|L2|aoqDh8)UCSrzWTmf znTI@GwASda0f9hTZmv#;K_C?k0K@7lfu5tH%2J?FNjU7{2*USooCH495**!*r~^-` zdgK)lNb{AO)BYofLO#R$)XgXiS%7lKZZfZp>N15UUM_i7bj#zHmKP&uRC=8~Ece&z z_39I*R)it;KS8_=1O2#VOLN#EM(?Z26F-JkW;);7vQ4M<@NrkT+qaGp@Qk&EtGAS} z>uQZkY0p~ov(&jW!j^m3*@Z34jZ6;Tr(Zyy|AB+_q`VAIGYZ9@N zG&ULO?sGCde(+m6V3H?PBb`J1q%#+=Css+jcoCy&s_y@l zHV_WzviYROK{5G!$D^Bnu6CEr3f$9Ym^V-q61dFWe0G~(9&lwjdW{zJdWKi-OiL=` z$3r0QF>rVpk1R3^^+r~ty%JjoY!Ce&y)@d-mj=?=eln39_L>wnu^8_lS$It3>M4iB zjUA(7-Osr<8WcEwynCE75UD6o?wN-A$sapVCRg?JD$@dLcZVODsrkF;9IvQp(zt+b zPxcSIv>Xo;`B{;z?*2pCX^Jy+c5bSYqSw)=AW7Wl$92(LSxRq)kV=B4gaF2ADRbIc z(tM1f;H9CDuP;(gqdpI(HPkKoF>M+WQelQr)I#?uaHUp(8J?M z1?_%$dAUvenA44fZ*1yLQp@h&4cQXY+-FJQ7Tm!?5=B@eSKjviNFRid$ee8LRtN3x}TT*LZp^voyd%F+gcarR{@`T z;SDt6sS%&j($a)mHdVism6dTHrhj8$Y3XO1G+kL_n^ZQ~#rz#MF>t4egGq^rjJ)ev zY`^2%DpxH{%^_xM3a==MS$@OVYdCjDa7;|hKlPvWAbM&-7{Z4(+h9zq zW>>CS#e16 z1s#CXaw|h=R<(8F#34St!E5`djg`6iVILnKB2p^00bH})?Eh&zJohpLa0@yWfusA%9NJ6SmB0!1JYVaDo-Igk|b(9@eHyayaiGq*Tg z;Dy!E(Gd+C(56jNv4n25^y&CFUDxyt3~)YJPoz8tFT+xSMQMQBgudSM_?mNb<3Y`E zzAwSdthwe^e*XPCckbjD7Pge>s5Ox*2yH!;*RDfACjDEyc{PAnJFGHPEbQz;;@TF*qjEym zqb;DrAyhXNbcTt>=$ed-4A^+@?H}u4 zbJ9#~q+v7#gNrUk!u#3Jal!uDcC!yJAmzRlel#)|bxO98F+mB(vXrzvhUkn{+VDMX z>QnT{Wpr0H6r2wZVGMk3Lm`eKy>@)>JZ)v*J?WGewR zrHz4{XAn<~)JP;*z|C491bAwCuEd(Bw8e<$5Gf<^9QvEq|W2<(tRoJ znMw)&o^$T5IUJ*h+OZCu^}SU+@%Qh*;F-mM%D~z(9EU4gm_r-sGG-TRmqisPWzID> zz9gr|t!Mhx4<+uR zxJ48tm!c?jkTZS7q9f3?&1WgFSA=PKn4F(O)YAQ#9ryIYHY6bUFz!&fM8ae;n-V9V zwHS~hI(}`M>$hdI3C31VrrCy&AU2yV5F{~R{;ksK<~ew(PVu;?eHD1<#fyMc+3f5Y z1BbL!X7&=p019nwZx4I@=wkBgi+W>hj`RT?h%UXlF)R#)=cRwT27hx2;iHRw&ZSjA zft(5i97=HBPHO}z2DgYl(!G~x97X}&FC2<4ws$%;i;NAmr`^nP@?|AgW Fe*gt7-z@+D diff --git a/test/ui/views/goldenFiles/newsView_1.png b/test/ui/views/goldenFiles/newsView_1.png index 9ff3b2f28fd4c4a8fe72c96d238ac9d54da7ecee..91a717a07c5390daf16694e02d5e4a837478c399 100644 GIT binary patch literal 1872 zcmeAS@N?(olHy`uVBq!ia0y~yVB`kkYaDDqk%X^n76U29;vjb?hIQv;UIIBR#ZI0f z96(URkIWgY$?Z4+CxXKLb1o#SpB zM7M0{Sg`#+=Rf}=8I!90toIx?_pFdOn4cD-BPP#$K>b+Zp4-3Qx-#5$)M;>`J$iCJ zUq3-sZSqNjxqkcK)`*LXAFi?czwPtcw9OCy{P}bH-1e8(f3KhWe)seqMFtmV6B&z_xVHFup&d10a9 zndhJ7XU{&HcKGMdpQnm%7uD|mx3i{n?(HM<6&;ks2%t^V#Fg_e`JMP#V`pPyqho8< z_xQudjekD%_w}_sfBsy4_U=7X6rpW;vU~OX~^X>ch>2lU~c5?IP&6_4yU0Er4 z@7}#>a?!`1Z}NQo=ZxCh2HE2u^K>`P@KLkgD}3orQT*M?pO^Pf&y9Qzl=~`Hsvyj* zAczCq{5hTHV0~;I>|(`iW2l|Gr5pWpub_wT9C?QVZe&-?s*-MV#cmoHzQ z`utDazVdgg?;lRTw(YgZ4c)T2Of$)gtWjN~Aut*O!!!g=#`9)I?>w;L`ww8P$l&Sf K=d#Wzp$P!%8;(5y literal 1534 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 Wy#F+omIR`5NJmRwv*7%V;Qs=INh#+5 literal 2461 zcmeHJYfMvT7;YI3v{0nZcnUWiahJ{&ZeuC*#XI_Q8xuS#u=6n-Le*)zxLt>#4V!n+0mMI{NAX(BX%R z&(q1`dx8yB6wamy_QC)zE^c$xPV#0^$ukv+OlH@)kJe**uc@axJ?V(<7vdem0(LHD(cw^9 ztxbm%D-yU{kw!Ujze*{@pAL7gcrF6f>MX;rfeE1rp!4P-1&W%JlLL2W8}BYK^$Urd zzW3$XfK(b!aO%$%fXho~OEMRaCP@N*C6&B9dhp)wvKTk_j8jVI^ z<5%%P{v|4TA(8`2X%7QD5lz}rNErv&F6n2(?YwWvf zgC?sJ{Px&_DStr2jT7=4(wg}Z9OrRfbWd+@Z^fwqzdpz*AInB!s-k`O-ShDZGcAY>ZcOPt@AX(r zN0hPAyHBh|ZU7Ko0p=&5wnTsTFJ`}LKa^4ZuB!t*4jtCL^P5zv86ah3WGs?>#HFw8 z>jzL<8LMT|ZcKAmJdSNbU($98R4+`atgNW0_(Hdhz6P2SXc&%8x};L+^DW+MJ)Di) z3JdVsLjIEfe<|>D14XMUgZGpsVY~utAfWNt$9s48duXq40^*0|>RG?#9h6sq`C+-< l*zsCZ-q`V news = [ News( - id: 1, - title: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis.", - description: "Test 1 description", - date: DateTime.now(), - image: "", - tags: [ - "tag1", - "tag2", + id: "4627a622-f7c7-4ff9-9a01-50c69333ff42", + title: 'Mock News 1', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis. 1', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + tags: [ + NewsTags( + id: 'e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 1", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))), + NewsTags( + id: 'faaaaaaa-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 2", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))) ], + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), News( - id: 2, - title: "Test 2", - description: "Test 2 description", - date: DateTime.now(), - image: "", - tags: [ - "tag1", - "tag2", + id: "4627a622-f7c7-4ff9-9a01-50c69333ff42", + title: 'Mock News 2', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis. 2', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + tags: [ + NewsTags( + id: 'e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 1", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))), + NewsTags( + id: 'faaaaaaa-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 2", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))) ], + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), News( - id: 3, - title: "Test 3", - description: "Test 3 description", - date: DateTime.now(), - image: "", - tags: [ - "tag1", - "tag2", + id: "4627a622-f7c7-4ff9-9a01-50c69333ff42", + title: 'Mock News 3', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tempus arcu sed quam tincidunt, non venenatis orci mollis. 3', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + tags: [ + NewsTags( + id: 'e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 1", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))), + NewsTags( + id: 'faaaaaaa-e3e3-e3e3-e3e3-e3e3e3e3e3e3', + name: "tag 2", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180))) ], + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), ]; + final PaginatedNews paginatedNews = PaginatedNews( + news: news, pageNumber: 1, pageSize: 3, totalRecords: 3, totalPages: 1); final List emptyNews = List.empty(); + final PaginatedNews paginatedEmptyNews = PaginatedNews( + news: emptyNews, + pageNumber: 1, + pageSize: 3, + totalRecords: 0, + totalPages: 1); group('NewsView -', () { setUp(() async { @@ -71,8 +142,7 @@ void main() { setupNetworkingServiceMock(); setupSettingsManagerMock(); - NewsRepositoryMock.stubGetNews(newsRepository, toReturn: news); - NewsRepositoryMock.stubNews(newsRepository, toReturn: news); + NewsRepositoryMock.stubGetNews(newsRepository, toReturn: paginatedNews); }); tearDown(() { @@ -84,37 +154,36 @@ void main() { }); testWidgets('Empty news', (WidgetTester tester) async { - NewsRepositoryMock.stubGetNews(newsRepository, toReturn: emptyNews); - NewsRepositoryMock.stubNews(newsRepository, toReturn: emptyNews); + NewsRepositoryMock.stubGetNews(newsRepository, + toReturn: paginatedEmptyNews); await tester.pumpWidget(localizedWidget(child: NewsView())); await tester.pumpAndSettle(const Duration(seconds: 1)); expect(find.byType(RefreshIndicator), findsOneWidget); - expect(find.byType(ListView), findsOneWidget); + expect(find.byKey(const Key("pagedListView")), findsOneWidget); expect(find.byType(NewsCard), findsNothing); }); testWidgets('List of news', (WidgetTester tester) async { - NewsRepositoryMock.stubGetNews(newsRepository, toReturn: news); - NewsRepositoryMock.stubNews(newsRepository, toReturn: news); + NewsRepositoryMock.stubGetNews(newsRepository, toReturn: paginatedNews); await tester.pumpWidget(localizedWidget(child: NewsView())); await tester.pumpAndSettle(const Duration(seconds: 5)); expect(find.byType(RefreshIndicator), findsOneWidget); - expect(find.byType(ListView), findsOneWidget); + expect(find.byKey(const Key("pagedListView")), findsOneWidget); expect(find.byType(NewsCard), findsNWidgets(3)); }); group("golden - ", () { testWidgets("news view empty", (WidgetTester tester) async { - NewsRepositoryMock.stubGetNews(newsRepository, toReturn: emptyNews); - NewsRepositoryMock.stubNews(newsRepository, toReturn: emptyNews); + NewsRepositoryMock.stubGetNews(newsRepository, + toReturn: paginatedEmptyNews); tester.binding.window.physicalSizeTestValue = const Size(800, 1410); @@ -126,8 +195,7 @@ void main() { }); testWidgets("news view", (WidgetTester tester) async { - NewsRepositoryMock.stubGetNews(newsRepository, toReturn: news); - NewsRepositoryMock.stubNews(newsRepository, toReturn: news); + NewsRepositoryMock.stubGetNews(newsRepository, toReturn: paginatedNews); tester.binding.window.physicalSizeTestValue = const Size(800, 1410); @@ -137,6 +205,6 @@ void main() { await expectLater(find.byType(NewsView), matchesGoldenFile(goldenFilePath("newsView_2"))); }); - }, skip: !Platform.isLinux); + }); }); } diff --git a/test/viewmodels/news_viewmodel_test.dart b/test/viewmodels/news_viewmodel_test.dart index 9c197d2ba..72a22129a 100644 --- a/test/viewmodels/news_viewmodel_test.dart +++ b/test/viewmodels/news_viewmodel_test.dart @@ -1,12 +1,15 @@ // Package imports: +// ignore_for_file: avoid_redundant_argument_values + +import 'package:ets_api_clients/models.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:logger/logger.dart'; +import 'package:mockito/mockito.dart'; // Project imports: import 'package:notredame/core/managers/news_repository.dart'; import 'package:notredame/core/managers/settings_manager.dart'; -import 'package:notredame/core/models/news.dart'; import 'package:notredame/core/viewmodels/news_viewmodel.dart'; import 'package:notredame/locator.dart'; import '../helpers.dart'; @@ -19,31 +22,59 @@ void main() { final List news = [ News( - id: 1, + id: "4627a622-f7c7-4ff9-9a01-50c69333ff42", title: 'Mock News 1', - description: 'Mock Description 1', - image: 'https://example.com/mock-image1.jpg', + content: 'Mock Description 1', + imageUrl: 'https://example.com/mock-image1.jpg', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), tags: [], - date: DateTime.now(), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), News( - id: 2, + id: "5627a622-f7c7-4ff9-9a01-50c69333ff42", title: 'Mock News 2', - description: 'Mock Description 2', - image: 'https://example.com/mock-image2.jpg', + content: 'Mock Description 2', + imageUrl: 'https://example.com/mock-image2.jpg', + state: 1, + publicationDate: DateTime.now().subtract(const Duration(days: 5)), + eventStartDate: DateTime.now().add(const Duration(days: 2)), + eventEndDate: DateTime.now().add(const Duration(days: 2, hours: 2)), + organizer: NewsUser( + id: "e3e3e3e3-e3e3-e3e3-e3e3-e3e3e3e3e3e3", + type: "organizer", + organisation: "Mock Organizer", + email: "", + createdAt: DateTime.now().subtract(const Duration(days: 180)), + updatedAt: DateTime.now().subtract(const Duration(days: 180)), + ), tags: [], - date: DateTime.now(), + createdAt: DateTime.now().subtract(const Duration(days: 5)), + updatedAt: DateTime.now().subtract(const Duration(days: 5)), ), ]; + final PaginatedNews paginatedNews = PaginatedNews( + news: news, totalRecords: 2, totalPages: 2, pageNumber: 1, pageSize: 3); + group('NewsViewModel tests', () { setUp(() async { newsRepository = setupNewsRepositoryMock(); setupLogger(); setupSettingsManagerMock(); - NewsRepositoryMock.stubNews(newsRepository, toReturn: news); - appIntl = await setupAppIntl(); - viewModel = NewsViewModel(intl: appIntl); + NewsRepositoryMock.stubGetNews(newsRepository, toReturn: paginatedNews); + viewModel = NewsViewModel(); }); tearDown(() { @@ -52,15 +83,22 @@ void main() { locator.unregister(); }); - test('Fetching news updates the news list', () async { + test('NewsViewModel fetch first page', () async { expect(viewModel.isBusy, isFalse); - await viewModel.futureToRun(); + await viewModel.fetchPage(1); + + verify(newsRepository.getNews(pageNumber: 1)).called(1); + expect(viewModel.pagingController.nextPageKey, 2); + }); - expect(viewModel.news, hasLength(2)); - expect(viewModel.news[0].title, equals('Mock News 1')); - expect(viewModel.news[1].title, equals('Mock News 2')); + test('NewsViewModel fetch last page', () async { expect(viewModel.isBusy, isFalse); + + await viewModel.fetchPage(2); + + verify(newsRepository.getNews(pageNumber: 2)).called(1); + expect(viewModel.pagingController.nextPageKey, 3); }); }); } From 615830c8237a91bbb658ece60b120d5c0726e32a Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Thu, 7 Mar 2024 23:13:12 -0500 Subject: [PATCH 10/15] fix news --- l10n/intl_en.arb | 2 ++ l10n/intl_fr.arb | 3 ++- lib/ui/views/news_view.dart | 16 ++++++++-------- pubspec.lock | 8 +++++--- pubspec.yaml | 9 +++++---- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/l10n/intl_en.arb b/l10n/intl_en.arb index 67a014413..5a813dc58 100644 --- a/l10n/intl_en.arb +++ b/l10n/intl_en.arb @@ -173,6 +173,8 @@ "news_title" : "News", "news_error_not_found_title" : "Oh oh!", "news_error_not_found" : "Something went wrong while trying to retrieve the news. Please try again later.", + "news_no_more_card_title": "You're all set!", + "news_no_more_card": "You have reached the end of the news list. Come back another time for more news!", "more_about_applets_title": "About ApplETS", "more_report_bug": "Report a bug or request a feature", diff --git a/l10n/intl_fr.arb b/l10n/intl_fr.arb index 3753195c0..ff7056df7 100644 --- a/l10n/intl_fr.arb +++ b/l10n/intl_fr.arb @@ -173,7 +173,8 @@ "news_title" : "Annonces", "news_error_not_found_title" : "Oh oh!", "news_error_not_found" : "Une erreur est survenue lors de la récupération des annonces. Veuillez réessayer plus tard.", - + "news_no_more_card_title": "Tu es à jours!", + "news_no_more_card": "Vous avez atteint la fin des annonces. Revenez plus tard pour voir les prochaines annonces!", "more_about_applets_title": "À propos d'ApplETS", "more_report_bug": "Rapporter un bogue ou une amélioration", diff --git a/lib/ui/views/news_view.dart b/lib/ui/views/news_view.dart index 54540ef2f..173c11724 100644 --- a/lib/ui/views/news_view.dart +++ b/lib/ui/views/news_view.dart @@ -34,11 +34,11 @@ class _NewsViewState extends State { if (status == PagingStatus.subsequentPageError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: const Text( - 'Something went wrong while fetching a new page.', + content: Text( + AppIntl.of(context)!.news_error_not_found, ), action: SnackBarAction( - label: 'Retry', + label: AppIntl.of(context)!.retry, onPressed: () => model.pagingController.retryLastFailedRequest(), ), @@ -108,12 +108,12 @@ class _NewsViewState extends State { Flexible( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text("You're all set!", - style: TextStyle(fontSize: 24)), - SizedBox(height: 16), + children: [ + Text(AppIntl.of(context)!.news_no_more_card_title, + style: const TextStyle(fontSize: 24)), + const SizedBox(height: 16), Text( - 'You have reached the end of the news list. Come back another time for more news!', + AppIntl.of(context)!.news_no_more_card, textAlign: TextAlign.justify, ), ], diff --git a/pubspec.lock b/pubspec.lock index 6322190ec..627b18868 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -284,9 +284,11 @@ packages: ets_api_clients: dependency: "direct main" description: - path: "../ETS-API-Clients" - relative: true - source: path + path: "." + ref: "ftr/add-news" + resolved-ref: cf61b19f41d01d367ea57fef78306e869930355e + url: "https://github.com/ApplETS/ETS-API-Clients.git" + source: git version: "0.5.0" fading_edge_scrollview: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index c8225f97d..b566d2cd4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,11 +41,12 @@ dependencies: flutter_siren: ^1.2.0 # Customs + # TODO: Change to the latest version, once reviewed and accepted ets_api_clients: - path: ../ETS-API-Clients/ - # git: - # url: https://github.com/ApplETS/ETS-API-Clients.git - # ref: ftr/add-news + # path: ../ETS-API-Clients/ + git: + url: https://github.com/ApplETS/ETS-API-Clients.git + ref: ftr/add-news # Other http: ^0.13.4 From 1a3429a8812f528bc2ec50040bc593be56730463 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Mon, 11 Mar 2024 10:18:14 -0400 Subject: [PATCH 11/15] fix comment trad --- l10n/intl_fr.arb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l10n/intl_fr.arb b/l10n/intl_fr.arb index bc03b7ec9..ce8279143 100644 --- a/l10n/intl_fr.arb +++ b/l10n/intl_fr.arb @@ -175,7 +175,7 @@ "news_event_date": "Date de l'événement", "news_error_not_found_title" : "Oh oh!", "news_error_not_found" : "Une erreur est survenue lors de la récupération des annonces. Veuillez réessayer plus tard.", - "news_no_more_card_title": "Tu es à jours!", + "news_no_more_card_title": "Tu es à jour!", "news_no_more_card": "Vous avez atteint la fin des annonces. Revenez plus tard pour voir les prochaines annonces!", "report_news": "Pourquoi reportez-vous cette annonce ?", From fba267bdc94964874179f88cbf634960778b3956 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Mon, 11 Mar 2024 10:22:18 -0400 Subject: [PATCH 12/15] Bump to tag version of ETS-API-CLient --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index b566d2cd4..eb86f33de 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,7 +46,7 @@ dependencies: # path: ../ETS-API-Clients/ git: url: https://github.com/ApplETS/ETS-API-Clients.git - ref: ftr/add-news + ref: 1.1.0 # Other http: ^0.13.4 From 6fda59d17a68767ff9d4397ba3bc80621a958542 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Mon, 11 Mar 2024 11:38:37 -0400 Subject: [PATCH 13/15] use patch version of 1.1 in ets api client --- pubspec.lock | 727 ++++++++++++++++++++++++++++++++++----------------- pubspec.yaml | 8 +- 2 files changed, 486 insertions(+), 249 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 627b18868..bc922ae8f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,415 +5,473 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" source: hosted - version: "50.0.0" + version: "61.0.0" _flutterfire_internals: dependency: transitive description: name: _flutterfire_internals - url: "https://pub.dartlang.org" + sha256: "3ff770dfff04a67b0863dff205a0936784de1b87a5e99b11c693fc10e66a9ce3" + url: "https://pub.dev" source: hosted version: "1.0.12" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.13.0" archive: dependency: transitive description: name: archive - url: "https://pub.dartlang.org" + sha256: "49b1fad315e57ab0bbc15bcbb874e83116a1d78f77ebd500a4af6c9407d6b28e" + url: "https://pub.dev" source: hosted version: "3.3.8" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: "0bd9a99b6eb96f07af141f0eb53eace8983e8e5aa5de59777aca31684680ef22" + url: "https://pub.dev" source: hosted version: "2.3.0" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.0" auto_size_text: dependency: "direct main" description: name: auto_size_text - url: "https://pub.dartlang.org" + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" source: hosted version: "3.0.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + url: "https://pub.dev" source: hosted version: "2.3.1" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" source: hosted version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" + url: "https://pub.dev" source: hosted version: "3.1.1" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + sha256: "7c35a3a7868626257d8aee47b51c26b9dba11eaddf3431117ed2744951416aab" + url: "https://pub.dev" source: hosted version: "2.1.0" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + url: "https://pub.dev" source: hosted version: "2.3.3" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" + url: "https://pub.dev" source: hosted version: "7.2.7" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + sha256: b6c9911b2d670376918d5b8779bc27e0e612a94ec3ff0343689e991d8d0a3b8a + url: "https://pub.dev" source: hosted version: "8.1.4" calendar_view: dependency: "direct main" description: name: calendar_view - url: "https://pub.dartlang.org" + sha256: bf3ea69813e73859b3c715ba33a2e745abeda6ad1c585776cb976936196f7781 + url: "https://pub.dev" source: hosted version: "1.0.1" carousel_slider: dependency: "direct main" description: name: carousel_slider - url: "https://pub.dartlang.org" + sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42" + url: "https://pub.dev" source: hosted version: "4.2.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 + url: "https://pub.dev" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 + url: "https://pub.dev" source: hosted version: "2.0.1" cli_util: dependency: transitive description: name: cli_util - url: "https://pub.dartlang.org" + sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c" + url: "https://pub.dev" source: hosted version: "0.3.5" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + sha256: "02ce3596b459c666530f045ad6f96209474e8fee6e4855940a3cee65fb872ec5" + url: "https://pub.dev" source: hosted version: "4.3.0" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.18.0" connectivity_plus: dependency: "direct main" description: name: connectivity_plus - url: "https://pub.dartlang.org" + sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b" + url: "https://pub.dev" source: hosted version: "4.0.2" connectivity_plus_platform_interface: dependency: transitive description: name: connectivity_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a + url: "https://pub.dev" source: hosted version: "1.2.4" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: f08428ad63615f96a27e34221c65e1a451439b5f26030f78d790f461c686d65d + url: "https://pub.dev" source: hosted version: "3.0.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: cf75650c66c0316274e21d7c43d3dea246273af5955bd94e8184837cd577575c + url: "https://pub.dev" source: hosted version: "3.0.1" csslib: dependency: transitive description: name: csslib - url: "https://pub.dartlang.org" + sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + url: "https://pub.dev" source: hosted version: "0.17.2" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + url: "https://pub.dev" source: hosted version: "2.2.4" dbus: dependency: transitive description: name: dbus - url: "https://pub.dartlang.org" + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.7.10" device_info_plus: dependency: "direct main" description: name: device_info_plus - url: "https://pub.dartlang.org" + sha256: b809c4ed5f7fcdb325ccc70b80ad934677dc4e2aa414bf46859a42bfdfafcbb6 + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.3" device_info_plus_linux: dependency: transitive description: name: device_info_plus_linux - url: "https://pub.dartlang.org" + sha256: "77a8b3c4af06bc46507f89304d9f49dfc64b4ae004b994532ed23b34adeae4b3" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "3.0.0" device_info_plus_macos: dependency: transitive description: name: device_info_plus_macos - url: "https://pub.dartlang.org" + sha256: "37961762fbd46d3620c7b69ca606671014db55fc1b7a11e696fd90ed2e8fe03d" + url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "3.0.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: "83fdba24fcf6846d3b10f10dfdc8b6c6d7ada5f8ed21d62ea2909c2dfa043773" + url: "https://pub.dev" source: hosted - version: "2.3.0+1" + version: "3.0.0" device_info_plus_web: dependency: transitive description: name: device_info_plus_web - url: "https://pub.dartlang.org" + sha256: "5890f6094df108181c7a29720bc23d0fd6159f17d82787fac093d1fefcaf6325" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "3.0.0" device_info_plus_windows: dependency: transitive description: name: device_info_plus_windows - url: "https://pub.dartlang.org" + sha256: "23a2874af0e23ee6e3a2a0ebcecec3a9da13241f2cb93a93a44c8764df123dd7" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "4.1.0" easter_egg_trigger: dependency: "direct main" description: name: easter_egg_trigger - url: "https://pub.dartlang.org" + sha256: "094c16e5ebf15c75131e2fe87944e91ca87524f4ffb88f0128e477befbe43501" + url: "https://pub.dev" source: hosted version: "1.0.1" enum_to_string: dependency: "direct main" description: name: enum_to_string - url: "https://pub.dartlang.org" + sha256: bd9e83a33b754cb43a75b36a9af2a0b92a757bfd9847d2621ca0b1bed45f8e7a + url: "https://pub.dev" source: hosted version: "2.0.1" ets_api_clients: dependency: "direct main" description: path: "." - ref: "ftr/add-news" - resolved-ref: cf61b19f41d01d367ea57fef78306e869930355e + ref: "1.1.1" + resolved-ref: db214ca128b8942988c7c2ace6682c5ed007e4f1 url: "https://github.com/ApplETS/ETS-API-Clients.git" source: git - version: "0.5.0" + version: "1.1.0" fading_edge_scrollview: dependency: transitive description: name: fading_edge_scrollview - url: "https://pub.dartlang.org" + sha256: fcc6184eb6ea6761f310a3619bccd1f59520380328cb1a9fa161730bb2078910 + url: "https://pub.dev" source: hosted version: "2.0.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" feature_discovery: dependency: "direct main" description: name: feature_discovery - url: "https://pub.dartlang.org" + sha256: c4008f3d78515883354ab095cabaefbd5116fb7005b150d28cead306f03f4b30 + url: "https://pub.dev" source: hosted version: "0.14.1" feedback: dependency: "direct main" description: name: feedback - url: "https://pub.dartlang.org" + sha256: "912ffe11317f88585410818885a5312d044f025bd9b5633eab18f5808d28ac54" + url: "https://pub.dev" source: hosted version: "2.5.0" ffi: dependency: transitive description: name: ffi - url: "https://pub.dartlang.org" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "2.1.2" file: dependency: transitive description: name: file - url: "https://pub.dartlang.org" + sha256: b69516f2c26a5bcac4eee2e32512e1a5205ab312b3536c1c1227b2b942b5f9ad + url: "https://pub.dev" source: hosted version: "6.1.2" firebase_analytics: dependency: "direct main" description: name: firebase_analytics - url: "https://pub.dartlang.org" + sha256: "2daceef653b9c2f3399a1f977e06cd14b895569e379f08339706f53a84c9cb5e" + url: "https://pub.dev" source: hosted version: "10.1.0" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface - url: "https://pub.dartlang.org" + sha256: "370fd678c4a1521da84759bf3969796796b4a7837f51db4d7104a1f1c77b12de" + url: "https://pub.dev" source: hosted version: "3.3.17" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web - url: "https://pub.dartlang.org" + sha256: "39c68ad46c0d02819a772606bd1392e984f767a2f4ea5203b5bcadc7c56c8a1d" + url: "https://pub.dev" source: hosted version: "0.5.1+8" firebase_core: dependency: "direct main" description: name: firebase_core - url: "https://pub.dartlang.org" + sha256: c129209ba55f3d4272c89fb4a4994c15bea77fb6de63a82d45fb6bc5c94e4355 + url: "https://pub.dev" source: hosted version: "2.4.1" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface - url: "https://pub.dartlang.org" + sha256: "5fab93f5b354648efa62e7cc829c90efb68c8796eecf87e0888cae2d5f3accd4" + url: "https://pub.dev" source: hosted version: "4.5.2" firebase_core_web: dependency: transitive description: name: firebase_core_web - url: "https://pub.dartlang.org" + sha256: "18b35ce111b0a4266abf723c825bcf9d4e2519d13638cc7f06f2a8dd960c75bc" + url: "https://pub.dev" source: hosted version: "2.1.0" firebase_crashlytics: dependency: "direct main" description: name: firebase_crashlytics - url: "https://pub.dartlang.org" + sha256: "9c05f1024086568b3fd99c2e7c6382443d5024b612538b20ccfc867be0b5c16a" + url: "https://pub.dev" source: hosted version: "3.0.9" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface - url: "https://pub.dartlang.org" + sha256: e62bbdfada6e4d5351d4819a79b59bd9ca0a13719b8326101022d7fa8cdc2d9f + url: "https://pub.dev" source: hosted version: "3.3.10" firebase_remote_config: dependency: "direct main" description: name: firebase_remote_config - url: "https://pub.dartlang.org" + sha256: c174c77624c3d8e8e97e065273325916685bcdae035bb3df5700b3de38712755 + url: "https://pub.dev" source: hosted version: "3.0.9" firebase_remote_config_platform_interface: dependency: transitive description: name: firebase_remote_config_platform_interface - url: "https://pub.dartlang.org" + sha256: ebd05dcb6b402ab0929f529e5282653bfc1812af5f057429c55afd68692cda4c + url: "https://pub.dev" source: hosted version: "1.1.29" firebase_remote_config_web: dependency: transitive description: name: firebase_remote_config_web - url: "https://pub.dartlang.org" + sha256: "59664125e74cd99b78af061f25b17d546056aabfba875335d9a7acaf3dca757d" + url: "https://pub.dev" source: hosted version: "1.1.18" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: "6a2ef17156f4dc49684f9d99aaf4a93aba8ac49f5eac861755f5730ddf6e2e4e" + url: "https://pub.dev" source: hosted version: "1.0.0" flutter: @@ -425,49 +483,56 @@ packages: dependency: "direct main" description: name: flutter_cache_manager - url: "https://pub.dartlang.org" + sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" + url: "https://pub.dev" source: hosted version: "3.3.0" flutter_config: dependency: "direct dev" description: name: flutter_config - url: "https://pub.dartlang.org" + sha256: "8e2be2d560a52e06d2ef53a31913a11fc80ef708a442571c96194fd32e29fb1a" + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_custom_tabs: dependency: "direct main" description: name: flutter_custom_tabs - url: "https://pub.dartlang.org" + sha256: bebb9552438eb3aea8f8511d48e41abdd0d05ff3e9a74622a4d1acd2bffd242c + url: "https://pub.dev" source: hosted version: "1.0.4" flutter_custom_tabs_platform_interface: dependency: transitive description: name: flutter_custom_tabs_platform_interface - url: "https://pub.dartlang.org" + sha256: bbd2d9a2ff22d27e079a35302ddd3da9f2328110c370d56c81655a7ba306fee2 + url: "https://pub.dev" source: hosted version: "1.0.1" flutter_custom_tabs_web: dependency: transitive description: name: flutter_custom_tabs_web - url: "https://pub.dartlang.org" + sha256: d735abff9a1b215018dfe2584f131fe0a3bb0e3b685fbd6ae8a55cf5c4d7dcd8 + url: "https://pub.dev" source: hosted version: "1.0.0" flutter_keychain: dependency: "direct main" description: name: flutter_keychain - url: "https://pub.dartlang.org" + sha256: de6f2d09ce2a006013db799ad37d6ae49b10530d6841de1c0c0525c4d3ec22a4 + url: "https://pub.dev" source: hosted version: "2.4.0" flutter_launcher_icons: dependency: "direct dev" description: name: flutter_launcher_icons - url: "https://pub.dartlang.org" + sha256: ce0e501cfc258907842238e4ca605e74b7fd1cdf04b3b43e86c43f3e40a1592c + url: "https://pub.dev" source: hosted version: "0.11.0" flutter_localizations: @@ -479,72 +544,82 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "5c574d21b98ec92adab05ead10afd2b13ff5856c7ca79696edb338a9dd8ed387" + url: "https://pub.dev" source: hosted version: "2.0.5" flutter_secure_storage: dependency: "direct main" description: name: flutter_secure_storage - url: "https://pub.dartlang.org" + sha256: de957362e046bc68da8dcf6c1d922cb8bdad8dd4979ec69480cf1a3c481abe8e + url: "https://pub.dev" source: hosted version: "6.1.0" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - url: "https://pub.dartlang.org" + sha256: "736436adaf91552433823f51ce22e098c2f0551db06b6596f58597a25b8ea797" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - url: "https://pub.dartlang.org" + sha256: "388f76fd0f093e7415a39ec4c169ae7cceeee6d9f9ba529d788a13f2be4de7bd" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - url: "https://pub.dartlang.org" + sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b + url: "https://pub.dev" source: hosted version: "1.0.1" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - url: "https://pub.dartlang.org" + sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" + url: "https://pub.dev" source: hosted version: "1.1.1" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - url: "https://pub.dartlang.org" + sha256: ca89c8059cf439985aa83c59619b3674c7ef6cc2e86943d169a7369d6a69cab5 + url: "https://pub.dev" source: hosted version: "1.1.3" flutter_siren: dependency: "direct main" description: name: flutter_siren - url: "https://pub.dartlang.org" + sha256: "0814d890072c0d474d49e1a0e1e3edfb5a88756fa1890663b07685d4a09b7f73" + url: "https://pub.dev" source: hosted version: "1.2.0" flutter_staggered_animations: dependency: "direct main" description: name: flutter_staggered_animations - url: "https://pub.dartlang.org" + sha256: "81d3c816c9bb0dca9e8a5d5454610e21ffb068aedb2bde49d2f8d04f75538351" + url: "https://pub.dev" source: hosted version: "1.1.1" flutter_svg: dependency: "direct main" description: name: flutter_svg - url: "https://pub.dartlang.org" + sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" + url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.1.6" flutter_test: dependency: "direct dev" description: flutter @@ -559,581 +634,696 @@ packages: dependency: "direct main" description: name: fluttertoast - url: "https://pub.dartlang.org" + sha256: b528e78a4e69957bb8a33d9e8ceaa728801bb7c6ce599e811e49cf6d94d17fef + url: "https://pub.dev" source: hosted version: "8.0.9" font_awesome_flutter: dependency: "direct main" description: name: font_awesome_flutter - url: "https://pub.dartlang.org" + sha256: "8f0ce0204bd0cafa8631536a6f3b7d05d9c16cdc6e8bd807843f917027c5cefd" + url: "https://pub.dev" source: hosted version: "10.2.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + url: "https://pub.dev" source: hosted version: "3.2.0" get_it: dependency: "direct main" description: name: get_it - url: "https://pub.dartlang.org" + sha256: "290fde3a86072e4b37dbb03c07bec6126f0ecc28dad403c12ffe2e5a2d751ab7" + url: "https://pub.dev" source: hosted version: "7.2.0" github: dependency: "direct main" description: name: github - url: "https://pub.dartlang.org" + sha256: "735991ba8a95eade0e1b7a991802d93f9e3f1b2f4bcba328be60ca9a92af4b4a" + url: "https://pub.dev" source: hosted version: "9.1.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: "8321dd2c0ab0683a91a51307fa844c6db4aa8e3981219b78961672aaab434658" + url: "https://pub.dev" source: hosted version: "2.0.2" google_maps: dependency: transitive description: name: google_maps - url: "https://pub.dartlang.org" + sha256: "555d5d736339b0478e821167ac521c810d7b51c3b2734e6802a9f046b64ea37a" + url: "https://pub.dev" source: hosted version: "6.3.0" google_maps_flutter: dependency: "direct main" description: name: google_maps_flutter - url: "https://pub.dartlang.org" + sha256: "7b417a64ee7a060f42cf44d8c274d3b562423f6fe57d2911b7b536857c0d8eb6" + url: "https://pub.dev" source: hosted version: "2.3.0" google_maps_flutter_android: dependency: transitive description: name: google_maps_flutter_android - url: "https://pub.dartlang.org" + sha256: "09e7e7fa642ea105bd507bb0c184c3d2fa9f9ad08f55bd8c8d609388d9078328" + url: "https://pub.dev" source: hosted version: "2.3.3" google_maps_flutter_ios: dependency: transitive description: name: google_maps_flutter_ios - url: "https://pub.dartlang.org" + sha256: "43a71553d9973af6886b6984e246dac18b8a62dc59581904d8d1292388b05ea5" + url: "https://pub.dev" source: hosted version: "2.1.12" google_maps_flutter_platform_interface: dependency: transitive description: name: google_maps_flutter_platform_interface - url: "https://pub.dartlang.org" + sha256: cde5d8713fd61f48ba675190be5ab294a022eec966748a2f83063f487d076fbc + url: "https://pub.dev" source: hosted version: "2.2.4" google_maps_flutter_web: dependency: transitive description: name: google_maps_flutter_web - url: "https://pub.dartlang.org" + sha256: "280170a2dcac3364317b5786f0d2e3c4128fdb795bc0d87ffe56226b0cf1f57d" + url: "https://pub.dev" source: hosted version: "0.5.1" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + sha256: ae0b3d956ff324c6f8671f08dcb2dbd71c99cdbf2aa3ca63a14190c47aa6679c + url: "https://pub.dev" source: hosted version: "2.1.0" home_widget: dependency: "direct main" description: name: home_widget - url: "https://pub.dartlang.org" + sha256: "9514c47422d511e87a3923ffed3fc4eb82540e168d7715d1560ceb1f02d5ec80" + url: "https://pub.dev" source: hosted version: "0.1.6" html: dependency: transitive description: name: html - url: "https://pub.dartlang.org" + sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8" + url: "https://pub.dev" source: hosted version: "0.15.3" http: - dependency: "direct main" + dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: "2ed163531e071c2c6b7c659635112f24cb64ecbebf6af46b550d536c0b1aa112" + url: "https://pub.dev" source: hosted version: "0.13.4" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 + url: "https://pub.dev" source: hosted version: "4.0.0" image: dependency: transitive description: name: image - url: "https://pub.dartlang.org" + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.3.0" import_sorter: dependency: "direct main" description: name: import_sorter - url: "https://pub.dartlang.org" + sha256: eb15738ccead84e62c31e0208ea4e3104415efcd4972b86906ca64a1187d0836 + url: "https://pub.dev" source: hosted version: "4.6.0" in_app_review: dependency: "direct main" description: name: in_app_review - url: "https://pub.dartlang.org" + sha256: "16328b8202d36522322b95804ae5d975577aa9f584d634985849ba1099645850" + url: "https://pub.dev" source: hosted version: "2.0.6" in_app_review_platform_interface: dependency: transitive description: name: in_app_review_platform_interface - url: "https://pub.dartlang.org" + sha256: b12ec9aaf6b34d3a72aa95895eb252b381896246bdad4ef378d444affe8410ef + url: "https://pub.dev" source: hosted version: "2.0.4" infinite_scroll_pagination: dependency: "direct main" description: name: infinite_scroll_pagination - url: "https://pub.dartlang.org" + sha256: "9517328f4e373f08f57dbb11c5aac5b05554142024d6b60c903f3b73476d52db" + url: "https://pub.dev" source: hosted version: "3.2.0" intl: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.18.1" io: dependency: transitive description: name: io - url: "https://pub.dartlang.org" + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" source: hosted version: "1.0.4" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: a5e201311cb08bf3912ebbe9a2be096e182d703f881136ec1e81a2338a9e120d + url: "https://pub.dev" source: hosted version: "0.6.4" js_wrapping: dependency: transitive description: name: js_wrapping - url: "https://pub.dartlang.org" + sha256: e385980f7c76a8c1c9a560dfb623b890975841542471eade630b2871d243851c + url: "https://pub.dev" source: hosted version: "0.7.4" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: "3520fa844009431b5d4491a5a778603520cdc399ab3406332dcc50f93547258c" + url: "https://pub.dev" source: hosted version: "4.7.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lint: dependency: "direct dev" description: name: lint - url: "https://pub.dartlang.org" + sha256: "3e9343b1cededcfb1e8b40d0dbd3592b7a1c6c0121545663a991433390c2bc97" + url: "https://pub.dev" source: hosted version: "2.0.1" logger: dependency: "direct main" description: name: logger - url: "https://pub.dartlang.org" + sha256: "5076f09225f91dc49289a4ccb92df2eeea9ea01cf7c26d49b3a1f04c6a49eec1" + url: "https://pub.dev" source: hosted version: "1.1.0" logging: dependency: transitive description: name: logging - url: "https://pub.dartlang.org" + sha256: "293ae2d49fd79d4c04944c3a26dfd313382d5f52e821ec57119230ae16031ad4" + url: "https://pub.dev" source: hosted version: "1.0.2" marquee: dependency: "direct main" description: name: marquee - url: "https://pub.dartlang.org" + sha256: ac5fd2176dd6262d9eec0d0cc6daa99edcbd88097433cfe86a889112cd254145 + url: "https://pub.dev" source: hosted version: "2.2.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.8.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.11.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" source: hosted version: "1.0.4" mockito: dependency: "direct dev" description: name: mockito - url: "https://pub.dartlang.org" + sha256: "8b46d7eb40abdda92d62edd01546051f0c27365e65608c284de336dccfef88cc" + url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "5.4.1" nested: dependency: transitive description: name: nested - url: "https://pub.dartlang.org" + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" source: hosted version: "1.0.0" nm: dependency: transitive description: name: nm - url: "https://pub.dartlang.org" + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" source: hosted version: "0.5.0" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: a4d5ede5ca9c3d88a2fef1147a078570c861714c806485c596b109819135bc12 + url: "https://pub.dev" source: hosted version: "2.0.2" package_info_plus: dependency: "direct main" description: name: package_info_plus - url: "https://pub.dartlang.org" + sha256: f62d7253edc197fe3c88d7c2ddab82d68f555e778d55390ccc3537eca8e8d637 + url: "https://pub.dev" source: hosted - version: "1.4.2" + version: "1.4.3+1" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux - url: "https://pub.dartlang.org" + sha256: "04b575f44233d30edbb80a94e57cad9107aada334fc02aabb42b6becd13c43fc" + url: "https://pub.dev" source: hosted version: "1.0.5" package_info_plus_macos: dependency: transitive description: name: package_info_plus_macos - url: "https://pub.dartlang.org" + sha256: a2ad8b4acf4cd479d4a0afa5a74ea3f5b1c7563b77e52cc32b3ee6956d5482a6 + url: "https://pub.dev" source: hosted version: "1.3.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - url: "https://pub.dartlang.org" + sha256: f7a0c8f1e7e981bc65f8b64137a53fd3c195b18d429fba960babc59a5a1c7ae8 + url: "https://pub.dev" source: hosted version: "1.0.2" package_info_plus_web: dependency: transitive description: name: package_info_plus_web - url: "https://pub.dartlang.org" + sha256: d652f0a865d2da52856e2001c53e83fe34a6009cd8d8751d38cf8173c0abf906 + url: "https://pub.dev" source: hosted version: "1.0.5" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows - url: "https://pub.dartlang.org" + sha256: "79524f11c42dd9078b96d797b3cf79c0a2883a50c4920dc43da8562c115089bc" + url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "2.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.0" path_drawing: dependency: transitive description: name: path_drawing - url: "https://pub.dartlang.org" + sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 + url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" path_parsing: dependency: transitive description: name: path_parsing - url: "https://pub.dartlang.org" + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" path_provider: dependency: "direct main" description: name: path_provider - url: "https://pub.dartlang.org" + sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd" + url: "https://pub.dev" source: hosted version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android - url: "https://pub.dartlang.org" + sha256: "8b759fb6c74955931e87f550cc9e890b0cccb7ef8e710943973efeaa9695c54d" + url: "https://pub.dev" source: hosted version: "2.0.12" path_provider_ios: dependency: transitive description: name: path_provider_ios - url: "https://pub.dartlang.org" + sha256: "943b76e54056386432cdc2731cb303e2f580346b61a1fc73819721767be72309" + url: "https://pub.dev" source: hosted version: "2.0.8" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.dartlang.org" + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.11" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.dartlang.org" + sha256: "0adeb313e1f2c3fc52baeeee59b0fe9c2d1f7da56fd96a9234e1702ec653a453" + url: "https://pub.dev" source: hosted version: "2.0.5" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.dartlang.org" + sha256: "3dc0d51b07f85fec3746d9f4e8d31c73bb173cafa2e763f03f8df2e8d1878882" + url: "https://pub.dev" source: hosted version: "2.0.3" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.dartlang.org" + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.7" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" + url: "https://pub.dev" source: hosted version: "1.11.1" percent_indicator: dependency: "direct main" description: name: percent_indicator - url: "https://pub.dartlang.org" + sha256: cec41f67181fbd5322aa68b355621d1a4eea827426b8eeb613f6cbe195ff7b4a + url: "https://pub.dev" source: hosted version: "4.2.2" petitparser: dependency: transitive description: name: petitparser - url: "https://pub.dartlang.org" + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "6.0.2" platform: dependency: transitive description: name: platform - url: "https://pub.dartlang.org" + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + url: "https://pub.dev" source: hosted version: "2.1.3" pointycastle: dependency: transitive description: name: pointycastle - url: "https://pub.dartlang.org" + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" source: hosted version: "3.7.3" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" process: dependency: transitive description: name: process - url: "https://pub.dartlang.org" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + url: "https://pub.dev" source: hosted version: "4.2.4" provider: dependency: "direct main" description: name: provider - url: "https://pub.dartlang.org" + sha256: e1e7413d70444ea3096815a60fe5da1b11bda8a9dc4769252cc82c53536f8bcc + url: "https://pub.dev" source: hosted version: "6.0.4" pub_semver: dependency: "direct main" description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" source: hosted version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + url: "https://pub.dev" source: hosted version: "1.2.1" reorderable_grid_view: dependency: "direct main" description: name: reorderable_grid_view - url: "https://pub.dartlang.org" + sha256: "7ac7058e5388276cbc37aa169547cc93522a2f1c669fac6903a143f2082e3ffc" + url: "https://pub.dev" source: hosted version: "2.2.6" rive: dependency: "direct main" description: name: rive - url: "https://pub.dartlang.org" + sha256: "23ffbeb1d45956b2d5ecd4b2c2d3bae2e61bc32b61fc2e9a48021e28feab6b5f" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + rive_common: + dependency: transitive + description: + name: rive_common + sha256: "3fcaa47dd20dde59d197fc71dce174ca0a7ce9083a0fb73cf457e2cd111b0bbc" + url: "https://pub.dev" source: hosted - version: "0.9.1" + version: "0.3.2" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.dartlang.org" + sha256: bc2d2b17b87fab32e2dca53ca3066d3147de6f96c74d76cfe1a379a24239c46d + url: "https://pub.dev" source: hosted version: "0.27.3" sanitize_html: dependency: transitive description: name: sanitize_html - url: "https://pub.dartlang.org" + sha256: "0a445f19bbaa196f5a4f93461aa066b94e6e025622eb1e9bc77872a5e25233a5" + url: "https://pub.dev" source: hosted version: "2.0.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - url: "https://pub.dartlang.org" + sha256: "76917b7d4b9526b2ba416808a7eb9fb2863c1a09cf63ec85f1453da240fa818a" + url: "https://pub.dev" source: hosted version: "2.0.15" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - url: "https://pub.dartlang.org" + sha256: bc236594233d10b7668dd90414fe0e09d906115aaa1dfe269e478e5f2af532a6 + url: "https://pub.dev" source: hosted version: "2.0.11" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios - url: "https://pub.dartlang.org" + sha256: "69d593a80fee48b97c66787eb930cdd42941c1537e80a1ff88a8c12a926c47d4" + url: "https://pub.dev" source: hosted version: "2.1.0" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - url: "https://pub.dartlang.org" + sha256: ac361c65c4cf342dfc0a8b9e45eab66b9b3ad6eaff9785850d4ec0cf6b474422 + url: "https://pub.dev" source: hosted version: "2.1.0" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos - url: "https://pub.dartlang.org" + sha256: f063907c3f678de8daa033d234b7c9e420df5fe3d499a97bfb82cc30cf171496 + url: "https://pub.dev" source: hosted version: "2.0.3" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - url: "https://pub.dartlang.org" + sha256: "992f0fdc46d0a3c0ac2e5859f2de0e577bbe51f78a77ee8f357cbe626a2ad32d" + url: "https://pub.dev" source: hosted version: "2.0.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - url: "https://pub.dartlang.org" + sha256: "09da0185028a227d51721cade7a3cbd5cc5f163a19593266f2acba87f729bf9c" + url: "https://pub.dev" source: hosted version: "2.0.3" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - url: "https://pub.dartlang.org" + sha256: ae68cf0df0910e38c95522dbd8a6082ce9715053c369750c5709d17de81d032e + url: "https://pub.dev" source: hosted version: "2.1.0" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" source: hosted version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" source: hosted version: "1.0.4" shimmer: dependency: "direct main" description: name: shimmer - url: "https://pub.dartlang.org" + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" source: hosted version: "3.0.0" simple_gesture_detector: dependency: transitive description: name: simple_gesture_detector - url: "https://pub.dartlang.org" + sha256: "86d08f85f1f58583b7b4b941d989f48ea6ce08c1724a1d10954a277c2ec36592" + url: "https://pub.dev" source: hosted version: "0.2.0" sky_engine: @@ -1145,289 +1335,338 @@ packages: dependency: transitive description: name: sliver_tools - url: "https://pub.dartlang.org" + sha256: eae28220badfb9d0559207badcbbc9ad5331aac829a88cb0964d330d2a4636a6 + url: "https://pub.dev" source: hosted version: "0.2.12" source_gen: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d" + url: "https://pub.dev" source: hosted version: "1.2.6" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.10.0" sqflite: dependency: transitive description: name: sqflite - url: "https://pub.dartlang.org" + sha256: f83e4c46d693b02436348a3a8693fa0fa50b0d98eeb55afc7579b70b0d8967f6 + url: "https://pub.dev" source: hosted version: "2.0.2" sqflite_common: dependency: transitive description: name: sqflite_common - url: "https://pub.dartlang.org" + sha256: c65f003175e4d0559af8180000eec451479b1017bd6c7a7d446c9ae3fecbea0a + url: "https://pub.dev" source: hosted version: "2.2.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.1" stacked: dependency: "direct main" description: name: stacked - url: "https://pub.dartlang.org" + sha256: e15b883f4175ed954994c5a778399217e4562cf07eecc66fa85fd292dc554a96 + url: "https://pub.dev" source: hosted version: "3.0.1" stacked_core: dependency: transitive description: name: stacked_core - url: "https://pub.dartlang.org" + sha256: "28889e0b3cb612bf8f13d85050df43fb386f9483bd0fba6756637d9bc7af23dd" + url: "https://pub.dev" source: hosted version: "1.2.4" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: ed464977cb26a1f41537e177e190c67223dbd9f4f683489b6ab2e5d211ec564e + url: "https://pub.dev" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.dartlang.org" + sha256: "271977ff1e9e82ceefb4f08424b8839f577c1852e0726b5ce855311b46d3ef83" + url: "https://pub.dev" source: hosted version: "3.0.0" table_calendar: dependency: "direct main" description: name: table_calendar - url: "https://pub.dartlang.org" + sha256: "1e3521a3e6d3fc7f645a58b135ab663d458ab12504f1ea7f9b4b81d47086c478" + url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.9" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.6.1" timeago: dependency: "direct main" description: name: timeago - url: "https://pub.dartlang.org" + sha256: d3204eb4c788214883380253da7f23485320a58c11d145babc82ad16bf4e7764 + url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.6.1" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" source: hosted version: "1.0.1" tint: dependency: transitive description: name: tint - url: "https://pub.dartlang.org" + sha256: "9652d9a589f4536d5e392cf790263d120474f15da3cf1bee7f1fdb31b4de5f46" + url: "https://pub.dev" source: hosted version: "2.0.1" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" source: hosted version: "1.3.0" universal_io: dependency: transitive description: name: universal_io - url: "https://pub.dartlang.org" + sha256: "79f78ddad839ee3aae3ec7c01eb4575faf0d5c860f8e5223bc9f9c17f7f03cef" + url: "https://pub.dev" source: hosted version: "2.0.4" url_launcher: dependency: "direct main" description: name: url_launcher - url: "https://pub.dartlang.org" + sha256: "3c92b0efb5e9dcb8f846aefabf9f0f739f91682ed486b991ceda51c288e60896" + url: "https://pub.dev" source: hosted version: "6.1.7" url_launcher_android: dependency: transitive description: name: url_launcher_android - url: "https://pub.dartlang.org" + sha256: b693e6698f7e6985710d67a050e3acbdda3b9cfc4b43b9f1c40cdbe42c705b92 + url: "https://pub.dev" source: hosted version: "6.0.15" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - url: "https://pub.dartlang.org" + sha256: e51a93f0da65733beb69fdbc43cea524d86ed8e524479e9faefc9304cec34a57 + url: "https://pub.dev" source: hosted version: "6.0.15" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - url: "https://pub.dartlang.org" + sha256: c3ec89d52305ec647cf037eafe2be8d2f1149b5723d1f2ec716fc3d58469de5d + url: "https://pub.dev" source: hosted version: "3.0.0" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - url: "https://pub.dartlang.org" + sha256: c028c7f80fdb99cf48b94c471c0f8b9b855a188f4865df76e2a7663ae640e9d2 + url: "https://pub.dev" source: hosted version: "3.0.0" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - url: "https://pub.dartlang.org" + sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + url: "https://pub.dev" source: hosted version: "2.1.1" url_launcher_web: dependency: transitive description: name: url_launcher_web - url: "https://pub.dartlang.org" + sha256: "2b5494722d4eb0fe1a12ceb15a4b132ba7dfc92793089c243bf109bed828d97f" + url: "https://pub.dev" source: hosted version: "2.0.9" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - url: "https://pub.dartlang.org" + sha256: aa14bdb9265fa22416fc387b33e44eb37fd38768bf465fafcec73d283f3457b1 + url: "https://pub.dev" source: hosted version: "3.0.0" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: "2469694ad079893e3b434a627970c33f2fa5adc46dfe03c9617546969a9a8afc" + url: "https://pub.dev" source: hosted version: "3.0.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" version: dependency: transitive description: name: version - url: "https://pub.dartlang.org" + sha256: "86d4b7303604b3616f47ccc7b2bca92460c1b391095e3b286a8c3cf41fa8cdaa" + url: "https://pub.dev" source: hosted version: "2.0.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: e42dfcc48f67618344da967b10f62de57e04bae01d9d3af4c2596f3712a88c99 + url: "https://pub.dev" source: hosted version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.dev" source: hosted version: "2.4.0" webview_flutter: dependency: "direct main" description: name: webview_flutter - url: "https://pub.dartlang.org" + sha256: "392c1d83b70fe2495de3ea2c84531268d5b8de2de3f01086a53334d8b6030a88" + url: "https://pub.dev" source: hosted version: "3.0.4" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - url: "https://pub.dartlang.org" + sha256: "6d796e709d14da8496ee7c750765fad0e860c57a60844bb50f5b93a9ee5ceeab" + url: "https://pub.dev" source: hosted version: "2.8.3" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - url: "https://pub.dartlang.org" + sha256: "6144d750f56ae63fdaad10ff09e0f762142beabde4fefdc2d32564f75572d905" + url: "https://pub.dev" source: hosted version: "1.8.1" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - url: "https://pub.dartlang.org" + sha256: "87c56a34f69867f3aaf0b66df5399a4fc18898b1df8c738b835e62b73059d66f" + url: "https://pub.dev" source: hosted version: "2.7.1" win32: dependency: transitive description: name: win32 - url: "https://pub.dartlang.org" + sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "3.1.4" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.dartlang.org" + sha256: "060b6e1c891d956f72b5ac9463466c37cce3fa962a921532fc001e86fe93438e" + url: "https://pub.dev" source: hosted version: "0.2.0+1" xml: dependency: transitive description: name: xml - url: "https://pub.dartlang.org" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "6.5.0" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: "3cee79b1715110341012d27756d9bae38e650588acd38d3f3c610822e1337ace" + url: "https://pub.dev" source: hosted version: "3.1.0" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.3.0-279.1.beta <4.0.0" flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index eb86f33de..3323fb6a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 4.34.0+1 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: flutter: @@ -41,15 +41,13 @@ dependencies: flutter_siren: ^1.2.0 # Customs - # TODO: Change to the latest version, once reviewed and accepted ets_api_clients: # path: ../ETS-API-Clients/ git: url: https://github.com/ApplETS/ETS-API-Clients.git - ref: 1.1.0 + ref: 1.1.1 # Other - http: ^0.13.4 flutter_cache_manager: ^3.0.1 flutter_secure_storage: ^6.1.0 shared_preferences: ^2.0.15 @@ -60,7 +58,7 @@ dependencies: package_info_plus: ^1.4.2 feature_discovery: ^0.14.0 path_provider: ^2.0.11 - rive: ^0.9.1 + rive: ^0.13.0 connectivity_plus: ^4.0.2 flutter_svg: ^1.0.3 font_awesome_flutter: ^10.2.1 From 8b3da579aab49973aa4ac5eae8d88485574c027e Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Mon, 11 Mar 2024 11:42:16 -0400 Subject: [PATCH 14/15] fix flutter version --- .github/workflows/dev-workflow.yaml | 2 +- .github/workflows/master-workflow.yaml | 2 +- .github/workflows/release-workflow.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-workflow.yaml b/.github/workflows/dev-workflow.yaml index 204f18ed2..079b82e63 100644 --- a/.github/workflows/dev-workflow.yaml +++ b/.github/workflows/dev-workflow.yaml @@ -39,7 +39,7 @@ jobs: java-version: '11' - uses: subosito/flutter-action@v2 with: - flutter-version: '3.3.x' + flutter-version: '3.x.x' channel: 'stable' cache: true - run: flutter doctor diff --git a/.github/workflows/master-workflow.yaml b/.github/workflows/master-workflow.yaml index d347b70a9..e926471e8 100644 --- a/.github/workflows/master-workflow.yaml +++ b/.github/workflows/master-workflow.yaml @@ -72,7 +72,7 @@ jobs: java-version: '11' - uses: subosito/flutter-action@v2 with: - flutter-version: '3.3.x' + flutter-version: '3.x.x' channel: 'stable' cache: true - run: flutter doctor diff --git a/.github/workflows/release-workflow.yaml b/.github/workflows/release-workflow.yaml index 08d0bc9da..2c91fe70d 100644 --- a/.github/workflows/release-workflow.yaml +++ b/.github/workflows/release-workflow.yaml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: - flutter-version: '3.3.x' + flutter-version: '3.x.x' channel: 'stable' cache: true - name: Setup Fastlane From 82a1fa2563b4fa13b62b63e59d48b1943b5b8d11 Mon Sep 17 00:00:00 2001 From: MysticFragilist Date: Mon, 11 Mar 2024 11:43:48 -0400 Subject: [PATCH 15/15] fix flutter version in ci p2 --- .github/workflows/dev-workflow.yaml | 2 +- .github/workflows/master-workflow.yaml | 2 +- .github/workflows/release-workflow.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-workflow.yaml b/.github/workflows/dev-workflow.yaml index 079b82e63..456c74842 100644 --- a/.github/workflows/dev-workflow.yaml +++ b/.github/workflows/dev-workflow.yaml @@ -39,7 +39,7 @@ jobs: java-version: '11' - uses: subosito/flutter-action@v2 with: - flutter-version: '3.x.x' + flutter-version: '3.x' channel: 'stable' cache: true - run: flutter doctor diff --git a/.github/workflows/master-workflow.yaml b/.github/workflows/master-workflow.yaml index e926471e8..8cecdab8d 100644 --- a/.github/workflows/master-workflow.yaml +++ b/.github/workflows/master-workflow.yaml @@ -72,7 +72,7 @@ jobs: java-version: '11' - uses: subosito/flutter-action@v2 with: - flutter-version: '3.x.x' + flutter-version: '3.x' channel: 'stable' cache: true - run: flutter doctor diff --git a/.github/workflows/release-workflow.yaml b/.github/workflows/release-workflow.yaml index 2c91fe70d..8cdfa79a6 100644 --- a/.github/workflows/release-workflow.yaml +++ b/.github/workflows/release-workflow.yaml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: - flutter-version: '3.x.x' + flutter-version: '3.x' channel: 'stable' cache: true - name: Setup Fastlane