✨ Post list now supports initial filter to prevent some mismatch
This commit is contained in:
@@ -26,6 +26,14 @@ sealed class PostListQuery with _$PostListQuery {
|
||||
}) = _PostListQuery;
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class PostListQueryConfig with _$PostListQueryConfig {
|
||||
const factory PostListQueryConfig({
|
||||
String? id,
|
||||
@Default(PostListQuery()) PostListQuery initialFilter,
|
||||
}) = _PostListQueryConfig;
|
||||
}
|
||||
|
||||
final postListProvider = AsyncNotifierProvider.autoDispose.family(
|
||||
PostListNotifier.new,
|
||||
);
|
||||
@@ -37,10 +45,17 @@ class PostListNotifier extends AsyncNotifier<List<SnPost>>
|
||||
static const int pageSize = 20;
|
||||
|
||||
final String? id;
|
||||
PostListNotifier(this.id);
|
||||
final PostListQueryConfig config;
|
||||
PostListNotifier(this.config) : id = config.id;
|
||||
|
||||
@override
|
||||
PostListQuery currentFilter = PostListQuery();
|
||||
late PostListQuery currentFilter;
|
||||
|
||||
@override
|
||||
Future<List<SnPost>> build() async {
|
||||
currentFilter = config.initialFilter;
|
||||
return fetch();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<SnPost>> fetch() async {
|
||||
@@ -72,7 +87,9 @@ class PostListNotifier extends AsyncNotifier<List<SnPost>>
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
|
||||
final List<dynamic> data = response.data;
|
||||
return data.map((json) => SnPost.fromJson(json)).toList();
|
||||
return response.data
|
||||
.map((json) => SnPost.fromJson(json))
|
||||
.cast<SnPost>()
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,4 +317,276 @@ as bool,
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$PostListQueryConfig {
|
||||
|
||||
String? get id; PostListQuery get initialFilter;
|
||||
/// Create a copy of PostListQueryConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$PostListQueryConfigCopyWith<PostListQueryConfig> get copyWith => _$PostListQueryConfigCopyWithImpl<PostListQueryConfig>(this as PostListQueryConfig, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PostListQueryConfig&&(identical(other.id, id) || other.id == id)&&(identical(other.initialFilter, initialFilter) || other.initialFilter == initialFilter));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,initialFilter);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PostListQueryConfig(id: $id, initialFilter: $initialFilter)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class $PostListQueryConfigCopyWith<$Res> {
|
||||
factory $PostListQueryConfigCopyWith(PostListQueryConfig value, $Res Function(PostListQueryConfig) _then) = _$PostListQueryConfigCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String? id, PostListQuery initialFilter
|
||||
});
|
||||
|
||||
|
||||
$PostListQueryCopyWith<$Res> get initialFilter;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$PostListQueryConfigCopyWithImpl<$Res>
|
||||
implements $PostListQueryConfigCopyWith<$Res> {
|
||||
_$PostListQueryConfigCopyWithImpl(this._self, this._then);
|
||||
|
||||
final PostListQueryConfig _self;
|
||||
final $Res Function(PostListQueryConfig) _then;
|
||||
|
||||
/// Create a copy of PostListQueryConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = freezed,Object? initialFilter = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String?,initialFilter: null == initialFilter ? _self.initialFilter : initialFilter // ignore: cast_nullable_to_non_nullable
|
||||
as PostListQuery,
|
||||
));
|
||||
}
|
||||
/// Create a copy of PostListQueryConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$PostListQueryCopyWith<$Res> get initialFilter {
|
||||
|
||||
return $PostListQueryCopyWith<$Res>(_self.initialFilter, (value) {
|
||||
return _then(_self.copyWith(initialFilter: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Adds pattern-matching-related methods to [PostListQueryConfig].
|
||||
extension PostListQueryConfigPatterns on PostListQueryConfig {
|
||||
/// 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( _PostListQueryConfig value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _PostListQueryConfig() 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( _PostListQueryConfig value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _PostListQueryConfig():
|
||||
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( _PostListQueryConfig value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _PostListQueryConfig() 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? id, PostListQuery initialFilter)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PostListQueryConfig() when $default != null:
|
||||
return $default(_that.id,_that.initialFilter);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? id, PostListQuery initialFilter) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PostListQueryConfig():
|
||||
return $default(_that.id,_that.initialFilter);}
|
||||
}
|
||||
/// 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? id, PostListQuery initialFilter)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PostListQueryConfig() when $default != null:
|
||||
return $default(_that.id,_that.initialFilter);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
|
||||
class _PostListQueryConfig implements PostListQueryConfig {
|
||||
const _PostListQueryConfig({this.id, this.initialFilter = const PostListQuery()});
|
||||
|
||||
|
||||
@override final String? id;
|
||||
@override@JsonKey() final PostListQuery initialFilter;
|
||||
|
||||
/// Create a copy of PostListQueryConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$PostListQueryConfigCopyWith<_PostListQueryConfig> get copyWith => __$PostListQueryConfigCopyWithImpl<_PostListQueryConfig>(this, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PostListQueryConfig&&(identical(other.id, id) || other.id == id)&&(identical(other.initialFilter, initialFilter) || other.initialFilter == initialFilter));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,id,initialFilter);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PostListQueryConfig(id: $id, initialFilter: $initialFilter)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$PostListQueryConfigCopyWith<$Res> implements $PostListQueryConfigCopyWith<$Res> {
|
||||
factory _$PostListQueryConfigCopyWith(_PostListQueryConfig value, $Res Function(_PostListQueryConfig) _then) = __$PostListQueryConfigCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String? id, PostListQuery initialFilter
|
||||
});
|
||||
|
||||
|
||||
@override $PostListQueryCopyWith<$Res> get initialFilter;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$PostListQueryConfigCopyWithImpl<$Res>
|
||||
implements _$PostListQueryConfigCopyWith<$Res> {
|
||||
__$PostListQueryConfigCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _PostListQueryConfig _self;
|
||||
final $Res Function(_PostListQueryConfig) _then;
|
||||
|
||||
/// Create a copy of PostListQueryConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = freezed,Object? initialFilter = null,}) {
|
||||
return _then(_PostListQueryConfig(
|
||||
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String?,initialFilter: null == initialFilter ? _self.initialFilter : initialFilter // ignore: cast_nullable_to_non_nullable
|
||||
as PostListQuery,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of PostListQueryConfig
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$PostListQueryCopyWith<$Res> get initialFilter {
|
||||
|
||||
return $PostListQueryCopyWith<$Res>(_self.initialFilter, (value) {
|
||||
return _then(_self.copyWith(initialFilter: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
||||
@@ -34,7 +34,9 @@ class PostSearchScreen extends HookConsumerWidget {
|
||||
// Single query state
|
||||
final queryState = useState(const PostListQuery());
|
||||
|
||||
final noti = ref.read(postListProvider(kSearchPostListId).notifier);
|
||||
final noti = ref.read(
|
||||
postListProvider(PostListQueryConfig(id: kSearchPostListId)).notifier,
|
||||
);
|
||||
|
||||
useEffect(() {
|
||||
return () {
|
||||
@@ -116,7 +118,9 @@ class PostSearchScreen extends HookConsumerWidget {
|
||||
),
|
||||
body: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final searchState = ref.watch(postListProvider(kSearchPostListId));
|
||||
final searchState = ref.watch(
|
||||
postListProvider(PostListQueryConfig(id: kSearchPostListId)),
|
||||
);
|
||||
|
||||
return isWideScreen(context)
|
||||
? Row(
|
||||
@@ -153,9 +157,11 @@ class PostSearchScreen extends HookConsumerWidget {
|
||||
SliverToBoxAdapter(child: buildFilterPanel()),
|
||||
// Use PaginationList with isSliver=true
|
||||
PaginationList(
|
||||
provider: postListProvider(kSearchPostListId),
|
||||
provider: postListProvider(
|
||||
PostListQueryConfig(id: kSearchPostListId),
|
||||
),
|
||||
notifier: postListProvider(
|
||||
kSearchPostListId,
|
||||
PostListQueryConfig(id: kSearchPostListId),
|
||||
).notifier,
|
||||
isSliver: true,
|
||||
isRefreshable: false,
|
||||
@@ -251,8 +257,12 @@ class PostSearchScreen extends HookConsumerWidget {
|
||||
),
|
||||
// Use PaginationList with isSliver=true
|
||||
PaginationList(
|
||||
provider: postListProvider(kSearchPostListId),
|
||||
notifier: postListProvider(kSearchPostListId).notifier,
|
||||
provider: postListProvider(
|
||||
PostListQueryConfig(id: kSearchPostListId),
|
||||
),
|
||||
notifier: postListProvider(
|
||||
PostListQueryConfig(id: kSearchPostListId),
|
||||
).notifier,
|
||||
isSliver: true,
|
||||
isRefreshable: false,
|
||||
itemBuilder: (context, index, post) {
|
||||
|
||||
@@ -43,17 +43,26 @@ class SliverPostList extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final provider = postListProvider(queryKey);
|
||||
final notifier = provider.notifier;
|
||||
final provider = postListProvider(
|
||||
PostListQueryConfig(
|
||||
id: queryKey,
|
||||
initialFilter: query ?? PostListQuery(),
|
||||
),
|
||||
);
|
||||
final notifier = ref.watch(provider.notifier);
|
||||
|
||||
final currentFilter = useState(query ?? PostListQuery());
|
||||
|
||||
useEffect(() {
|
||||
ref.read(notifier).applyFilter(query!);
|
||||
if (currentFilter.value != query) {
|
||||
notifier.applyFilter(query ?? PostListQuery());
|
||||
}
|
||||
return null;
|
||||
}, [query]);
|
||||
}, [query, queryKey]);
|
||||
|
||||
return PaginationList(
|
||||
provider: provider,
|
||||
notifier: notifier,
|
||||
notifier: provider.notifier,
|
||||
isRefreshable: false,
|
||||
isSliver: true,
|
||||
footerSkeletonChild: const PostItemSkeleton(),
|
||||
|
||||
@@ -17,15 +17,16 @@ class PostShuffleScreen extends HookConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
const query = PostListQuery(shuffle: true);
|
||||
final postListState = ref.watch(postListProvider(kShufflePostListId));
|
||||
final postListNotifier = ref.watch(
|
||||
postListProvider(kShufflePostListId).notifier,
|
||||
final cfg = PostListQueryConfig(
|
||||
id: kShufflePostListId,
|
||||
initialFilter: query,
|
||||
);
|
||||
final postListState = ref.watch(postListProvider(cfg));
|
||||
final postListNotifier = ref.watch(postListProvider(cfg).notifier);
|
||||
|
||||
final cardSwiperController = useMemoized(() => CardSwiperController(), []);
|
||||
|
||||
useEffect(() {
|
||||
postListNotifier.applyFilter(query);
|
||||
return cardSwiperController.dispose;
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user