import 'package:cached_network_image/cached_network_image.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:flutter/material.dart'; import 'package:html/parser.dart'; /// User interface utilities /// /// @author Pierre HUBERT /// Build centered progress bar Widget buildCenteredProgressBar() { return Center( child: CircularProgressIndicator(), ); } /// Build and return a full loading page Widget buildLoadingPage({ bool showAppBar = false, String routeTitle, }) { return Scaffold( appBar: showAppBar ? AppBar( title: routeTitle == null ? null : Text(routeTitle), ) : null, body: buildCenteredProgressBar(), ); } /// Build and return an error card Widget buildErrorCard(String message, {List actions}) { return Card( elevation: 2.0, color: Colors.red, child: Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Padding( padding: const EdgeInsets.only(right: 8.0), child: Icon( Icons.error, color: Colors.white, ), ), Flexible( child: Text( message, style: TextStyle(color: Colors.white), maxLines: null, ), ), Row( children: actions == null ? [] : actions, ) ], ), ), ); } /// Show an image with a given [url] in full screen void showImageFullScreen(BuildContext context, String url) { Navigator.of(context).push(MaterialPageRoute(builder: (c) { // TODO : add better support later return CachedNetworkImage( imageUrl: url, ); })); } /// Show simple snack void showSimpleSnack(BuildContext context, String message) { Scaffold.of(context).showSnackBar(SnackBar(content: Text(message))); } /// Show an alert dialog to ask the user to enter a string /// /// Returns entered string if the dialog is confirmed, null else Future askUserString({ @required BuildContext context, @required String title, @required String message, @required String defaultValue, @required String hint, }) async { assert(context != null); assert(title != null); assert(message != null); assert(defaultValue != null); assert(hint != null); TextEditingController controller = TextEditingController(text: defaultValue); final confirm = await showDialog( context: context, builder: (c) => AlertDialog( title: Text(title), content: Column( children: [ Text(message), TextField( controller: controller, maxLines: null, maxLength: 200, keyboardType: TextInputType.text, decoration: InputDecoration( labelText: hint, alignLabelWithHint: true, ), ) ], ), actions: [ FlatButton( child: Text(tr("Cancel").toUpperCase()), onPressed: () => Navigator.pop(c, false), ), FlatButton( child: Text(tr("OK")), onPressed: () => Navigator.pop(c, true), ), ], )); if (confirm == null || !confirm) return null; return controller.text; } /// Show an alert dialog to get user confirmation for something /// /// Return value of this function is never null Future showConfirmDialog({ @required BuildContext context, String title, @required String message, }) async { if (title == null) title = tr("Confirm operation"); final result = await showDialog( context: context, builder: (c) => AlertDialog( title: Text(title), content: Text(message), actions: [ FlatButton( onPressed: () => Navigator.pop(context, false), child: Text(tr("Cancel").toUpperCase()), ), FlatButton( onPressed: () => Navigator.pop(context, true), child: Text( tr("Confirm").toUpperCase(), style: TextStyle(color: Colors.red), ), ), ], )); return result != null && result; } /// Smart [InputCounterWidgetBuilder] that show text limit only when some /// text has already been entered by the user Widget smartInputCounterWidgetBuilder( BuildContext context, { @required int currentLength, @required int maxLength, @required bool isFocused, }) => currentLength > 0 ? Text("$currentLength/$maxLength") : Container(); /// Parse an HTML String to decode special characters String htmlDecodeCharacters(String input) { if (input == null || input == "") return ""; return parse(input).documentElement.text; }