From d0bdac5c9d26ad3760ca6e7e4f293971051bfcf2 Mon Sep 17 00:00:00 2001 From: matt-hagemann Date: Thu, 14 Sep 2023 14:53:39 +0200 Subject: [PATCH] refactor: removing ratingsListModelProvider Removed the ratingsListModelProvider, opting to use ratingsModelProvider instead and nesting the calls deeper in the widget tree --- lib/src/detail/detail_page.dart | 122 ++++++++++++----------- lib/src/explore/explore_page.dart | 40 +++----- lib/src/ratings/ratings_l10n.dart | 2 +- lib/src/ratings/ratings_list_model.dart | 40 -------- lib/src/ratings/ratings_service.dart | 27 +----- lib/src/search/search_page.dart | 81 ++++++---------- lib/src/widgets/snap_card.dart | 48 +++++---- lib/src/widgets/snap_grid.dart | 9 -- test/search_page_test.dart | 59 ++++------- test/snap_card_test.dart | 44 +++++++++ test/store_app_test.dart | 1 - test/test_utils.dart | 15 --- test/test_utils.mocks.dart | 124 +++--------------------- 13 files changed, 220 insertions(+), 392 deletions(-) delete mode 100644 lib/src/ratings/ratings_list_model.dart create mode 100644 test/snap_card_test.dart diff --git a/lib/src/detail/detail_page.dart b/lib/src/detail/detail_page.dart index dfc326469..21d70a181 100644 --- a/lib/src/detail/detail_page.dart +++ b/lib/src/detail/detail_page.dart @@ -1,3 +1,5 @@ +import 'package:app_center/src/ratings/ratings_l10n.dart'; +import 'package:app_center/src/ratings/ratings_model.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -15,13 +17,16 @@ import '/l10n.dart'; import '/layout.dart'; import '/snapd.dart'; import '/widgets.dart'; -import '../ratings/ratings_l10n.dart'; -import '../ratings/ratings_model.dart'; const _kPrimaryButtonMaxWidth = 136.0; const _kChannelDropdownWidth = 220.0; -typedef SnapInfo = ({String label, Widget value}); +class SnapInfo { + final String label; + final Widget value; + + SnapInfo({required this.label, required this.value}); +} class DetailPage extends ConsumerWidget { const DetailPage({super.key, required this.snapName}); @@ -34,22 +39,12 @@ class DetailPage extends ConsumerWidget { final updatesModel = ref.watch(updatesModelProvider); return snapModel.state.when( - data: (snapData) { - final snapId = snapModel.snap.id; // Replace with actual field name - final ratingsModel = ref.watch(ratingsModelProvider(snapId)); - - return ratingsModel.state.when( - data: (_) => ResponsiveLayoutBuilder( - builder: (_) => _SnapView( - snapModel: snapModel, - updatesModel: updatesModel, - ratingsModel: ratingsModel, - ), - ), - error: (error, stackTrace) => ErrorWidget(error), - loading: () => const Center(child: YaruCircularProgressIndicator()), - ); - }, + data: (snapData) => ResponsiveLayoutBuilder( + builder: (_) => _SnapView( + snapModel: snapModel, + updatesModel: updatesModel, + ), + ), error: (error, stackTrace) => ErrorWidget(error), loading: () => const Center(child: YaruCircularProgressIndicator()), ); @@ -60,28 +55,17 @@ class _SnapView extends ConsumerWidget { const _SnapView({ required this.snapModel, required this.updatesModel, - required this.ratingsModel, }); final SnapModel snapModel; final UpdatesModel updatesModel; - final RatingsModel ratingsModel; @override Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context); + final snapInfos = [ - ( - label: - '${ratingsModel.snapRating?.totalVotes ?? 0} ${l10n.snapRatingsVotes}', - value: Text( - ratingsModel.snapRating?.ratingsBand.localize(l10n) ?? ' ', - style: TextStyle( - color: ratingsModel.snapRating!.ratingsBand.getColor(context), - fontSize: 12), - ) - ), // Placeholder - ( + SnapInfo( label: l10n.detailPageConfinementLabel, value: Row( mainAxisSize: MainAxisSize.min, @@ -99,15 +83,15 @@ class _SnapView extends ConsumerWidget { ], ), ), - ( + SnapInfo( label: l10n.detailPageDownloadSizeLabel, value: Text( snapModel.channelInfo != null ? context.formatByteSize(snapModel.channelInfo!.size) : '', - ) + ), ), - ( + SnapInfo( label: l10n.detailPagePublishedLabel, value: Text( snapModel.channelInfo != null @@ -115,11 +99,11 @@ class _SnapView extends ConsumerWidget { : '', ), ), - ( + SnapInfo( label: l10n.detailPageLicenseLabel, value: Text(snapModel.snap.license ?? ''), ), - ( + SnapInfo( label: l10n.detailPageLinksLabel, value: Column( children: [ @@ -158,7 +142,11 @@ class _SnapView extends ConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _SnapInfos(snapInfos: snapInfos, layout: layout), + _SnapInfos( + snapInfos: snapInfos, + snapId: snapModel.snap.id, + layout: layout, + ), const Divider(), if (snapModel.hasGallery) _Section( @@ -191,36 +179,58 @@ class _SnapView extends ConsumerWidget { } } -class _SnapInfos extends StatelessWidget { +class _SnapInfos extends ConsumerWidget { const _SnapInfos({ required this.snapInfos, + required this.snapId, required this.layout, }); final List snapInfos; final ResponsiveLayout layout; + final String snapId; @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final l10n = AppLocalizations.of(context); + final ratingsModel = ref.watch(ratingsModelProvider(snapId)); + + final ratings = ratingsModel.state.whenOrNull( + data: (_) => SnapInfo( + label: + '${ratingsModel.snapRating?.totalVotes ?? 0} ${l10n.snapRatingsVotes}', + value: Text( + ratingsModel.snapRating?.ratingsBand.localize(l10n) ?? '', + style: TextStyle( + color: ratingsModel.snapRating?.ratingsBand.getColor(context)), + ), + ), + ); + return Wrap( spacing: kPagePadding, runSpacing: 8, - children: snapInfos - .map((info) => SizedBox( - width: (layout.totalWidth - - (layout.snapInfoColumnCount - 1) * kPagePadding) / - layout.snapInfoColumnCount, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(info.label), - DefaultTextStyle.merge( - style: const TextStyle(fontWeight: FontWeight.w500), - child: info.value, - ), - ], - ), - )) + children: [ + if (ratings != null) ratings, + ...snapInfos, + ] + .map( + (info) => SizedBox( + width: (layout.totalWidth - + (layout.snapInfoColumnCount - 1) * kPagePadding) / + layout.snapInfoColumnCount, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(info.label), + DefaultTextStyle.merge( + style: const TextStyle(fontWeight: FontWeight.w500), + child: info.value, + ), + ], + ), + ), + ) .toList(), ); } diff --git a/lib/src/explore/explore_page.dart b/lib/src/explore/explore_page.dart index 8ff3df503..8bf70cb92 100644 --- a/lib/src/explore/explore_page.dart +++ b/lib/src/explore/explore_page.dart @@ -3,9 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:snapd/snapd.dart'; import 'package:yaru_icons/yaru_icons.dart'; -import 'package:yaru_widgets/widgets.dart'; -import '../ratings/ratings_list_model.dart'; import '/l10n.dart'; import '/layout.dart'; import '/snapd.dart'; @@ -129,33 +127,17 @@ class _CategorySnapList extends ConsumerWidget { .toList() ?? []; - final snapIds = snaps.map((snap) => snap.id).toList(); - - return Consumer( - builder: (BuildContext context, WidgetRef ref, Widget? child) { - final ratingsList = ref.watch(ratingsListModelProvider(snapIds)); - - return ratingsList.state.when( - data: (ratings) => showScreenshots - ? SnapImageCardGrid( - snaps: snaps, - ratings: ratingsList.snapRatings!, - onTap: (snap) => - StoreNavigator.pushDetail(context, name: snap.name), - ) - : SnapCardGrid( - snaps: snaps, - ratings: ratingsList.snapRatings!, - onTap: (snap) => - StoreNavigator.pushDetail(context, name: snap.name), - ), - error: (error, stack) => - SliverToBoxAdapter(child: ErrorWidget(error)), - loading: () => const SliverToBoxAdapter( - child: Center(child: YaruCircularProgressIndicator())), - ); - }, - ); + return showScreenshots + ? SnapImageCardGrid( + snaps: snaps, + onTap: (snap) => + StoreNavigator.pushDetail(context, name: snap.name), + ) + : SnapCardGrid( + snaps: snaps, + onTap: (snap) => + StoreNavigator.pushDetail(context, name: snap.name), + ); } } diff --git a/lib/src/ratings/ratings_l10n.dart b/lib/src/ratings/ratings_l10n.dart index e08a14b85..2917e984d 100644 --- a/lib/src/ratings/ratings_l10n.dart +++ b/lib/src/ratings/ratings_l10n.dart @@ -1,6 +1,6 @@ +import 'package:app_center/l10n.dart'; import 'package:flutter/material.dart'; -import '../../l10n.dart'; import 'exports.dart'; extension RatingsBandL10n on RatingsBand { diff --git a/lib/src/ratings/ratings_list_model.dart b/lib/src/ratings/ratings_list_model.dart deleted file mode 100644 index 81ea9c96a..000000000 --- a/lib/src/ratings/ratings_list_model.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:app_center/src/ratings/ratings_service.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:ubuntu_service/ubuntu_service.dart'; - -import 'exports.dart'; - -final ratingsListModelProvider = - ChangeNotifierProvider.family.autoDispose>( - (ref, snapIds) => RatingsListModel( - ratingsService: getService(), - snapIds: snapIds, - )..init(), -); - -class RatingsListModel extends ChangeNotifier { - RatingsListModel({ - required this.ratingsService, - required this.snapIds, - }) : _state = const AsyncValue.loading(); - final RatingsService ratingsService; - final List snapIds; - - Map? snapRatings; - - AsyncValue get state => _state; - AsyncValue _state; - - Future init() async { - _state = await AsyncValue.guard(() async { - final snapRatings = await ratingsService.getRatings(snapIds); - _setSnapRatings(snapRatings); - notifyListeners(); - }); - } - - void _setSnapRatings(Map snapRatings) { - this.snapRatings = snapRatings; - } -} diff --git a/lib/src/ratings/ratings_service.dart b/lib/src/ratings/ratings_service.dart index 4827cb813..21b2ff122 100644 --- a/lib/src/ratings/ratings_service.dart +++ b/lib/src/ratings/ratings_service.dart @@ -31,12 +31,8 @@ class RatingsService { } Future getRating(String snapId) async { - try { - await _ensureValidToken(); - return _client.getRating(snapId, _jwt!); - } catch (e) { - return null; - } + await _ensureValidToken(); + return _client.getRating(snapId, _jwt!); } Future vote(Vote vote) async { @@ -53,23 +49,4 @@ class RatingsService { await _ensureValidToken(); return await _client.listMyVotes(snapFilter, _jwt!); } - - Future> getRatings(List snapIds) async { - await _ensureValidToken(); - - final Map resultMap = {}; - final List> futures = []; - - for (final String snapId in snapIds) { - final future = getRating(snapId).then((rating) { - resultMap[snapId] = rating; - }).catchError((error) { - resultMap[snapId] = null; - }); - futures.add(future); - } - - await Future.wait(futures); - return resultMap; - } } diff --git a/lib/src/search/search_page.dart b/lib/src/search/search_page.dart index 08a96fc5c..12e868dfe 100644 --- a/lib/src/search/search_page.dart +++ b/lib/src/search/search_page.dart @@ -4,7 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:ubuntu_widgets/ubuntu_widgets.dart'; import 'package:yaru_widgets/yaru_widgets.dart'; -import '../ratings/ratings_list_model.dart'; import '/l10n.dart'; import '/layout.dart'; import '/snapd.dart'; @@ -119,58 +118,40 @@ class SearchPage extends StatelessWidget { ), ); return results.when( - data: (data) { - if (data.isNotEmpty) { - final snapIds = data.map((snap) => snap.id).toList(); - return Consumer( - builder: (context, ref, child) { - final ratingsList = - ref.watch(ratingsListModelProvider(snapIds)); - return ratingsList.state.when( - data: (ratings) => ResponsiveLayoutScrollView( - slivers: [ - SnapCardGrid( - snaps: data, - ratings: ratingsList.snapRatings!, - onTap: (snap) => - StoreNavigator.pushSearchDetail( - context, - name: snap.name, - query: query, - ), - ), - ], + data: (data) => data.isNotEmpty + ? ResponsiveLayoutScrollView( + slivers: [ + SnapCardGrid( + snaps: data, + onTap: (snap) => StoreNavigator.pushSearchDetail( + context, + name: snap.name, + query: query, + ), ), - error: (error, stack) => ErrorWidget(error), - loading: () => const Center( - child: YaruCircularProgressIndicator()), - ); - }, - ); - } else { - return Padding( - padding: ResponsiveLayout.of(context).padding, - child: Column( - children: [ - const Spacer(flex: 1), - Text( - category == null - ? l10n.searchPageNoResults(query!) - : l10n.searchPageNoResultsCategory, - style: Theme.of(context).textTheme.headlineSmall, - ), - Text( - category == null - ? l10n.searchPageNoResultsHint - : l10n.searchPageNoResultsCategoryHint, - style: Theme.of(context).textTheme.titleMedium, - ), - const Spacer(flex: 3), ], + ) + : Padding( + padding: ResponsiveLayout.of(context).padding, + child: Column( + children: [ + const Spacer(flex: 1), + Text( + category == null + ? l10n.searchPageNoResults(query!) + : l10n.searchPageNoResultsCategory, + style: Theme.of(context).textTheme.headlineSmall, + ), + Text( + category == null + ? l10n.searchPageNoResultsHint + : l10n.searchPageNoResultsCategoryHint, + style: Theme.of(context).textTheme.titleMedium, + ), + const Spacer(flex: 3), + ], + ), ), - ); - } - }, error: (error, stack) => ErrorWidget(error), loading: () => const Center(child: YaruCircularProgressIndicator()), diff --git a/lib/src/widgets/snap_card.dart b/lib/src/widgets/snap_card.dart index ac772d2da..08e4b3f36 100644 --- a/lib/src/widgets/snap_card.dart +++ b/lib/src/widgets/snap_card.dart @@ -1,20 +1,19 @@ +import 'package:app_center/l10n.dart'; +import 'package:app_center/src/ratings/ratings_l10n.dart'; +import 'package:app_center/src/ratings/ratings_model.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_html/flutter_html.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:snapd/snapd.dart'; import 'package:yaru_widgets/yaru_widgets.dart'; import '/layout.dart'; import '/snapd.dart'; import '/widgets.dart'; -import '../../l10n.dart'; -import '../ratings/exports.dart'; -import '../ratings/ratings_l10n.dart'; class SnapCard extends StatelessWidget { SnapCard({ super.key, required this.snap, - required this.rating, this.onTap, this.compact = false, }); @@ -22,7 +21,6 @@ class SnapCard extends StatelessWidget { final Snap snap; final VoidCallback? onTap; final bool compact; - Rating? rating; @override Widget build(BuildContext context) { @@ -35,7 +33,7 @@ class SnapCard extends StatelessWidget { children: [ SnapIcon(iconUrl: snap.iconUrl), const SizedBox(width: 16, height: 16), - Expanded(child: _SnapCardBody(snap: snap, rating: rating)), + Expanded(child: _SnapCardBody(snap: snap)), ], ), ); @@ -43,12 +41,10 @@ class SnapCard extends StatelessWidget { } class SnapImageCard extends StatelessWidget { - SnapImageCard( - {super.key, required this.snap, this.onTap, required this.rating}); + SnapImageCard({super.key, required this.snap, this.onTap}); final Snap snap; final VoidCallback? onTap; - Rating? rating; @override Widget build(BuildContext context) { @@ -77,7 +73,6 @@ class SnapImageCard extends StatelessWidget { child: _SnapCardBody( snap: snap, maxlines: 1, - rating: rating, ), ), ), @@ -88,15 +83,13 @@ class SnapImageCard extends StatelessWidget { } class _SnapCardBody extends StatelessWidget { - _SnapCardBody({required this.snap, this.maxlines = 2, required this.rating}); + _SnapCardBody({required this.snap, this.maxlines = 2}); final Snap snap; final int maxlines; - Rating? rating; @override Widget build(BuildContext context) { - final l10n = AppLocalizations.of(context); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -116,7 +109,26 @@ class _SnapCardBody extends StatelessWidget { ), ), const SizedBox(height: 8), - Wrap( + _RatingsInfo(snapId: snap.id), + ], + ); + } +} + +class _RatingsInfo extends ConsumerWidget { + const _RatingsInfo({required this.snapId}); + + final String snapId; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final ratingsModel = ref.watch(ratingsModelProvider(snapId)); + final l10n = AppLocalizations.of(context); + + return ratingsModel.state.when( + data: (ratingsData) { + final rating = ratingsModel.snapRating; + return Wrap( children: [ Text( rating?.ratingsBand.localize(l10n) ?? ' ', @@ -134,8 +146,10 @@ class _SnapCardBody extends StatelessWidget { ), ], ], - ), - ], + ); + }, + error: (error, stackTrace) => const Text(""), + loading: () => const Center(child: YaruCircularProgressIndicator()), ); } } diff --git a/lib/src/widgets/snap_grid.dart b/lib/src/widgets/snap_grid.dart index be4dafaa0..cd8504bc7 100644 --- a/lib/src/widgets/snap_grid.dart +++ b/lib/src/widgets/snap_grid.dart @@ -2,20 +2,17 @@ import 'package:flutter/material.dart'; import 'package:snapd/snapd.dart'; import '/layout.dart'; -import '../ratings/exports.dart'; import 'snap_card.dart'; class SnapCardGrid extends StatelessWidget { const SnapCardGrid({ super.key, required this.snaps, - required this.ratings, required this.onTap, }); final List snaps; final ValueChanged onTap; - final Map ratings; @override Widget build(BuildContext context) { @@ -30,11 +27,9 @@ class SnapCardGrid extends StatelessWidget { itemCount: snaps.length, itemBuilder: (context, index) { final snap = snaps[index]; - final rating = ratings[snap.id]; return SnapCard( key: ValueKey(snap.id), snap: snap, - rating: rating, onTap: () => onTap(snap), ); }, @@ -47,12 +42,10 @@ class SnapImageCardGrid extends StatelessWidget { super.key, required this.snaps, required this.onTap, - required this.ratings, }); final List snaps; final ValueChanged onTap; - final Map ratings; @override Widget build(BuildContext context) { @@ -75,12 +68,10 @@ class SnapImageCardGrid extends StatelessWidget { itemCount: snaps.length, itemBuilder: (context, index) { final snap = snaps[index]; - final rating = ratings[snap.id]; return SnapImageCard( key: ValueKey(snap.id), snap: snap, onTap: () => onTap(snap), - rating: rating, ); }, ); diff --git a/test/search_page_test.dart b/test/search_page_test.dart index 3433024eb..54239ca43 100644 --- a/test/search_page_test.dart +++ b/test/search_page_test.dart @@ -1,7 +1,7 @@ import 'package:app_center/search.dart'; import 'package:app_center/snapd.dart'; import 'package:app_center/src/ratings/exports.dart'; -import 'package:app_center/src/ratings/ratings_list_model.dart'; +import 'package:app_center/src/ratings/ratings_model.dart'; import 'package:app_center/widgets.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -9,30 +9,19 @@ import 'package:snapd/snapd.dart'; import 'package:ubuntu_widgets/ubuntu_widgets.dart'; import 'test_utils.dart'; -import 'test_utils.mocks.dart'; -const snapRatings = { - 'testsnapid': Rating( - snapId: 'testsnapid', totalVotes: 123, ratingsBand: RatingsBand.good), - 'testsnap2id': Rating( - snapId: 'testsnap2id', - totalVotes: 321, - ratingsBand: RatingsBand.veryGood), - 'testsnap3id': Rating( - snapId: 'testsnap3id', totalVotes: 222, ratingsBand: RatingsBand.good), - 'educational-snapid': Rating( - snapId: 'educational-snapid', - totalVotes: 123, - ratingsBand: RatingsBand.neutral), -}; - -const snapIds = [ - 'testsnapid', - 'testsnap2id', - 'testsnap3id', -]; +const snapId = "r4LxMVp7zWramXsJQAKdamxy6TAWlaDD"; +const snapRating = Rating( + snapId: snapId, + totalVotes: 123, + ratingsBand: RatingsBand.good, +); void main() { + final ratingsModel = createMockRatingsModel( + snapId: snapId, + snapRating: snapRating, + ); final mockSearchProvider = createMockSnapSearchProvider({ const SnapSearchParameters(query: 'testsn'): const [ Snap(name: 'testsnap', title: 'Test Snap', downloadSize: 3), @@ -49,16 +38,13 @@ void main() { Snap(name: 'educational-snap', title: 'Educational Snap'), ], }); - final mockRatingsListModel = - createMockRatingsListModel(snapIds: snapIds, snapRatings: snapRatings); testWidgets('query', (tester) async { await tester.pumpApp( (_) => ProviderScope( overrides: [ snapSearchProvider .overrideWith((ref, query) => mockSearchProvider(query)), - ratingsListModelProvider - .overrideWith((ref, arg) => mockRatingsListModel), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage(query: 'testsn'), ), @@ -83,8 +69,7 @@ void main() { overrides: [ snapSearchProvider .overrideWith((ref, query) => mockSearchProvider(query)), - ratingsListModelProvider - .overrideWith((ref, arg) => mockRatingsListModel), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage( query: 'testsn', @@ -112,8 +97,7 @@ void main() { overrides: [ snapSearchProvider .overrideWith((ref, query) => mockSearchProvider(query)), - ratingsListModelProvider - .overrideWith((ref, arg) => mockRatingsListModel), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage( category: 'education', @@ -138,8 +122,7 @@ void main() { overrides: [ snapSearchProvider .overrideWith((ref, query) => mockSearchProvider(query)), - ratingsListModelProvider - .overrideWith((ref, arg) => mockRatingsListModel), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage(query: 'testsn'), ), @@ -165,8 +148,7 @@ void main() { overrides: [ snapSearchProvider .overrideWith((ref, query) => mockSearchProvider(query)), - ratingsListModelProvider - .overrideWith((ref, arg) => mockRatingsListModel), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage(query: 'testsn'), ), @@ -195,8 +177,7 @@ void main() { overrides: [ snapSearchProvider .overrideWith((ref, query) => mockSearchProvider(query)), - ratingsListModelProvider - .overrideWith((ref, arg) => mockRatingsListModel), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage(query: 'testsn'), ), @@ -228,8 +209,7 @@ void main() { overrides: [ snapSearchProvider .overrideWith((ref, query) => mockSearchProvider(query)), - ratingsListModelProvider - .overrideWith((ref, arg) => mockRatingsListModel), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage(query: 'foo'), ), @@ -246,7 +226,8 @@ void main() { (_) => ProviderScope( overrides: [ snapSearchProvider - .overrideWith((ref, query) => mockSearchProvider(query)) + .overrideWith((ref, query) => mockSearchProvider(query)), + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), ], child: const SearchPage(query: 'foo', category: 'social'), ), diff --git a/test/snap_card_test.dart b/test/snap_card_test.dart new file mode 100644 index 000000000..75668837c --- /dev/null +++ b/test/snap_card_test.dart @@ -0,0 +1,44 @@ +import 'package:app_center/src/ratings/exports.dart'; +import 'package:app_center/src/ratings/ratings_model.dart'; +import 'package:app_center/widgets.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:snapd/snapd.dart'; + +import 'test_utils.dart'; + +const snapId = "r4LxMVp7zWramXsJQAKdamxy6TAWlaDD"; +const snapRating = Rating( + snapId: snapId, + totalVotes: 123, + ratingsBand: RatingsBand.good, +); + +const snap = Snap( + name: 'testsnap', + id: 'r4LxMVp7zWramXsJQAKdamxy6TAWlaDD', + summary: 'Its a summary!'); + +void main() { + final ratingsModel = createMockRatingsModel( + snapId: snapId, + snapRating: snapRating, + ); + + testWidgets('query', (tester) async { + await tester.pumpApp( + (_) => ProviderScope( + overrides: [ + ratingsModelProvider.overrideWith((ref, arg) => ratingsModel), + ], + child: SnapCard(snap: snap), + ), + ); + + await tester.pumpAndSettle(); + + expect(find.text('testsnap'), findsOneWidget); + expect(find.text('Good'), findsOneWidget); + expect(find.text(' | 123 votes'), findsOneWidget); + }); +} diff --git a/test/store_app_test.dart b/test/store_app_test.dart index 7341a4504..5830df117 100644 --- a/test/store_app_test.dart +++ b/test/store_app_test.dart @@ -1,5 +1,4 @@ import 'package:app_center/snapd.dart'; -import 'package:app_center/src/ratings/exports.dart'; import 'package:app_center/src/ratings/ratings_service.dart'; import 'package:app_center/src/store/store_app.dart'; import 'package:flutter/material.dart'; diff --git a/test/test_utils.dart b/test/test_utils.dart index c35256d0f..883594e28 100644 --- a/test/test_utils.dart +++ b/test/test_utils.dart @@ -4,7 +4,6 @@ import 'package:app_center/l10n.dart'; import 'package:app_center/snapd.dart'; import 'package:app_center/src/manage/manage_model.dart'; import 'package:app_center/src/ratings/exports.dart'; -import 'package:app_center/src/ratings/ratings_list_model.dart'; import 'package:app_center/src/ratings/ratings_model.dart'; import 'package:app_center/src/ratings/ratings_service.dart'; import 'package:appstream/appstream.dart'; @@ -73,20 +72,6 @@ RatingsModel createMockRatingsModel({ return model; } -@GenerateMocks([RatingsListModel]) -RatingsListModel createMockRatingsListModel( - {AsyncValue? state, - Map? snapRatings, - List? snapIds}) { - final model = MockRatingsListModel(); - - when(model.state).thenReturn(state ?? AsyncValue.data(() {}())); - when(model.snapRatings).thenReturn(snapRatings ?? {}); - when(model.snapIds).thenReturn(snapIds ?? []); - - return model; -} - @GenerateMocks([SnapModel]) SnapModel createMockSnapModel({ bool? hasUpdate, diff --git a/test/test_utils.mocks.dart b/test/test_utils.mocks.dart index b1f76a50e..c4a516f86 100644 --- a/test/test_utils.mocks.dart +++ b/test/test_utils.mocks.dart @@ -6,15 +6,14 @@ import 'dart:async' as _i10; import 'package:app_center/snapd.dart' as _i6; -import 'package:app_center/src/manage/manage_model.dart' as _i12; +import 'package:app_center/src/manage/manage_model.dart' as _i11; import 'package:app_center/src/ratings/exports.dart' as _i9; -import 'package:app_center/src/ratings/ratings_list_model.dart' as _i11; import 'package:app_center/src/ratings/ratings_model.dart' as _i8; import 'package:app_center/src/ratings/ratings_service.dart' as _i4; -import 'package:dbus/dbus.dart' as _i15; -import 'package:file/file.dart' as _i13; +import 'package:dbus/dbus.dart' as _i14; +import 'package:file/file.dart' as _i12; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i5; -import 'package:gtk/src/gtk_application_notifier.dart' as _i14; +import 'package:gtk/src/gtk_application_notifier.dart' as _i13; import 'package:mockito/mockito.dart' as _i1; import 'package:packagekit/src/packagekit_client.dart' as _i7; import 'package:snapcraft_launcher/snapcraft_launcher.dart' as _i3; @@ -271,91 +270,6 @@ class MockRatingsModel extends _i1.Mock implements _i8.RatingsModel { ); } -/// A class which mocks [RatingsListModel]. -/// -/// See the documentation for Mockito's code generation for more information. -class MockRatingsListModel extends _i1.Mock implements _i11.RatingsListModel { - MockRatingsListModel() { - _i1.throwOnMissingStub(this); - } - - @override - _i4.RatingsService get ratingsService => (super.noSuchMethod( - Invocation.getter(#ratingsService), - returnValue: _FakeRatingsService_2( - this, - Invocation.getter(#ratingsService), - ), - ) as _i4.RatingsService); - @override - List get snapIds => (super.noSuchMethod( - Invocation.getter(#snapIds), - returnValue: [], - ) as List); - @override - set snapRatings(Map? _snapRatings) => super.noSuchMethod( - Invocation.setter( - #snapRatings, - _snapRatings, - ), - returnValueForMissingStub: null, - ); - @override - _i5.AsyncValue get state => (super.noSuchMethod( - Invocation.getter(#state), - returnValue: _FakeAsyncValue_3( - this, - Invocation.getter(#state), - ), - ) as _i5.AsyncValue); - @override - bool get hasListeners => (super.noSuchMethod( - Invocation.getter(#hasListeners), - returnValue: false, - ) as bool); - @override - _i10.Future init() => (super.noSuchMethod( - Invocation.method( - #init, - [], - ), - returnValue: _i10.Future.value(), - returnValueForMissingStub: _i10.Future.value(), - ) as _i10.Future); - @override - void addListener(dynamic listener) => super.noSuchMethod( - Invocation.method( - #addListener, - [listener], - ), - returnValueForMissingStub: null, - ); - @override - void removeListener(dynamic listener) => super.noSuchMethod( - Invocation.method( - #removeListener, - [listener], - ), - returnValueForMissingStub: null, - ); - @override - void dispose() => super.noSuchMethod( - Invocation.method( - #dispose, - [], - ), - returnValueForMissingStub: null, - ); - @override - void notifyListeners() => super.noSuchMethod( - Invocation.method( - #notifyListeners, - [], - ), - returnValueForMissingStub: null, - ); -} - /// A class which mocks [SnapModel]. /// /// See the documentation for Mockito's code generation for more information. @@ -515,7 +429,7 @@ class MockSnapModel extends _i1.Mock implements _i6.SnapModel { /// A class which mocks [ManageModel]. /// /// See the documentation for Mockito's code generation for more information. -class MockManageModel extends _i1.Mock implements _i12.ManageModel { +class MockManageModel extends _i1.Mock implements _i11.ManageModel { MockManageModel() { _i1.throwOnMissingStub(this); } @@ -990,7 +904,7 @@ class MockSnapdService extends _i1.Mock implements _i6.SnapdService { _i10.Stream> getCategory( String? name, { Duration? expiry = const Duration(days: 1), - _i13.FileSystem? fs, + _i12.FileSystem? fs, }) => (super.noSuchMethod( Invocation.method( @@ -1007,7 +921,7 @@ class MockSnapdService extends _i1.Mock implements _i6.SnapdService { _i10.Stream<_i2.Snap?> getStoreSnap( String? name, { Duration? expiry = const Duration(minutes: 1), - _i13.FileSystem? fs, + _i12.FileSystem? fs, }) => (super.noSuchMethod( Invocation.method( @@ -1024,7 +938,7 @@ class MockSnapdService extends _i1.Mock implements _i6.SnapdService { _i10.Stream> getStoreSnaps( List? names, { Duration? expiry = const Duration(minutes: 1), - _i13.FileSystem? fs, + _i12.FileSystem? fs, }) => (super.noSuchMethod( Invocation.method( @@ -1166,13 +1080,13 @@ class MockUpdatesModel extends _i1.Mock implements _i6.UpdatesModel { /// /// See the documentation for Mockito's code generation for more information. class MockGtkApplicationNotifier extends _i1.Mock - implements _i14.GtkApplicationNotifier { + implements _i13.GtkApplicationNotifier { MockGtkApplicationNotifier() { _i1.throwOnMissingStub(this); } @override - void addCommandLineListener(_i14.GtkCommandLineListener? listener) => + void addCommandLineListener(_i13.GtkCommandLineListener? listener) => super.noSuchMethod( Invocation.method( #addCommandLineListener, @@ -1181,7 +1095,7 @@ class MockGtkApplicationNotifier extends _i1.Mock returnValueForMissingStub: null, ); @override - void removeCommandLineListener(_i14.GtkCommandLineListener? listener) => + void removeCommandLineListener(_i13.GtkCommandLineListener? listener) => super.noSuchMethod( Invocation.method( #removeCommandLineListener, @@ -1190,7 +1104,7 @@ class MockGtkApplicationNotifier extends _i1.Mock returnValueForMissingStub: null, ); @override - void addOpenListener(_i14.GtkOpenListener? listener) => super.noSuchMethod( + void addOpenListener(_i13.GtkOpenListener? listener) => super.noSuchMethod( Invocation.method( #addOpenListener, [listener], @@ -1198,7 +1112,7 @@ class MockGtkApplicationNotifier extends _i1.Mock returnValueForMissingStub: null, ); @override - void removeOpenListener(_i14.GtkOpenListener? listener) => super.noSuchMethod( + void removeOpenListener(_i13.GtkOpenListener? listener) => super.noSuchMethod( Invocation.method( #removeOpenListener, [listener], @@ -1388,7 +1302,7 @@ class MockPackageKitClient extends _i1.Mock implements _i7.PackageKitClient { ) as _i10.Future); @override _i10.Future<_i7.PackageKitTransaction> getTransaction( - _i15.DBusObjectPath? path) => + _i14.DBusObjectPath? path) => (super.noSuchMethod( Invocation.method( #getTransaction, @@ -1871,14 +1785,4 @@ class MockRatingsService extends _i1.Mock implements _i4.RatingsService { ), returnValue: _i10.Future>.value(<_i9.Vote>[]), ) as _i10.Future>); - @override - _i10.Future> getRatings(List? snapIds) => - (super.noSuchMethod( - Invocation.method( - #getRatings, - [snapIds], - ), - returnValue: _i10.Future>.value( - {}), - ) as _i10.Future>); }