186 lines
5.6 KiB
Dart
186 lines
5.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../../../api/marianumcloud/talk/create_poll/create_poll.dart';
|
|
import '../../../../api/marianumcloud/talk/create_poll/create_poll_params.dart';
|
|
import '../../../../api/marianumcloud/talk/get_poll/get_poll_state_response.dart';
|
|
import '../../../../widget/async_action_button.dart';
|
|
import '../../../../widget/demo_restricted.dart';
|
|
import '../../../../widget/details_bottom_sheet.dart';
|
|
|
|
/// Opens the poll creation form. On success the server posts the poll message
|
|
/// into the chat itself, so the caller only needs to refresh via [onCreated].
|
|
void showPollCreateSheet(
|
|
BuildContext context, {
|
|
required String token,
|
|
required VoidCallback onCreated,
|
|
}) {
|
|
showDetailsBottomSheet(
|
|
context,
|
|
header: const ListTile(
|
|
leading: Icon(Icons.poll_outlined),
|
|
title: Text('Umfrage erstellen'),
|
|
),
|
|
children: (sheetCtx) => [_PollCreateBody(token: token, onCreated: onCreated)],
|
|
);
|
|
}
|
|
|
|
class _PollCreateBody extends StatefulWidget {
|
|
final String token;
|
|
final VoidCallback onCreated;
|
|
|
|
const _PollCreateBody({required this.token, required this.onCreated});
|
|
|
|
@override
|
|
State<_PollCreateBody> createState() => _PollCreateBodyState();
|
|
}
|
|
|
|
class _PollCreateBodyState extends State<_PollCreateBody> {
|
|
final TextEditingController _question = TextEditingController();
|
|
final List<TextEditingController> _options = [
|
|
TextEditingController(),
|
|
TextEditingController(),
|
|
];
|
|
final AsyncActionController _submitController = AsyncActionController();
|
|
bool _hideResults = false;
|
|
bool _multipleChoice = false;
|
|
String? _validationError;
|
|
|
|
@override
|
|
void dispose() {
|
|
_question.dispose();
|
|
for (final controller in _options) {
|
|
controller.dispose();
|
|
}
|
|
_submitController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _addOption() {
|
|
setState(() => _options.add(TextEditingController()));
|
|
}
|
|
|
|
void _removeOption(int index) {
|
|
setState(() {
|
|
_options.removeAt(index).dispose();
|
|
});
|
|
}
|
|
|
|
Future<void> _submit() async {
|
|
if (guardDemoAction(context)) return;
|
|
final question = _question.text.trim();
|
|
final options = _options
|
|
.map((c) => c.text.trim())
|
|
.where((text) => text.isNotEmpty)
|
|
.toList();
|
|
|
|
if (question.isEmpty) {
|
|
setState(() => _validationError = 'Bitte gib eine Frage ein.');
|
|
return;
|
|
}
|
|
if (options.length < 2) {
|
|
setState(
|
|
() => _validationError = 'Bitte gib mindestens zwei Optionen an.',
|
|
);
|
|
return;
|
|
}
|
|
setState(() => _validationError = null);
|
|
|
|
await CreatePoll(
|
|
token: widget.token,
|
|
params: CreatePollParams(
|
|
question: question,
|
|
options: options,
|
|
resultMode: _hideResults
|
|
? pollResultModeHidden
|
|
: pollResultModePublic,
|
|
maxVotes: _multipleChoice ? 0 : 1,
|
|
),
|
|
).run();
|
|
|
|
if (!mounted) return;
|
|
Navigator.of(context).pop();
|
|
widget.onCreated();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
child: TextField(
|
|
controller: _question,
|
|
textCapitalization: TextCapitalization.sentences,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Frage',
|
|
hintText: 'Worüber soll abgestimmt werden?',
|
|
),
|
|
),
|
|
),
|
|
...List.generate(_options.length, (index) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: TextField(
|
|
controller: _options[index],
|
|
textCapitalization: TextCapitalization.sentences,
|
|
decoration: InputDecoration(
|
|
labelText: 'Option ${index + 1}',
|
|
),
|
|
),
|
|
),
|
|
IconButton(
|
|
tooltip: 'Option entfernen',
|
|
icon: const Icon(Icons.remove_circle_outline),
|
|
onPressed: _options.length > 2
|
|
? () => _removeOption(index)
|
|
: null,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}),
|
|
Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: TextButton.icon(
|
|
onPressed: _addOption,
|
|
icon: const Icon(Icons.add),
|
|
label: const Text('Option hinzufügen'),
|
|
),
|
|
),
|
|
SwitchListTile(
|
|
value: _hideResults,
|
|
onChanged: (value) => setState(() => _hideResults = value),
|
|
title: const Text('Ergebnisse bis zum Schließen verbergen'),
|
|
),
|
|
SwitchListTile(
|
|
value: _multipleChoice,
|
|
onChanged: (value) => setState(() => _multipleChoice = value),
|
|
title: const Text('Mehrfachauswahl erlauben'),
|
|
),
|
|
if (_validationError != null)
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
|
child: Text(
|
|
_validationError!,
|
|
style: TextStyle(color: theme.colorScheme.error),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
child: AsyncActionButton(
|
|
controller: _submitController,
|
|
onPressed: _submit,
|
|
child: const Text('Umfrage erstellen'),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|