From 7d2e4ef86d90f56d49d954df8c4201f47c583eae Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Sun, 10 Jul 2022 12:30:24 +0300 Subject: [PATCH] Sign in with Apple --- lib/ui/app/forms/app_toggle_buttons.dart | 48 +++++------ lib/ui/auth/login_view.dart | 82 ++++++++----------- lib/ui/auth/login_vm.dart | 60 ++++++++++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.foss.yaml | 1 + pubspec.lock | 21 +++++ pubspec.next.yaml | 1 + pubspec.yaml | 1 + 8 files changed, 143 insertions(+), 73 deletions(-) diff --git a/lib/ui/app/forms/app_toggle_buttons.dart b/lib/ui/app/forms/app_toggle_buttons.dart index ee3e0a104..a318236c0 100644 --- a/lib/ui/app/forms/app_toggle_buttons.dart +++ b/lib/ui/app/forms/app_toggle_buttons.dart @@ -25,28 +25,15 @@ class AppToggleButtons extends StatelessWidget { toggleWidth -= 46 / tabLabels.length; } - return Padding( - padding: const EdgeInsets.only(bottom: 20), - child: ToggleButtons( - children: [ - Container( - width: toggleWidth, - height: 40, - child: Center(child: Text(tabLabels[0])), - ), - Container( - width: toggleWidth, - height: 40, - child: Center(child: Text(tabLabels[1])), - ), - if (tabLabels.length == 3) - Container( - width: toggleWidth, - height: 40, - child: Center(child: Text(tabLabels[2])), - ), - ], - isSelected: tabLabels.length == 3 + final isSelected = tabLabels.length == 4 + ? (selectedIndex == 0 + ? [true, false, false, false] + : selectedIndex == 1 + ? [false, true, false, false] + : selectedIndex == 2 + ? [false, false, true, false] + : [false, false, false, true]) + : tabLabels.length == 3 ? (selectedIndex == 0 ? [true, false, false] : selectedIndex == 1 @@ -54,7 +41,22 @@ class AppToggleButtons extends StatelessWidget { : [false, false, true]) : selectedIndex == 0 ? [true, false] - : [false, true], + : [false, true]; + + final children = tabLabels + .map((label) => Container( + width: toggleWidth, + height: 40, + child: Center( + child: Text(label[0].toUpperCase() + label.substring(1))), + )) + .toList(); + + return Padding( + padding: const EdgeInsets.only(bottom: 20), + child: ToggleButtons( + children: children, + isSelected: isSelected, onPressed: (index) => onTabChanged(index), ), ); diff --git a/lib/ui/auth/login_view.dart b/lib/ui/auth/login_view.dart index 22f5a77d8..ddfa0511e 100644 --- a/lib/ui/auth/login_view.dart +++ b/lib/ui/auth/login_view.dart @@ -65,14 +65,16 @@ class _LoginState extends State { static const String LOGIN_TYPE_EMAIL = 'email'; static const String LOGIN_TYPE_GOOGLE = 'google'; static const String LOGIN_TYPE_MICROSOFT = 'microsoft'; + static const String LOGIN_TYPE_APPLE = 'apple'; String _loginError = ''; - String _loginType = LOGIN_TYPE_GOOGLE; + String _loginType = LOGIN_TYPE_EMAIL; + + List _loginTypes; bool _tokenLogin = false; bool _isSelfHosted = false; bool _createAccount = false; - bool _hideGoogle = false; bool _recoverPassword = false; bool _autoValidate = false; @@ -91,13 +93,15 @@ class _LoginState extends State { } else if (WebUtils.getHtmlValue('signup') == 'true') { _createAccount = true; } - } else if (isApple() || !GoogleOAuth.isEnabled) { - _loginType = LOGIN_TYPE_EMAIL; - _hideGoogle = true; - } else if (isWindows() || isLinux()) { - _loginType = LOGIN_TYPE_EMAIL; - _hideGoogle = true; } + + _loginTypes = [ + LOGIN_TYPE_EMAIL, + if (!kReleaseMode || kIsWeb || isMobileOS()) LOGIN_TYPE_GOOGLE, + if (!kReleaseMode || kIsWeb) LOGIN_TYPE_MICROSOFT, + if (!kReleaseMode || kIsWeb || isMobileOS() || isMacOS()) + LOGIN_TYPE_APPLE, + ]; } @override @@ -213,6 +217,8 @@ class _LoginState extends State { ); } else if (_loginType == LOGIN_TYPE_MICROSOFT) { viewModel.onMicrosoftSignUpPressed(context, completer, url); + } else if (_loginType == LOGIN_TYPE_APPLE) { + viewModel.onAppleSignUpPressed(context, completer, url); } else { viewModel.onGoogleSignUpPressed(context, completer, url); } @@ -288,6 +294,11 @@ class _LoginState extends State { url: url, secret: _isSelfHosted ? _secretController.text : '', oneTimePassword: _oneTimePasswordController.text); + } else if (_loginType == LOGIN_TYPE_APPLE) { + viewModel.onAppleLoginPressed(context, completer, + url: url, + secret: _isSelfHosted ? _secretController.text : '', + oneTimePassword: _oneTimePasswordController.text); } else { viewModel.onGoogleLoginPressed(context, completer, url: url, @@ -401,49 +412,18 @@ class _LoginState extends State { }, ), ], - if (!_isSelfHosted && - (!kReleaseMode || !_hideGoogle)) ...[ + if (!_isSelfHosted && _loginTypes.length > 1) ...[ RuledText(localization.selectMethod), - if (kIsWeb) - AppToggleButtons( - tabLabels: [ - 'Google', - 'Microsoft', - localization.email, - ], - selectedIndex: _loginType == LOGIN_TYPE_EMAIL - ? 2 - : _loginType == LOGIN_TYPE_MICROSOFT - ? 1 - : 0, - onTabChanged: (index) { - setState(() { - _loginType = index == 2 - ? LOGIN_TYPE_EMAIL - : index == 1 - ? LOGIN_TYPE_MICROSOFT - : LOGIN_TYPE_GOOGLE; - _loginError = ''; - }); - }, - ) - else - AppToggleButtons( - tabLabels: [ - 'Google', - localization.email, - ], - selectedIndex: - _loginType == LOGIN_TYPE_EMAIL ? 1 : 0, - onTabChanged: (index) { - setState(() { - _loginType = index == 1 - ? LOGIN_TYPE_EMAIL - : LOGIN_TYPE_GOOGLE; - _loginError = ''; - }); - }, - ), + AppToggleButtons( + tabLabels: _loginTypes, + selectedIndex: _loginTypes.indexOf(_loginType), + onTabChanged: (index) { + setState(() { + _loginType = _loginTypes[index]; + _loginError = ''; + }); + }, + ) ], Padding( padding: EdgeInsets.symmetric( @@ -610,6 +590,8 @@ class _LoginState extends State { Icon(Icons.mail, color: Colors.white) else if (_loginType == LOGIN_TYPE_MICROSOFT) Icon(MdiIcons.microsoft, color: Colors.white) + else if (_loginType == LOGIN_TYPE_APPLE) + Icon(MdiIcons.apple, color: Colors.white) else ClipOval( child: Image.asset( diff --git a/lib/ui/auth/login_vm.dart b/lib/ui/auth/login_vm.dart index 5948fdca9..bccc50062 100644 --- a/lib/ui/auth/login_vm.dart +++ b/lib/ui/auth/login_vm.dart @@ -60,6 +60,8 @@ class LoginVM { @required this.onGoogleSignUpPressed, @required this.onMicrosoftLoginPressed, @required this.onMicrosoftSignUpPressed, + @required this.onAppleLoginPressed, + @required this.onAppleSignUpPressed, @required this.onTokenLoginPressed, }); @@ -110,6 +112,11 @@ class LoginVM { final Function(BuildContext, Completer completer, String url) onMicrosoftSignUpPressed; + final Function(BuildContext, Completer completer, + {String url, String secret, String oneTimePassword}) onAppleLoginPressed; + final Function(BuildContext, Completer completer, String url) + onAppleSignUpPressed; + static LoginVM fromStore(Store store) { void _handleLogin({BuildContext context, bool isSignUp = false}) { final layout = calculateLayout(context); @@ -266,6 +273,59 @@ class LoginVM { print('## onMicrosoftSignUpPressed: $error'); } }, + onAppleLoginPressed: ( + BuildContext context, + Completer completer, { + @required String url, + @required String secret, + @required String oneTimePassword, + }) async { + try { + /* + WebUtils.microsoftLogin((idToken, accessToken) { + store.dispatch(OAuthLoginRequest( + completer: completer, + idToken: idToken, + accessToken: accessToken, + url: _formatApiUrl(url), + secret: secret.trim(), + platform: getPlatform(context), + provider: UserEntity.OAUTH_PROVIDER_MICROSOFT, + oneTimePassword: oneTimePassword, + )); + completer.future.then((_) => _handleLogin(context: context)); + }, (dynamic error) { + completer.completeError(error); + }); + */ + } catch (error) { + completer.completeError(error); + print('## onAppleLoginPressed: $error'); + } + }, + onAppleSignUpPressed: + (BuildContext context, Completer completer, String url) async { + try { + /* + WebUtils.microsoftLogin((idToken, accessToken) { + store.dispatch(OAuthSignUpRequest( + url: url, + completer: completer, + idToken: idToken, + provider: UserEntity.OAUTH_PROVIDER_MICROSOFT, + accessToken: accessToken, + )); + completer.future + .then((_) => _handleLogin(context: context, isSignUp: true)); + }, (dynamic error) { + completer.completeError(error); + }); + */ + } catch (error) { + completer.completeError(error); + print('## onAppleSignUpPressed: $error'); + } + }, onSignUpPressed: ( BuildContext context, Completer completer, { diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 3700c79e6..123aa6c66 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -12,6 +12,7 @@ import path_provider_macos import printing import sentry_flutter import shared_preferences_macos +import sign_in_with_apple import sqflite import url_launcher_macos @@ -23,6 +24,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin")) SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.foss.yaml b/pubspec.foss.yaml index 035bd5133..336c4ca52 100644 --- a/pubspec.foss.yaml +++ b/pubspec.foss.yaml @@ -72,6 +72,7 @@ dependencies: printing: ^5.8.0 image_cropper: ^2.0.2 msal_js: ^2.14.0 + sign_in_with_apple: ^4.0.0 # bitsdojo_window: ^0.1.2 # quick_actions: ^0.2.1 # idb_shim: ^1.11.1+1 diff --git a/pubspec.lock b/pubspec.lock index 25edb3788..a484649e2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1092,6 +1092,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + sign_in_with_apple: + dependency: "direct main" + description: + name: sign_in_with_apple + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + sign_in_with_apple_platform_interface: + dependency: transitive + description: + name: sign_in_with_apple_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + sign_in_with_apple_web: + dependency: transitive + description: + name: sign_in_with_apple_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.next.yaml b/pubspec.next.yaml index 49221c769..5f537e8ed 100644 --- a/pubspec.next.yaml +++ b/pubspec.next.yaml @@ -71,6 +71,7 @@ dependencies: printing: ^5.8.0 image_cropper: ^2.0.2 msal_js: ^2.14.0 + sign_in_with_apple: ^4.0.0 # bitsdojo_window: ^0.1.2 # quick_actions: ^0.2.1 # idb_shim: ^1.11.1+1 diff --git a/pubspec.yaml b/pubspec.yaml index 0da8ddf67..0a780b8e3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -72,6 +72,7 @@ dependencies: printing: ^5.8.0 image_cropper: ^2.0.2 msal_js: ^2.14.0 + sign_in_with_apple: ^4.0.0 # bitsdojo_window: ^0.1.2 # quick_actions: ^0.2.1 # idb_shim: ^1.11.1+1