diff --git a/api/Passport/Developer Notify One User.bru b/api/Passport/Developer Notify One User.bru index 51522d0..bbd3125 100644 --- a/api/Passport/Developer Notify One User.bru +++ b/api/Passport/Developer Notify One User.bru @@ -5,7 +5,7 @@ meta { } post { - url: {{endpoint}}/cgi/id/dev/notify/1 + url: {{endpoint}}/cgi/id/dev/notify/122 body: json auth: inherit } @@ -15,12 +15,9 @@ body:json { "client_id": "{{third_client_id}}", "client_secret":"{{third_client_tk}}", "type": "general", - "subject": "测试", - "subtitle": "Alphabot です", - "content": "全新通知动画", - "metadata": { - "image": "D2EDbcrsTugs3xk5" - }, + "subject": "处理该帐号 @solian 的决定", + "subtitle": "违反用户协议", + "content": "您的帐号违反了我们用户协议中关于冒充我们官方的行为,至此做出停权的决定。还请见谅。该决定是最终决定,不接受上诉。", "priority": 10 } } diff --git a/lib/types/poll.dart b/lib/types/poll.dart index 28786c2..6f449fc 100644 --- a/lib/types/poll.dart +++ b/lib/types/poll.dart @@ -16,8 +16,7 @@ class SnPoll with _$SnPoll { required SnPollMetric metric, }) = _SnPoll; - factory SnPoll.fromJson(Map json) => - _$SnPollFromJson(json); + factory SnPoll.fromJson(Map json) => _$SnPollFromJson(json); } @freezed @@ -25,11 +24,11 @@ class SnPollMetric with _$SnPollMetric { const factory SnPollMetric({ required int totalAnswer, @Default({}) Map byOptions, - @Default({}) Map byOptionsPercentage, + @Default({}) Map byOptionsPercentage, }) = _SnPollMetric; - factory SnPollMetric.fromJson(Map json) - => _$SnPollMetricFromJson(json); + factory SnPollMetric.fromJson(Map json) => + _$SnPollMetricFromJson(json); } @freezed @@ -41,6 +40,6 @@ class SnPollOption with _$SnPollOption { required String description, }) = _SnPollOption; - factory SnPollOption.fromJson(Map json) - => _$SnPollOptionFromJson(json); + factory SnPollOption.fromJson(Map json) => + _$SnPollOptionFromJson(json); } diff --git a/lib/types/poll.freezed.dart b/lib/types/poll.freezed.dart index eaeb28e..bc63e22 100644 --- a/lib/types/poll.freezed.dart +++ b/lib/types/poll.freezed.dart @@ -345,7 +345,7 @@ SnPollMetric _$SnPollMetricFromJson(Map json) { mixin _$SnPollMetric { int get totalAnswer => throw _privateConstructorUsedError; Map get byOptions => throw _privateConstructorUsedError; - Map get byOptionsPercentage => + Map get byOptionsPercentage => throw _privateConstructorUsedError; /// Serializes this SnPollMetric to a JSON map. @@ -367,7 +367,7 @@ abstract class $SnPollMetricCopyWith<$Res> { $Res call( {int totalAnswer, Map byOptions, - Map byOptionsPercentage}); + Map byOptionsPercentage}); } /// @nodoc @@ -401,7 +401,7 @@ class _$SnPollMetricCopyWithImpl<$Res, $Val extends SnPollMetric> byOptionsPercentage: null == byOptionsPercentage ? _value.byOptionsPercentage : byOptionsPercentage // ignore: cast_nullable_to_non_nullable - as Map, + as Map, ) as $Val); } } @@ -417,7 +417,7 @@ abstract class _$$SnPollMetricImplCopyWith<$Res> $Res call( {int totalAnswer, Map byOptions, - Map byOptionsPercentage}); + Map byOptionsPercentage}); } /// @nodoc @@ -449,7 +449,7 @@ class __$$SnPollMetricImplCopyWithImpl<$Res> byOptionsPercentage: null == byOptionsPercentage ? _value._byOptionsPercentage : byOptionsPercentage // ignore: cast_nullable_to_non_nullable - as Map, + as Map, )); } } @@ -460,7 +460,7 @@ class _$SnPollMetricImpl implements _SnPollMetric { const _$SnPollMetricImpl( {required this.totalAnswer, final Map byOptions = const {}, - final Map byOptionsPercentage = const {}}) + final Map byOptionsPercentage = const {}}) : _byOptions = byOptions, _byOptionsPercentage = byOptionsPercentage; @@ -478,10 +478,10 @@ class _$SnPollMetricImpl implements _SnPollMetric { return EqualUnmodifiableMapView(_byOptions); } - final Map _byOptionsPercentage; + final Map _byOptionsPercentage; @override @JsonKey() - Map get byOptionsPercentage { + Map get byOptionsPercentage { if (_byOptionsPercentage is EqualUnmodifiableMapView) return _byOptionsPercentage; // ignore: implicit_dynamic_type @@ -534,7 +534,7 @@ abstract class _SnPollMetric implements SnPollMetric { const factory _SnPollMetric( {required final int totalAnswer, final Map byOptions, - final Map byOptionsPercentage}) = _$SnPollMetricImpl; + final Map byOptionsPercentage}) = _$SnPollMetricImpl; factory _SnPollMetric.fromJson(Map json) = _$SnPollMetricImpl.fromJson; @@ -544,7 +544,7 @@ abstract class _SnPollMetric implements SnPollMetric { @override Map get byOptions; @override - Map get byOptionsPercentage; + Map get byOptionsPercentage; /// Create a copy of SnPollMetric /// with the given fields replaced by the non-null parameter values. diff --git a/lib/types/poll.g.dart b/lib/types/poll.g.dart index 445a263..94dba79 100644 --- a/lib/types/poll.g.dart +++ b/lib/types/poll.g.dart @@ -40,7 +40,7 @@ _$SnPollMetricImpl _$$SnPollMetricImplFromJson(Map json) => const {}, byOptionsPercentage: (json['by_options_percentage'] as Map?)?.map( - (k, e) => MapEntry(k, (e as num).toInt()), + (k, e) => MapEntry(k, (e as num).toDouble()), ) ?? const {}, ); diff --git a/lib/widgets/post/post_poll.dart b/lib/widgets/post/post_poll.dart index 22d4a4a..695f8d0 100644 --- a/lib/widgets/post/post_poll.dart +++ b/lib/widgets/post/post_poll.dart @@ -31,19 +31,27 @@ class _PostPollState extends State { String? _answeredChoice; + Future _refreshPoll() async { + final sn = context.read(); + final resp = await sn.client.get('/cgi/co/polls/${widget.poll.id}'); + if (!mounted) return; + setState(() => _poll = SnPoll.fromJson(resp.data!)); + } + Future _fetchAnswer() async { final ua = context.read(); if (!ua.isAuthorized) return; try { setState(() => _isBusy = true); final sn = context.read(); - final resp = await sn.client.get('/cgi/co/polls/${widget.poll.id}/answer'); + final resp = + await sn.client.get('/cgi/co/polls/${widget.poll.id}/answer'); _answeredChoice = resp.data?['answer']; if (!mounted) return; setState(() {}); } catch (err) { if (!mounted) return; - context.showErrorDialog(err); + // ignore because it may not found } finally { setState(() => _isBusy = false); } @@ -59,8 +67,9 @@ class _PostPollState extends State { 'answer': option.id, }); if (!mounted) return; - context.showSnackbar('pollAnswered'.tr()); HapticFeedback.heavyImpact(); + _answeredChoice = option.id; + _refreshPoll(); } catch (err) { if (!mounted) return; context.showErrorDialog(err); @@ -78,15 +87,24 @@ class _PostPollState extends State { for (final option in _poll.options) Stack( children: [ - Container( - height: 60, - width: MediaQuery.of(context).size.width * (_poll.metric.byOptionsPercentage[option.id] ?? 0).toDouble(), - color: Theme.of(context).colorScheme.surfaceContainerHigh, + ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: Container( + height: 60, + width: MediaQuery.of(context).size.width * + (_poll.metric.byOptionsPercentage[option.id] ?? 0) + .toDouble(), + color: Theme.of(context).colorScheme.surfaceContainerHigh, + ), ), ListTile( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), minTileHeight: 60, - leading: _answeredChoice == option.id ? const Icon(Symbols.circle, fill: 1) : const Icon(Symbols.circle), + leading: _answeredChoice == option.id + ? const Icon(Symbols.circle, fill: 1) + : const Icon(Symbols.circle), title: Text(option.name), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -95,14 +113,18 @@ class _PostPollState extends State { Row( mainAxisSize: MainAxisSize.min, children: [ - Text('pollVotes'.plural(_poll.metric.byOptions[option.id] ?? 0)), + Text( + 'pollVotes' + .plural(_poll.metric.byOptions[option.id] ?? 0), + ), Text(' · ').padding(horizontal: 4), Text( '${((_poll.metric.byOptionsPercentage[option.id] ?? 0).toDouble() * 100).toStringAsFixed(2)}%', ), ], ), - if (option.description.isNotEmpty) Text(option.description), + if (option.description.isNotEmpty) + Text(option.description), ], ), onTap: _isBusy ? null : () => _voteForOption(option),