♻️ Continued to migrate list pagination
This commit is contained in:
@@ -4,60 +4,51 @@ import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/poll.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
import 'package:island/screens/poll/poll_editor.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:island/widgets/poll/poll_feedback.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'poll_list.g.dart';
|
||||
|
||||
@riverpod
|
||||
class PollListNotifier extends _$PollListNotifier
|
||||
with CursorPagingNotifierMixin<SnPollWithStats> {
|
||||
static const int _pageSize = 20;
|
||||
final pollListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
|
||||
PollListNotifier.new,
|
||||
);
|
||||
|
||||
class PollListNotifier
|
||||
extends AutoDisposeFamilyAsyncNotifier<List<SnPollWithStats>, String?>
|
||||
with FamilyAsyncPaginationController<SnPollWithStats, String?> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPollWithStats>> build(String? pubName) {
|
||||
// immediately load first page
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPollWithStats>> fetch({
|
||||
required String? cursor,
|
||||
}) async {
|
||||
Future<List<SnPollWithStats>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
// read the current family argument passed to provider
|
||||
final currentPub = pubName;
|
||||
final queryParams = {
|
||||
'offset': offset,
|
||||
'take': _pageSize,
|
||||
if (currentPub != null) 'pub': currentPub,
|
||||
'offset': fetchedCount.toString(),
|
||||
'take': pageSize,
|
||||
if (arg != null) 'pub': arg,
|
||||
};
|
||||
|
||||
final response = await client.get(
|
||||
'/sphere/polls/me',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final List<dynamic> data = response.data;
|
||||
final items = data.map((json) => SnPollWithStats.fromJson(json)).toList();
|
||||
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final items =
|
||||
response.data
|
||||
.map((json) => SnPollWithStats.fromJson(json))
|
||||
.cast<SnPollWithStats>()
|
||||
.toList();
|
||||
|
||||
final hasMore = offset + items.length < total;
|
||||
final nextCursor = hasMore ? (offset + items.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: items,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,20 +88,11 @@ class CreatorPollListScreen extends HookConsumerWidget {
|
||||
),
|
||||
body: ExtendedRefreshIndicator(
|
||||
onRefresh: () => ref.refresh(pollListNotifierProvider(pubName).future),
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
PagingHelperSliverView(
|
||||
child: PaginationList(
|
||||
provider: pollListNotifierProvider(pubName),
|
||||
futureRefreshable: pollListNotifierProvider(pubName).future,
|
||||
notifierRefreshable: pollListNotifierProvider(pubName).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => SliverList.builder(
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
final pollWithStats = data.items[index];
|
||||
notifier: pollListNotifierProvider(pubName).notifier,
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
itemBuilder: (context, index, pollWithStats) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 640),
|
||||
child: _CreatorPollItem(
|
||||
@@ -121,9 +103,6 @@ class CreatorPollListScreen extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,154 +148,5 @@ class _PollWithStatsProviderElement
|
||||
String get id => (origin as PollWithStatsProvider).id;
|
||||
}
|
||||
|
||||
String _$pollListNotifierHash() => r'd5b822e737788be8982f5cb3b501d460441930c1';
|
||||
|
||||
abstract class _$PollListNotifier
|
||||
extends
|
||||
BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPollWithStats>> {
|
||||
late final String? pubName;
|
||||
|
||||
FutureOr<CursorPagingData<SnPollWithStats>> build(String? pubName);
|
||||
}
|
||||
|
||||
/// See also [PollListNotifier].
|
||||
@ProviderFor(PollListNotifier)
|
||||
const pollListNotifierProvider = PollListNotifierFamily();
|
||||
|
||||
/// See also [PollListNotifier].
|
||||
class PollListNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnPollWithStats>>> {
|
||||
/// See also [PollListNotifier].
|
||||
const PollListNotifierFamily();
|
||||
|
||||
/// See also [PollListNotifier].
|
||||
PollListNotifierProvider call(String? pubName) {
|
||||
return PollListNotifierProvider(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
PollListNotifierProvider getProviderOverride(
|
||||
covariant PollListNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.pubName);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'pollListNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [PollListNotifier].
|
||||
class PollListNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
PollListNotifier,
|
||||
CursorPagingData<SnPollWithStats>
|
||||
> {
|
||||
/// See also [PollListNotifier].
|
||||
PollListNotifierProvider(String? pubName)
|
||||
: this._internal(
|
||||
() => PollListNotifier()..pubName = pubName,
|
||||
from: pollListNotifierProvider,
|
||||
name: r'pollListNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$pollListNotifierHash,
|
||||
dependencies: PollListNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
PollListNotifierFamily._allTransitiveDependencies,
|
||||
pubName: pubName,
|
||||
);
|
||||
|
||||
PollListNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.pubName,
|
||||
}) : super.internal();
|
||||
|
||||
final String? pubName;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnPollWithStats>> runNotifierBuild(
|
||||
covariant PollListNotifier notifier,
|
||||
) {
|
||||
return notifier.build(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(PollListNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: PollListNotifierProvider._internal(
|
||||
() => create()..pubName = pubName,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
pubName: pubName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
PollListNotifier,
|
||||
CursorPagingData<SnPollWithStats>
|
||||
>
|
||||
createElement() {
|
||||
return _PollListNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is PollListNotifierProvider && other.pubName == pubName;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, pubName.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin PollListNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnPollWithStats>> {
|
||||
/// The parameter `pubName` of this provider.
|
||||
String? get pubName;
|
||||
}
|
||||
|
||||
class _PollListNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
PollListNotifier,
|
||||
CursorPagingData<SnPollWithStats>
|
||||
>
|
||||
with PollListNotifierRef {
|
||||
_PollListNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get pubName => (origin as PollListNotifierProvider).pubName;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -6,54 +6,43 @@ import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/publication_site.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
import 'package:island/screens/creators/sites/site_edit.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:island/widgets/extended_refresh_indicator.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'site_list.g.dart';
|
||||
final siteListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
|
||||
SiteListNotifier.new,
|
||||
);
|
||||
|
||||
@riverpod
|
||||
class SiteListNotifier extends _$SiteListNotifier
|
||||
with CursorPagingNotifierMixin<SnPublicationSite> {
|
||||
static const int _pageSize = 20;
|
||||
class SiteListNotifier
|
||||
extends AutoDisposeFamilyAsyncNotifier<List<SnPublicationSite>, String>
|
||||
with FamilyAsyncPaginationController<SnPublicationSite, String> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPublicationSite>> build(String? pubName) {
|
||||
// immediately load first page
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnPublicationSite>> fetch({
|
||||
required String? cursor,
|
||||
}) async {
|
||||
Future<List<SnPublicationSite>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
// read the current family argument passed to provider
|
||||
final queryParams = {'offset': offset, 'take': _pageSize};
|
||||
final queryParams = {'offset': fetchedCount.toString(), 'take': pageSize};
|
||||
|
||||
final response = await client.get(
|
||||
'/zone/sites/$pubName',
|
||||
'/zone/sites/$arg',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final List<dynamic> data = response.data;
|
||||
final items = data.map((json) => SnPublicationSite.fromJson(json)).toList();
|
||||
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final items =
|
||||
response.data
|
||||
.map((json) => SnPublicationSite.fromJson(json))
|
||||
.cast<SnPublicationSite>()
|
||||
.toList();
|
||||
|
||||
final hasMore = offset + items.length < total;
|
||||
final nextCursor = hasMore ? (offset + items.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: items,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,25 +73,16 @@ class CreatorSiteListScreen extends HookConsumerWidget {
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
const SliverGap(8),
|
||||
PagingHelperSliverView(
|
||||
PaginationList(
|
||||
provider: siteListNotifierProvider(pubName),
|
||||
futureRefreshable: siteListNotifierProvider(pubName).future,
|
||||
notifierRefreshable: siteListNotifierProvider(pubName).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => SliverList.builder(
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
final site = data.items[index];
|
||||
notifier: siteListNotifierProvider(pubName).notifier,
|
||||
itemBuilder: (context, index, site) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 640),
|
||||
child: _CreatorSiteItem(site: site, pubName: pubName),
|
||||
).center();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'site_list.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$siteListNotifierHash() => r'1670cadcc0c7ccbd98bc33bbf5b4af21e9cb166c';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$SiteListNotifier
|
||||
extends
|
||||
BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPublicationSite>> {
|
||||
late final String? pubName;
|
||||
|
||||
FutureOr<CursorPagingData<SnPublicationSite>> build(String? pubName);
|
||||
}
|
||||
|
||||
/// See also [SiteListNotifier].
|
||||
@ProviderFor(SiteListNotifier)
|
||||
const siteListNotifierProvider = SiteListNotifierFamily();
|
||||
|
||||
/// See also [SiteListNotifier].
|
||||
class SiteListNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnPublicationSite>>> {
|
||||
/// See also [SiteListNotifier].
|
||||
const SiteListNotifierFamily();
|
||||
|
||||
/// See also [SiteListNotifier].
|
||||
SiteListNotifierProvider call(String? pubName) {
|
||||
return SiteListNotifierProvider(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
SiteListNotifierProvider getProviderOverride(
|
||||
covariant SiteListNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.pubName);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'siteListNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [SiteListNotifier].
|
||||
class SiteListNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
SiteListNotifier,
|
||||
CursorPagingData<SnPublicationSite>
|
||||
> {
|
||||
/// See also [SiteListNotifier].
|
||||
SiteListNotifierProvider(String? pubName)
|
||||
: this._internal(
|
||||
() => SiteListNotifier()..pubName = pubName,
|
||||
from: siteListNotifierProvider,
|
||||
name: r'siteListNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$siteListNotifierHash,
|
||||
dependencies: SiteListNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
SiteListNotifierFamily._allTransitiveDependencies,
|
||||
pubName: pubName,
|
||||
);
|
||||
|
||||
SiteListNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.pubName,
|
||||
}) : super.internal();
|
||||
|
||||
final String? pubName;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnPublicationSite>> runNotifierBuild(
|
||||
covariant SiteListNotifier notifier,
|
||||
) {
|
||||
return notifier.build(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(SiteListNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: SiteListNotifierProvider._internal(
|
||||
() => create()..pubName = pubName,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
pubName: pubName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
SiteListNotifier,
|
||||
CursorPagingData<SnPublicationSite>
|
||||
>
|
||||
createElement() {
|
||||
return _SiteListNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is SiteListNotifierProvider && other.pubName == pubName;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, pubName.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin SiteListNotifierRef
|
||||
on
|
||||
AutoDisposeAsyncNotifierProviderRef<
|
||||
CursorPagingData<SnPublicationSite>
|
||||
> {
|
||||
/// The parameter `pubName` of this provider.
|
||||
String? get pubName;
|
||||
}
|
||||
|
||||
class _SiteListNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
SiteListNotifier,
|
||||
CursorPagingData<SnPublicationSite>
|
||||
>
|
||||
with SiteListNotifierRef {
|
||||
_SiteListNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get pubName => (origin as SiteListNotifierProvider).pubName;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -7,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/models/sticker.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
@@ -14,10 +15,10 @@ import 'package:island/widgets/content/cloud_file_picker.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:island/screens/creators/stickers/pack_detail.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
|
||||
part 'stickers.g.dart';
|
||||
|
||||
@@ -81,20 +82,10 @@ class SliverStickerPacksList extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return PagingHelperView(
|
||||
return PaginationList(
|
||||
provider: stickerPacksNotifierProvider(pubName),
|
||||
futureRefreshable: stickerPacksNotifierProvider(pubName).future,
|
||||
notifierRefreshable: stickerPacksNotifierProvider(pubName).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
|
||||
final sticker = data.items[index];
|
||||
notifier: stickerPacksNotifierProvider(pubName).notifier,
|
||||
itemBuilder: (context, index, sticker) {
|
||||
return ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
@@ -124,9 +115,7 @@ class SliverStickerPacksList extends HookConsumerWidget {
|
||||
),
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
ref.invalidate(
|
||||
stickerPackContentProvider(id),
|
||||
);
|
||||
ref.invalidate(stickerPackContentProvider(id));
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -146,46 +135,41 @@ class SliverStickerPacksList extends HookConsumerWidget {
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class StickerPacksNotifier extends _$StickerPacksNotifier
|
||||
with CursorPagingNotifierMixin<SnStickerPack> {
|
||||
static const int _pageSize = 20;
|
||||
final stickerPacksNotifierProvider = AsyncNotifierProvider.family.autoDispose(
|
||||
StickerPacksNotifier.new,
|
||||
);
|
||||
|
||||
class StickerPacksNotifier
|
||||
extends AutoDisposeFamilyAsyncNotifier<List<SnStickerPack>, String>
|
||||
with FamilyAsyncPaginationController<SnStickerPack, String> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnStickerPack>> build(String pubName) {
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnStickerPack>> fetch({
|
||||
required String? cursor,
|
||||
}) async {
|
||||
Future<List<SnStickerPack>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
try {
|
||||
final response = await client.get(
|
||||
'/sphere/stickers',
|
||||
queryParameters: {'offset': offset, 'take': _pageSize, 'pub': pubName},
|
||||
queryParameters: {
|
||||
'offset': fetchedCount.toString(),
|
||||
'take': pageSize,
|
||||
'pub': arg,
|
||||
},
|
||||
);
|
||||
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final List<dynamic> data = response.data;
|
||||
final stickers = data.map((e) => SnStickerPack.fromJson(e)).toList();
|
||||
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final stickers =
|
||||
response.data
|
||||
.map((e) => SnStickerPack.fromJson(e))
|
||||
.cast<SnStickerPack>()
|
||||
.toList();
|
||||
|
||||
final hasMore = offset + stickers.length < total;
|
||||
final nextCursor = hasMore ? (offset + stickers.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: stickers,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
return stickers;
|
||||
} catch (err) {
|
||||
rethrow;
|
||||
}
|
||||
|
||||
@@ -147,154 +147,5 @@ class _StickerPackProviderElement
|
||||
String? get packId => (origin as StickerPackProvider).packId;
|
||||
}
|
||||
|
||||
String _$stickerPacksNotifierHash() =>
|
||||
r'30024b35235f3085a5b1ec2204d0a974ee907e22';
|
||||
|
||||
abstract class _$StickerPacksNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnStickerPack>> {
|
||||
late final String pubName;
|
||||
|
||||
FutureOr<CursorPagingData<SnStickerPack>> build(String pubName);
|
||||
}
|
||||
|
||||
/// See also [StickerPacksNotifier].
|
||||
@ProviderFor(StickerPacksNotifier)
|
||||
const stickerPacksNotifierProvider = StickerPacksNotifierFamily();
|
||||
|
||||
/// See also [StickerPacksNotifier].
|
||||
class StickerPacksNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnStickerPack>>> {
|
||||
/// See also [StickerPacksNotifier].
|
||||
const StickerPacksNotifierFamily();
|
||||
|
||||
/// See also [StickerPacksNotifier].
|
||||
StickerPacksNotifierProvider call(String pubName) {
|
||||
return StickerPacksNotifierProvider(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
StickerPacksNotifierProvider getProviderOverride(
|
||||
covariant StickerPacksNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.pubName);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'stickerPacksNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [StickerPacksNotifier].
|
||||
class StickerPacksNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
StickerPacksNotifier,
|
||||
CursorPagingData<SnStickerPack>
|
||||
> {
|
||||
/// See also [StickerPacksNotifier].
|
||||
StickerPacksNotifierProvider(String pubName)
|
||||
: this._internal(
|
||||
() => StickerPacksNotifier()..pubName = pubName,
|
||||
from: stickerPacksNotifierProvider,
|
||||
name: r'stickerPacksNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$stickerPacksNotifierHash,
|
||||
dependencies: StickerPacksNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
StickerPacksNotifierFamily._allTransitiveDependencies,
|
||||
pubName: pubName,
|
||||
);
|
||||
|
||||
StickerPacksNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.pubName,
|
||||
}) : super.internal();
|
||||
|
||||
final String pubName;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnStickerPack>> runNotifierBuild(
|
||||
covariant StickerPacksNotifier notifier,
|
||||
) {
|
||||
return notifier.build(pubName);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(StickerPacksNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: StickerPacksNotifierProvider._internal(
|
||||
() => create()..pubName = pubName,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
pubName: pubName,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
StickerPacksNotifier,
|
||||
CursorPagingData<SnStickerPack>
|
||||
>
|
||||
createElement() {
|
||||
return _StickerPacksNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is StickerPacksNotifierProvider && other.pubName == pubName;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, pubName.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin StickerPacksNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnStickerPack>> {
|
||||
/// The parameter `pubName` of this provider.
|
||||
String get pubName;
|
||||
}
|
||||
|
||||
class _StickerPacksNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
StickerPacksNotifier,
|
||||
CursorPagingData<SnStickerPack>
|
||||
>
|
||||
with StickerPacksNotifierRef {
|
||||
_StickerPacksNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get pubName => (origin as StickerPacksNotifierProvider).pubName;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -1,41 +1,37 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/webfeed.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:island/widgets/web_article_card.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
|
||||
part 'articles.g.dart';
|
||||
part 'articles.freezed.dart';
|
||||
|
||||
@riverpod
|
||||
class ArticlesListNotifier extends _$ArticlesListNotifier
|
||||
with CursorPagingNotifierMixin<SnWebArticle> {
|
||||
static const int _pageSize = 20;
|
||||
@freezed
|
||||
sealed class ArticleListQuery with _$ArticleListQuery {
|
||||
const factory ArticleListQuery({String? feedId, String? publisherId}) =
|
||||
_ArticleListQuery;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _params = {};
|
||||
final articlesListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
|
||||
ArticlesListNotifier.new,
|
||||
);
|
||||
|
||||
class ArticlesListNotifier
|
||||
extends AutoDisposeFamilyAsyncNotifier<List<SnWebArticle>, ArticleListQuery>
|
||||
with FamilyAsyncPaginationController<SnWebArticle, ArticleListQuery> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnWebArticle>> build({
|
||||
String? feedId,
|
||||
String? publisherId,
|
||||
}) async {
|
||||
_params = {
|
||||
if (feedId != null) 'feedId': feedId,
|
||||
if (publisherId != null) 'publisherId': publisherId,
|
||||
};
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnWebArticle>> fetch({
|
||||
required String? cursor,
|
||||
}) async {
|
||||
Future<List<SnWebArticle>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final queryParams = {'limit': _pageSize, 'offset': offset, ..._params};
|
||||
final queryParams = {'limit': pageSize, 'offset': fetchedCount.toString()};
|
||||
|
||||
try {
|
||||
final response = await client.get(
|
||||
@@ -43,23 +39,17 @@ class ArticlesListNotifier extends _$ArticlesListNotifier
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
|
||||
final List<dynamic> data = response.data;
|
||||
final articles =
|
||||
data
|
||||
response.data
|
||||
.map(
|
||||
(json) => SnWebArticle.fromJson(json as Map<String, dynamic>),
|
||||
)
|
||||
.cast<SnWebArticle>()
|
||||
.toList();
|
||||
|
||||
final total = int.tryParse(response.headers.value('X-Total') ?? '0') ?? 0;
|
||||
final hasMore = offset + articles.length < total;
|
||||
final nextCursor = hasMore ? (offset + articles.length).toString() : null;
|
||||
totalCount = int.tryParse(response.headers.value('X-Total') ?? '0') ?? 0;
|
||||
|
||||
return CursorPagingData(
|
||||
items: articles,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
return articles;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching articles: $e');
|
||||
rethrow;
|
||||
@@ -85,34 +75,17 @@ class SliverArticlesList extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return PagingHelperSliverView(
|
||||
provider: articlesListNotifierProvider(
|
||||
feedId: feedId,
|
||||
publisherId: publisherId,
|
||||
),
|
||||
futureRefreshable:
|
||||
articlesListNotifierProvider(
|
||||
feedId: feedId,
|
||||
publisherId: publisherId,
|
||||
).future,
|
||||
notifierRefreshable:
|
||||
articlesListNotifierProvider(
|
||||
feedId: feedId,
|
||||
publisherId: publisherId,
|
||||
).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => SliverList.separated(
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
|
||||
final article = data.items[index];
|
||||
final provider = articlesListNotifierProvider(
|
||||
ArticleListQuery(feedId: feedId, publisherId: publisherId),
|
||||
);
|
||||
return PaginationList(
|
||||
provider: provider,
|
||||
notifier: provider.notifier,
|
||||
isRefreshable: false,
|
||||
isSliver: true,
|
||||
itemBuilder: (context, index, article) {
|
||||
return WebArticleCard(article: article, showDetails: true);
|
||||
},
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
268
lib/screens/discovery/articles.freezed.dart
Normal file
268
lib/screens/discovery/articles.freezed.dart
Normal file
@@ -0,0 +1,268 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'articles.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$ArticleListQuery {
|
||||
|
||||
String? get feedId; String? get publisherId;
|
||||
/// Create a copy of ArticleListQuery
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$ArticleListQueryCopyWith<ArticleListQuery> get copyWith => _$ArticleListQueryCopyWithImpl<ArticleListQuery>(this as ArticleListQuery, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is ArticleListQuery&&(identical(other.feedId, feedId) || other.feedId == feedId)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,feedId,publisherId);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ArticleListQuery(feedId: $feedId, publisherId: $publisherId)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $ArticleListQueryCopyWith<$Res> {
|
||||
factory $ArticleListQueryCopyWith(ArticleListQuery value, $Res Function(ArticleListQuery) _then) = _$ArticleListQueryCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String? feedId, String? publisherId
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$ArticleListQueryCopyWithImpl<$Res>
|
||||
implements $ArticleListQueryCopyWith<$Res> {
|
||||
_$ArticleListQueryCopyWithImpl(this._self, this._then);
|
||||
|
||||
final ArticleListQuery _self;
|
||||
final $Res Function(ArticleListQuery) _then;
|
||||
|
||||
/// Create a copy of ArticleListQuery
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? feedId = freezed,Object? publisherId = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
feedId: freezed == feedId ? _self.feedId : feedId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [ArticleListQuery].
|
||||
extension ArticleListQueryPatterns on ArticleListQuery {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ArticleListQuery value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ArticleListQuery() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ArticleListQuery value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ArticleListQuery():
|
||||
return $default(_that);}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ArticleListQuery value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _ArticleListQuery() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? feedId, String? publisherId)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ArticleListQuery() when $default != null:
|
||||
return $default(_that.feedId,_that.publisherId);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? feedId, String? publisherId) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ArticleListQuery():
|
||||
return $default(_that.feedId,_that.publisherId);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? feedId, String? publisherId)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _ArticleListQuery() when $default != null:
|
||||
return $default(_that.feedId,_that.publisherId);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _ArticleListQuery implements ArticleListQuery {
|
||||
const _ArticleListQuery({this.feedId, this.publisherId});
|
||||
|
||||
|
||||
@override final String? feedId;
|
||||
@override final String? publisherId;
|
||||
|
||||
/// Create a copy of ArticleListQuery
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$ArticleListQueryCopyWith<_ArticleListQuery> get copyWith => __$ArticleListQueryCopyWithImpl<_ArticleListQuery>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ArticleListQuery&&(identical(other.feedId, feedId) || other.feedId == feedId)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,feedId,publisherId);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ArticleListQuery(feedId: $feedId, publisherId: $publisherId)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$ArticleListQueryCopyWith<$Res> implements $ArticleListQueryCopyWith<$Res> {
|
||||
factory _$ArticleListQueryCopyWith(_ArticleListQuery value, $Res Function(_ArticleListQuery) _then) = __$ArticleListQueryCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String? feedId, String? publisherId
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$ArticleListQueryCopyWithImpl<$Res>
|
||||
implements _$ArticleListQueryCopyWith<$Res> {
|
||||
__$ArticleListQueryCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _ArticleListQuery _self;
|
||||
final $Res Function(_ArticleListQuery) _then;
|
||||
|
||||
/// Create a copy of ArticleListQuery
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? feedId = freezed,Object? publisherId = freezed,}) {
|
||||
return _then(_ArticleListQuery(
|
||||
feedId: freezed == feedId ? _self.feedId : feedId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
@@ -25,201 +25,5 @@ final subscribedFeedsProvider =
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef SubscribedFeedsRef = AutoDisposeFutureProviderRef<List<SnWebFeed>>;
|
||||
String _$articlesListNotifierHash() =>
|
||||
r'579741af4d90c7c81f2e2697e57c4895b7a9dabc';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$ArticlesListNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnWebArticle>> {
|
||||
late final String? feedId;
|
||||
late final String? publisherId;
|
||||
|
||||
FutureOr<CursorPagingData<SnWebArticle>> build({
|
||||
String? feedId,
|
||||
String? publisherId,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ArticlesListNotifier].
|
||||
@ProviderFor(ArticlesListNotifier)
|
||||
const articlesListNotifierProvider = ArticlesListNotifierFamily();
|
||||
|
||||
/// See also [ArticlesListNotifier].
|
||||
class ArticlesListNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnWebArticle>>> {
|
||||
/// See also [ArticlesListNotifier].
|
||||
const ArticlesListNotifierFamily();
|
||||
|
||||
/// See also [ArticlesListNotifier].
|
||||
ArticlesListNotifierProvider call({String? feedId, String? publisherId}) {
|
||||
return ArticlesListNotifierProvider(
|
||||
feedId: feedId,
|
||||
publisherId: publisherId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ArticlesListNotifierProvider getProviderOverride(
|
||||
covariant ArticlesListNotifierProvider provider,
|
||||
) {
|
||||
return call(feedId: provider.feedId, publisherId: provider.publisherId);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'articlesListNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [ArticlesListNotifier].
|
||||
class ArticlesListNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
ArticlesListNotifier,
|
||||
CursorPagingData<SnWebArticle>
|
||||
> {
|
||||
/// See also [ArticlesListNotifier].
|
||||
ArticlesListNotifierProvider({String? feedId, String? publisherId})
|
||||
: this._internal(
|
||||
() =>
|
||||
ArticlesListNotifier()
|
||||
..feedId = feedId
|
||||
..publisherId = publisherId,
|
||||
from: articlesListNotifierProvider,
|
||||
name: r'articlesListNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$articlesListNotifierHash,
|
||||
dependencies: ArticlesListNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ArticlesListNotifierFamily._allTransitiveDependencies,
|
||||
feedId: feedId,
|
||||
publisherId: publisherId,
|
||||
);
|
||||
|
||||
ArticlesListNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.feedId,
|
||||
required this.publisherId,
|
||||
}) : super.internal();
|
||||
|
||||
final String? feedId;
|
||||
final String? publisherId;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnWebArticle>> runNotifierBuild(
|
||||
covariant ArticlesListNotifier notifier,
|
||||
) {
|
||||
return notifier.build(feedId: feedId, publisherId: publisherId);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(ArticlesListNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: ArticlesListNotifierProvider._internal(
|
||||
() =>
|
||||
create()
|
||||
..feedId = feedId
|
||||
..publisherId = publisherId,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
feedId: feedId,
|
||||
publisherId: publisherId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
ArticlesListNotifier,
|
||||
CursorPagingData<SnWebArticle>
|
||||
>
|
||||
createElement() {
|
||||
return _ArticlesListNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ArticlesListNotifierProvider &&
|
||||
other.feedId == feedId &&
|
||||
other.publisherId == publisherId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, feedId.hashCode);
|
||||
hash = _SystemHash.combine(hash, publisherId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin ArticlesListNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnWebArticle>> {
|
||||
/// The parameter `feedId` of this provider.
|
||||
String? get feedId;
|
||||
|
||||
/// The parameter `publisherId` of this provider.
|
||||
String? get publisherId;
|
||||
}
|
||||
|
||||
class _ArticlesListNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
ArticlesListNotifier,
|
||||
CursorPagingData<SnWebArticle>
|
||||
>
|
||||
with ArticlesListNotifierRef {
|
||||
_ArticlesListNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get feedId => (origin as ArticlesListNotifierProvider).feedId;
|
||||
@override
|
||||
String? get publisherId =>
|
||||
(origin as ArticlesListNotifierProvider).publisherId;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/webfeed.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:island/widgets/web_article_card.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'feed_detail.g.dart';
|
||||
@@ -23,52 +22,32 @@ Future<SnWebFeed> marketplaceWebFeed(Ref ref, String feedId) async {
|
||||
return SnWebFeed.fromJson(resp.data);
|
||||
}
|
||||
|
||||
/// Provider for web feed articles content
|
||||
@riverpod
|
||||
final marketplaceWebFeedContentNotifierProvider = AsyncNotifierProvider.family
|
||||
.autoDispose(MarketplaceWebFeedContentNotifier.new);
|
||||
|
||||
class MarketplaceWebFeedContentNotifier
|
||||
extends _$MarketplaceWebFeedContentNotifier
|
||||
with CursorPagingNotifierMixin<SnWebArticle> {
|
||||
static const int _pageSize = 20;
|
||||
extends AutoDisposeFamilyAsyncNotifier<List<SnWebArticle>, String>
|
||||
with FamilyAsyncPaginationController<SnWebArticle, String> {
|
||||
static const int pageSize = 20;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnWebArticle>> build(String feedId) async {
|
||||
_feedId = feedId;
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
late final String _feedId;
|
||||
ValueNotifier<int> totalCount = ValueNotifier(0);
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnWebArticle>> fetch({
|
||||
required String? cursor,
|
||||
}) async {
|
||||
Future<List<SnWebArticle>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final queryParams = {'offset': offset, 'take': _pageSize};
|
||||
final queryParams = {'offset': fetchedCount.toString(), 'take': pageSize};
|
||||
|
||||
final response = await client.get(
|
||||
'/sphere/feeds/$_feedId/articles',
|
||||
'/sphere/feeds/$arg/articles',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
totalCount.value = total;
|
||||
final List<dynamic> data = response.data;
|
||||
final articles = data.map((json) => SnWebArticle.fromJson(json)).toList();
|
||||
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final articles =
|
||||
response.data
|
||||
.map((json) => SnWebArticle.fromJson(json))
|
||||
.cast<SnWebArticle>()
|
||||
.toList();
|
||||
|
||||
final hasMore = offset + articles.length < total;
|
||||
final nextCursor = hasMore ? (offset + articles.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: articles,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
totalCount.dispose();
|
||||
return articles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,10 +105,6 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
|
||||
marketplaceWebFeedContentNotifierProvider(id).notifier,
|
||||
);
|
||||
|
||||
useEffect(() {
|
||||
return feedNotifier.dispose;
|
||||
}, []);
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: Text(feed.value?.title ?? 'loading'.tr())),
|
||||
body: Column(
|
||||
@@ -147,13 +122,9 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
|
||||
spacing: 4,
|
||||
children: [
|
||||
const Icon(Symbols.rss_feed, size: 16),
|
||||
ListenableBuilder(
|
||||
listenable: feedNotifier.totalCount,
|
||||
builder:
|
||||
(context, _) => Text(
|
||||
Text(
|
||||
'webFeedArticleCount'.plural(
|
||||
feedNotifier.totalCount.value,
|
||||
),
|
||||
feedNotifier.totalCount ?? 0,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -174,29 +145,12 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
|
||||
const Divider(height: 1),
|
||||
// Articles list
|
||||
Expanded(
|
||||
child: PagingHelperView(
|
||||
child: PaginationList(
|
||||
provider: marketplaceWebFeedContentNotifierProvider(id),
|
||||
futureRefreshable:
|
||||
marketplaceWebFeedContentNotifierProvider(id).future,
|
||||
notifierRefreshable:
|
||||
marketplaceWebFeedContentNotifierProvider(id).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 20,
|
||||
),
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
|
||||
final article = data.items[index];
|
||||
notifier: marketplaceWebFeedContentNotifierProvider(id).notifier,
|
||||
itemBuilder: (context, index, article) {
|
||||
return WebArticleCard(article: article);
|
||||
},
|
||||
separatorBuilder: (context, index) => const Gap(12),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
|
||||
@@ -290,169 +290,5 @@ class _MarketplaceWebFeedSubscriptionProviderElement
|
||||
(origin as MarketplaceWebFeedSubscriptionProvider).feedId;
|
||||
}
|
||||
|
||||
String _$marketplaceWebFeedContentNotifierHash() =>
|
||||
r'25688082884cb824eeff300888ba38c9748295dc';
|
||||
|
||||
abstract class _$MarketplaceWebFeedContentNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnWebArticle>> {
|
||||
late final String feedId;
|
||||
|
||||
FutureOr<CursorPagingData<SnWebArticle>> build(String feedId);
|
||||
}
|
||||
|
||||
/// Provider for web feed articles content
|
||||
///
|
||||
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||
@ProviderFor(MarketplaceWebFeedContentNotifier)
|
||||
const marketplaceWebFeedContentNotifierProvider =
|
||||
MarketplaceWebFeedContentNotifierFamily();
|
||||
|
||||
/// Provider for web feed articles content
|
||||
///
|
||||
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||
class MarketplaceWebFeedContentNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnWebArticle>>> {
|
||||
/// Provider for web feed articles content
|
||||
///
|
||||
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||
const MarketplaceWebFeedContentNotifierFamily();
|
||||
|
||||
/// Provider for web feed articles content
|
||||
///
|
||||
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||
MarketplaceWebFeedContentNotifierProvider call(String feedId) {
|
||||
return MarketplaceWebFeedContentNotifierProvider(feedId);
|
||||
}
|
||||
|
||||
@override
|
||||
MarketplaceWebFeedContentNotifierProvider getProviderOverride(
|
||||
covariant MarketplaceWebFeedContentNotifierProvider provider,
|
||||
) {
|
||||
return call(provider.feedId);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'marketplaceWebFeedContentNotifierProvider';
|
||||
}
|
||||
|
||||
/// Provider for web feed articles content
|
||||
///
|
||||
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||
class MarketplaceWebFeedContentNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
MarketplaceWebFeedContentNotifier,
|
||||
CursorPagingData<SnWebArticle>
|
||||
> {
|
||||
/// Provider for web feed articles content
|
||||
///
|
||||
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||
MarketplaceWebFeedContentNotifierProvider(String feedId)
|
||||
: this._internal(
|
||||
() => MarketplaceWebFeedContentNotifier()..feedId = feedId,
|
||||
from: marketplaceWebFeedContentNotifierProvider,
|
||||
name: r'marketplaceWebFeedContentNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$marketplaceWebFeedContentNotifierHash,
|
||||
dependencies: MarketplaceWebFeedContentNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
MarketplaceWebFeedContentNotifierFamily._allTransitiveDependencies,
|
||||
feedId: feedId,
|
||||
);
|
||||
|
||||
MarketplaceWebFeedContentNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.feedId,
|
||||
}) : super.internal();
|
||||
|
||||
final String feedId;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnWebArticle>> runNotifierBuild(
|
||||
covariant MarketplaceWebFeedContentNotifier notifier,
|
||||
) {
|
||||
return notifier.build(feedId);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(MarketplaceWebFeedContentNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: MarketplaceWebFeedContentNotifierProvider._internal(
|
||||
() => create()..feedId = feedId,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
feedId: feedId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
MarketplaceWebFeedContentNotifier,
|
||||
CursorPagingData<SnWebArticle>
|
||||
>
|
||||
createElement() {
|
||||
return _MarketplaceWebFeedContentNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MarketplaceWebFeedContentNotifierProvider &&
|
||||
other.feedId == feedId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, feedId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin MarketplaceWebFeedContentNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnWebArticle>> {
|
||||
/// The parameter `feedId` of this provider.
|
||||
String get feedId;
|
||||
}
|
||||
|
||||
class _MarketplaceWebFeedContentNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
MarketplaceWebFeedContentNotifier,
|
||||
CursorPagingData<SnWebArticle>
|
||||
>
|
||||
with MarketplaceWebFeedContentNotifierRef {
|
||||
_MarketplaceWebFeedContentNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get feedId =>
|
||||
(origin as MarketplaceWebFeedContentNotifierProvider).feedId;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
@@ -6,52 +7,44 @@ import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/webfeed.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/paging.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
final marketplaceWebFeedsNotifierProvider = AsyncNotifierProvider(
|
||||
MarketplaceWebFeedsNotifier.new,
|
||||
);
|
||||
|
||||
part 'feed_marketplace.g.dart';
|
||||
|
||||
@riverpod
|
||||
class MarketplaceWebFeedsNotifier extends _$MarketplaceWebFeedsNotifier
|
||||
with CursorPagingNotifierMixin<SnWebFeed> {
|
||||
String? _query;
|
||||
class MarketplaceWebFeedsNotifier extends AsyncNotifier<List<SnWebFeed>>
|
||||
with
|
||||
AsyncPaginationController<SnWebFeed>,
|
||||
AsyncPaginationFilter<String?, SnWebFeed> {
|
||||
@override
|
||||
String? currentFilter;
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnWebFeed>> build({required String? query}) {
|
||||
_query = query;
|
||||
return fetch(cursor: null);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<CursorPagingData<SnWebFeed>> fetch({required String? cursor}) async {
|
||||
Future<List<SnWebFeed>> fetch() async {
|
||||
final client = ref.read(apiClientProvider);
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final response = await client.get(
|
||||
'/sphere/feeds/explore',
|
||||
queryParameters: {
|
||||
'offset': offset,
|
||||
'offset': fetchedCount.toString(),
|
||||
'take': 20,
|
||||
if (_query != null && _query!.isNotEmpty) 'query': _query,
|
||||
if (currentFilter != null && currentFilter!.isNotEmpty)
|
||||
'query': currentFilter,
|
||||
},
|
||||
);
|
||||
|
||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final List<dynamic> data = response.data;
|
||||
final feeds = data.map((e) => SnWebFeed.fromJson(e)).toList();
|
||||
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final feeds =
|
||||
response.data
|
||||
.map((e) => SnWebFeed.fromJson(e))
|
||||
.cast<SnWebFeed>()
|
||||
.toList();
|
||||
|
||||
final hasMore = offset + feeds.length < total;
|
||||
final nextCursor = hasMore ? (offset + feeds.length).toString() : null;
|
||||
|
||||
return CursorPagingData(
|
||||
items: feeds,
|
||||
hasMore: hasMore,
|
||||
nextCursor: nextCursor,
|
||||
);
|
||||
return feeds;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,16 +79,8 @@ class MarketplaceWebFeedsScreen extends HookConsumerWidget {
|
||||
title: const Text('webFeeds').tr(),
|
||||
actions: const [Gap(8)],
|
||||
),
|
||||
body: PagingHelperView(
|
||||
provider: marketplaceWebFeedsNotifierProvider(query: query.value),
|
||||
futureRefreshable:
|
||||
marketplaceWebFeedsNotifierProvider(query: query.value).future,
|
||||
notifierRefreshable:
|
||||
marketplaceWebFeedsNotifierProvider(query: query.value).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => Column(
|
||||
body: Column(
|
||||
children: [
|
||||
// Search bar above the list
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SearchBar(
|
||||
@@ -137,15 +122,11 @@ class MarketplaceWebFeedsScreen extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
child: PaginationList(
|
||||
provider: marketplaceWebFeedsNotifierProvider,
|
||||
notifier: marketplaceWebFeedsNotifierProvider.notifier,
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
|
||||
final feed = data.items[index];
|
||||
itemBuilder: (context, index, feed) {
|
||||
return ListTile(
|
||||
title: Text(feed.title),
|
||||
subtitle: Text(feed.description ?? ''),
|
||||
@@ -163,7 +144,6 @@ class MarketplaceWebFeedsScreen extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'feed_marketplace.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$marketplaceWebFeedsNotifierHash() =>
|
||||
r'774b2985f2f7d61fe958f534f84e39f814327c4e';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$MarketplaceWebFeedsNotifier
|
||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnWebFeed>> {
|
||||
late final String? query;
|
||||
|
||||
FutureOr<CursorPagingData<SnWebFeed>> build({required String? query});
|
||||
}
|
||||
|
||||
/// See also [MarketplaceWebFeedsNotifier].
|
||||
@ProviderFor(MarketplaceWebFeedsNotifier)
|
||||
const marketplaceWebFeedsNotifierProvider = MarketplaceWebFeedsNotifierFamily();
|
||||
|
||||
/// See also [MarketplaceWebFeedsNotifier].
|
||||
class MarketplaceWebFeedsNotifierFamily
|
||||
extends Family<AsyncValue<CursorPagingData<SnWebFeed>>> {
|
||||
/// See also [MarketplaceWebFeedsNotifier].
|
||||
const MarketplaceWebFeedsNotifierFamily();
|
||||
|
||||
/// See also [MarketplaceWebFeedsNotifier].
|
||||
MarketplaceWebFeedsNotifierProvider call({required String? query}) {
|
||||
return MarketplaceWebFeedsNotifierProvider(query: query);
|
||||
}
|
||||
|
||||
@override
|
||||
MarketplaceWebFeedsNotifierProvider getProviderOverride(
|
||||
covariant MarketplaceWebFeedsNotifierProvider provider,
|
||||
) {
|
||||
return call(query: provider.query);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'marketplaceWebFeedsNotifierProvider';
|
||||
}
|
||||
|
||||
/// See also [MarketplaceWebFeedsNotifier].
|
||||
class MarketplaceWebFeedsNotifierProvider
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderImpl<
|
||||
MarketplaceWebFeedsNotifier,
|
||||
CursorPagingData<SnWebFeed>
|
||||
> {
|
||||
/// See also [MarketplaceWebFeedsNotifier].
|
||||
MarketplaceWebFeedsNotifierProvider({required String? query})
|
||||
: this._internal(
|
||||
() => MarketplaceWebFeedsNotifier()..query = query,
|
||||
from: marketplaceWebFeedsNotifierProvider,
|
||||
name: r'marketplaceWebFeedsNotifierProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$marketplaceWebFeedsNotifierHash,
|
||||
dependencies: MarketplaceWebFeedsNotifierFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
MarketplaceWebFeedsNotifierFamily._allTransitiveDependencies,
|
||||
query: query,
|
||||
);
|
||||
|
||||
MarketplaceWebFeedsNotifierProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.query,
|
||||
}) : super.internal();
|
||||
|
||||
final String? query;
|
||||
|
||||
@override
|
||||
FutureOr<CursorPagingData<SnWebFeed>> runNotifierBuild(
|
||||
covariant MarketplaceWebFeedsNotifier notifier,
|
||||
) {
|
||||
return notifier.build(query: query);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(MarketplaceWebFeedsNotifier Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: MarketplaceWebFeedsNotifierProvider._internal(
|
||||
() => create()..query = query,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
query: query,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
MarketplaceWebFeedsNotifier,
|
||||
CursorPagingData<SnWebFeed>
|
||||
>
|
||||
createElement() {
|
||||
return _MarketplaceWebFeedsNotifierProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MarketplaceWebFeedsNotifierProvider && other.query == query;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, query.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin MarketplaceWebFeedsNotifierRef
|
||||
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnWebFeed>> {
|
||||
/// The parameter `query` of this provider.
|
||||
String? get query;
|
||||
}
|
||||
|
||||
class _MarketplaceWebFeedsNotifierProviderElement
|
||||
extends
|
||||
AutoDisposeAsyncNotifierProviderElement<
|
||||
MarketplaceWebFeedsNotifier,
|
||||
CursorPagingData<SnWebFeed>
|
||||
>
|
||||
with MarketplaceWebFeedsNotifierRef {
|
||||
_MarketplaceWebFeedsNotifierProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String? get query => (origin as MarketplaceWebFeedsNotifierProvider).query;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -9,8 +9,8 @@ import 'package:island/screens/creators/poll/poll_list.dart';
|
||||
import 'package:island/screens/poll/poll_editor.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:island/widgets/paging/pagination_list.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:island/widgets/post/publishers_modal.dart';
|
||||
|
||||
@@ -45,23 +45,10 @@ class ComposePollSheet extends HookConsumerWidget {
|
||||
child: TabBarView(
|
||||
children: [
|
||||
// Link/Select existing poll list
|
||||
PagingHelperView(
|
||||
PaginationList(
|
||||
provider: pollListNotifierProvider(pub?.name),
|
||||
futureRefreshable:
|
||||
pollListNotifierProvider(pub?.name).future,
|
||||
notifierRefreshable:
|
||||
pollListNotifierProvider(pub?.name).notifier,
|
||||
contentBuilder:
|
||||
(data, widgetCount, endItemView) => ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == widgetCount - 1) {
|
||||
return endItemView;
|
||||
}
|
||||
|
||||
final poll = data.items[index];
|
||||
|
||||
notifier: pollListNotifierProvider(pub?.name).notifier,
|
||||
itemBuilder: (context, index, poll) {
|
||||
return ListTile(
|
||||
leading: const Icon(Symbols.how_to_vote, fill: 1),
|
||||
title: Text(poll.title ?? 'untitled'.tr()),
|
||||
@@ -74,7 +61,6 @@ class ComposePollSheet extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// Create new poll and return it
|
||||
SingleChildScrollView(
|
||||
|
||||
Reference in New Issue
Block a user