diff --git a/lib/models/poll.dart b/lib/models/poll.dart index 2c7b7e97..e11552e2 100644 --- a/lib/models/poll.dart +++ b/lib/models/poll.dart @@ -1,4 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:island/models/account.dart'; import 'package:island/models/publisher.dart'; part 'poll.freezed.dart'; @@ -101,6 +102,7 @@ sealed class SnPollAnswer with _$SnPollAnswer { required DateTime createdAt, required DateTime updatedAt, required DateTime? deletedAt, + SnAccount? account, }) = _SnPollAnswer; factory SnPollAnswer.fromJson(Map json) => diff --git a/lib/models/poll.freezed.dart b/lib/models/poll.freezed.dart index b39ddb1a..d54dcdb5 100644 --- a/lib/models/poll.freezed.dart +++ b/lib/models/poll.freezed.dart @@ -1187,7 +1187,7 @@ as int, /// @nodoc mixin _$SnPollAnswer { - String get id; Map get answer; String get accountId; String get pollId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; + String get id; Map get answer; String get accountId; String get pollId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; SnAccount? get account; /// Create a copy of SnPollAnswer /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -1200,16 +1200,16 @@ $SnPollAnswerCopyWith get copyWith => _$SnPollAnswerCopyWithImpl Object.hash(runtimeType,id,const DeepCollectionEquality().hash(answer),accountId,pollId,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,const DeepCollectionEquality().hash(answer),accountId,pollId,createdAt,updatedAt,deletedAt,account); @override String toString() { - return 'SnPollAnswer(id: $id, answer: $answer, accountId: $accountId, pollId: $pollId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnPollAnswer(id: $id, answer: $answer, accountId: $accountId, pollId: $pollId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, account: $account)'; } @@ -1220,11 +1220,11 @@ abstract mixin class $SnPollAnswerCopyWith<$Res> { factory $SnPollAnswerCopyWith(SnPollAnswer value, $Res Function(SnPollAnswer) _then) = _$SnPollAnswerCopyWithImpl; @useResult $Res call({ - String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccount? account }); - +$SnAccountCopyWith<$Res>? get account; } /// @nodoc @@ -1237,7 +1237,7 @@ class _$SnPollAnswerCopyWithImpl<$Res> /// Create a copy of SnPollAnswer /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? answer = null,Object? accountId = null,Object? pollId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? answer = null,Object? accountId = null,Object? pollId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? account = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,answer: null == answer ? _self.answer : answer // ignore: cast_nullable_to_non_nullable @@ -1246,10 +1246,23 @@ as String,pollId: null == pollId ? _self.pollId : pollId // ignore: cast_nullabl as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == 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?, +as DateTime?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable +as SnAccount?, )); } +/// Create a copy of SnPollAnswer +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnAccountCopyWith<$Res>? get account { + if (_self.account == null) { + return null; + } + return $SnAccountCopyWith<$Res>(_self.account!, (value) { + return _then(_self.copyWith(account: value)); + }); +} } @@ -1328,10 +1341,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccount? account)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _SnPollAnswer() when $default != null: -return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.account);case _: return orElse(); } @@ -1349,10 +1362,10 @@ return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.created /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccount? account) $default,) {final _that = this; switch (_that) { case _SnPollAnswer(): -return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.createdAt,_that.updatedAt,_that.deletedAt);} +return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.account);} } /// A variant of `when` that fallback to returning `null` /// @@ -1366,10 +1379,10 @@ return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.created /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccount? account)? $default,) {final _that = this; switch (_that) { case _SnPollAnswer() when $default != null: -return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.account);case _: return null; } @@ -1381,7 +1394,7 @@ return $default(_that.id,_that.answer,_that.accountId,_that.pollId,_that.created @JsonSerializable() class _SnPollAnswer implements SnPollAnswer { - const _SnPollAnswer({required this.id, required final Map answer, required this.accountId, required this.pollId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _answer = answer; + const _SnPollAnswer({required this.id, required final Map answer, required this.accountId, required this.pollId, required this.createdAt, required this.updatedAt, required this.deletedAt, this.account}): _answer = answer; factory _SnPollAnswer.fromJson(Map json) => _$SnPollAnswerFromJson(json); @override final String id; @@ -1397,6 +1410,7 @@ class _SnPollAnswer implements SnPollAnswer { @override final DateTime createdAt; @override final DateTime updatedAt; @override final DateTime? deletedAt; +@override final SnAccount? account; /// Create a copy of SnPollAnswer /// with the given fields replaced by the non-null parameter values. @@ -1411,16 +1425,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPollAnswer&&(identical(other.id, id) || other.id == id)&&const DeepCollectionEquality().equals(other._answer, _answer)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.pollId, pollId) || other.pollId == pollId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPollAnswer&&(identical(other.id, id) || other.id == id)&&const DeepCollectionEquality().equals(other._answer, _answer)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.pollId, pollId) || other.pollId == pollId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.account, account) || other.account == account)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,const DeepCollectionEquality().hash(_answer),accountId,pollId,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,const DeepCollectionEquality().hash(_answer),accountId,pollId,createdAt,updatedAt,deletedAt,account); @override String toString() { - return 'SnPollAnswer(id: $id, answer: $answer, accountId: $accountId, pollId: $pollId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnPollAnswer(id: $id, answer: $answer, accountId: $accountId, pollId: $pollId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, account: $account)'; } @@ -1431,11 +1445,11 @@ abstract mixin class _$SnPollAnswerCopyWith<$Res> implements $SnPollAnswerCopyWi factory _$SnPollAnswerCopyWith(_SnPollAnswer value, $Res Function(_SnPollAnswer) _then) = __$SnPollAnswerCopyWithImpl; @override @useResult $Res call({ - String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, Map answer, String accountId, String pollId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccount? account }); - +@override $SnAccountCopyWith<$Res>? get account; } /// @nodoc @@ -1448,7 +1462,7 @@ class __$SnPollAnswerCopyWithImpl<$Res> /// Create a copy of SnPollAnswer /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? answer = null,Object? accountId = null,Object? pollId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? answer = null,Object? accountId = null,Object? pollId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? account = freezed,}) { return _then(_SnPollAnswer( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,answer: null == answer ? _self._answer : answer // ignore: cast_nullable_to_non_nullable @@ -1457,11 +1471,24 @@ as String,pollId: null == pollId ? _self.pollId : pollId // ignore: cast_nullabl as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == 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?, +as DateTime?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable +as SnAccount?, )); } +/// Create a copy of SnPollAnswer +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$SnAccountCopyWith<$Res>? get account { + if (_self.account == null) { + return null; + } + return $SnAccountCopyWith<$Res>(_self.account!, (value) { + return _then(_self.copyWith(account: value)); + }); +} } // dart format on diff --git a/lib/models/poll.g.dart b/lib/models/poll.g.dart index 54bbaa15..31acd33b 100644 --- a/lib/models/poll.g.dart +++ b/lib/models/poll.g.dart @@ -144,6 +144,10 @@ _SnPollAnswer _$SnPollAnswerFromJson(Map json) => json['deleted_at'] == null ? null : DateTime.parse(json['deleted_at'] as String), + account: + json['account'] == null + ? null + : SnAccount.fromJson(json['account'] as Map), ); Map _$SnPollAnswerToJson(_SnPollAnswer instance) => @@ -155,4 +159,5 @@ Map _$SnPollAnswerToJson(_SnPollAnswer instance) => 'created_at': instance.createdAt.toIso8601String(), 'updated_at': instance.updatedAt.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(), + 'account': instance.account?.toJson(), }; diff --git a/lib/widgets/poll/poll_feedback.dart b/lib/widgets/poll/poll_feedback.dart index 17dc7031..5940c438 100644 --- a/lib/widgets/poll/poll_feedback.dart +++ b/lib/widgets/poll/poll_feedback.dart @@ -6,6 +6,8 @@ import 'package:island/models/poll.dart'; import 'package:island/pods/network.dart'; import 'package:island/screens/creators/poll/poll_list.dart'; import 'package:island/services/time.dart'; +import 'package:island/widgets/account/account_pfc.dart'; +import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/sheet.dart'; import 'package:island/widgets/poll/poll_stats_widget.dart'; import 'package:island/widgets/response.dart'; @@ -134,19 +136,27 @@ class _PollHeader extends StatelessWidget { ), ), ], - ), - Text('pollQuestions').tr().fontSize(17).bold(), - for (final q in poll.questions) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (q.title.isNotEmpty) Text(q.title).bold(), - if (q.description?.isNotEmpty ?? false) Text(q.description!), - PollStatsWidget(question: q, stats: poll.stats), - ], - ), + ).padding(horizontal: 20, top: 16), + ExpansionTile( + title: Text('pollQuestions').tr().fontSize(17).bold(), + tilePadding: EdgeInsets.symmetric(horizontal: 20), + children: + poll.questions + .map( + (q) => Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (q.title.isNotEmpty) Text(q.title).bold(), + if (q.description?.isNotEmpty ?? false) + Text(q.description!), + PollStatsWidget(question: q, stats: poll.stats), + ], + ).padding(horizontal: 20, top: 8, bottom: 16), + ) + .toList(), + ), ], - ).padding(horizontal: 20, vertical: 16); + ); } } @@ -207,7 +217,10 @@ class _PollAnswerTile extends StatelessWidget { @override Widget build(BuildContext context) { // Submit date/time (title) - final submitText = answer.createdAt.formatSystem(); + final submitText = + answer.account == null + ? answer.createdAt.formatSystem() + : '${answer.account!.nick} ยท ${answer.createdAt.formatSystem()}'; // Compose content from poll questions if provided, otherwise fallback to joined key-values String content; @@ -244,10 +257,18 @@ class _PollAnswerTile extends StatelessWidget { return ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20), isThreeLine: true, - leading: const CircleAvatar( - radius: 16, - child: Icon(Icons.how_to_vote, size: 16), - ), + leading: + answer.account == null + ? const CircleAvatar( + radius: 16, + child: Icon(Icons.how_to_vote, size: 16), + ) + : AccountPfcGestureDetector( + uname: answer.account!.name, + child: ProfilePictureWidget( + file: answer.account!.profile.picture, + ), + ), title: Text(submitText), subtitle: Text(content), trailing: null,