Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(authenticator): Align logos and sort Apple first #1161

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions packages/amplify_authenticator/lib/src/widgets/form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class AuthenticatorFormState<T extends AuthenticatorForm<T>>
List<AuthenticatorFormField> runtimeFields(BuildContext context) => const [];

/// Additional actions defined at runtime.
List<AuthenticatorComponent> runtimeActions(BuildContext context) => const [];
List<Widget> runtimeActions(BuildContext context) => const [];

final ValueNotifier<bool> obscureTextToggleValue = ValueNotifier(true);

Expand Down Expand Up @@ -319,7 +319,7 @@ class _SignInFormState extends AuthenticatorFormState<SignInForm> {
_SignInFormState() : super._();

@override
List<AuthenticatorButton> runtimeActions(BuildContext context) {
List<Widget> runtimeActions(BuildContext context) {
if (!widget.includeDefaultSocialProviders) {
return const [];
}
Expand All @@ -335,21 +335,32 @@ class _SignInFormState extends AuthenticatorFormState<SignInForm> {
return const [];
}

return socialProviders
.map((provider) {
switch (provider) {
// Sort Apple first based off their app guidelines.
socialProviders.sort((a, b) {
if (a == SocialProvider.apple) {
return -1;
} else if (b == SocialProvider.apple) {
return 1;
}
return describeEnum(a).compareTo(describeEnum(b));
});

return [
SocialSignInButtons(
providers: socialProviders.map((e) {
switch (e) {
case SocialProvider.facebook:
return const SocialSignInButton.facebook();
return AuthProvider.facebook;
case SocialProvider.google:
return const SocialSignInButton.google();
return AuthProvider.google;
case SocialProvider.amazon:
return const SocialSignInButton.amazon();
return AuthProvider.amazon;
case SocialProvider.apple:
return const SocialSignInButton.apple();
return AuthProvider.apple;
}
})
.whereType<AuthenticatorButton>()
.toList();
}).toList(),
),
];
}
}

Expand Down
117 changes: 101 additions & 16 deletions packages/amplify_authenticator/lib/src/widgets/social/social_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,78 @@
* permissions and limitations under the License.
*/

import 'dart:math';

import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_authenticator/src/l10n/auth_strings_resolver.dart';
import 'package:amplify_authenticator/src/state/auth_viewmodel.dart';
import 'package:amplify_authenticator/src/theme/amplify_theme.dart';
import 'package:amplify_authenticator/src/utils/list.dart';
import 'package:amplify_authenticator/src/widgets/button.dart';
import 'package:amplify_authenticator/src/widgets/component.dart';
import 'package:amplify_authenticator/src/widgets/social/social_icons.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class SocialSignInButtons extends StatelessAuthenticatorComponent {
const SocialSignInButtons({
Key? key,
required this.providers,
}) : super(key: key);

final List<AuthProvider> providers;

@override
Widget builder(
BuildContext context,
AuthViewModel viewModel,
AuthStringResolver stringResolver,
) {
return LayoutBuilder(builder: (context, constraints) {
// Perform a layout on each of the Text items to determine the maximum
// width, so that we can size all button labels to that width and align
// the logos in the column.
var maxWidth = 0.0;
for (var provider in providers) {
final text = stringResolver.buttons.resolve(
context,
ButtonResolverKey.signInWith(provider),
);
final style = Theme.of(context)
.outlinedButtonTheme
.style
?.textStyle
?.resolve({}) ??
Theme.of(context).textTheme.button;
final tp = TextPainter(
text: TextSpan(
text: text,
style: style,
),
maxLines: 1,
textDirection: TextDirection.ltr,
)..layout(maxWidth: constraints.maxWidth);
maxWidth = max(maxWidth, tp.width);
}

return Column(
children: <Widget>[
for (var provider in providers)
SocialSignInButton(provider: provider, maxWidth: maxWidth),
].spacedBy(const SizedBox(height: 12)),
);
});
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(IterableProperty<AuthProvider>('providers', providers));
}
}

/// {@template authenticator.social_sign_in_button}
/// A button for launching a social sign in UI.
/// {@endtemplate}
Expand All @@ -32,6 +93,7 @@ class SocialSignInButton extends AuthenticatorButton<SocialSignInButton> {
const SocialSignInButton({
Key? key,
required this.provider,
this.maxWidth = double.infinity,
}) : super(key: key);

/// A social sign-in button for Facebook.
Expand All @@ -53,6 +115,9 @@ class SocialSignInButton extends AuthenticatorButton<SocialSignInButton> {
/// The Cognito social sign-in provider.
final AuthProvider provider;

/// The maximum width of the button texts. Used to align logos properly.
final double maxWidth;

@override
ButtonResolverKey get labelKey => ButtonResolverKey.signInWith(provider);

Expand All @@ -71,11 +136,14 @@ class SocialSignInButton extends AuthenticatorButton<SocialSignInButton> {
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(EnumProperty<AuthProvider>('provider', provider));
properties.add(DoubleProperty('maxWidth', maxWidth));
}
}

class _SocialSignInButtonState
extends AuthenticatorButtonState<SocialSignInButton> {
static const _spacing = 5.0;

Widget get icon {
final bool isDark = AmplifyTheme.of(context).isDark;
switch (widget.provider) {
Expand Down Expand Up @@ -106,6 +174,15 @@ class _SocialSignInButtonState
}
}

double calculatePadding(BoxConstraints constraints) {
final logoWidth = constraints.maxHeight + _spacing;
final textWidth = widget.maxWidth;
return max(
0,
(constraints.maxWidth - logoWidth - textWidth) / 2,
);
}

@override
Widget build(BuildContext context) {
final resolver = stringResolver.buttons;
Expand Down Expand Up @@ -136,23 +213,31 @@ class _SocialSignInButtonState
onPressed: viewModel.isBusy
? null
: () => viewModel.signInWithProvider(widget.provider),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: widget.provider.padding,
child: AspectRatio(
aspectRatio: 1,
child: icon,
),
child: LayoutBuilder(builder: (context, constraints) {
final padding = calculatePadding(constraints);
return Padding(
padding: EdgeInsets.symmetric(horizontal: padding),
child: Row(
mainAxisAlignment: padding == 0
? MainAxisAlignment.center
: MainAxisAlignment.start,
children: [
Padding(
padding: widget.provider.padding,
child: AspectRatio(
aspectRatio: 1,
child: icon,
),
),
const SizedBox(width: _spacing),
Text(resolver.resolve(
context,
ButtonResolverKey.signInWith(widget.provider),
)),
],
),
const SizedBox(width: 5),
Text(resolver.resolve(
context,
ButtonResolverKey.signInWith(widget.provider),
)),
],
),
);
}),
),
);
}
Expand Down