diff --git a/assets b/assets index e390ea238..80a7aa847 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit e390ea238c1066be3de7d6baba652e34d8ddf981 +Subproject commit 80a7aa847c6c9481fd19cf4b22d42ae5b5b14c7b diff --git a/lib/gateway/feralfile_api.dart b/lib/gateway/feralfile_api.dart index 52c5c6e18..f34b93dfb 100644 --- a/lib/gateway/feralfile_api.dart +++ b/lib/gateway/feralfile_api.dart @@ -7,7 +7,7 @@ import 'package:autonomy_flutter/model/ff_account.dart'; import 'package:autonomy_flutter/model/ff_exhibition.dart'; -import 'package:autonomy_flutter/model/ff_exhibition_artworks_response.dart'; +import 'package:autonomy_flutter/model/ff_list_response.dart'; import 'package:autonomy_flutter/model/ff_series.dart'; import 'package:dio/dio.dart'; import 'package:retrofit/retrofit.dart'; @@ -37,6 +37,7 @@ abstract class FeralFileApi { @Query('sortBy') String? sortBy, @Query('sortOrder') String? sortOrder, @Query('includeArtist') bool includeArtist = true, + @Query('includeFirstArtwork') bool includeFirstArtwork = false, @Query('includeUniqueFilePath') bool includeUniqueFilePath = true, }); @@ -64,9 +65,11 @@ abstract class FeralFileApi { Future getFeaturedExhibition(); @GET('/api/artworks') - Future getListArtworks({ + Future> getListArtworks({ @Query('exhibitionID') String? exhibitionId, @Query('seriesID') String? seriesId, + @Query('offset') int? offset, + @Query('limit') int? limit, @Query('includeActiveSwap') bool includeActiveSwap = true, @Query('sortBy') String sortBy = 'index', @Query('sortOrder') String sortOrder = 'ASC', diff --git a/lib/gateway/feralfile_api.g.dart b/lib/gateway/feralfile_api.g.dart index a61074af9..e44967e7d 100644 --- a/lib/gateway/feralfile_api.g.dart +++ b/lib/gateway/feralfile_api.g.dart @@ -89,6 +89,7 @@ class _FeralFileApi implements FeralFileApi { String? sortBy, String? sortOrder, bool includeArtist = true, + bool includeFirstArtwork = false, bool includeUniqueFilePath = true, }) async { const _extra = {}; @@ -97,6 +98,7 @@ class _FeralFileApi implements FeralFileApi { r'sortBy': sortBy, r'sortOrder': sortOrder, r'includeArtist': includeArtist, + r'includeFirstArtwork': includeFirstArtwork, r'includeUniqueFilePath': includeUniqueFilePath, }; queryParameters.removeWhere((k, v) => v == null); @@ -252,9 +254,11 @@ class _FeralFileApi implements FeralFileApi { } @override - Future getListArtworks({ + Future> getListArtworks({ String? exhibitionId, String? seriesId, + int? offset, + int? limit, bool includeActiveSwap = true, String sortBy = 'index', String sortOrder = 'ASC', @@ -263,6 +267,8 @@ class _FeralFileApi implements FeralFileApi { final queryParameters = { r'exhibitionID': exhibitionId, r'seriesID': seriesId, + r'offset': offset, + r'limit': limit, r'includeActiveSwap': includeActiveSwap, r'sortBy': sortBy, r'sortOrder': sortOrder, @@ -270,8 +276,8 @@ class _FeralFileApi implements FeralFileApi { queryParameters.removeWhere((k, v) => v == null); final _headers = {}; final Map? _data = null; - final _result = await _dio - .fetch>(_setStreamType(Options( + final _result = await _dio.fetch>( + _setStreamType>(Options( method: 'GET', headers: _headers, extra: _extra, @@ -287,7 +293,8 @@ class _FeralFileApi implements FeralFileApi { _dio.options.baseUrl, baseUrl, )))); - final value = ArtworksResponse.fromJson(_result.data!); + final value = FeralFileListResponse.fromJson( + _result.data!, Artwork.fromJson); return value; } diff --git a/lib/gateway/source_exhibition_api.dart b/lib/gateway/source_exhibition_api.dart index defc70087..a17cefbe9 100644 --- a/lib/gateway/source_exhibition_api.dart +++ b/lib/gateway/source_exhibition_api.dart @@ -38,7 +38,7 @@ extension SourceExhibitionAPIHelper on SourceExhibitionAPI { ?.map((element) => FFSeries.fromJson(element)) .toList() ?? []; - return series; + return series.map((e) => e.copyWith(artwork: e.artworks!.first)).toList(); } catch (e) { return []; } diff --git a/lib/model/ff_exhibition_artworks_response.dart b/lib/model/ff_exhibition_artworks_response.dart deleted file mode 100644 index f2941209c..000000000 --- a/lib/model/ff_exhibition_artworks_response.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:autonomy_flutter/model/ff_account.dart'; - -class ArtworksResponse { - final List result; - - ArtworksResponse({ - required this.result, - }); - - factory ArtworksResponse.fromJson(Map json) => - ArtworksResponse( - result: (json['result'] as List) - .map((e) => Artwork.fromJson(e as Map)) - .toList(), - ); - - Map toJson() => { - 'result': result.map((e) => e.toJson()).toList(), - }; -} diff --git a/lib/model/ff_list_response.dart b/lib/model/ff_list_response.dart new file mode 100644 index 000000000..115fc273f --- /dev/null +++ b/lib/model/ff_list_response.dart @@ -0,0 +1,59 @@ +class FeralFileListResponse { + final List result; + final Paging paging; + + FeralFileListResponse({required this.result, required this.paging}); + + factory FeralFileListResponse.fromJson( + Map json, + T Function(Map) fromJson, + ) => + FeralFileListResponse( + result: (json['result'] as List) + .map((e) => fromJson(e as Map)) + .toList(), + paging: Paging.fromJson(json['paging']), + ); + + Map toJson(Map Function(T) toJson) => { + 'result': result.map((e) => toJson(e)).toList(), + 'paging': paging.toJson(), + }; + + FeralFileListResponse copyWith({ + List? result, + Paging? paging, + }) => + FeralFileListResponse( + result: result ?? this.result, + paging: paging ?? this.paging, + ); +} + +class Paging { + final int offset; + final int limit; + final int total; + + Paging({ + required this.offset, + required this.limit, + required this.total, + }); + + factory Paging.fromJson(Map json) => Paging( + offset: json['offset'], + limit: json['limit'], + total: json['total'], + ); + + Map toJson() => { + 'offset': offset, + 'limit': limit, + 'total': total, + }; +} + +extension PagingExtension on Paging { + bool get shouldLoadMore => offset + limit < total; +} diff --git a/lib/model/ff_series.dart b/lib/model/ff_series.dart index b40d01f65..7d3a5bf8f 100644 --- a/lib/model/ff_series.dart +++ b/lib/model/ff_series.dart @@ -143,6 +143,63 @@ class FFSeries { 'uniquePreviewPath': uniquePreviewPath, 'onchainID': onchainID, }; + + FFSeries copyWith({ + String? id, + String? artistID, + String? assetID, + String? title, + String? slug, + String? medium, + String? description, + String? thumbnailURI, + String? exhibitionID, + Map? metadata, + int? displayIndex, + int? featuringIndex, + FFSeriesSettings? settings, + FFArtist? artist, + Exhibition? exhibition, + DateTime? createdAt, + DateTime? mintedAt, + DateTime? updatedAt, + FileInfo? originalFile, + FileInfo? previewFile, + Artwork? artwork, + String? externalSource, + String? uniqueThumbnailPath, + String? uniquePreviewPath, + String? onchainID, + List? artworks, + }) => + FFSeries( + id ?? this.id, + artistID ?? this.artistID, + assetID ?? this.assetID, + title ?? this.title, + slug ?? this.slug, + medium ?? this.medium, + description ?? this.description, + thumbnailURI ?? this.thumbnailURI, + exhibitionID ?? this.exhibitionID, + metadata ?? this.metadata, + settings ?? this.settings, + artist ?? this.artist, + exhibition ?? this.exhibition, + createdAt ?? this.createdAt, + mintedAt ?? this.mintedAt, + displayIndex ?? this.displayIndex, + featuringIndex ?? this.featuringIndex, + updatedAt ?? this.updatedAt, + originalFile ?? this.originalFile, + previewFile ?? this.previewFile, + artwork ?? this.artwork, + externalSource ?? this.externalSource, + uniqueThumbnailPath ?? this.uniqueThumbnailPath, + uniquePreviewPath ?? this.uniquePreviewPath, + onchainID ?? this.onchainID, + artworks ?? this.artworks, + ); } class FFSeriesResponse { diff --git a/lib/screen/exhibition_details/exhibition_detail_bloc.dart b/lib/screen/exhibition_details/exhibition_detail_bloc.dart index 69ee240ff..e65f4e76e 100644 --- a/lib/screen/exhibition_details/exhibition_detail_bloc.dart +++ b/lib/screen/exhibition_details/exhibition_detail_bloc.dart @@ -1,8 +1,6 @@ // create exhibition_detail bloc import 'package:autonomy_flutter/au_bloc.dart'; -import 'package:autonomy_flutter/model/ff_account.dart'; -import 'package:autonomy_flutter/model/ff_exhibition.dart'; import 'package:autonomy_flutter/screen/exhibition_details/exhibition_detail_state.dart'; import 'package:autonomy_flutter/service/feralfile_service.dart'; @@ -13,15 +11,15 @@ class ExhibitionDetailBloc ExhibitionDetailBloc(this._feralFileService) : super(ExhibitionDetailState()) { on((event, emit) async { - final result = await Future.wait([ - _feralFileService.getExhibition(event.exhibitionId), - _feralFileService.getExhibitionArtworks(event.exhibitionId, - withSeries: true) - ]); - final exhibitionDetail = ExhibitionDetail( - exhibition: result[0] as Exhibition, - artworks: result[1] as List); - emit(state.copyWith(exhibitionDetail: exhibitionDetail)); + final exhibition = + await _feralFileService.getExhibition(event.exhibitionId); + + final seriesDetails = await Future.wait(exhibition.series!.map((e) => + _feralFileService.getSeries(e.id, + exhibitionID: event.exhibitionId, includeFirstArtwork: true))); + + emit(state.copyWith( + exhibition: exhibition.copyWith(series: seriesDetails))); }); } } diff --git a/lib/screen/exhibition_details/exhibition_detail_page.dart b/lib/screen/exhibition_details/exhibition_detail_page.dart index f6f4c8c1d..5f38ef92b 100644 --- a/lib/screen/exhibition_details/exhibition_detail_page.dart +++ b/lib/screen/exhibition_details/exhibition_detail_page.dart @@ -10,7 +10,6 @@ import 'package:autonomy_flutter/screen/exhibition_details/exhibition_detail_blo import 'package:autonomy_flutter/screen/exhibition_details/exhibition_detail_state.dart'; import 'package:autonomy_flutter/service/metric_client_service.dart'; import 'package:autonomy_flutter/util/constants.dart'; -import 'package:autonomy_flutter/util/exhibition_ext.dart'; import 'package:autonomy_flutter/util/log.dart'; import 'package:autonomy_flutter/view/back_appbar.dart'; import 'package:autonomy_flutter/view/cast_button.dart'; @@ -61,29 +60,27 @@ class _ExhibitionDetailPageState extends State Widget build(BuildContext context) => BlocConsumer( builder: (context, state) => Scaffold( - appBar: _getAppBar(context, state.exhibitionDetail), + appBar: _getAppBar(context, state.exhibition), backgroundColor: AppColor.primaryBlack, body: _body(context, state), ), listener: (context, state) {}, listenWhen: (previous, current) { - if (previous.exhibitionDetail == null && - current.exhibitionDetail != null) { - _stream(current.exhibitionDetail!); + if (previous.exhibition == null && current.exhibition != null) { + _stream(current.exhibition!); } return true; }); Widget _body(BuildContext context, ExhibitionDetailState state) { - final exhibitionDetail = state.exhibitionDetail; - if (exhibitionDetail == null) { + final exhibition = state.exhibition; + if (exhibition == null) { return const Center( child: CircularProgressIndicator(), ); } - final viewingArtworks = exhibitionDetail.representArtworks; - final itemCount = viewingArtworks.length + 3; + final itemCount = (exhibition.series?.length ?? 0) + 3; return Column( children: [ Expanded( @@ -93,7 +90,7 @@ class _ExhibitionDetailPageState extends State setState(() { _currentIndex = index; }); - _stream(exhibitionDetail); + _stream(exhibition); }, scrollDirection: Axis.vertical, itemCount: itemCount, @@ -110,14 +107,16 @@ class _ExhibitionDetailPageState extends State switch (index) { case 0: - return _getPreviewPage(exhibitionDetail.exhibition); + return _getPreviewPage(exhibition); case 1: - return _notePage(exhibitionDetail); + return _notePage(exhibition); default: final seriesIndex = index - 2; - final series = exhibitionDetail.getSeriesByIndex(seriesIndex); - final artwork = - exhibitionDetail.representArtworkByIndex(seriesIndex); + final series = exhibition.series![seriesIndex]; + final artwork = series.artwork; + if (artwork == null) { + return const SizedBox(); + } return Padding( padding: const EdgeInsets.only(bottom: 40), child: FeralFileArtworkPreview( @@ -136,11 +135,11 @@ class _ExhibitionDetailPageState extends State ); } - void _stream(ExhibitionDetail exhibitionDetail) { + void _stream(Exhibition exhibition) { final controllingDevice = _canvasDeviceBloc.state.controllingDevice; log.info('onPageChanged: $_currentIndex'); if (controllingDevice != null) { - final request = _getCastExhibitionRequest(exhibitionDetail); + final request = _getCastExhibitionRequest(exhibition); log.info('onPageChanged: request: $request'); _canvasDeviceBloc.add( CanvasDeviceCastExhibitionEvent(controllingDevice, request), @@ -173,62 +172,58 @@ class _ExhibitionDetailPageState extends State ), ); - Widget _notePage(ExhibitionDetail exhibitionDetail) { - final exhibition = exhibitionDetail.exhibition; - return LayoutBuilder( - builder: (context, constraints) => Center( - child: CarouselSlider( - items: [ - ExhibitionNoteView( - exhibition: exhibition, - onReadMore: () async { - await Navigator.pushNamed( - context, - AppRouter.exhibitionNotePage, - arguments: exhibition, - ); + Widget _notePage(Exhibition exhibition) => LayoutBuilder( + builder: (context, constraints) => Center( + child: CarouselSlider( + items: [ + ExhibitionNoteView( + exhibition: exhibition, + onReadMore: () async { + await Navigator.pushNamed( + context, + AppRouter.exhibitionNotePage, + arguments: exhibition, + ); + }, + ), + ...exhibition.posts + ?.where((post) => post.coverURI != null) + .map((e) => ExhibitionPostView( + post: e, + )) ?? + [] + ], + options: CarouselOptions( + aspectRatio: constraints.maxWidth / constraints.maxHeight, + viewportFraction: 0.76, + enableInfiniteScroll: false, + enlargeCenterPage: true, + onPageChanged: (index, reason) { + _carouselIndex = index; + final controllingDevice = + _canvasDeviceBloc.state.controllingDevice; + final request = _getCastExhibitionRequest(exhibition); + if (controllingDevice != null) { + _canvasDeviceBloc.add( + CanvasDeviceCastExhibitionEvent(controllingDevice, request), + ); + } }, ), - ...exhibition.posts - ?.where((post) => post.coverURI != null) - .map((e) => ExhibitionPostView( - post: e, - )) ?? - [] - ], - options: CarouselOptions( - aspectRatio: constraints.maxWidth / constraints.maxHeight, - viewportFraction: 0.76, - enableInfiniteScroll: false, - enlargeCenterPage: true, - onPageChanged: (index, reason) { - _carouselIndex = index; - final controllingDevice = - _canvasDeviceBloc.state.controllingDevice; - final request = _getCastExhibitionRequest(exhibitionDetail); - if (controllingDevice != null) { - _canvasDeviceBloc.add( - CanvasDeviceCastExhibitionEvent(controllingDevice, request), - ); - } - }, ), ), - ), - ); - } + ); - AppBar _getAppBar( - BuildContext buildContext, ExhibitionDetail? exhibitionDetail) => + AppBar _getAppBar(BuildContext buildContext, Exhibition? exhibition) => getFFAppBar( buildContext, onBack: () => Navigator.pop(buildContext), - action: exhibitionDetail != null + action: exhibition != null ? Padding( padding: const EdgeInsets.only(right: 14, bottom: 10, top: 10), child: FFCastButton( onDeviceSelected: (device) async { - final request = _getCastExhibitionRequest(exhibitionDetail); + final request = _getCastExhibitionRequest(exhibition); _canvasDeviceBloc.add( CanvasDeviceCastExhibitionEvent(device, request), ); @@ -239,7 +234,7 @@ class _ExhibitionDetailPageState extends State ); Pair _getCurrentCatalogInfo( - ExhibitionDetail exhibitionDetail) { + Exhibition exhibition) { ExhibitionKatalog? catalog; String? catalogId; switch (_currentIndex) { @@ -250,22 +245,20 @@ class _ExhibitionDetailPageState extends State catalog = ExhibitionKatalog.CURATOR_NOTE; } else { catalog = ExhibitionKatalog.RESOURCE; - catalogId = exhibitionDetail.exhibition.posts![_carouselIndex - 1].id; + catalogId = exhibition.posts![_carouselIndex - 1].id; } default: catalog = ExhibitionKatalog.ARTWORK; final seriesIndex = _currentIndex - 2; - final currentArtwork = - exhibitionDetail.representArtworkByIndex(seriesIndex).id; + final currentArtwork = exhibition.series?[seriesIndex].id; catalogId = currentArtwork; } return Pair(catalog, catalogId); } - CastExhibitionRequest _getCastExhibitionRequest( - ExhibitionDetail exhibitionDetail) { - final exhibitionId = exhibitionDetail.exhibition.id; - final katalogInfo = _getCurrentCatalogInfo(exhibitionDetail); + CastExhibitionRequest _getCastExhibitionRequest(Exhibition exhibition) { + final exhibitionId = exhibition.id; + final katalogInfo = _getCurrentCatalogInfo(exhibition); final katalog = katalogInfo.first; final katalogId = katalogInfo.second; CastExhibitionRequest request = CastExhibitionRequest( diff --git a/lib/screen/exhibition_details/exhibition_detail_state.dart b/lib/screen/exhibition_details/exhibition_detail_state.dart index 851dd902c..86f9d7c0b 100644 --- a/lib/screen/exhibition_details/exhibition_detail_state.dart +++ b/lib/screen/exhibition_details/exhibition_detail_state.dart @@ -9,12 +9,10 @@ class GetExhibitionDetailEvent extends ExhibitionDetailEvent { } class ExhibitionDetailState { - ExhibitionDetailState({this.exhibitionDetail}); + ExhibitionDetailState({this.exhibition}); - final ExhibitionDetail? exhibitionDetail; + final Exhibition? exhibition; - ExhibitionDetailState copyWith({ExhibitionDetail? exhibitionDetail}) => - ExhibitionDetailState( - exhibitionDetail: exhibitionDetail ?? this.exhibitionDetail, - ); + ExhibitionDetailState copyWith({Exhibition? exhibition}) => + ExhibitionDetailState(exhibition: exhibition ?? this.exhibition); } diff --git a/lib/screen/exhibitions/exhibitions_page.dart b/lib/screen/exhibitions/exhibitions_page.dart index a3298cf4a..3640c082b 100644 --- a/lib/screen/exhibitions/exhibitions_page.dart +++ b/lib/screen/exhibitions/exhibitions_page.dart @@ -307,8 +307,8 @@ class ExhibitionsPageState extends State with RouteAware { divider, ]) .flattened, - if (!isSubscribed && proExhibitions.isNotEmpty) - _pastExhibitionHeader(context), + if (proExhibitions.isNotEmpty) + _pastExhibitionHeader(context, isSubscribed), ...proExhibitions .map((e) => [ _exhibitionItem( @@ -329,7 +329,7 @@ class ExhibitionsPageState extends State with RouteAware { ), ); - Widget _pastExhibitionHeader(BuildContext context) { + Widget _pastExhibitionHeader(BuildContext context, bool isSubscribed) { final theme = Theme.of(context); return Padding( padding: const EdgeInsets.only(bottom: 18), @@ -343,24 +343,28 @@ class ExhibitionsPageState extends State with RouteAware { style: theme.textTheme.ppMori400White14), Row( children: [ - _lockIcon(), - const SizedBox(width: 5), + if (!isSubscribed) ...[ + _lockIcon(), + const SizedBox(width: 5), + ], Text('premium_membership'.tr(), style: theme.textTheme.ppMori400Grey14), ], ), ], ), - PrimaryButton( - color: AppColor.feralFileLightBlue, - padding: EdgeInsets.zero, - elevatedPadding: const EdgeInsets.symmetric(horizontal: 15), - borderRadius: 20, - text: 'get_premium'.tr(), - onTap: () async { - await Navigator.of(context).pushNamed(AppRouter.subscriptionPage); - }, - ), + if (!isSubscribed) + PrimaryButton( + color: AppColor.feralFileLightBlue, + padding: EdgeInsets.zero, + elevatedPadding: const EdgeInsets.symmetric(horizontal: 15), + borderRadius: 20, + text: 'get_premium'.tr(), + onTap: () async { + await Navigator.of(context) + .pushNamed(AppRouter.subscriptionPage); + }, + ), ], ), ); diff --git a/lib/screen/feralfile_series/feralfile_series_bloc.dart b/lib/screen/feralfile_series/feralfile_series_bloc.dart index 8a0bf6926..320e7ecc0 100644 --- a/lib/screen/feralfile_series/feralfile_series_bloc.dart +++ b/lib/screen/feralfile_series/feralfile_series_bloc.dart @@ -1,10 +1,6 @@ import 'package:autonomy_flutter/au_bloc.dart'; -import 'package:autonomy_flutter/model/ff_account.dart'; -import 'package:autonomy_flutter/model/ff_exhibition.dart'; -import 'package:autonomy_flutter/model/ff_series.dart'; import 'package:autonomy_flutter/screen/feralfile_series/feralfile_series_state.dart'; import 'package:autonomy_flutter/service/feralfile_service.dart'; -import 'package:autonomy_flutter/util/exhibition_ext.dart'; class FeralFileSeriesBloc extends AuBloc { @@ -12,28 +8,10 @@ class FeralFileSeriesBloc FeralFileSeriesBloc(this._feralFileService) : super(FeralFileSeriesState()) { on((event, emit) async { - final result = await Future.wait([ - _feralFileService.getExhibition(event.exhibitionId), - _feralFileService.getSeriesArtworks(event.seriesId, - exhibitionID: event.exhibitionId, withSeries: true), - _feralFileService.getSeries(event.seriesId, - exhibitionID: event.exhibitionId), - ]); - final exhibition = result[0] as Exhibition; - final artworks = result[1] as List; - final series = result[2] as FFSeries; - final exhibitionDetail = ExhibitionDetail( - exhibition: exhibition, - artworks: artworks, - ); - final tokenIds = artworks - .map((e) => exhibitionDetail.getArtworkTokenId(e) ?? '') - .toList(); + final series = await _feralFileService.getSeries(event.seriesId, + exhibitionID: event.exhibitionId); emit(state.copyWith( - exhibitionDetail: exhibitionDetail, series: series, - artworks: artworks, - tokenIds: tokenIds, )); }); } diff --git a/lib/screen/feralfile_series/feralfile_series_page.dart b/lib/screen/feralfile_series/feralfile_series_page.dart index 399ef5062..92e12393f 100644 --- a/lib/screen/feralfile_series/feralfile_series_page.dart +++ b/lib/screen/feralfile_series/feralfile_series_page.dart @@ -1,12 +1,14 @@ import 'package:autonomy_flutter/common/injector.dart'; import 'package:autonomy_flutter/model/ff_account.dart'; -import 'package:autonomy_flutter/model/ff_exhibition.dart'; +import 'package:autonomy_flutter/model/ff_list_response.dart'; import 'package:autonomy_flutter/model/ff_series.dart'; import 'package:autonomy_flutter/screen/app_router.dart'; import 'package:autonomy_flutter/screen/detail/preview/canvas_device_bloc.dart'; import 'package:autonomy_flutter/screen/feralfile_artwork_preview/feralfile_artwork_preview_page.dart'; import 'package:autonomy_flutter/screen/feralfile_series/feralfile_series_bloc.dart'; import 'package:autonomy_flutter/screen/feralfile_series/feralfile_series_state.dart'; +import 'package:autonomy_flutter/service/feralfile_service.dart'; +import 'package:autonomy_flutter/util/style.dart'; import 'package:autonomy_flutter/view/back_appbar.dart'; import 'package:autonomy_flutter/view/ff_artwork_thumbnail_view.dart'; import 'package:autonomy_flutter/view/series_title_view.dart'; @@ -14,6 +16,7 @@ import 'package:feralfile_app_theme/feral_file_app_theme.dart'; import 'package:feralfile_app_tv_proto/feralfile_app_tv_proto.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; class FeralFileSeriesPage extends StatefulWidget { const FeralFileSeriesPage({required this.payload, super.key}); @@ -29,6 +32,9 @@ class _FeralFileSeriesPageState extends State { final _canvasDeviceBloc = injector.get(); static const _padding = 14.0; static const _axisSpacing = 10.0; + final PagingController _pagingController = + PagingController(firstPageKey: 0); + static const _pageSize = 300; @override void initState() { @@ -36,16 +42,45 @@ class _FeralFileSeriesPageState extends State { _feralFileSeriesBloc = context.read(); _feralFileSeriesBloc.add(FeralFileSeriesGetSeriesEvent( widget.payload.seriesId, widget.payload.exhibitionId)); + _pagingController.addPageRequestListener((pageKey) async { + await _fetchPage(pageKey); + }); + } + + Future _fetchPage(int pageKey) async { + try { + final newItems = await injector().getSeriesArtworks( + widget.payload.seriesId, widget.payload.exhibitionId, + offset: pageKey, + // ignore: avoid_redundant_argument_values + limit: _pageSize); + final isLastPage = !newItems.paging.shouldLoadMore; + if (isLastPage) { + _pagingController.appendLastPage(newItems.result); + } else { + final nextPageKey = pageKey + _pageSize; + _pagingController.appendPage(newItems.result, nextPageKey); + } + } catch (error) { + _pagingController.error = error; + } + } + + @override + void dispose() { + _pagingController.dispose(); + super.dispose(); } @override Widget build(BuildContext context) => BlocConsumer( - builder: (context, state) => Scaffold( - appBar: _getAppBar(context, state.series), - backgroundColor: AppColor.primaryBlack, - body: _body(context, state)), - listener: (context, state) {}); + builder: (context, state) => Scaffold( + appBar: _getAppBar(context, state.series), + backgroundColor: AppColor.primaryBlack, + body: _body(context, state.series)), + listener: (context, state) {}, + ); AppBar _getAppBar(BuildContext buildContext, FFSeries? series) => getFFAppBar( buildContext, @@ -58,60 +93,72 @@ class _FeralFileSeriesPageState extends State { crossAxisAlignment: CrossAxisAlignment.center), ); - Widget _body(BuildContext context, FeralFileSeriesState state) { - final series = state.series; + Widget _body(BuildContext context, FFSeries? series) { if (series == null) { - return const Center( - child: CircularProgressIndicator(), - ); + return _loadingIndicator(); } - return _artworkGridView(context, state.exhibitionDetail, state.artworks); + return _artworkSliverGrid(context, series); } - Widget _artworkGridView(BuildContext context, - ExhibitionDetail? exhibitionDetail, List artworks) => - Padding( + Widget _loadingIndicator() => Center( + child: Padding( + padding: const EdgeInsets.all(10), + child: loadingIndicator(valueColor: AppColor.auGrey), + ), + ); + + Widget _artworkSliverGrid(BuildContext context, FFSeries series) => Padding( padding: const EdgeInsets.only(left: _padding, right: _padding, bottom: 20), - child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - crossAxisSpacing: _axisSpacing, - mainAxisSpacing: _axisSpacing, - ), - itemBuilder: (context, index) { - final artwork = artworks[index]; - return FFArtworkThumbnailView( - artwork: artwork, - cacheSize: (MediaQuery.sizeOf(context).width - - _padding * 2 - - _axisSpacing * 2) ~/ - 3, - onTap: () async { - final controllingDevice = - _canvasDeviceBloc.state.controllingDevice; - if (controllingDevice != null) { - final castRequest = CastExhibitionRequest( - exhibitionId: exhibitionDetail!.exhibition.id, - katalog: ExhibitionKatalog.ARTWORK, - katalogId: artwork.id); - _canvasDeviceBloc.add( - CanvasDeviceCastExhibitionEvent( - controllingDevice, - castRequest, - ), - ); - } - await Navigator.of(context).pushNamed( - AppRouter.ffArtworkPreviewPage, - arguments: FeralFileArtworkPreviewPagePayload( - artwork: artwork, - ), - ); - }, - ); - }, - itemCount: artworks.length, + child: CustomScrollView( + slivers: [ + PagedSliverGrid( + pagingController: _pagingController, + showNewPageErrorIndicatorAsGridChild: false, + showNewPageProgressIndicatorAsGridChild: false, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisSpacing: _axisSpacing, + mainAxisSpacing: _axisSpacing, + crossAxisCount: 3, + ), + builderDelegate: PagedChildBuilderDelegate( + itemBuilder: (context, artwork, index) => + FFArtworkThumbnailView( + artwork: artwork, + cacheSize: (MediaQuery.sizeOf(context).width - + _padding * 2 - + _axisSpacing * 2) ~/ + 3, + onTap: () async { + final controllingDevice = + _canvasDeviceBloc.state.controllingDevice; + if (controllingDevice != null) { + final castRequest = CastExhibitionRequest( + exhibitionId: artwork.series!.exhibitionID, + katalog: ExhibitionKatalog.ARTWORK, + katalogId: artwork.id); + _canvasDeviceBloc.add( + CanvasDeviceCastExhibitionEvent( + controllingDevice, + castRequest, + ), + ); + } + await Navigator.of(context).pushNamed( + AppRouter.ffArtworkPreviewPage, + arguments: FeralFileArtworkPreviewPagePayload( + artwork: artwork.copyWith(series: series), + ), + ); + }, + ), + newPageProgressIndicatorBuilder: (context) => + _loadingIndicator(), + firstPageErrorIndicatorBuilder: (context) => const SizedBox(), + newPageErrorIndicatorBuilder: (context) => const SizedBox(), + ), + ) + ], ), ); } diff --git a/lib/screen/feralfile_series/feralfile_series_state.dart b/lib/screen/feralfile_series/feralfile_series_state.dart index 7e4eb45b3..ddcd4d8e9 100644 --- a/lib/screen/feralfile_series/feralfile_series_state.dart +++ b/lib/screen/feralfile_series/feralfile_series_state.dart @@ -1,5 +1,3 @@ -import 'package:autonomy_flutter/model/ff_account.dart'; -import 'package:autonomy_flutter/model/ff_exhibition.dart'; import 'package:autonomy_flutter/model/ff_series.dart'; class FeralFileSeriesEvent {} @@ -12,28 +10,16 @@ class FeralFileSeriesGetSeriesEvent extends FeralFileSeriesEvent { } class FeralFileSeriesState { - final ExhibitionDetail? exhibitionDetail; final FFSeries? series; - final List artworks; - final List tokenIds; FeralFileSeriesState({ - this.exhibitionDetail, this.series, - this.artworks = const [], - this.tokenIds = const [], }); FeralFileSeriesState copyWith({ - ExhibitionDetail? exhibitionDetail, FFSeries? series, - List? artworks, - List? tokenIds, }) => FeralFileSeriesState( - exhibitionDetail: exhibitionDetail ?? this.exhibitionDetail, series: series ?? this.series, - artworks: artworks ?? this.artworks, - tokenIds: tokenIds ?? this.tokenIds, ); } diff --git a/lib/service/feralfile_service.dart b/lib/service/feralfile_service.dart index bbdea7f9a..a58cfcba3 100644 --- a/lib/service/feralfile_service.dart +++ b/lib/service/feralfile_service.dart @@ -15,6 +15,7 @@ import 'package:autonomy_flutter/gateway/feralfile_api.dart'; import 'package:autonomy_flutter/gateway/source_exhibition_api.dart'; import 'package:autonomy_flutter/model/ff_account.dart'; import 'package:autonomy_flutter/model/ff_exhibition.dart'; +import 'package:autonomy_flutter/model/ff_list_response.dart'; import 'package:autonomy_flutter/model/ff_series.dart'; import 'package:autonomy_flutter/service/account_service.dart'; import 'package:autonomy_flutter/util/constants.dart'; @@ -125,9 +126,14 @@ enum GenerativeMediumTypes { } abstract class FeralFileService { - Future getSeries(String id, {String? exhibitionID}); + static const int offset = 0; + static const int limit = 300; - Future> getListSeries(String exhibitionId); + Future getSeries(String id, + {String? exhibitionID, bool includeFirstArtwork = false}); + + Future> getListSeries(String exhibitionId, + {bool includeFirstArtwork = false}); Future getExhibitionFromTokenID(String artworkID); @@ -148,11 +154,9 @@ abstract class FeralFileService { Future getFeaturedExhibition(); - Future> getExhibitionArtworks(String exhibitionId, - {bool withSeries = false}); - - Future> getSeriesArtworks(String seriesId, - {String? exhibitionID, bool withSeries = false}); + Future> getSeriesArtworks( + String seriesId, String exhibitionID, + {bool withSeries = false, int offset = offset, int limit = limit}); Future getFeralfileActionMessage( {required String address, required FeralfileAction action}); @@ -181,11 +185,22 @@ class FeralFileServiceImpl extends FeralFileService { ); @override - Future getSeries(String id, {String? exhibitionID}) async { + Future getSeries(String id, + {String? exhibitionID, bool includeFirstArtwork = false}) async { if (exhibitionID == SOURCE_EXHIBITION_ID) { return await _getSourceSeries(id); } - return (await _feralFileApi.getSeries(seriesId: id)).result; + final series = (await _feralFileApi.getSeries( + seriesId: id, includeFirstArtwork: includeFirstArtwork)) + .result; + + if (includeFirstArtwork && series.artwork == null) { + final exhibition = await getExhibition(series.exhibitionID); + final artworks = await _getFakeSeriesArtworks(exhibition, series, 0, 1); + return series.copyWith(artwork: artworks.first); + } + + return series; } @override @@ -239,50 +254,57 @@ class FeralFileServiceImpl extends FeralFileService { return exhibitionResponse.result; } - Future> _getExhibitionArtworkByDirectApi(String exhibitionId, - {bool withSeries = false}) async { - final artworks = - await _feralFileApi.getListArtworks(exhibitionId: exhibitionId); - List listArtwork = artworks.result; - log - ..info( - '[FeralFileService] [_getExhibitionByDirectApi] ' - 'Get exhibition artworks: ${listArtwork.length}', - ) - ..info( - '[FeralFileService] [_getExhibitionByDirectApi] ' - 'Get exhibition artworks: ' - '${listArtwork.map((e) => e.id).toList()}', + Future> _getFakeSeriesArtworks( + Exhibition exhibition, FFSeries series, int offset, int limit) async { + if (exhibition.isJohnGerrardShow) { + return await _getJohnGerrardFakeArtworks( + series: series, + offset: offset, + limit: limit, + onlySignedArtwork: true, ); - if (withSeries) { - final listSeries = await getListSeries(exhibitionId); - final seriesMap = - Map.fromEntries(listSeries.map((e) => MapEntry(e.id, e))); - listArtwork = listArtwork - .map((e) => e.copyWith(series: seriesMap[e.seriesID])) - .toList(); } - return listArtwork; + final fakeArtworks = + _createFakeSeriesArtworks(series, exhibition, offset, limit); + return fakeArtworks; } - Future> _getExhibitionFakeArtworks(String exhibitionId) async { - List listArtworks = []; - final exhibition = await getExhibition(exhibitionId); - final series = await getListSeries(exhibitionId); - - if (exhibition.isJohnGerrardShow) { - return await _getJohnGerrardFakeArtworks( - series: series.first, - offset: 0, - limit: 1, + Future> _createFakeSeriesArtworks( + FFSeries series, Exhibition exhibition, int offset, int limit) async { + final List artworks = []; + final maxArtworks = limit; + for (var i = offset; i < maxArtworks; i++) { + final previewURI = await _getPreviewURI(series, i, exhibition); + final artworkId = getFeralfileTokenId( + seriesOnchainID: series.onchainID ?? '', + exhibitionID: series.exhibitionID, + artworkIndex: i, + ); + final thumbnailURI = _getThumbnailURI(series, i); + final fakeArtwork = Artwork( + artworkId, + series.id, + i, + '#${i + 1}', + 'Artwork category $i', + 'ownerAccountID', + null, + null, + 'blockchainStatus', + false, + thumbnailURI, + previewURI ?? '', + {}, + DateTime.now(), + DateTime.now(), + DateTime.now(), + null, + series, + null, ); + artworks.add(fakeArtwork); } - - await Future.wait(series.map((e) => _fakeSeriesArtworks(e, exhibition))) - .then((value) { - listArtworks.addAll(value.expand((element) => element)); - }); - return listArtworks; + return artworks; } String getFeralfileTokenId( @@ -360,95 +382,57 @@ class FeralFileServiceImpl extends FeralFileService { ? '${series.uniqueThumbnailPath}/$artworkIndex-large.jpg' : series.thumbnailURI ?? ''; - Future> _fakeSeriesArtworks( - FFSeries series, Exhibition exhibition) async { - final List artworks = []; - final maxArtworks = series.maxEdition; - for (var i = 0; i < maxArtworks; i++) { - final previewURI = await _getPreviewURI(series, i, exhibition); - final artworkId = getFeralfileTokenId( - seriesOnchainID: series.onchainID ?? '', - exhibitionID: series.exhibitionID, - artworkIndex: i, - ); - final thumbnailURI = _getThumbnailURI(series, i); - final fakeArtwork = Artwork( - artworkId, - series.id, - i, - '#${i + 1}', - 'Artwork category $i', - 'ownerAccountID', - null, - null, - 'blockchainStatus', - false, - thumbnailURI, - previewURI ?? '', - {}, - DateTime.now(), - DateTime.now(), - DateTime.now(), - null, - series, - null, - ); - artworks.add(fakeArtwork); - } - return artworks; - } - - @override - Future> getExhibitionArtworks(String exhibitionId, - {bool withSeries = false}) async { - if (exhibitionId == SOURCE_EXHIBITION_ID) { - return await _getSourceArtworks(); - } - - List listArtworks = []; - listArtworks = await _getExhibitionArtworkByDirectApi(exhibitionId, - withSeries: withSeries); - if (listArtworks.isNotEmpty) { - return listArtworks; - } else { - listArtworks = await _getExhibitionFakeArtworks(exhibitionId); - } - return listArtworks; + Future> _fakeSeriesArtworks( + String seriesId, String exhibitionId, + {required int offset, required int limit}) async { + final exhibition = await getExhibition(exhibitionId); + final series = await getSeries(seriesId); + final List seriesArtworks = + await _getFakeSeriesArtworks(exhibition, series, offset, limit); + final total = series.latestRevealedArtworkIndex == null + ? series.maxEdition + : series.latestRevealedArtworkIndex! + 1; + return FeralFileListResponse( + result: seriesArtworks, + paging: Paging(offset: offset, limit: limit, total: total)); } @override - Future> getSeriesArtworks(String seriesId, - {String? exhibitionID, bool withSeries = false}) async { + Future> getSeriesArtworks( + String seriesId, String exhibitionID, + {bool withSeries = false, + int offset = FeralFileService.offset, + int limit = FeralFileService.limit}) async { if (exhibitionID == SOURCE_EXHIBITION_ID) { - return await _getSourceSeriesArtworks(seriesId); - } - - final artworks = await _feralFileApi.getListArtworks(seriesId: seriesId); - List listArtwork = artworks.result; - if (listArtwork.isEmpty) { - final series = await getSeries(seriesId); - if (series.exhibition?.isJohnGerrardShow == true) { - listArtwork = await _getJohnGerrardFakeArtworks( - series: series, - offset: 0, - onlySignedArtwork: true, - ); - } else { - listArtwork = await _fakeSeriesArtworks(series, series.exhibition!); - } + final artworks = await _getSourceSeriesArtworks(seriesId); + return FeralFileListResponse( + result: + artworks.sublist(offset, min(artworks.length, offset + limit)), + paging: Paging(offset: 0, limit: limit, total: artworks.length)); + } + + FeralFileListResponse artworksResponse = await _feralFileApi + .getListArtworks(seriesId: seriesId, offset: offset, limit: limit); + if (artworksResponse.result.isEmpty) { + return await _fakeSeriesArtworks(seriesId, exhibitionID, + offset: offset, limit: limit); } else if (withSeries) { final series = await getSeries(seriesId); - listArtwork = listArtwork.map((e) => e.copyWith(series: series)).toList(); + artworksResponse.copyWith( + result: artworksResponse.result + .map((e) => e.copyWith(series: series)) + .toList()); } log ..info( - '[FeralFileService] Get series artworks: ${listArtwork.length}', + '[FeralFileService] Get series artworks:' + ' ${artworksResponse.result.length}, offset $offset, limit $limit', ) ..info( '[FeralFileService] Get series artworks: ' - '${listArtwork.map((e) => e.id).toList()}', + '${artworksResponse.result.map((e) => e.id).toList()}', ); - return listArtwork; + return artworksResponse; } @override @@ -514,9 +498,13 @@ class FeralFileServiceImpl extends FeralFileService { } @override - Future> getListSeries(String exhibitionId) async { + Future> getListSeries(String exhibitionId, + {bool includeFirstArtwork = false}) async { final response = await _feralFileApi.getListSeries( - exhibitionID: exhibitionId, sortBy: 'displayIndex', sortOrder: 'ASC'); + exhibitionID: exhibitionId, + sortBy: 'displayIndex', + sortOrder: 'ASC', + includeFirstArtwork: includeFirstArtwork); return response.result; } @@ -536,37 +524,16 @@ class FeralFileServiceImpl extends FeralFileService { Future _getSourceSeries(String seriesID) async { if (sourceExhibition != null && sourceExhibition!.series != null) { return sourceExhibition!.series! - .where((series) => series.id == seriesID) - .first; + .firstWhere((series) => series.id == seriesID); } final listSeries = await _sourceExhibitionAPI.getSourceExhibitionSeries(); - return listSeries.where((series) => series.id == seriesID).first; + return listSeries.firstWhere((series) => series.id == seriesID); } Future> _getSourceSeriesArtworks(String seriesID) async { final series = await _getSourceSeries(seriesID); - final artworks = (series.artworks ?? []) - .map((artwork) => artwork.copyWith(series: series)) - .toList(); - return artworks; - } - - Future> _getSourceArtworks() async { - final List listSeries; - if (sourceExhibition != null) { - listSeries = sourceExhibition!.series!; - } else { - listSeries = await _sourceExhibitionAPI.getSourceExhibitionSeries(); - } - List listArtwork = []; - for (var series in listSeries) { - final artworks = (series.artworks ?? []) - .map((artwork) => artwork.copyWith(series: series)) - .toList(); - listArtwork.addAll(artworks); - } - return listArtwork; + return series.artworks!; } // John Gerrard exhibition diff --git a/lib/util/exhibition_ext.dart b/lib/util/exhibition_ext.dart index 4acbf511c..afb8025d5 100644 --- a/lib/util/exhibition_ext.dart +++ b/lib/util/exhibition_ext.dart @@ -111,30 +111,6 @@ extension ListExhibitionDetailExt on List { } extension ExhibitionDetailExt on ExhibitionDetail { - List get seriesIds => - artworks?.map((e) => e.seriesID).toSet().toList() ?? []; - - Artwork? representArtwork(String seriesId) => - artworks!.firstWhereOrNull((e) => e.seriesID == seriesId); - - List get representArtworks => - seriesIds.map((e) => representArtwork(e)).whereNotNull().toList(); - - Artwork representArtworkByIndex(int seriesIndex) { - if (seriesIndex < 0 || seriesIndex >= representArtworks.length) { - throw Exception('Invalid series index'); - } - return representArtworks[seriesIndex]; - } - - FFSeries getSeriesByIndex(int seriesIndex) { - if (seriesIndex < 0 || seriesIndex >= seriesIds.length) { - throw Exception('Invalid series index'); - } - return exhibition.series! - .firstWhere((e) => e.id == representArtworks[seriesIndex].seriesID); - } - String? getArtworkTokenId(Artwork artwork) { if (artwork.swap != null) { if (artwork.swap!.token == null) { diff --git a/pubspec.lock b/pubspec.lock index eda1b3f4d..e5d31d3c1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1061,6 +1061,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + flutter_staggered_grid_view: + dependency: transitive + description: + name: flutter_staggered_grid_view + sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" + url: "https://pub.dev" + source: hosted + version: "0.7.0" flutter_svg: dependency: "direct main" description: @@ -1600,10 +1608,10 @@ packages: dependency: "direct main" description: name: infinite_scroll_pagination - sha256: "9517328f4e373f08f57dbb11c5aac5b05554142024d6b60c903f3b73476d52db" + sha256: b68bce20752fcf36c7739e60de4175494f74e99e9a69b4dd2fe3a1dd07a7f16a url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" injector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 01f5730c5..88c927c75 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,7 +60,7 @@ dependencies: http: ^1.1.0 image_picker: ^1.0.1 in_app_purchase: ^3.1.13 - infinite_scroll_pagination: ^3.2.0 + infinite_scroll_pagination: ^4.0.0 intl: ^0.18.0 jiffy: ^6.2.1 flutter_keyboard_visibility: ^6.0.0 diff --git a/test/generate_mock/service/mock_feral_file_service.mocks.dart b/test/generate_mock/service/mock_feral_file_service.mocks.dart index 41055bc23..6c9e153d9 100644 --- a/test/generate_mock/service/mock_feral_file_service.mocks.dart +++ b/test/generate_mock/service/mock_feral_file_service.mocks.dart @@ -3,16 +3,17 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i6; -import 'dart:io' as _i8; +import 'dart:async' as _i7; +import 'dart:io' as _i9; import 'package:autonomy_flutter/model/ff_account.dart' as _i3; import 'package:autonomy_flutter/model/ff_exhibition.dart' as _i4; +import 'package:autonomy_flutter/model/ff_list_response.dart' as _i5; import 'package:autonomy_flutter/model/ff_series.dart' as _i2; -import 'package:autonomy_flutter/service/feralfile_service.dart' as _i5; +import 'package:autonomy_flutter/service/feralfile_service.dart' as _i6; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i7; -import 'package:nft_collection/models/asset_token.dart' as _i9; +import 'package:mockito/src/dummies.dart' as _i8; +import 'package:nft_collection/models/asset_token.dart' as _i10; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -58,8 +59,19 @@ class _FakeExhibition_2 extends _i1.SmartFake implements _i4.Exhibition { ); } -class _FakeArtwork_3 extends _i1.SmartFake implements _i3.Artwork { - _FakeArtwork_3( +class _FakeFeralFileListResponse_3 extends _i1.SmartFake + implements _i5.FeralFileListResponse { + _FakeFeralFileListResponse_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeArtwork_4 extends _i1.SmartFake implements _i3.Artwork { + _FakeArtwork_4( Object parent, Invocation parentInvocation, ) : super( @@ -71,57 +83,68 @@ class _FakeArtwork_3 extends _i1.SmartFake implements _i3.Artwork { /// A class which mocks [FeralFileService]. /// /// See the documentation for Mockito's code generation for more information. -class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { +class MockFeralFileService extends _i1.Mock implements _i6.FeralFileService { MockFeralFileService() { _i1.throwOnMissingStub(this); } @override - _i6.Future<_i2.FFSeries> getSeries( + _i7.Future<_i2.FFSeries> getSeries( String? id, { String? exhibitionID, + bool? includeFirstArtwork = false, }) => (super.noSuchMethod( Invocation.method( #getSeries, [id], - {#exhibitionID: exhibitionID}, + { + #exhibitionID: exhibitionID, + #includeFirstArtwork: includeFirstArtwork, + }, ), - returnValue: _i6.Future<_i2.FFSeries>.value(_FakeFFSeries_0( + returnValue: _i7.Future<_i2.FFSeries>.value(_FakeFFSeries_0( this, Invocation.method( #getSeries, [id], - {#exhibitionID: exhibitionID}, + { + #exhibitionID: exhibitionID, + #includeFirstArtwork: includeFirstArtwork, + }, ), )), - ) as _i6.Future<_i2.FFSeries>); + ) as _i7.Future<_i2.FFSeries>); @override - _i6.Future> getListSeries(String? exhibitionId) => + _i7.Future> getListSeries( + String? exhibitionId, { + bool? includeFirstArtwork = false, + }) => (super.noSuchMethod( Invocation.method( #getListSeries, [exhibitionId], + {#includeFirstArtwork: includeFirstArtwork}, ), - returnValue: _i6.Future>.value(<_i2.FFSeries>[]), - ) as _i6.Future>); + returnValue: _i7.Future>.value(<_i2.FFSeries>[]), + ) as _i7.Future>); @override - _i6.Future<_i4.Exhibition?> getExhibitionFromTokenID(String? artworkID) => + _i7.Future<_i4.Exhibition?> getExhibitionFromTokenID(String? artworkID) => (super.noSuchMethod( Invocation.method( #getExhibitionFromTokenID, [artworkID], ), - returnValue: _i6.Future<_i4.Exhibition?>.value(), - ) as _i6.Future<_i4.Exhibition?>); + returnValue: _i7.Future<_i4.Exhibition?>.value(), + ) as _i7.Future<_i4.Exhibition?>); @override - _i6.Future<_i3.FeralFileResaleInfo> getResaleInfo(String? exhibitionID) => + _i7.Future<_i3.FeralFileResaleInfo> getResaleInfo(String? exhibitionID) => (super.noSuchMethod( Invocation.method( #getResaleInfo, [exhibitionID], ), - returnValue: _i6.Future<_i3.FeralFileResaleInfo>.value( + returnValue: _i7.Future<_i3.FeralFileResaleInfo>.value( _FakeFeralFileResaleInfo_1( this, Invocation.method( @@ -129,32 +152,32 @@ class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { [exhibitionID], ), )), - ) as _i6.Future<_i3.FeralFileResaleInfo>); + ) as _i7.Future<_i3.FeralFileResaleInfo>); @override - _i6.Future getPartnerFullName(String? exhibitionId) => + _i7.Future getPartnerFullName(String? exhibitionId) => (super.noSuchMethod( Invocation.method( #getPartnerFullName, [exhibitionId], ), - returnValue: _i6.Future.value(), - ) as _i6.Future); + returnValue: _i7.Future.value(), + ) as _i7.Future); @override - _i6.Future<_i4.Exhibition> getExhibition(String? id) => (super.noSuchMethod( + _i7.Future<_i4.Exhibition> getExhibition(String? id) => (super.noSuchMethod( Invocation.method( #getExhibition, [id], ), - returnValue: _i6.Future<_i4.Exhibition>.value(_FakeExhibition_2( + returnValue: _i7.Future<_i4.Exhibition>.value(_FakeExhibition_2( this, Invocation.method( #getExhibition, [id], ), )), - ) as _i6.Future<_i4.Exhibition>); + ) as _i7.Future<_i4.Exhibition>); @override - _i6.Future> getAllExhibitions({ + _i7.Future> getAllExhibitions({ String? sortBy = r'openAt', String? sortOrder = r'DESC', int? limit = 8, @@ -171,70 +194,78 @@ class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { #offset: offset, }, ), - returnValue: _i6.Future>.value(<_i4.Exhibition>[]), - ) as _i6.Future>); + returnValue: _i7.Future>.value(<_i4.Exhibition>[]), + ) as _i7.Future>); @override - _i6.Future<_i4.Exhibition> getSourceExhibition() => (super.noSuchMethod( + _i7.Future<_i4.Exhibition> getSourceExhibition() => (super.noSuchMethod( Invocation.method( #getSourceExhibition, [], ), - returnValue: _i6.Future<_i4.Exhibition>.value(_FakeExhibition_2( + returnValue: _i7.Future<_i4.Exhibition>.value(_FakeExhibition_2( this, Invocation.method( #getSourceExhibition, [], ), )), - ) as _i6.Future<_i4.Exhibition>); + ) as _i7.Future<_i4.Exhibition>); @override - _i6.Future<_i4.Exhibition> getFeaturedExhibition() => (super.noSuchMethod( + _i7.Future<_i4.Exhibition> getFeaturedExhibition() => (super.noSuchMethod( Invocation.method( #getFeaturedExhibition, [], ), - returnValue: _i6.Future<_i4.Exhibition>.value(_FakeExhibition_2( + returnValue: _i7.Future<_i4.Exhibition>.value(_FakeExhibition_2( this, Invocation.method( #getFeaturedExhibition, [], ), )), - ) as _i6.Future<_i4.Exhibition>); - @override - _i6.Future> getExhibitionArtworks( - String? exhibitionId, { - bool? withSeries = false, - }) => - (super.noSuchMethod( - Invocation.method( - #getExhibitionArtworks, - [exhibitionId], - {#withSeries: withSeries}, - ), - returnValue: _i6.Future>.value(<_i3.Artwork>[]), - ) as _i6.Future>); + ) as _i7.Future<_i4.Exhibition>); @override - _i6.Future> getSeriesArtworks( - String? seriesId, { - String? exhibitionID, + _i7.Future<_i5.FeralFileListResponse<_i3.Artwork>> getSeriesArtworks( + String? seriesId, + String? exhibitionID, { bool? withSeries = false, + int? offset = 0, + int? limit = 300, }) => (super.noSuchMethod( Invocation.method( #getSeriesArtworks, - [seriesId], + [ + seriesId, + exhibitionID, + ], { - #exhibitionID: exhibitionID, #withSeries: withSeries, + #offset: offset, + #limit: limit, }, ), - returnValue: _i6.Future>.value(<_i3.Artwork>[]), - ) as _i6.Future>); + returnValue: _i7.Future<_i5.FeralFileListResponse<_i3.Artwork>>.value( + _FakeFeralFileListResponse_3<_i3.Artwork>( + this, + Invocation.method( + #getSeriesArtworks, + [ + seriesId, + exhibitionID, + ], + { + #withSeries: withSeries, + #offset: offset, + #limit: limit, + }, + ), + )), + ) as _i7.Future<_i5.FeralFileListResponse<_i3.Artwork>>); @override - _i6.Future getFeralfileActionMessage({ + _i7.Future getFeralfileActionMessage({ required String? address, - required _i5.FeralfileAction? action, + required _i6.FeralfileAction? action, }) => (super.noSuchMethod( Invocation.method( @@ -245,7 +276,7 @@ class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { #action: action, }, ), - returnValue: _i6.Future.value(_i7.dummyValue( + returnValue: _i7.Future.value(_i8.dummyValue( this, Invocation.method( #getFeralfileActionMessage, @@ -256,9 +287,9 @@ class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { }, ), )), - ) as _i6.Future); + ) as _i7.Future); @override - _i6.Future getFeralfileArtworkDownloadUrl({ + _i7.Future getFeralfileArtworkDownloadUrl({ required String? artworkId, required String? owner, required String? signature, @@ -273,7 +304,7 @@ class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { #signature: signature, }, ), - returnValue: _i6.Future.value(_i7.dummyValue( + returnValue: _i7.Future.value(_i8.dummyValue( this, Invocation.method( #getFeralfileArtworkDownloadUrl, @@ -285,24 +316,24 @@ class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { }, ), )), - ) as _i6.Future); + ) as _i7.Future); @override - _i6.Future<_i3.Artwork> getArtwork(String? artworkId) => (super.noSuchMethod( + _i7.Future<_i3.Artwork> getArtwork(String? artworkId) => (super.noSuchMethod( Invocation.method( #getArtwork, [artworkId], ), - returnValue: _i6.Future<_i3.Artwork>.value(_FakeArtwork_3( + returnValue: _i7.Future<_i3.Artwork>.value(_FakeArtwork_4( this, Invocation.method( #getArtwork, [artworkId], ), )), - ) as _i6.Future<_i3.Artwork>); + ) as _i7.Future<_i3.Artwork>); @override - _i6.Future<_i8.File?> downloadFeralfileArtwork( - _i9.AssetToken? assetToken, { + _i7.Future<_i9.File?> downloadFeralfileArtwork( + _i10.AssetToken? assetToken, { dynamic Function( int, int, @@ -314,6 +345,6 @@ class MockFeralFileService extends _i1.Mock implements _i5.FeralFileService { [assetToken], {#onReceiveProgress: onReceiveProgress}, ), - returnValue: _i6.Future<_i8.File?>.value(), - ) as _i6.Future<_i8.File?>); + returnValue: _i7.Future<_i9.File?>.value(), + ) as _i7.Future<_i9.File?>); }