Compare commits
	
		
			3 Commits
		
	
	
		
			215ca705ac
			...
			3.2.0+132
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c9727e92b8 | |||
| 9b8768061d | |||
| 0949f0da54 | 
| @@ -124,3 +124,21 @@ sealed class SnPostEmbedView with _$SnPostEmbedView { | ||||
|   factory SnPostEmbedView.fromJson(Map<String, dynamic> json) => | ||||
|       _$SnPostEmbedViewFromJson(json); | ||||
| } | ||||
|  | ||||
| @freezed | ||||
| sealed class SnPostAward with _$SnPostAward { | ||||
|   const factory SnPostAward({ | ||||
|     required String id, | ||||
|     required double amount, | ||||
|     required int attitude, | ||||
|     String? message, | ||||
|     required String postId, | ||||
|     required String accountId, | ||||
|     @Default(null) DateTime? createdAt, | ||||
|     @Default(null) DateTime? updatedAt, | ||||
|     DateTime? deletedAt, | ||||
|   }) = _SnPostAward; | ||||
|  | ||||
|   factory SnPostAward.fromJson(Map<String, dynamic> json) => | ||||
|       _$SnPostAwardFromJson(json); | ||||
| } | ||||
|   | ||||
| @@ -1617,6 +1617,287 @@ as PostEmbedViewRenderer, | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// @nodoc | ||||
| mixin _$SnPostAward { | ||||
|  | ||||
|  String get id; double get amount; int get attitude; String? get message; String get postId; String get accountId; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; | ||||
| /// Create a copy of SnPostAward | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| $SnPostAwardCopyWith<SnPostAward> get copyWith => _$SnPostAwardCopyWithImpl<SnPostAward>(this as SnPostAward, _$identity); | ||||
|  | ||||
|   /// Serializes this SnPostAward to a JSON map. | ||||
|   Map<String, dynamic> toJson(); | ||||
|  | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostAward&&(identical(other.id, id) || other.id == id)&&(identical(other.amount, amount) || other.amount == amount)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.message, message) || other.message == message)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,amount,attitude,message,postId,accountId,createdAt,updatedAt,deletedAt); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPostAward(id: $id, amount: $amount, attitude: $attitude, message: $message, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class $SnPostAwardCopyWith<$Res>  { | ||||
|   factory $SnPostAwardCopyWith(SnPostAward value, $Res Function(SnPostAward) _then) = _$SnPostAwardCopyWithImpl; | ||||
| @useResult | ||||
| $Res call({ | ||||
|  String id, double amount, int attitude, String? message, String postId, String accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class _$SnPostAwardCopyWithImpl<$Res> | ||||
|     implements $SnPostAwardCopyWith<$Res> { | ||||
|   _$SnPostAwardCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final SnPostAward _self; | ||||
|   final $Res Function(SnPostAward) _then; | ||||
|  | ||||
| /// Create a copy of SnPostAward | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? amount = null,Object? attitude = null,Object? message = freezed,Object? postId = null,Object? accountId = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,}) { | ||||
|   return _then(_self.copyWith( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,amount: null == amount ? _self.amount : amount // ignore: cast_nullable_to_non_nullable | ||||
| as double,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable | ||||
| as int,message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable | ||||
| as String?,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable | ||||
| as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?, | ||||
|   )); | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| /// Adds pattern-matching-related methods to [SnPostAward]. | ||||
| extension SnPostAwardPatterns on SnPostAward { | ||||
| /// 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( _SnPostAward value)?  $default,{required TResult orElse(),}){ | ||||
| final _that = this; | ||||
| switch (_that) { | ||||
| case _SnPostAward() 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( _SnPostAward value)  $default,){ | ||||
| final _that = this; | ||||
| switch (_that) { | ||||
| case _SnPostAward(): | ||||
| 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( _SnPostAward value)?  $default,){ | ||||
| final _that = this; | ||||
| switch (_that) { | ||||
| case _SnPostAward() 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,  double amount,  int attitude,  String? message,  String postId,  String accountId,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt)?  $default,{required TResult orElse(),}) {final _that = this; | ||||
| switch (_that) { | ||||
| case _SnPostAward() when $default != null: | ||||
| return $default(_that.id,_that.amount,_that.attitude,_that.message,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);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,  double amount,  int attitude,  String? message,  String postId,  String accountId,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt)  $default,) {final _that = this; | ||||
| switch (_that) { | ||||
| case _SnPostAward(): | ||||
| return $default(_that.id,_that.amount,_that.attitude,_that.message,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} | ||||
| } | ||||
| /// 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,  double amount,  int attitude,  String? message,  String postId,  String accountId,  DateTime? createdAt,  DateTime? updatedAt,  DateTime? deletedAt)?  $default,) {final _that = this; | ||||
| switch (_that) { | ||||
| case _SnPostAward() when $default != null: | ||||
| return $default(_that.id,_that.amount,_that.attitude,_that.message,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: | ||||
|   return null; | ||||
|  | ||||
| } | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| @JsonSerializable() | ||||
|  | ||||
| class _SnPostAward implements SnPostAward { | ||||
|   const _SnPostAward({required this.id, required this.amount, required this.attitude, this.message, required this.postId, required this.accountId, this.createdAt = null, this.updatedAt = null, this.deletedAt}); | ||||
|   factory _SnPostAward.fromJson(Map<String, dynamic> json) => _$SnPostAwardFromJson(json); | ||||
|  | ||||
| @override final  String id; | ||||
| @override final  double amount; | ||||
| @override final  int attitude; | ||||
| @override final  String? message; | ||||
| @override final  String postId; | ||||
| @override final  String accountId; | ||||
| @override@JsonKey() final  DateTime? createdAt; | ||||
| @override@JsonKey() final  DateTime? updatedAt; | ||||
| @override final  DateTime? deletedAt; | ||||
|  | ||||
| /// Create a copy of SnPostAward | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @pragma('vm:prefer-inline') | ||||
| _$SnPostAwardCopyWith<_SnPostAward> get copyWith => __$SnPostAwardCopyWithImpl<_SnPostAward>(this, _$identity); | ||||
|  | ||||
| @override | ||||
| Map<String, dynamic> toJson() { | ||||
|   return _$SnPostAwardToJson(this, ); | ||||
| } | ||||
|  | ||||
| @override | ||||
| bool operator ==(Object other) { | ||||
|   return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostAward&&(identical(other.id, id) || other.id == id)&&(identical(other.amount, amount) || other.amount == amount)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.message, message) || other.message == message)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); | ||||
| } | ||||
|  | ||||
| @JsonKey(includeFromJson: false, includeToJson: false) | ||||
| @override | ||||
| int get hashCode => Object.hash(runtimeType,id,amount,attitude,message,postId,accountId,createdAt,updatedAt,deletedAt); | ||||
|  | ||||
| @override | ||||
| String toString() { | ||||
|   return 'SnPostAward(id: $id, amount: $amount, attitude: $attitude, message: $message, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| /// @nodoc | ||||
| abstract mixin class _$SnPostAwardCopyWith<$Res> implements $SnPostAwardCopyWith<$Res> { | ||||
|   factory _$SnPostAwardCopyWith(_SnPostAward value, $Res Function(_SnPostAward) _then) = __$SnPostAwardCopyWithImpl; | ||||
| @override @useResult | ||||
| $Res call({ | ||||
|  String id, double amount, int attitude, String? message, String postId, String accountId, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt | ||||
| }); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| /// @nodoc | ||||
| class __$SnPostAwardCopyWithImpl<$Res> | ||||
|     implements _$SnPostAwardCopyWith<$Res> { | ||||
|   __$SnPostAwardCopyWithImpl(this._self, this._then); | ||||
|  | ||||
|   final _SnPostAward _self; | ||||
|   final $Res Function(_SnPostAward) _then; | ||||
|  | ||||
| /// Create a copy of SnPostAward | ||||
| /// with the given fields replaced by the non-null parameter values. | ||||
| @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? amount = null,Object? attitude = null,Object? message = freezed,Object? postId = null,Object? accountId = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,}) { | ||||
|   return _then(_SnPostAward( | ||||
| id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable | ||||
| as String,amount: null == amount ? _self.amount : amount // ignore: cast_nullable_to_non_nullable | ||||
| as double,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable | ||||
| as int,message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable | ||||
| as String?,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable | ||||
| as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable | ||||
| as String,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable | ||||
| as DateTime?, | ||||
|   )); | ||||
| } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| // dart format on | ||||
|   | ||||
| @@ -196,3 +196,37 @@ Map<String, dynamic> _$SnPostEmbedViewToJson(_SnPostEmbedView instance) => | ||||
|     }; | ||||
|  | ||||
| const _$PostEmbedViewRendererEnumMap = {PostEmbedViewRenderer.webView: 0}; | ||||
|  | ||||
| _SnPostAward _$SnPostAwardFromJson(Map<String, dynamic> json) => _SnPostAward( | ||||
|   id: json['id'] as String, | ||||
|   amount: (json['amount'] as num).toDouble(), | ||||
|   attitude: (json['attitude'] as num).toInt(), | ||||
|   message: json['message'] as String?, | ||||
|   postId: json['post_id'] as String, | ||||
|   accountId: json['account_id'] as String, | ||||
|   createdAt: | ||||
|       json['created_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['created_at'] as String), | ||||
|   updatedAt: | ||||
|       json['updated_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['updated_at'] as String), | ||||
|   deletedAt: | ||||
|       json['deleted_at'] == null | ||||
|           ? null | ||||
|           : DateTime.parse(json['deleted_at'] as String), | ||||
| ); | ||||
|  | ||||
| Map<String, dynamic> _$SnPostAwardToJson(_SnPostAward instance) => | ||||
|     <String, dynamic>{ | ||||
|       'id': instance.id, | ||||
|       'amount': instance.amount, | ||||
|       'attitude': instance.attitude, | ||||
|       'message': instance.message, | ||||
|       'post_id': instance.postId, | ||||
|       'account_id': instance.accountId, | ||||
|       'created_at': instance.createdAt?.toIso8601String(), | ||||
|       'updated_at': instance.updatedAt?.toIso8601String(), | ||||
|       'deleted_at': instance.deletedAt?.toIso8601String(), | ||||
|     }; | ||||
|   | ||||
| @@ -162,7 +162,7 @@ class ActivityRpcServer { | ||||
|         shelf_io.serveRequests(_httpServer!, (Request request) async { | ||||
|           developer.log('new request', name: kRpcLogPrefix); | ||||
|           if (request.headers['upgrade']?.toLowerCase() == 'websocket') { | ||||
|             final handler = webSocketHandler((WebSocketChannel channel) { | ||||
|             final handler = webSocketHandler((WebSocketChannel channel, _) { | ||||
|               _wsSockets.add(channel); | ||||
|               _onWsConnection(channel, request); | ||||
|             }); | ||||
|   | ||||
| @@ -13,6 +13,7 @@ import 'package:island/widgets/alert.dart'; | ||||
| import 'package:island/widgets/app_scaffold.dart'; | ||||
| import 'package:island/widgets/extended_refresh_indicator.dart'; | ||||
| import 'package:island/widgets/post/post_item.dart'; | ||||
| import 'package:island/widgets/post/post_award_history_sheet.dart'; | ||||
| import 'package:island/widgets/post/post_pin_sheet.dart'; | ||||
| import 'package:island/widgets/post/post_quick_reply.dart'; | ||||
| import 'package:island/widgets/post/post_replies.dart'; | ||||
| @@ -273,6 +274,13 @@ class PostActionButtons extends HookConsumerWidget { | ||||
|     actions.add( | ||||
|       FilledButton.tonalIcon( | ||||
|         onPressed: () {}, | ||||
|         onLongPress: () { | ||||
|           showModalBottomSheet( | ||||
|             context: context, | ||||
|             isScrollControlled: true, | ||||
|             builder: (context) => PostAwardHistorySheet(postId: post.id), | ||||
|           ); | ||||
|         }, | ||||
|         icon: const Icon(Symbols.star), | ||||
|         label: | ||||
|             post.awardedScore > 0 | ||||
|   | ||||
							
								
								
									
										164
									
								
								lib/widgets/post/post_award_history_sheet.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								lib/widgets/post/post_award_history_sheet.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:island/models/post.dart'; | ||||
| import 'package:island/pods/network.dart'; | ||||
| import 'package:island/widgets/content/sheet.dart'; | ||||
| import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||||
| import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; | ||||
|  | ||||
| part 'post_award_history_sheet.g.dart'; | ||||
|  | ||||
| @riverpod | ||||
| class PostAwardListNotifier extends _$PostAwardListNotifier | ||||
|     with CursorPagingNotifierMixin<SnPostAward> { | ||||
|   static const int _pageSize = 20; | ||||
|  | ||||
|   @override | ||||
|   Future<CursorPagingData<SnPostAward>> build({required String postId}) { | ||||
|     return fetch(cursor: null); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Future<CursorPagingData<SnPostAward>> fetch({required String? cursor}) async { | ||||
|     final client = ref.read(apiClientProvider); | ||||
|     final offset = cursor == null ? 0 : int.parse(cursor); | ||||
|  | ||||
|     final queryParams = {'offset': offset, 'take': _pageSize}; | ||||
|  | ||||
|     final response = await client.get( | ||||
|       '/sphere/posts/$postId/awards', | ||||
|       queryParameters: queryParams, | ||||
|     ); | ||||
|     final total = int.parse(response.headers.value('X-Total') ?? '0'); | ||||
|     final List<dynamic> data = response.data; | ||||
|     final awards = data.map((json) => SnPostAward.fromJson(json)).toList(); | ||||
|  | ||||
|     final hasMore = offset + awards.length < total; | ||||
|     final nextCursor = hasMore ? (offset + awards.length).toString() : null; | ||||
|  | ||||
|     return CursorPagingData( | ||||
|       items: awards, | ||||
|       hasMore: hasMore, | ||||
|       nextCursor: nextCursor, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class PostAwardHistorySheet extends HookConsumerWidget { | ||||
|   final String postId; | ||||
|  | ||||
|   const PostAwardHistorySheet({super.key, required this.postId}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final provider = postAwardListNotifierProvider(postId: postId); | ||||
|  | ||||
|     return SheetScaffold( | ||||
|       titleText: 'Award History', | ||||
|       child: PagingHelperView( | ||||
|         provider: provider, | ||||
|         futureRefreshable: provider.future, | ||||
|         notifierRefreshable: provider.notifier, | ||||
|         contentBuilder: | ||||
|             (data, widgetCount, endItemView) => ListView.builder( | ||||
|               itemCount: widgetCount, | ||||
|               itemBuilder: (context, index) { | ||||
|                 if (index == widgetCount - 1) { | ||||
|                   return endItemView; | ||||
|                 } | ||||
|  | ||||
|                 final award = data.items[index]; | ||||
|                 return Column( | ||||
|                   children: [ | ||||
|                     PostAwardItem(award: award), | ||||
|                     const Divider(height: 1), | ||||
|                   ], | ||||
|                 ); | ||||
|               }, | ||||
|             ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class PostAwardItem extends StatelessWidget { | ||||
|   final SnPostAward award; | ||||
|  | ||||
|   const PostAwardItem({super.key, required this.award}); | ||||
|  | ||||
|   String _getAttitudeText(int attitude) { | ||||
|     switch (attitude) { | ||||
|       case 0: | ||||
|         return 'Positive'; | ||||
|       case 2: | ||||
|         return 'Negative'; | ||||
|       default: | ||||
|         return 'Neutral'; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Color _getAttitudeColor(int attitude, BuildContext context) { | ||||
|     switch (attitude) { | ||||
|       case 0: | ||||
|         return Colors.green; | ||||
|       case 2: | ||||
|         return Colors.red; | ||||
|       default: | ||||
|         return Theme.of(context).colorScheme.onSurfaceVariant; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return ListTile( | ||||
|       leading: CircleAvatar( | ||||
|         backgroundColor: _getAttitudeColor( | ||||
|           award.attitude, | ||||
|           context, | ||||
|         ).withOpacity(0.1), | ||||
|         child: Icon( | ||||
|           award.attitude == 0 | ||||
|               ? Icons.thumb_up | ||||
|               : award.attitude == 2 | ||||
|               ? Icons.thumb_down | ||||
|               : Icons.thumbs_up_down, | ||||
|           color: _getAttitudeColor(award.attitude, context), | ||||
|         ), | ||||
|       ), | ||||
|       title: Text( | ||||
|         '${award.amount} pts', | ||||
|         style: Theme.of( | ||||
|           context, | ||||
|         ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600), | ||||
|       ), | ||||
|       subtitle: Column( | ||||
|         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|         children: [ | ||||
|           Text( | ||||
|             _getAttitudeText(award.attitude), | ||||
|             style: TextStyle( | ||||
|               color: _getAttitudeColor(award.attitude, context), | ||||
|               fontWeight: FontWeight.w500, | ||||
|             ), | ||||
|           ), | ||||
|           if (award.message != null && award.message!.isNotEmpty) ...[ | ||||
|             const SizedBox(height: 4), | ||||
|             Text(award.message!, style: Theme.of(context).textTheme.bodyMedium), | ||||
|           ], | ||||
|           const SizedBox(height: 2), | ||||
|           if (award.createdAt != null) ...[ | ||||
|             const SizedBox(height: 2), | ||||
|             Text( | ||||
|               award.createdAt!.toLocal().toString().split('.')[0], | ||||
|               style: Theme.of(context).textTheme.bodySmall?.copyWith( | ||||
|                 color: Theme.of(context).colorScheme.onSurfaceVariant, | ||||
|               ), | ||||
|             ), | ||||
|           ], | ||||
|         ], | ||||
|       ), | ||||
|       isThreeLine: award.message != null && award.message!.isNotEmpty, | ||||
|       contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										180
									
								
								lib/widgets/post/post_award_history_sheet.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								lib/widgets/post/post_award_history_sheet.g.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
|  | ||||
| part of 'post_award_history_sheet.dart'; | ||||
|  | ||||
| // ************************************************************************** | ||||
| // RiverpodGenerator | ||||
| // ************************************************************************** | ||||
|  | ||||
| String _$postAwardListNotifierHash() => | ||||
|     r'492ae59a5dbbfb5c98f863f036023193b6e08668'; | ||||
|  | ||||
| /// 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 _$PostAwardListNotifier | ||||
|     extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPostAward>> { | ||||
|   late final String postId; | ||||
|  | ||||
|   FutureOr<CursorPagingData<SnPostAward>> build({required String postId}); | ||||
| } | ||||
|  | ||||
| /// See also [PostAwardListNotifier]. | ||||
| @ProviderFor(PostAwardListNotifier) | ||||
| const postAwardListNotifierProvider = PostAwardListNotifierFamily(); | ||||
|  | ||||
| /// See also [PostAwardListNotifier]. | ||||
| class PostAwardListNotifierFamily | ||||
|     extends Family<AsyncValue<CursorPagingData<SnPostAward>>> { | ||||
|   /// See also [PostAwardListNotifier]. | ||||
|   const PostAwardListNotifierFamily(); | ||||
|  | ||||
|   /// See also [PostAwardListNotifier]. | ||||
|   PostAwardListNotifierProvider call({required String postId}) { | ||||
|     return PostAwardListNotifierProvider(postId: postId); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   PostAwardListNotifierProvider getProviderOverride( | ||||
|     covariant PostAwardListNotifierProvider provider, | ||||
|   ) { | ||||
|     return call(postId: provider.postId); | ||||
|   } | ||||
|  | ||||
|   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'postAwardListNotifierProvider'; | ||||
| } | ||||
|  | ||||
| /// See also [PostAwardListNotifier]. | ||||
| class PostAwardListNotifierProvider | ||||
|     extends | ||||
|         AutoDisposeAsyncNotifierProviderImpl< | ||||
|           PostAwardListNotifier, | ||||
|           CursorPagingData<SnPostAward> | ||||
|         > { | ||||
|   /// See also [PostAwardListNotifier]. | ||||
|   PostAwardListNotifierProvider({required String postId}) | ||||
|     : this._internal( | ||||
|         () => PostAwardListNotifier()..postId = postId, | ||||
|         from: postAwardListNotifierProvider, | ||||
|         name: r'postAwardListNotifierProvider', | ||||
|         debugGetCreateSourceHash: | ||||
|             const bool.fromEnvironment('dart.vm.product') | ||||
|                 ? null | ||||
|                 : _$postAwardListNotifierHash, | ||||
|         dependencies: PostAwardListNotifierFamily._dependencies, | ||||
|         allTransitiveDependencies: | ||||
|             PostAwardListNotifierFamily._allTransitiveDependencies, | ||||
|         postId: postId, | ||||
|       ); | ||||
|  | ||||
|   PostAwardListNotifierProvider._internal( | ||||
|     super._createNotifier, { | ||||
|     required super.name, | ||||
|     required super.dependencies, | ||||
|     required super.allTransitiveDependencies, | ||||
|     required super.debugGetCreateSourceHash, | ||||
|     required super.from, | ||||
|     required this.postId, | ||||
|   }) : super.internal(); | ||||
|  | ||||
|   final String postId; | ||||
|  | ||||
|   @override | ||||
|   FutureOr<CursorPagingData<SnPostAward>> runNotifierBuild( | ||||
|     covariant PostAwardListNotifier notifier, | ||||
|   ) { | ||||
|     return notifier.build(postId: postId); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Override overrideWith(PostAwardListNotifier Function() create) { | ||||
|     return ProviderOverride( | ||||
|       origin: this, | ||||
|       override: PostAwardListNotifierProvider._internal( | ||||
|         () => create()..postId = postId, | ||||
|         from: from, | ||||
|         name: null, | ||||
|         dependencies: null, | ||||
|         allTransitiveDependencies: null, | ||||
|         debugGetCreateSourceHash: null, | ||||
|         postId: postId, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   AutoDisposeAsyncNotifierProviderElement< | ||||
|     PostAwardListNotifier, | ||||
|     CursorPagingData<SnPostAward> | ||||
|   > | ||||
|   createElement() { | ||||
|     return _PostAwardListNotifierProviderElement(this); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   bool operator ==(Object other) { | ||||
|     return other is PostAwardListNotifierProvider && other.postId == postId; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   int get hashCode { | ||||
|     var hash = _SystemHash.combine(0, runtimeType.hashCode); | ||||
|     hash = _SystemHash.combine(hash, postId.hashCode); | ||||
|  | ||||
|     return _SystemHash.finish(hash); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||
| // ignore: unused_element | ||||
| mixin PostAwardListNotifierRef | ||||
|     on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnPostAward>> { | ||||
|   /// The parameter `postId` of this provider. | ||||
|   String get postId; | ||||
| } | ||||
|  | ||||
| class _PostAwardListNotifierProviderElement | ||||
|     extends | ||||
|         AutoDisposeAsyncNotifierProviderElement< | ||||
|           PostAwardListNotifier, | ||||
|           CursorPagingData<SnPostAward> | ||||
|         > | ||||
|     with PostAwardListNotifierRef { | ||||
|   _PostAwardListNotifierProviderElement(super.provider); | ||||
|  | ||||
|   @override | ||||
|   String get postId => (origin as PostAwardListNotifierProvider).postId; | ||||
| } | ||||
|  | ||||
| // 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 | ||||
							
								
								
									
										12
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								pubspec.lock
									
									
									
									
									
								
							| @@ -485,10 +485,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: drift_flutter | ||||
|       sha256: ccfb42bc942e59f81500b16228df59cf8eb40d2fbd96637ff677df923350af7b | ||||
|       sha256: b52bd710f809db11e25259d429d799d034ba1c5224ce6a73fe8419feb980d44c | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "0.2.5" | ||||
|     version: "0.2.6" | ||||
|   dropdown_button2: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
| @@ -2217,10 +2217,10 @@ packages: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: shelf_web_socket | ||||
|       sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 | ||||
|       sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.0.1" | ||||
|     version: "3.0.0" | ||||
|   shortid: | ||||
|     dependency: transitive | ||||
|     description: | ||||
| @@ -2760,10 +2760,10 @@ packages: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: webrtc_interface | ||||
|       sha256: "86fe3afc81a08481dfb25cf14a5a94e27062ecef25544783f352c914e0bbc1ca" | ||||
|       sha256: "2e604a31703ad26781782fb14fa8a4ee621154ee2c513d2b9938e486fa695233" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.2.2+hotfix.2" | ||||
|     version: "1.3.0" | ||||
|   win32: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|   | ||||
| @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev | ||||
| # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html | ||||
| # In Windows, build-name is used as the major, minor, and patch parts | ||||
| # of the product and file versions while build-number is used as the build suffix. | ||||
| version: 3.2.0+131 | ||||
| version: 3.2.0+132 | ||||
|  | ||||
| environment: | ||||
|   sdk: ^3.7.2 | ||||
| @@ -85,7 +85,7 @@ dependencies: | ||||
|   web_socket_channel: ^3.0.3 | ||||
|   material_symbols_icons: ^4.2872.0 | ||||
|   drift: ^2.28.1 | ||||
|   drift_flutter: ^0.2.5 | ||||
|   drift_flutter: ^0.2.6 | ||||
|   path: ^1.9.1 | ||||
|   collection: ^1.19.1 | ||||
|   markdown_editor_plus: ^0.2.15 | ||||
| @@ -133,7 +133,7 @@ dependencies: | ||||
|   waveform_flutter: ^1.2.0 | ||||
|   flutter_app_update: ^3.2.2 | ||||
|   archive: ^4.0.7 | ||||
|   process_run: ^1.2.0 | ||||
|   process_run: ^1.2.4 | ||||
|   firebase_crashlytics: ^5.0.1 | ||||
|   firebase_analytics: ^12.0.1 | ||||
|   material_color_utilities: ^0.11.1 | ||||
| @@ -146,7 +146,7 @@ dependencies: | ||||
|   wakelock_plus: ^1.3.2 | ||||
|   slide_countdown: ^2.0.2 | ||||
|   shelf: ^1.4.2 | ||||
|   shelf_web_socket: ^2.0.0 | ||||
|   shelf_web_socket: ^3.0.0 | ||||
|  | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user