diff --git a/lib/helpers/posts_helper.dart b/lib/helpers/posts_helper.dart index 237735e..5afd541 100644 --- a/lib/helpers/posts_helper.dart +++ b/lib/helpers/posts_helper.dart @@ -158,6 +158,11 @@ class PostsHelper { "time-end", (post.timeEnd.millisecondsSinceEpoch / 1000).floor()); break; + case PostKind.SURVEY: + request.addString("question", post.survey.question); + request.addString("answers", post.survey.answers.join("<>")); + break; + default: throw Exception("Unsupported post type :" + post.kind.toString()); break; diff --git a/lib/models/new_post.dart b/lib/models/new_post.dart index d4f27fa..c58de2e 100644 --- a/lib/models/new_post.dart +++ b/lib/models/new_post.dart @@ -9,6 +9,17 @@ import 'package:meta/meta.dart'; /// /// @author Pierre HUBERT +class NewSurvey { + final String question; + final Set answers; + + const NewSurvey({ + @required this.question, + @required this.answers, + }) : assert(question != null), + assert(answers.length > 1); +} + class NewPost { final PostTarget target; final int targetID; @@ -18,6 +29,7 @@ class NewPost { final List pdf; final PostKind kind; final DateTime timeEnd; + final NewSurvey survey; const NewPost({ @required this.target, @@ -28,6 +40,7 @@ class NewPost { @required this.image, @required this.pdf, @required this.timeEnd, + @required this.survey, }) : assert(target != null), assert(targetID != null), assert(visibility != null), @@ -35,5 +48,6 @@ class NewPost { assert(kind != PostKind.TEXT || content.length > 3), assert(kind != PostKind.IMAGE || image != null), assert(kind != PostKind.PDF || pdf != null), - assert(kind != PostKind.COUNTDOWN || timeEnd != null); + assert(kind != PostKind.COUNTDOWN || timeEnd != null), + assert(kind != PostKind.SURVEY || survey != null); } diff --git a/lib/ui/dialogs/new_survey_dialog.dart b/lib/ui/dialogs/new_survey_dialog.dart new file mode 100644 index 0000000..9a84835 --- /dev/null +++ b/lib/ui/dialogs/new_survey_dialog.dart @@ -0,0 +1,137 @@ +import 'package:comunic/models/new_post.dart'; +import 'package:comunic/utils/intl_utils.dart'; +import 'package:flutter/material.dart'; + +/// Create a new survey dialog +/// +/// @author Pierre Hubert + +/// Show a dialog to prompt information about a new survey to create +Future showNewSurveyDialog( + {@required BuildContext context, NewSurvey initialSurvey}) async { + return await showDialog( + context: context, + builder: (c) => _SurveyDialog( + initialSurvey: initialSurvey, + )); +} + +class _SurveyDialog extends StatefulWidget { + final NewSurvey initialSurvey; + + const _SurveyDialog({Key key, this.initialSurvey}) : super(key: key); + + @override + __SurveyDialogState createState() => __SurveyDialogState(); +} + +class __SurveyDialogState extends State<_SurveyDialog> { + TextEditingController _questionController; + final _choiceController = TextEditingController(); + var _choices = Set(); + + bool get canConfirm => + _questionController.text.length > 2 && _choices.length > 1; + + NewSurvey get newSurvey => + NewSurvey(question: _questionController.text, answers: _choices); + + @override + void initState() { + super.initState(); + _questionController = TextEditingController( + text: widget.initialSurvey == null ? "" : widget.initialSurvey.question, + ); + if (widget.initialSurvey != null) _choices = widget.initialSurvey.answers; + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(tr("New survey")), + content: _buildBody(), + actions: [ + // Cancel + MaterialButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(tr("Cancel").toUpperCase()), + ), + + // Confirm + MaterialButton( + onPressed: + canConfirm ? () => Navigator.of(context).pop(newSurvey) : null, + child: Text(tr("Confirm").toUpperCase()), + ), + ], + ); + } + + Widget _buildBody() { + return ConstrainedBox( + constraints: + BoxConstraints(maxHeight: MediaQuery.of(context).size.height - 50), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // Survey question + TextField( + controller: _questionController, + onChanged: (s) => setState(() {}), + decoration: InputDecoration( + alignLabelWithHint: true, labelText: tr("Question")), + ), + + Container(height: 30), + Text(tr("Current choices:")), + _buildCurrentChoices(), + + Container( + height: 10, + ), + + // Add choice form + TextField( + controller: _choiceController, + onChanged: (s) => setState(() {}), + onSubmitted: (s) => _addChoice(), + decoration: InputDecoration( + hintText: tr("New choice..."), + suffixIcon: IconButton( + icon: Icon(Icons.add), + onPressed: () => _choiceController.text.length > 0 + ? _addChoice() + : null, + )), + ), + ]), + ), + ); + } + + Widget _buildCurrentChoices() { + if (_choices.length == 0) return Text(tr("No choice yet.")); + + return Column( + children: _choices + .map((f) => ListTile( + title: Text(f), + dense: true, + trailing: IconButton( + icon: Icon(Icons.delete), + iconSize: 15, + onPressed: () => setState(() => _choices.remove(f)), + ))) + .toList(), + ); + } + + void _addChoice() { + if (_choiceController.text.length == 0) return; + setState(() { + _choices.add(_choiceController.text); + _choiceController.text = ""; + }); + } +} diff --git a/lib/ui/widgets/post_create_form_widget.dart b/lib/ui/widgets/post_create_form_widget.dart index 0ab9f6a..17d88c1 100644 --- a/lib/ui/widgets/post_create_form_widget.dart +++ b/lib/ui/widgets/post_create_form_widget.dart @@ -5,6 +5,7 @@ import 'package:comunic/enums/post_target.dart'; import 'package:comunic/enums/post_visibility_level.dart'; import 'package:comunic/helpers/posts_helper.dart'; import 'package:comunic/models/new_post.dart'; +import 'package:comunic/ui/dialogs/new_survey_dialog.dart'; import 'package:comunic/utils/files_utils.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/post_utils.dart'; @@ -50,6 +51,7 @@ class _PostCreateFormWidgetState extends State { File _postImage; List _postPDF; DateTime _timeEnd; + NewSurvey _postSurvey; bool get hasImage => _postImage != null; @@ -57,6 +59,8 @@ class _PostCreateFormWidgetState extends State { bool get hasTimeEnd => _timeEnd != null; + bool get hasSurvey => _postSurvey != null; + bool get canSubmitForm => !_isCreating && _postTextController.text.length > 5 || postKind != PostKind.TEXT; @@ -68,6 +72,8 @@ class _PostCreateFormWidgetState extends State { return PostKind.PDF; else if (hasTimeEnd) return PostKind.COUNTDOWN; + else if (hasSurvey) + return PostKind.SURVEY; else return PostKind.TEXT; } @@ -132,6 +138,13 @@ class _PostCreateFormWidgetState extends State { selected: postKind == PostKind.COUNTDOWN, onTap: _pickCountdownTime, ), + + // Add survey + _PostOptionWidget( + icon: Icons.insert_chart, + selected: postKind == PostKind.SURVEY, + onTap: _pickSurvey, + ), ], ), ), @@ -192,6 +205,7 @@ class _PostCreateFormWidgetState extends State { _postImage = null; _postPDF = null; _timeEnd = null; + _postSurvey = null; }); } @@ -262,6 +276,19 @@ class _PostCreateFormWidgetState extends State { }); } + /// Pick a new survey for this post + Future _pickSurvey() async { + final newSurvey = + await showNewSurveyDialog(context: context, initialSurvey: _postSurvey); + + if (newSurvey == null) return; + + _resetPostSelection(); + setState(() { + _postSurvey = newSurvey; + }); + } + /// Submit new post Future _submitForm() async { if (!canSubmitForm) @@ -271,15 +298,15 @@ class _PostCreateFormWidgetState extends State { try { await _postHelper.createPost(NewPost( - target: widget.postTarget, - targetID: widget.targetID, - visibility: _postVisibilityLevel, - content: _postTextController.text, - kind: postKind, - image: _postImage, - pdf: _postPDF, - timeEnd: _timeEnd, - )); + target: widget.postTarget, + targetID: widget.targetID, + visibility: _postVisibilityLevel, + content: _postTextController.text, + kind: postKind, + image: _postImage, + pdf: _postPDF, + timeEnd: _timeEnd, + survey: _postSurvey)); setState(() => _isCreating = false); showSimpleSnack(context, tr("The post has been successfully created!"));