Sign in with Apple

This commit is contained in:
Hillel Coren 2022-07-10 12:30:24 +03:00
parent 047ee8f700
commit 7d2e4ef86d
8 changed files with 143 additions and 73 deletions

View File

@ -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),
),
);

View File

@ -65,14 +65,16 @@ class _LoginState extends State<LoginView> {
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<String> _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<LoginView> {
} 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<LoginView> {
);
} 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<LoginView> {
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<LoginView> {
},
),
],
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,
tabLabels: _loginTypes,
selectedIndex: _loginTypes.indexOf(_loginType),
onTabChanged: (index) {
setState(() {
_loginType = index == 2
? LOGIN_TYPE_EMAIL
: index == 1
? LOGIN_TYPE_MICROSOFT
: LOGIN_TYPE_GOOGLE;
_loginType = _loginTypes[index];
_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 = '';
});
},
),
],
Padding(
padding: EdgeInsets.symmetric(
@ -610,6 +590,8 @@ class _LoginState extends State<LoginView> {
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(

View File

@ -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<Null> completer, String url)
onMicrosoftSignUpPressed;
final Function(BuildContext, Completer<Null> completer,
{String url, String secret, String oneTimePassword}) onAppleLoginPressed;
final Function(BuildContext, Completer<Null> completer, String url)
onAppleSignUpPressed;
static LoginVM fromStore(Store<AppState> 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<Null> 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<Null> 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<Null> completer, {

View File

@ -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"))
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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