From 6aaab942b91267fac60737f6869d61191d40edea Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Jun 2018 14:16:36 -0700 Subject: [PATCH] Clients --- lib/ui/client/view/client_details.dart | 66 +++++++++++++++++++------- lib/utils/formatting.dart | 19 ++++++-- lib/utils/localization.dart | 2 + lib/utils/platforms.dart | 6 +++ 4 files changed, 73 insertions(+), 20 deletions(-) create mode 100644 lib/utils/platforms.dart diff --git a/lib/ui/client/view/client_details.dart b/lib/ui/client/view/client_details.dart index 0a2747a13..f8140c646 100644 --- a/lib/ui/client/view/client_details.dart +++ b/lib/ui/client/view/client_details.dart @@ -1,9 +1,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:invoiceninja/data/models/models.dart'; import 'package:invoiceninja/utils/formatting.dart'; import 'package:invoiceninja/utils/localization.dart'; +import 'package:invoiceninja/utils/platforms.dart'; import 'package:url_launcher/url_launcher.dart'; class ClientDetails extends StatefulWidget { @@ -16,10 +18,9 @@ class ClientDetails extends StatefulWidget { } class _ClientDetailsState extends State { - Future _launched; - Future _launchInBrowser(String url) async { + Future _launchURL(String url) async { if (await canLaunch(url)) { await launch(url, forceSafariVC: false, forceWebView: false); } else { @@ -43,6 +44,9 @@ class _ClientDetailsState extends State { _buildDetailsList() { var listTiles = []; + listTiles + .add(FutureBuilder(future: _launched, builder: _launchStatus)); + var contacts = client.contacts; contacts.forEach((contact) { if (contact.email.isNotEmpty) { @@ -50,6 +54,9 @@ class _ClientDetailsState extends State { icon: Icons.email, title: contact.fullName() + '\n' + contact.email, subtitle: localization.email, + onTap: () => setState(() { + _launched = _launchURL('mailto:' + contact.email); + }), )); } @@ -58,6 +65,11 @@ class _ClientDetailsState extends State { icon: Icons.phone, title: contact.fullName() + '\n' + contact.phone, subtitle: localization.phone, + onTap: () => setState(() { + _launched = + _launchURL('sms:' + cleanPhoneNumber(contact.phone)); + //_launched = _launchURL('tel:' + cleanPhoneNumber(contact.phone)); + }), )); } }); @@ -68,11 +80,9 @@ class _ClientDetailsState extends State { title: client.website, subtitle: localization.website, onTap: () => setState(() { - _launched = _launchInBrowser(client.website); - }), + _launched = _launchURL(formatURL(client.website)); + }), )); - - listTiles.add(FutureBuilder(future: _launched, builder: _launchStatus)); } if (client.workPhone.isNotEmpty) { @@ -80,6 +90,11 @@ class _ClientDetailsState extends State { icon: Icons.phone, title: client.workPhone, subtitle: localization.phone, + onTap: () => setState(() { + _launched = + _launchURL('sms:' + cleanPhoneNumber(client.workPhone)); + //_launched = _launchURL('tel:' + cleanPhoneNumber(client.workPhone)); + }), )); } @@ -90,6 +105,11 @@ class _ClientDetailsState extends State { icon: Icons.location_city, title: client.vatNumber, subtitle: localization.vatNumber, + onTap: () { + Clipboard.setData(ClipboardData(text: client.vatNumber)); + Scaffold.of(context).showSnackBar( + SnackBar(content: Text(localization.copiedToClipboard))); + }, )); } @@ -98,26 +118,39 @@ class _ClientDetailsState extends State { icon: Icons.business, title: client.idNumber, subtitle: localization.idNumber, + onTap: () { + Clipboard.setData(ClipboardData(text: client.idNumber)); + Scaffold.of(context).showSnackBar( + SnackBar(content: Text(localization.copiedToClipboard))); + }, )); } - var billingAddress = formatAddress(client); - var shippingAddress = formatAddress(client, true); + var billingAddress = formatAddress(object: client); + var shippingAddress = formatAddress(object: client, isShipping: true); if (billingAddress.isNotEmpty) { listTiles.add(AppListTile( - icon: Icons.pin_drop, - title: billingAddress, - subtitle: localization.billingAddress, - )); + icon: Icons.pin_drop, + title: billingAddress, + subtitle: localization.billingAddress, + onTap: () { + _launched = _launchURL(getMapURL(context) + + Uri.encodeFull( + formatAddress(object: client, delimiter: ','))); + })); } if (shippingAddress.isNotEmpty) { listTiles.add(AppListTile( - icon: Icons.pin_drop, - title: shippingAddress, - subtitle: localization.shippingAddress, - )); + icon: Icons.pin_drop, + title: shippingAddress, + subtitle: localization.shippingAddress, + onTap: () { + _launched = _launchURL(getMapURL(context) + + Uri.encodeFull(formatAddress( + object: client, delimiter: ',', isShipping: true))); + })); } return listTiles; @@ -132,7 +165,6 @@ class _ClientDetailsState extends State { } } - class AppListTile extends StatelessWidget { AppListTile({ this.icon, diff --git a/lib/utils/formatting.dart b/lib/utils/formatting.dart index b282c92df..9f2748c3e 100644 --- a/lib/utils/formatting.dart +++ b/lib/utils/formatting.dart @@ -1,4 +1,17 @@ -String formatAddress(dynamic object, [bool isShipping = false]) { +String cleanPhoneNumber(String phoneNumber) { + return phoneNumber.replaceAll(RegExp(r'\D'), ''); +} + +String formatURL(String url) { + if (url.startsWith('http')) { + return url; + } + + return 'http://' + url; +} + + +String formatAddress({dynamic object, bool isShipping = false, String delimiter = '\n'}) { var str = ''; String address1 = isShipping ? object.shippingAddress1 : object.address1; @@ -8,10 +21,10 @@ String formatAddress(dynamic object, [bool isShipping = false]) { String postalCode = isShipping ? object.postalCode : object.postalCode; if (address1.isNotEmpty) { - str += address1 + '\n'; + str += address1 + delimiter; } if (address2.isNotEmpty) { - str += address2 + '\n'; + str += address2 + delimiter; } if (city.isNotEmpty || state.isNotEmpty || postalCode.isNotEmpty) { diff --git a/lib/utils/localization.dart b/lib/utils/localization.dart index 04a60c3f1..b1d064e06 100644 --- a/lib/utils/localization.dart +++ b/lib/utils/localization.dart @@ -55,6 +55,7 @@ class AppLocalization { 'vat_number': 'VAT Number', 'id_number': 'Id Number', 'create': 'Create', + 'copied_to_clipboard': 'Copied to clipboard', 'product': 'Product', 'products': 'Products', @@ -126,6 +127,7 @@ class AppLocalization { String get vatNumber => _localizedValues[locale.languageCode]['vat_number']; String get idNumber => _localizedValues[locale.languageCode]['id_number']; String get create => _localizedValues[locale.languageCode]['create']; + String get copiedToClipboard => _localizedValues[locale.languageCode]['copied_to_clipboard']; String get product => _localizedValues[locale.languageCode]['product']; String get products => _localizedValues[locale.languageCode]['products']; diff --git a/lib/utils/platforms.dart b/lib/utils/platforms.dart new file mode 100644 index 000000000..69db74cfc --- /dev/null +++ b/lib/utils/platforms.dart @@ -0,0 +1,6 @@ +import 'package:flutter/material.dart'; + +String getMapURL(BuildContext context) { + bool iOS = Theme.of(context).platform == TargetPlatform.iOS; + return iOS ? 'http://maps.apple.com/?address=' : 'https://maps.google.com/?q='; +} \ No newline at end of file