Sign in with Apple
This commit is contained in:
parent
047ee8f700
commit
7d2e4ef86d
|
|
@ -25,28 +25,15 @@ class AppToggleButtons extends StatelessWidget {
|
||||||
toggleWidth -= 46 / tabLabels.length;
|
toggleWidth -= 46 / tabLabels.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(
|
final isSelected = tabLabels.length == 4
|
||||||
padding: const EdgeInsets.only(bottom: 20),
|
? (selectedIndex == 0
|
||||||
child: ToggleButtons(
|
? [true, false, false, false]
|
||||||
children: [
|
: selectedIndex == 1
|
||||||
Container(
|
? [false, true, false, false]
|
||||||
width: toggleWidth,
|
: selectedIndex == 2
|
||||||
height: 40,
|
? [false, false, true, false]
|
||||||
child: Center(child: Text(tabLabels[0])),
|
: [false, false, false, true])
|
||||||
),
|
: tabLabels.length == 3
|
||||||
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
|
|
||||||
? (selectedIndex == 0
|
? (selectedIndex == 0
|
||||||
? [true, false, false]
|
? [true, false, false]
|
||||||
: selectedIndex == 1
|
: selectedIndex == 1
|
||||||
|
|
@ -54,7 +41,22 @@ class AppToggleButtons extends StatelessWidget {
|
||||||
: [false, false, true])
|
: [false, false, true])
|
||||||
: selectedIndex == 0
|
: selectedIndex == 0
|
||||||
? [true, false]
|
? [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),
|
onPressed: (index) => onTabChanged(index),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -65,14 +65,16 @@ class _LoginState extends State<LoginView> {
|
||||||
static const String LOGIN_TYPE_EMAIL = 'email';
|
static const String LOGIN_TYPE_EMAIL = 'email';
|
||||||
static const String LOGIN_TYPE_GOOGLE = 'google';
|
static const String LOGIN_TYPE_GOOGLE = 'google';
|
||||||
static const String LOGIN_TYPE_MICROSOFT = 'microsoft';
|
static const String LOGIN_TYPE_MICROSOFT = 'microsoft';
|
||||||
|
static const String LOGIN_TYPE_APPLE = 'apple';
|
||||||
|
|
||||||
String _loginError = '';
|
String _loginError = '';
|
||||||
String _loginType = LOGIN_TYPE_GOOGLE;
|
String _loginType = LOGIN_TYPE_EMAIL;
|
||||||
|
|
||||||
|
List<String> _loginTypes;
|
||||||
|
|
||||||
bool _tokenLogin = false;
|
bool _tokenLogin = false;
|
||||||
bool _isSelfHosted = false;
|
bool _isSelfHosted = false;
|
||||||
bool _createAccount = false;
|
bool _createAccount = false;
|
||||||
bool _hideGoogle = false;
|
|
||||||
|
|
||||||
bool _recoverPassword = false;
|
bool _recoverPassword = false;
|
||||||
bool _autoValidate = false;
|
bool _autoValidate = false;
|
||||||
|
|
@ -91,13 +93,15 @@ class _LoginState extends State<LoginView> {
|
||||||
} else if (WebUtils.getHtmlValue('signup') == 'true') {
|
} else if (WebUtils.getHtmlValue('signup') == 'true') {
|
||||||
_createAccount = 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
|
@override
|
||||||
|
|
@ -213,6 +217,8 @@ class _LoginState extends State<LoginView> {
|
||||||
);
|
);
|
||||||
} else if (_loginType == LOGIN_TYPE_MICROSOFT) {
|
} else if (_loginType == LOGIN_TYPE_MICROSOFT) {
|
||||||
viewModel.onMicrosoftSignUpPressed(context, completer, url);
|
viewModel.onMicrosoftSignUpPressed(context, completer, url);
|
||||||
|
} else if (_loginType == LOGIN_TYPE_APPLE) {
|
||||||
|
viewModel.onAppleSignUpPressed(context, completer, url);
|
||||||
} else {
|
} else {
|
||||||
viewModel.onGoogleSignUpPressed(context, completer, url);
|
viewModel.onGoogleSignUpPressed(context, completer, url);
|
||||||
}
|
}
|
||||||
|
|
@ -288,6 +294,11 @@ class _LoginState extends State<LoginView> {
|
||||||
url: url,
|
url: url,
|
||||||
secret: _isSelfHosted ? _secretController.text : '',
|
secret: _isSelfHosted ? _secretController.text : '',
|
||||||
oneTimePassword: _oneTimePasswordController.text);
|
oneTimePassword: _oneTimePasswordController.text);
|
||||||
|
} else if (_loginType == LOGIN_TYPE_APPLE) {
|
||||||
|
viewModel.onAppleLoginPressed(context, completer,
|
||||||
|
url: url,
|
||||||
|
secret: _isSelfHosted ? _secretController.text : '',
|
||||||
|
oneTimePassword: _oneTimePasswordController.text);
|
||||||
} else {
|
} else {
|
||||||
viewModel.onGoogleLoginPressed(context, completer,
|
viewModel.onGoogleLoginPressed(context, completer,
|
||||||
url: url,
|
url: url,
|
||||||
|
|
@ -401,49 +412,18 @@ class _LoginState extends State<LoginView> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (!_isSelfHosted &&
|
if (!_isSelfHosted && _loginTypes.length > 1) ...[
|
||||||
(!kReleaseMode || !_hideGoogle)) ...[
|
|
||||||
RuledText(localization.selectMethod),
|
RuledText(localization.selectMethod),
|
||||||
if (kIsWeb)
|
AppToggleButtons(
|
||||||
AppToggleButtons(
|
tabLabels: _loginTypes,
|
||||||
tabLabels: [
|
selectedIndex: _loginTypes.indexOf(_loginType),
|
||||||
'Google',
|
onTabChanged: (index) {
|
||||||
'Microsoft',
|
setState(() {
|
||||||
localization.email,
|
_loginType = _loginTypes[index];
|
||||||
],
|
_loginError = '';
|
||||||
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 = '';
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
|
|
@ -610,6 +590,8 @@ class _LoginState extends State<LoginView> {
|
||||||
Icon(Icons.mail, color: Colors.white)
|
Icon(Icons.mail, color: Colors.white)
|
||||||
else if (_loginType == LOGIN_TYPE_MICROSOFT)
|
else if (_loginType == LOGIN_TYPE_MICROSOFT)
|
||||||
Icon(MdiIcons.microsoft, color: Colors.white)
|
Icon(MdiIcons.microsoft, color: Colors.white)
|
||||||
|
else if (_loginType == LOGIN_TYPE_APPLE)
|
||||||
|
Icon(MdiIcons.apple, color: Colors.white)
|
||||||
else
|
else
|
||||||
ClipOval(
|
ClipOval(
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ class LoginVM {
|
||||||
@required this.onGoogleSignUpPressed,
|
@required this.onGoogleSignUpPressed,
|
||||||
@required this.onMicrosoftLoginPressed,
|
@required this.onMicrosoftLoginPressed,
|
||||||
@required this.onMicrosoftSignUpPressed,
|
@required this.onMicrosoftSignUpPressed,
|
||||||
|
@required this.onAppleLoginPressed,
|
||||||
|
@required this.onAppleSignUpPressed,
|
||||||
@required this.onTokenLoginPressed,
|
@required this.onTokenLoginPressed,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -110,6 +112,11 @@ class LoginVM {
|
||||||
final Function(BuildContext, Completer<Null> completer, String url)
|
final Function(BuildContext, Completer<Null> completer, String url)
|
||||||
onMicrosoftSignUpPressed;
|
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) {
|
static LoginVM fromStore(Store<AppState> store) {
|
||||||
void _handleLogin({BuildContext context, bool isSignUp = false}) {
|
void _handleLogin({BuildContext context, bool isSignUp = false}) {
|
||||||
final layout = calculateLayout(context);
|
final layout = calculateLayout(context);
|
||||||
|
|
@ -266,6 +273,59 @@ class LoginVM {
|
||||||
print('## onMicrosoftSignUpPressed: $error');
|
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: (
|
onSignUpPressed: (
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Completer<Null> completer, {
|
Completer<Null> completer, {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import path_provider_macos
|
||||||
import printing
|
import printing
|
||||||
import sentry_flutter
|
import sentry_flutter
|
||||||
import shared_preferences_macos
|
import shared_preferences_macos
|
||||||
|
import sign_in_with_apple
|
||||||
import sqflite
|
import sqflite
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
|
|
||||||
|
|
@ -23,6 +24,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
|
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
|
||||||
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
|
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ dependencies:
|
||||||
printing: ^5.8.0
|
printing: ^5.8.0
|
||||||
image_cropper: ^2.0.2
|
image_cropper: ^2.0.2
|
||||||
msal_js: ^2.14.0
|
msal_js: ^2.14.0
|
||||||
|
sign_in_with_apple: ^4.0.0
|
||||||
# bitsdojo_window: ^0.1.2
|
# bitsdojo_window: ^0.1.2
|
||||||
# quick_actions: ^0.2.1
|
# quick_actions: ^0.2.1
|
||||||
# idb_shim: ^1.11.1+1
|
# idb_shim: ^1.11.1+1
|
||||||
|
|
|
||||||
21
pubspec.lock
21
pubspec.lock
|
|
@ -1092,6 +1092,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
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:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ dependencies:
|
||||||
printing: ^5.8.0
|
printing: ^5.8.0
|
||||||
image_cropper: ^2.0.2
|
image_cropper: ^2.0.2
|
||||||
msal_js: ^2.14.0
|
msal_js: ^2.14.0
|
||||||
|
sign_in_with_apple: ^4.0.0
|
||||||
# bitsdojo_window: ^0.1.2
|
# bitsdojo_window: ^0.1.2
|
||||||
# quick_actions: ^0.2.1
|
# quick_actions: ^0.2.1
|
||||||
# idb_shim: ^1.11.1+1
|
# idb_shim: ^1.11.1+1
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ dependencies:
|
||||||
printing: ^5.8.0
|
printing: ^5.8.0
|
||||||
image_cropper: ^2.0.2
|
image_cropper: ^2.0.2
|
||||||
msal_js: ^2.14.0
|
msal_js: ^2.14.0
|
||||||
|
sign_in_with_apple: ^4.0.0
|
||||||
# bitsdojo_window: ^0.1.2
|
# bitsdojo_window: ^0.1.2
|
||||||
# quick_actions: ^0.2.1
|
# quick_actions: ^0.2.1
|
||||||
# idb_shim: ^1.11.1+1
|
# idb_shim: ^1.11.1+1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue