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:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; class VotePanel extends StatefulWidget { final VoteInfo voteInfo; final FutureOr> Function(Set, bool) callback; final bool embedded; const VotePanel({ super.key, required this.voteInfo, required this.callback, this.embedded = false, }); @override State createState() => _VotePanelState(); } class _VotePanelState extends State { bool anonymity = false; late VoteInfo _voteInfo; late final bool _embedded; late final groupValue = _voteInfo.myVotes?.toSet() ?? {}; 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; late final _selectedNum = ValueNotifier(groupValue.length); late final _canVote = ValueNotifier(false); @override void initState() { super.initState(); _voteInfo = widget.voteInfo; _embedded = widget.embedded || widget.voteInfo.options.length < 5; } @override void dispose() { _selectedNum.dispose(); _canVote.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); return 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), Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '至 ${DateTime.fromMillisecondsSinceEpoch(_voteInfo.endTime! * 1000).toString().substring(0, 19)}', ), Text.rich( TextSpan( children: [ TextSpan( text: _voteInfo.joinNum.toString(), style: TextStyle(color: theme.colorScheme.primary), ), const TextSpan(text: '人参与'), ], ), ), ], ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( _enabled ? '投票选项' : groupValue.isEmpty ? '已结束' : '已完成', ), ValueListenableBuilder( valueListenable: _selectedNum, builder: (_, val, __) => Text('$val / $_maxCnt'), ), ], ), if (_embedded) _buildContext() else Flexible(fit: FlexFit.loose, child: _buildContext()), if (_enabled) Padding( padding: const EdgeInsets.only(top: 16), child: ValueListenableBuilder( valueListenable: _canVote, builder: (_, val, __) => OutlinedButton( onPressed: val ? () 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 { SmartDialog.showToast((res as Error).errMsg); } } : null, child: const Center(child: Text('投票')), ), ), ), ], ); } List get _checkBoxs => [ CheckBoxText( text: '显示比例', selected: _showPercentage, onChanged: (value) { setState(() { _showPercentage = value; }); }, ), CheckBoxText( text: '匿名', selected: anonymity, onChanged: (val) { anonymity = val; }, ), // TODO 转发到动态 ]; Widget _buildOptions(int index) { final opt = _voteInfo.options[index]; return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: PercentageChip( label: opt.optdesc!, value: opt.optidx!, groupValue: groupValue, disabled: groupValue.length >= _maxCnt, percentage: _showPercentage ? _percentage[index] : null, callback: _enabled ? _toggleSelection : null, )); } Widget _buildContext() { return _embedded ? Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ ...List.generate(_voteInfo.options.length, _buildOptions), if (_enabled) ..._checkBoxs, ], ) : CustomScrollView( slivers: [ SliverList.builder( itemCount: _voteInfo.options.length, itemBuilder: (context, index) => _buildOptions(index), ), if (_enabled) SliverList.list(children: _checkBoxs) ], ); } static List _cnt2Percentage(List