implemented full interactive poll support in Talk, including creation, voting, and closing functionality
This commit is contained in:
@@ -1,44 +1,112 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../api/errors/error_mapper.dart';
|
||||
import '../../../../api/marianumcloud/talk/get_poll/get_poll_state.dart';
|
||||
import '../../../../api/marianumcloud/talk/get_poll/get_poll_state_response.dart';
|
||||
import '../../../../api/marianumcloud/talk/room/get_room_response.dart';
|
||||
import '../../../../widget/details_bottom_sheet.dart';
|
||||
import '../../../../widget/loading_spinner.dart';
|
||||
import 'poll_options_list.dart';
|
||||
|
||||
/// Opens the poll dialog that lets a user vote on a Talk poll attached to
|
||||
/// a message. Loads the poll state lazily and renders the option list.
|
||||
void showChatBubblePollDialog(
|
||||
/// Opens the poll bottom sheet for a Talk poll attached to a message. Loads the
|
||||
/// poll state lazily; voting and closing reload the state in place and refresh
|
||||
/// the chat so the surrounding message list stays in sync.
|
||||
void showChatBubblePollSheet(
|
||||
BuildContext context, {
|
||||
required String chatToken,
|
||||
required String messageToken,
|
||||
required GetRoomResponseObject room,
|
||||
required int pollId,
|
||||
required String pollName,
|
||||
required void Function({bool renew}) refetch,
|
||||
}) {
|
||||
final pollState = GetPollState(token: messageToken, pollId: pollId).run();
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (dialogCtx) => AlertDialog(
|
||||
showDetailsBottomSheet(
|
||||
context,
|
||||
header: ListTile(
|
||||
leading: const Icon(Icons.poll_outlined),
|
||||
title: Text(pollName, overflow: TextOverflow.ellipsis),
|
||||
content: FutureBuilder(
|
||||
future: pollState,
|
||||
builder: (_, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [LoadingSpinner()],
|
||||
);
|
||||
}
|
||||
final pollData = snapshot.data!.data;
|
||||
return SingleChildScrollView(
|
||||
child: PollOptionsList(pollData: pollData, chatToken: chatToken),
|
||||
);
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(dialogCtx).pop(),
|
||||
child: const Text('Zurück'),
|
||||
),
|
||||
],
|
||||
subtitle: const Text('Umfrage'),
|
||||
),
|
||||
children: (sheetCtx) => [
|
||||
const SizedBox(height: 8),
|
||||
_PollSheetBody(room: room, pollId: pollId, refetch: refetch),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class _PollSheetBody extends StatefulWidget {
|
||||
final GetRoomResponseObject room;
|
||||
final int pollId;
|
||||
final void Function({bool renew}) refetch;
|
||||
|
||||
const _PollSheetBody({
|
||||
required this.room,
|
||||
required this.pollId,
|
||||
required this.refetch,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_PollSheetBody> createState() => _PollSheetBodyState();
|
||||
}
|
||||
|
||||
class _PollSheetBodyState extends State<_PollSheetBody> {
|
||||
Future<GetPollStateResponse>? _future;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_future = GetPollState(token: widget.room.token, pollId: widget.pollId).run();
|
||||
}
|
||||
|
||||
void _reload() {
|
||||
setState(() {
|
||||
_future = GetPollState(
|
||||
token: widget.room.token,
|
||||
pollId: widget.pollId,
|
||||
).run();
|
||||
});
|
||||
}
|
||||
|
||||
void _applyState(GetPollStateResponse state) {
|
||||
setState(() {
|
||||
// Block body: an arrow would return the Future, which setState rejects.
|
||||
_future = Future.value(state);
|
||||
});
|
||||
widget.refetch(renew: true);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => FutureBuilder<GetPollStateResponse>(
|
||||
future: _future,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(24),
|
||||
child: LoadingSpinner(),
|
||||
);
|
||||
}
|
||||
if (snapshot.hasError) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
errorToUserMessage(snapshot.error),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
FilledButton.tonal(
|
||||
onPressed: _reload,
|
||||
child: const Text('Erneut versuchen'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return PollOptionsList(
|
||||
pollData: snapshot.data!.data,
|
||||
room: widget.room,
|
||||
onStateChanged: _applyState,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user