Surface/lib/widgets/post/post_poll.dart

117 lines
3.8 KiB
Dart
Raw Normal View History

2025-02-12 23:56:45 +08:00
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
2025-02-13 22:35:53 +08:00
import 'package:flutter/services.dart';
2025-02-12 23:56:45 +08:00
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
2025-02-13 22:35:53 +08:00
import 'package:styled_widget/styled_widget.dart';
2025-02-12 23:56:45 +08:00
import 'package:surface/providers/sn_network.dart';
2025-02-13 22:35:53 +08:00
import 'package:surface/providers/userinfo.dart';
2025-02-12 23:56:45 +08:00
import 'package:surface/types/poll.dart';
import 'package:surface/widgets/dialog.dart';
2025-02-13 22:35:53 +08:00
class PostPoll extends StatefulWidget {
final SnPoll poll;
2025-02-12 23:56:45 +08:00
2025-02-13 22:35:53 +08:00
const PostPoll({super.key, required this.poll});
2025-02-12 23:56:45 +08:00
@override
2025-02-13 22:35:53 +08:00
State<PostPoll> createState() => _PostPollState();
2025-02-12 23:56:45 +08:00
}
2025-02-13 22:35:53 +08:00
class _PostPollState extends State<PostPoll> {
2025-02-12 23:56:45 +08:00
bool _isBusy = false;
2025-02-13 22:35:53 +08:00
late SnPoll _poll;
2025-02-12 23:56:45 +08:00
2025-02-13 22:35:53 +08:00
@override
void initState() {
_poll = widget.poll;
_fetchAnswer();
super.initState();
2025-02-12 23:56:45 +08:00
}
2025-02-13 22:35:53 +08:00
String? _answeredChoice;
Future<void> _fetchAnswer() async {
final ua = context.read<UserProvider>();
if (!ua.isAuthorized) return;
2025-02-12 23:56:45 +08:00
try {
setState(() => _isBusy = true);
final sn = context.read<SnNetworkProvider>();
2025-02-13 22:35:53 +08:00
final resp = await sn.client.get('/cgi/co/polls/${widget.poll.id}/answer');
_answeredChoice = resp.data?['answer'];
2025-02-12 23:56:45 +08:00
if (!mounted) return;
2025-02-13 22:35:53 +08:00
setState(() {});
2025-02-12 23:56:45 +08:00
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
2025-02-13 22:35:53 +08:00
Future<void> _voteForOption(SnPollOption option) async {
final ua = context.read<UserProvider>();
if (!ua.isAuthorized) return;
2025-02-12 23:56:45 +08:00
try {
setState(() => _isBusy = true);
final sn = context.read<SnNetworkProvider>();
2025-02-13 22:35:53 +08:00
await sn.client.post('/cgi/co/polls/${widget.poll.id}/answer', data: {
'answer': option.id,
});
2025-02-12 23:56:45 +08:00
if (!mounted) return;
2025-02-13 22:35:53 +08:00
context.showSnackbar('pollAnswered'.tr());
HapticFeedback.heavyImpact();
2025-02-12 23:56:45 +08:00
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
@override
Widget build(BuildContext context) {
2025-02-13 22:35:53 +08:00
return Card(
margin: EdgeInsets.zero,
child: Column(
2025-02-12 23:56:45 +08:00
children: [
2025-02-13 22:35:53 +08:00
for (final option in _poll.options)
Stack(
2025-02-12 23:56:45 +08:00
children: [
2025-02-13 22:35:53 +08:00
Container(
height: 60,
width: MediaQuery.of(context).size.width * (_poll.metric.byOptionsPercentage[option.id] ?? 0).toDouble(),
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
2025-02-12 23:56:45 +08:00
ListTile(
2025-02-13 22:35:53 +08:00
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
minTileHeight: 60,
leading: _answeredChoice == option.id ? const Icon(Symbols.circle, fill: 1) : const Icon(Symbols.circle),
title: Text(option.name),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('pollVotes'.plural(_poll.metric.byOptions[option.id] ?? 0)),
Text(' · ').padding(horizontal: 4),
Text(
'${((_poll.metric.byOptionsPercentage[option.id] ?? 0).toDouble() * 100).toStringAsFixed(2)}%',
),
],
2025-02-12 23:56:45 +08:00
),
2025-02-13 22:35:53 +08:00
if (option.description.isNotEmpty) Text(option.description),
],
),
onTap: _isBusy ? null : () => _voteForOption(option),
2025-02-12 23:56:45 +08:00
),
],
2025-02-13 22:35:53 +08:00
)
2025-02-12 23:56:45 +08:00
],
),
);
}
}