import 'dart:async'; import 'package:PiliPlus/common/widgets/dialog/report.dart'; import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/dynamics/vote_model.dart'; import 'package:PiliPlus/utils/context_ext.dart'; import 'package:PiliPlus/utils/date_util.dart'; import 'package:PiliPlus/utils/num_util.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart' hide ContextExtensionss; class VotePanel extends StatefulWidget { final VoteInfo voteInfo; final FutureOr> Function(Set, bool) callback; const VotePanel({ super.key, required this.voteInfo, required this.callback, }); @override State createState() => _VotePanelState(); } class _VotePanelState extends State { bool anonymity = false; late VoteInfo _voteInfo; late final RxSet groupValue = (_voteInfo.myVotes?.toSet() ?? {}).obs; late var _percentage = _cnt2Percentage(_voteInfo.options); late bool _enabled = groupValue.isEmpty && _voteInfo.endTime! * 1000 > DateTime.now().millisecondsSinceEpoch; late bool _showPercentage = !_enabled; late final _maxCnt = _voteInfo.choiceCnt ?? _voteInfo.options.length; @override void initState() { super.initState(); _voteInfo = widget.voteInfo; } @override Widget build(BuildContext context) { final theme = Theme.of(context); final usePortrait = context.isPortrait || context.isTablet; final right = [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( _enabled ? '投票选项' : groupValue.isEmpty ? '已结束' : '已完成', ), if (_enabled) Obx(() => Text('${groupValue.length} / $_maxCnt')), ], ), Flexible( child: ListView.builder( key: const PageStorageKey('vote_opions'), shrinkWrap: true, itemCount: _voteInfo.options.length, itemBuilder: (context, index) => _buildOptions(index), ), ), if (_enabled) ...[ _checkBoxs, Padding( padding: const EdgeInsets.only(top: 8), child: Obx( () => OutlinedButton( onPressed: groupValue.isNotEmpty ? () async { final res = await widget.callback( groupValue, anonymity, ); if (res.isSuccess) { if (mounted) { setState(() { _enabled = false; _showPercentage = true; _voteInfo = res.data; _percentage = _cnt2Percentage(_voteInfo.options); }); } } else { res.toast(); } } : null, child: const Center(child: Text('投票')), ), ), ), ], ]; Widget child = Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ if (_voteInfo.title != null) Text(_voteInfo.title!, style: theme.textTheme.titleMedium), if (_voteInfo.desc != null) Text( _voteInfo.desc!, style: theme.textTheme.titleSmall!.copyWith( color: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.8), ), ), Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Wrap( spacing: 10, runSpacing: 5, children: [ Text( '至 ${DateUtil.format(_voteInfo.endTime, format: DateUtil.longFormatDs)}', ), Text.rich( TextSpan( children: [ TextSpan( text: NumUtil.numFormat(_voteInfo.joinNum), style: TextStyle(color: theme.colorScheme.primary), ), const TextSpan(text: '人参与'), ], ), ), ], ), ), if (usePortrait) ...right, ], ); if (!usePortrait) { child = Row( spacing: 12, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: child), Expanded( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: right, ), ), ], ); } return child; } Widget get _checkBoxs => Row( spacing: 16, children: [ CheckBoxText( text: '显示比例', selected: _showPercentage, onChanged: (value) { setState(() { _showPercentage = value; }); }, ), CheckBoxText( text: '匿名', selected: anonymity, onChanged: (val) { anonymity = val; }, ), ], ); Widget _buildOptions(int index) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Builder( builder: (context) { final opt = _voteInfo.options[index]; final selected = groupValue.contains(opt.optIdx); return PercentageChip( label: opt.optDesc!, percentage: _showPercentage ? _percentage[index] : null, selected: selected, onSelected: !_enabled || (groupValue.length >= _maxCnt && !selected) ? null : (value) => _onSelected(context, value, opt.optIdx!), ); }, ), ); } void _onSelected(BuildContext context, bool value, int optidx) { bool isMax = groupValue.length >= _maxCnt; if (value) { groupValue.add(optidx); } else { groupValue.remove(optidx); } if ((isMax && _maxCnt != _voteInfo.options.length && groupValue.length < _maxCnt) || (groupValue.length >= _maxCnt && _maxCnt < _voteInfo.options.length)) { setState(() {}); } else { (context as Element).markNeedsBuild(); } } static List _cnt2Percentage(List