diff --git a/lib/helpers/posts_helper.dart b/lib/helpers/posts_helper.dart index 5afd541..eb54a85 100644 --- a/lib/helpers/posts_helper.dart +++ b/lib/helpers/posts_helper.dart @@ -146,6 +146,10 @@ class PostsHelper { request.addFile("image", post.image); break; + case PostKind.WEB_LINK: + request.addString("url", post.url); + break; + case PostKind.PDF: request.addBytesFile( "pdf", diff --git a/lib/models/new_post.dart b/lib/models/new_post.dart index c58de2e..3657a77 100644 --- a/lib/models/new_post.dart +++ b/lib/models/new_post.dart @@ -26,6 +26,7 @@ class NewPost { final PostVisibilityLevel visibility; final String content; final File image; + final String url; final List pdf; final PostKind kind; final DateTime timeEnd; @@ -38,6 +39,7 @@ class NewPost { @required this.content, @required this.kind, @required this.image, + @required this.url, @required this.pdf, @required this.timeEnd, @required this.survey, @@ -47,6 +49,7 @@ class NewPost { assert(content != null), assert(kind != PostKind.TEXT || content.length > 3), assert(kind != PostKind.IMAGE || image != null), + assert(kind != PostKind.WEB_LINK || url != null), assert(kind != PostKind.PDF || pdf != null), assert(kind != PostKind.COUNTDOWN || timeEnd != null), assert(kind != PostKind.SURVEY || survey != null); diff --git a/lib/ui/dialogs/url_dialog.dart b/lib/ui/dialogs/url_dialog.dart new file mode 100644 index 0000000..9059f0d --- /dev/null +++ b/lib/ui/dialogs/url_dialog.dart @@ -0,0 +1,86 @@ +import 'package:comunic/utils/input_utils.dart'; +import 'package:comunic/utils/intl_utils.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// Ask the user to enter an URL +/// +/// @author Pierre Hubert + +/// Ask the user to enter an URL +Future showInputURLDialog({ + @required BuildContext context, + @required String title, + String initialURL, +}) async { + return await showDialog( + context: context, + builder: (c) => _InputURLDialog( + title: title, + initialURL: initialURL, + ), + ); +} + +class _InputURLDialog extends StatefulWidget { + final String title; + final String initialURL; + + const _InputURLDialog({ + Key key, + @required this.title, + @required this.initialURL, + }) : assert(title != null), + super(key: key); + + @override + __InputURLDialogState createState() => __InputURLDialogState(); +} + +class __InputURLDialogState extends State<_InputURLDialog> { + TextEditingController _controller; + + bool get _isValid => + _controller.text.isNotEmpty && validateUrl(_controller.text); + + @override + void initState() { + super.initState(); + _controller = new TextEditingController(text: widget.initialURL); + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text(widget.title), + content: TextField( + controller: _controller, + onChanged: (s) => setState(() {}), + decoration: InputDecoration( + icon: Icon(Icons.link), + alignLabelWithHint: true, + labelText: "http://...", + errorText: _controller.text.isNotEmpty && !_isValid + ? tr("Invalid URL!") + : null, + ), + ), + actions: [ + // Cancel + MaterialButton( + child: Text(tr("Cancel").toUpperCase()), + onPressed: () => Navigator.of(context).pop(), + textColor: Colors.red, + ), + + // Confirm + MaterialButton( + child: Text(tr("Confirm").toUpperCase()), + onPressed: _isValid + ? () => Navigator.of(context).pop(_controller.text) + : null, + ), + ], + ); + } +} diff --git a/lib/ui/widgets/post_create_form_widget.dart b/lib/ui/widgets/post_create_form_widget.dart index 17d88c1..fbaca35 100644 --- a/lib/ui/widgets/post_create_form_widget.dart +++ b/lib/ui/widgets/post_create_form_widget.dart @@ -6,6 +6,7 @@ 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/ui/dialogs/url_dialog.dart'; import 'package:comunic/utils/files_utils.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/post_utils.dart'; @@ -49,12 +50,15 @@ class _PostCreateFormWidgetState extends State { final TextEditingController _postTextController = TextEditingController(); PostVisibilityLevel _postVisibilityLevel; File _postImage; + String _postURL; List _postPDF; DateTime _timeEnd; NewSurvey _postSurvey; bool get hasImage => _postImage != null; + bool get hasURL => _postURL != null; + bool get hasPDF => _postPDF != null; bool get hasTimeEnd => _timeEnd != null; @@ -70,6 +74,8 @@ class _PostCreateFormWidgetState extends State { return PostKind.IMAGE; else if (hasPDF) return PostKind.PDF; + else if (hasURL) + return PostKind.WEB_LINK; else if (hasTimeEnd) return PostKind.COUNTDOWN; else if (hasSurvey) @@ -125,6 +131,13 @@ class _PostCreateFormWidgetState extends State { onTap: _pickImageForPost, ), + // Web link + _PostOptionWidget( + icon: Icons.link, + selected: postKind == PostKind.WEB_LINK, + onTap: _pickURLForPost, + ), + // Include PDF button _PostOptionWidget( icon: Icons.picture_as_pdf, @@ -150,6 +163,8 @@ class _PostCreateFormWidgetState extends State { ), ), + Container(width: 20), + // Post visibility level _PostOptionWidget( icon: PostVisibilityLevelsMapIcons[_postVisibilityLevel], @@ -203,6 +218,7 @@ class _PostCreateFormWidgetState extends State { void _resetPostSelection() { setState(() { _postImage = null; + _postURL = null; _postPDF = null; _timeEnd = null; _postSurvey = null; @@ -222,6 +238,23 @@ class _PostCreateFormWidgetState extends State { }); } + /// Choose a new URL for the post + Future _pickURLForPost() async { + final url = await showInputURLDialog( + context: context, + title: tr("Specify URL"), + initialURL: _postURL, + ); + + if (url == null) return; + + _resetPostSelection(); + + setState(() { + _postURL = url; + }); + } + /// Pick a PDF for the new post Future _pickPDFForPost() async { try { @@ -304,6 +337,7 @@ class _PostCreateFormWidgetState extends State { content: _postTextController.text, kind: postKind, image: _postImage, + url: _postURL, pdf: _postPDF, timeEnd: _timeEnd, survey: _postSurvey));