diff --git a/lib/constants.dart b/lib/constants.dart index 9a66f46a7..9fc1cb64f 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -4,6 +4,8 @@ import 'package:flutter/material.dart'; const String kAppVersion = '0.1.47'; const String kSiteUrl = 'https://invoiceninja.com'; const String kAppUrl = 'https://app.invoiceninja.com'; +const String kPrivacyPolicyURL = 'https://www.invoiceninja.com/privacy-policy'; +const String kTermsOfServiceURL = 'https://www.invoiceninja.com/terms'; const String kAppleStoreUrl = 'https://itunes.apple.com/us/app/invoice-ninja/id1435514417?ls=1&mt=8'; diff --git a/lib/ui/app/link_text.dart b/lib/ui/app/link_text.dart new file mode 100644 index 000000000..8dcf42639 --- /dev/null +++ b/lib/ui/app/link_text.dart @@ -0,0 +1,14 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class LinkTextSpan extends TextSpan { + LinkTextSpan({TextStyle style, String url, String text}) + : super( + style: style, + text: text ?? url, + recognizer: TapGestureRecognizer() + ..onTap = () { + launch(url, forceSafariVC: false); + }); +} diff --git a/lib/ui/auth/login_view.dart b/lib/ui/auth/login_view.dart index fd8394961..77180655f 100644 --- a/lib/ui/auth/login_view.dart +++ b/lib/ui/auth/login_view.dart @@ -3,6 +3,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/redux/ui/ui_state.dart'; import 'package:invoiceninja_flutter/ui/app/buttons/elevated_button.dart'; +import 'package:invoiceninja_flutter/ui/app/link_text.dart'; import 'package:invoiceninja_flutter/ui/app/progress_button.dart'; import 'package:invoiceninja_flutter/ui/auth/login_vm.dart'; import 'package:invoiceninja_flutter/utils/formatting.dart'; @@ -39,6 +40,7 @@ class _LoginState extends State { bool _createAccount = false; bool _isSelfHosted = false; bool _autoValidate = false; + bool _termsChecked = false; @override void didChangeDependencies() { @@ -92,6 +94,11 @@ class _LoginState extends State { final isOneTimePassword = error.contains(OTP_ERROR) || _oneTimePasswordController.text.isNotEmpty; + final ThemeData themeData = Theme.of(context); + final TextStyle aboutTextStyle = themeData.textTheme.body2; + final TextStyle linkStyle = + themeData.textTheme.body2.copyWith(color: themeData.accentColor); + if (!viewModel.authState.isInitialized) { return Container(); } @@ -193,6 +200,38 @@ class _LoginState extends State { labelText: localization.secret), obscureText: true, ), + if (_createAccount) + Padding( + padding: EdgeInsets.only(top: 20, bottom: 8), + child: CheckboxListTile( + onChanged: (value) => + setState(() => _termsChecked = value), + controlAffinity: + ListTileControlAffinity.leading, + activeColor: Theme.of(context).accentColor, + value: _termsChecked, + title: RichText( + text: TextSpan( + children: [ + TextSpan( + style: aboutTextStyle, + text: localization.iAgreeToThe + ' ', + ), + LinkTextSpan( + style: linkStyle, + url: kTermsOfServiceURL, + text: localization.termsOfServiceLink, + ), + LinkTextSpan( + style: linkStyle, + url: kPrivacyPolicyURL, + text: localization.privacyPolicyLink, + ), + ], + ), + ), + ), + ), ], ), if (viewModel.authState.error != null && @@ -270,8 +309,7 @@ class _LoginState extends State { child: Text(localization.hostedLogin)) : FlatButton( key: ValueKey(localization.selfhostLogin), - onPressed: () => - setState(() { + onPressed: () => setState(() { _isSelfHosted = true; _createAccount = false; }), diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index 875ca0b17..e6261d2cf 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -14,6 +14,13 @@ abstract class LocaleCodeAware { mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { + 'please_agree_to_terms': + 'Please agree to the terms of service to create an account.', + 'please_agree_to_privacy': + 'Please agree to the privacy policy to create an account.', + 'i_agree_to_the': 'I agree to the', + 'terms_of_service_link': 'terms of service', + 'privacy_policy_link': 'privacy policy', 'sign_up': 'Sign Up', 'account_login': 'Account Login', 'view_website': 'View Website', @@ -13818,6 +13825,20 @@ mixin LocalizationsProvider on LocaleCodeAware { String get signUp => _localizedValues[localeCode]['sign_up']; + String get pleaseAgreeToTerms => + _localizedValues[localeCode]['please_agree_to_terms']; + + String get pleaseAgreeToPrivacy => + _localizedValues[localeCode]['please_agree_to_privacy']; + + String get iAgreeToThe => _localizedValues[localeCode]['i_agree_to_the']; + + String get termsOfServiceLink => + _localizedValues[localeCode]['terms_of_service_link']; + + String get privacyPolicyLink => + _localizedValues[localeCode]['privacy_policy_link']; + String lookup(String key) { final lookupKey = toSnakeCase(key); return _localizedValues[localeCode][lookupKey] ??