diff --git a/lib/data/models/settings_model.dart b/lib/data/models/settings_model.dart index 3bdbfa39d..bf4e00d4f 100644 --- a/lib/data/models/settings_model.dart +++ b/lib/data/models/settings_model.dart @@ -95,7 +95,7 @@ abstract class SettingsEntity static const EMAIL_SENDING_METHOD_DEFAULT = 'default'; static const EMAIL_SENDING_METHOD_GMAIL = 'gmail'; - static const EMAIL_SENDING_METHOD_MICROSOFT = 'microsoft'; + static const EMAIL_SENDING_METHOD_MICROSOFT = 'office365'; static const LOCK_INVOICES_OFF = 'off'; static const LOCK_INVOICES_SENT = 'when_sent'; diff --git a/lib/data/models/user_model.dart b/lib/data/models/user_model.dart index 9add4a439..a9c9e074c 100644 --- a/lib/data/models/user_model.dart +++ b/lib/data/models/user_model.dart @@ -311,14 +311,16 @@ abstract class UserEntity extends Object @override FormatNumberType get listDisplayAmountType => null; + bool get isConnectedToOAuth => isConnectedToGoogle || isConnectedToMicrosoft; + bool get isConnectedToGoogle => oauthProvider == UserEntity.OAUTH_PROVIDER_GOOGLE; bool get isConnectedToMicrosoft => oauthProvider == UserEntity.OAUTH_PROVIDER_MICROSOFT; - bool get isConnectedToGmail => - isConnectedToGoogle && oauthUserToken.isNotEmpty; + bool get isConnectedToEmail => + isConnectedToOAuth && oauthUserToken.isNotEmpty; bool get isEmailVerified => emailVerifiedAt != null; diff --git a/lib/redux/user/user_selectors.dart b/lib/redux/user/user_selectors.dart index 6fa9b43e8..e191bd58a 100644 --- a/lib/redux/user/user_selectors.dart +++ b/lib/redux/user/user_selectors.dart @@ -95,7 +95,7 @@ List gmailUserList(BuiltMap userMap) { return userList(userMap).where((userId) { final user = (userMap[userId] ?? UserEntity) as UserEntity; - return user.isActive && user.isConnectedToGmail; + return user.isActive && user.isConnectedToEmail; }).toList(); } diff --git a/lib/ui/settings/user_details.dart b/lib/ui/settings/user_details.dart index 19e47a22a..a6b34eb01 100644 --- a/lib/ui/settings/user_details.dart +++ b/lib/ui/settings/user_details.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:built_collection/built_collection.dart'; import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_styled_toast/flutter_styled_toast.dart'; +import 'package:invoiceninja_flutter/utils/platforms.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -35,7 +36,6 @@ import 'package:invoiceninja_flutter/ui/settings/user_details_vm.dart'; import 'package:invoiceninja_flutter/utils/completers.dart'; import 'package:invoiceninja_flutter/utils/dialogs.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; -import 'package:invoiceninja_flutter/utils/platforms.dart'; class UserDetails extends StatefulWidget { const UserDetails({ @@ -140,6 +140,106 @@ class _UserDetailsState extends State final user = viewModel.user; final state = viewModel.state; + final googleButton = Expanded( + child: OutlinedButton( + child: Text((state.user.isConnectedToGoogle + ? localization.disconnectGoogle + : localization.connectGoogle) + .toUpperCase()), + onPressed: state.user.isConnectedToEmail + ? null + : () { + if (state.settingsUIState.isChanged) { + showMessageDialog( + context: context, + message: localization.errorUnsavedChanges); + return; + } + + if (state.user.isConnectedToGoogle) { + viewModel.onDisconnectGooglePressed(context); + } else { + viewModel.onConnectGooglePressed(context); + } + }, + ), + ); + + final gmailButton = Expanded( + child: OutlinedButton( + child: Text((user.isConnectedToEmail + ? localization.disconnectGmail + : localization.connectGmail) + .toUpperCase()), + onPressed: !state.user.isConnectedToGoogle + ? null + : () async { + if (state.settingsUIState.isChanged) { + showMessageDialog( + context: context, + message: localization.errorUnsavedChanges); + return; + } + + if (state.user.isConnectedToEmail) { + viewModel.onDisconnectGmailPressed(context); + } else { + launch('$kAppProductionUrl/auth/google'); + } + }, + ), + ); + + final microsoftButton = Expanded( + child: OutlinedButton( + child: Text((state.user.isConnectedToMicrosoft + ? localization.disconnectMicrosoft + : localization.connectMicrosoft) + .toUpperCase()), + onPressed: state.user.isConnectedToEmail + ? null + : () { + if (state.settingsUIState.isChanged) { + showMessageDialog( + context: context, + message: localization.errorUnsavedChanges); + return; + } + + if (state.user.isConnectedToMicrosoft) { + viewModel.onDisconnectMicrosoftPressed(context); + } else { + viewModel.onConnectMicrosoftPressed(context); + } + }, + ), + ); + + final office365Button = Expanded( + child: OutlinedButton( + child: Text((user.isConnectedToEmail + ? localization.disconnectEmail + : localization.connectEmail) + .toUpperCase()), + onPressed: !state.user.isConnectedToMicrosoft + ? null + : () async { + if (state.settingsUIState.isChanged) { + showMessageDialog( + context: context, + message: localization.errorUnsavedChanges); + return; + } + + if (state.user.isConnectedToEmail) { + viewModel.onDisconnectMicrosoftEmailPressed(context); + } else { + launch('$kAppProductionUrl/auth/microsoft'); + } + }, + ), + ); + return EditScaffold( title: localization.userDetails, onSavePressed: (context) { @@ -222,85 +322,22 @@ class _UserDetailsState extends State child: Row( children: [ if (state.isHosted && !isApple() && !isDesktopOS()) ...[ - Expanded( - child: OutlinedButton( - child: Text((state.user.isConnectedToGoogle - ? localization.disconnectGoogle - : localization.connectGoogle) - .toUpperCase()), - onPressed: state.user.isConnectedToGmail || - state.user.isConnectedToMicrosoft - ? null - : () { - if (state.settingsUIState.isChanged) { - showMessageDialog( - context: context, - message: - localization.errorUnsavedChanges); - return; - } - - if (state.user.isConnectedToGoogle) { - viewModel - .onDisconnectGooglePressed(context); - } else { - viewModel.onConnectGooglePressed(context); - } - }, - ), - ), - SizedBox(width: kTableColumnGap), - if (kIsWeb && !state.user.isConnectedToGoogle) - Expanded( - child: OutlinedButton( - child: Text((state.user.isConnectedToMicrosoft - ? localization.disconnectMicrosoft - : localization.connectMicrosoft) - .toUpperCase()), - onPressed: () async { - if (state.settingsUIState.isChanged) { - showMessageDialog( - context: context, - message: localization.errorUnsavedChanges); - return; - } - - if (state.user.isConnectedToMicrosoft) { - viewModel.onDisconnectMicrosoftPressed(context); - } else { - viewModel.onConnectMicrosoftPressed(context); - } - }, - ), - ) - else - Expanded( - child: OutlinedButton( - child: Text((user.isConnectedToGmail - ? localization.disconnectGmail - : localization.connectGmail) - .toUpperCase()), - onPressed: !state.user.isConnectedToGoogle - ? null - : () async { - if (state.settingsUIState.isChanged) { - showMessageDialog( - context: context, - message: - localization.errorUnsavedChanges); - return; - } - - if (state.user.isConnectedToGmail) { - viewModel - .onDisconnectGmailPressed(context); - } else { - launch('$kAppProductionUrl/auth/google'); - } - }, - ), - ), - SizedBox(width: kTableColumnGap), + if (user.isConnectedToGoogle) ...[ + googleButton, + SizedBox(width: kTableColumnGap), + gmailButton, + SizedBox(width: kTableColumnGap), + ] else if (user.isConnectedToMicrosoft) ...[ + microsoftButton, + SizedBox(width: kTableColumnGap), + office365Button, + SizedBox(width: kTableColumnGap), + ] else ...[ + googleButton, + SizedBox(width: kTableColumnGap), + microsoftButton, + SizedBox(width: kTableColumnGap), + ] ], Expanded( child: OutlinedButton( diff --git a/lib/ui/settings/user_details_vm.dart b/lib/ui/settings/user_details_vm.dart index 424a9b7a7..281761df4 100644 --- a/lib/ui/settings/user_details_vm.dart +++ b/lib/ui/settings/user_details_vm.dart @@ -56,6 +56,7 @@ class UserDetailsVM { @required this.onDisableTwoFactorPressed, @required this.onConnectMicrosoftPressed, @required this.onDisconnectMicrosoftPressed, + @required this.onDisconnectMicrosoftEmailPressed, }); static UserDetailsVM fromStore(Store store) { @@ -98,6 +99,26 @@ class UserDetailsVM { } */ }, + onDisconnectMicrosoftEmailPressed: (context) { + confirmCallback( + context: context, + callback: (_) { + passwordCallback( + context: context, + callback: (password, idToken) { + final completer = snackBarCompleter( + context, AppLocalization.of(context).disconnectedEmail); + store.dispatch( + SaveAuthUserRequest( + user: state.user.rebuild((b) => b..oauthUserToken = ''), + password: password, + idToken: idToken, + completer: completer, + ), + ); + }); + }); + }, onDisconnectGmailPressed: (context) { confirmCallback( context: context, @@ -322,6 +343,7 @@ class UserDetailsVM { final Function(BuildContext) onDisconnectGooglePressed; final Function(BuildContext) onConnectMicrosoftPressed; final Function(BuildContext) onDisconnectMicrosoftPressed; + final Function(BuildContext) onDisconnectMicrosoftEmailPressed; final Function(BuildContext, Completer, String) onConnectGmailPressed; final Function(BuildContext) onDisconnectGmailPressed; final Function(BuildContext) onDisableTwoFactorPressed; diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index f4557400c..15046b434 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -16,7 +16,10 @@ mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { // STARTER: lang key - do not remove comment - 'use_web_app_to_connect_microsoft': + 'disconnected_email': 'Successfully connected email', + 'connect_email': 'Connect Email', + 'disconnect_email': 'Disconnect Email', + 'use_web_app_to_connect_microsoft': 'Please use the web app to connect to Microsoft', 'email_provider': 'Email Provider', 'connect_microsoft': 'Connect Microsoft', @@ -70740,6 +70743,19 @@ mixin LocalizationsProvider on LocaleCodeAware { _localizedValues[localeCode]['use_web_app_to_connect_microsoft'] ?? _localizedValues['en']['use_web_app_to_connect_microsoft']; + String get connectEmail => + _localizedValues[localeCode]['connect_email'] ?? + _localizedValues['en']['connect_email']; + + String get disconnectEmail => + _localizedValues[localeCode]['disconnect_email'] ?? + _localizedValues['en']['disconnect_email']; + + String get disconnectedEmail => + _localizedValues[localeCode]['disconnected_email'] ?? + _localizedValues['en']['disconnected_email']; + + // STARTER: lang field - do not remove comment String lookup(String key) {