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

[google_sign_in_web] Update button_tester to use web_only library. #6868

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
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@

import 'package:flutter/material.dart';
import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart';
import 'package:google_sign_in_web/google_sign_in_web.dart';
import 'package:google_sign_in_web/web_only.dart';

import 'src/button_configuration_column.dart';

// The instance of the plugin is automatically created by Flutter before calling
// our main code, let's grab it directly from the Platform interface of the plugin.
final GoogleSignInPlugin _plugin =
GoogleSignInPlatform.instance as GoogleSignInPlugin;
// Let's use the Platform Interface directly, no need to use anything web-specific
// from it. (In a normal app, we'd use the plugin interface!)
// All the web-specific imports come from the `web_only.dart` library.
final GoogleSignInPlatform _platform = GoogleSignInPlatform.instance;

Future<void> main() async {
await _plugin.initWithParams(const SignInInitParameters(
await _platform.initWithParams(const SignInInitParameters(
clientId: 'your-client_id.apps.googleusercontent.com',
));
runApp(
Expand All @@ -41,15 +41,15 @@ class _ButtonConfiguratorState extends State<ButtonConfiguratorDemo> {
@override
void initState() {
super.initState();
_plugin.userDataEvents?.listen((GoogleSignInUserData? userData) {
_platform.userDataEvents?.listen((GoogleSignInUserData? userData) {
setState(() {
_userData = userData;
});
});
}

void _handleSignOut() {
_plugin.signOut();
_platform.signOut();
setState(() {
// signOut does not broadcast through the userDataEvents, so we fake it.
_userData = null;
Expand All @@ -70,7 +70,7 @@ class _ButtonConfiguratorState extends State<ButtonConfiguratorDemo> {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_userData == null)
_plugin.renderButton(configuration: _buttonConfiguration),
renderButton(configuration: _buttonConfiguration),
if (_userData != null) ...<Widget>[
Text('Hello, ${_userData!.displayName}!'),
ElevatedButton(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
// found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:google_sign_in_web/google_sign_in_web.dart';
import 'package:google_sign_in_web/web_only.dart';

/// Type of the onChange function for `ButtonConfiguration`.
typedef OnWebConfigChangeFn = void Function(GSIButtonConfiguration newConfig);

/// (Incomplete) List of the locales that can be used to configure the button.
const List<String> availableLocales = <String>[
/// The type of the widget builder function for each Card in the ListView builder
typedef CardBuilder = Widget Function(
GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange);

// (Incomplete) List of the locales that can be used to configure the button.
const List<String> _availableLocales = <String>[
'en_US',
'es_ES',
'pt_BR',
Expand All @@ -18,123 +22,146 @@ const List<String> availableLocales = <String>[
'de_DE',
];

// The builder functions for the Cards that let users customize the button.
final List<CardBuilder> _cards = <CardBuilder>[
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderLocaleCard(
value: currentConfig?.locale ?? 'en_US',
locales: _availableLocales,
onChanged: _onChanged<String>(currentConfig, onChange),
),
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderMinimumWidthCard(
value: currentConfig?.minimumWidth,
max: 500,
actualMax: 400,
onChanged: _onChanged<double>(currentConfig, onChange),
),
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderRadioListTileCard<GSIButtonType>(
title: 'ButtonType',
values: GSIButtonType.values,
selected: currentConfig?.type ?? GSIButtonType.standard,
onChanged: _onChanged<GSIButtonType>(currentConfig, onChange),
),
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderRadioListTileCard<GSIButtonShape>(
title: 'ButtonShape',
values: GSIButtonShape.values,
selected: currentConfig?.shape ?? GSIButtonShape.rectangular,
onChanged: _onChanged<GSIButtonShape>(currentConfig, onChange),
),
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderRadioListTileCard<GSIButtonSize>(
title: 'ButtonSize',
values: GSIButtonSize.values,
selected: currentConfig?.size ?? GSIButtonSize.large,
onChanged: _onChanged<GSIButtonSize>(currentConfig, onChange),
),
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderRadioListTileCard<GSIButtonTheme>(
title: 'ButtonTheme',
values: GSIButtonTheme.values,
selected: currentConfig?.theme ?? GSIButtonTheme.outline,
onChanged: _onChanged<GSIButtonTheme>(currentConfig, onChange),
),
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderRadioListTileCard<GSIButtonText>(
title: 'ButtonText',
values: GSIButtonText.values,
selected: currentConfig?.text ?? GSIButtonText.signinWith,
onChanged: _onChanged<GSIButtonText>(currentConfig, onChange),
),
(GSIButtonConfiguration? currentConfig, OnWebConfigChangeFn? onChange) =>
_renderRadioListTileCard<GSIButtonLogoAlignment>(
title: 'ButtonLogoAlignment',
values: GSIButtonLogoAlignment.values,
selected: currentConfig?.logoAlignment ?? GSIButtonLogoAlignment.left,
onChanged: _onChanged<GSIButtonLogoAlignment>(currentConfig, onChange),
),
];

/// Renders a Scrollable Column widget that allows the user to see (and change) a ButtonConfiguration.
Widget renderWebButtonConfiguration(
GSIButtonConfiguration? currentConfig, {
OnWebConfigChangeFn? onChange,
}) {
final ScrollController scrollController = ScrollController();
return Scrollbar(
controller: scrollController,
thumbVisibility: true,
interactive: true,
child: SingleChildScrollView(
controller: scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_renderLocaleCard(
value: currentConfig?.locale,
locales: availableLocales,
onChanged: _onChanged<String>(currentConfig, onChange),
),
_renderMinimumWidthCard(
value: currentConfig?.minimumWidth,
max: 500,
actualMax: 400,
onChanged: _onChanged<double>(currentConfig, onChange),
),
_renderRadioListTileCard<GSIButtonType>(
title: 'ButtonType',
values: GSIButtonType.values,
selected: currentConfig?.type,
onChanged: _onChanged<GSIButtonType>(currentConfig, onChange),
),
_renderRadioListTileCard<GSIButtonShape>(
title: 'ButtonShape',
values: GSIButtonShape.values,
selected: currentConfig?.shape,
onChanged: _onChanged<GSIButtonShape>(currentConfig, onChange),
),
_renderRadioListTileCard<GSIButtonSize>(
title: 'ButtonSize',
values: GSIButtonSize.values,
selected: currentConfig?.size,
onChanged: _onChanged<GSIButtonSize>(currentConfig, onChange),
),
_renderRadioListTileCard<GSIButtonTheme>(
title: 'ButtonTheme',
values: GSIButtonTheme.values,
selected: currentConfig?.theme,
onChanged: _onChanged<GSIButtonTheme>(currentConfig, onChange),
),
_renderRadioListTileCard<GSIButtonText>(
title: 'ButtonText',
values: GSIButtonText.values,
selected: currentConfig?.text,
onChanged: _onChanged<GSIButtonText>(currentConfig, onChange),
),
_renderRadioListTileCard<GSIButtonLogoAlignment>(
title: 'ButtonLogoAlignment',
values: GSIButtonLogoAlignment.values,
selected: currentConfig?.logoAlignment,
onChanged:
_onChanged<GSIButtonLogoAlignment>(currentConfig, onChange),
),
],
)));
controller: scrollController,
thumbVisibility: true,
interactive: true,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 250),
child: ListView.builder(
controller: scrollController,
itemCount: _cards.length,
itemBuilder: (BuildContext _, int index) =>
_cards[index](currentConfig, onChange),
),
),
);
}

/// Renders a Config card with a dropdown of locales.
Widget _renderLocaleCard(
{String? value,
required List<String> locales,
void Function(String?)? onChanged}) {
return _renderConfigCard(title: 'locale', children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: DropdownButton<String>(
items: locales
.map((String locale) => DropdownMenuItem<String>(
value: locale,
child: Text(locale),
))
.toList(),
value: value,
onChanged: onChanged,
isExpanded: true,
// padding: const EdgeInsets.symmetric(horizontal: 16), // Prefer padding here!
Widget _renderLocaleCard({
String? value,
required List<String> locales,
void Function(String?)? onChanged,
}) {
return _renderConfigCard(
title: 'locale',
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: DropdownButton<String>(
items: locales
.map((String locale) => DropdownMenuItem<String>(
value: locale,
child: Text(locale),
))
.toList(),
value: value,
onChanged: onChanged,
isExpanded: true,
// padding: const EdgeInsets.symmetric(horizontal: 16), // Prefer padding here!
),
),
),
]);
],
);
}

/// Renders a card with a slider
Widget _renderMinimumWidthCard(
{double? value,
double min = 0,
double actualMax = 10,
double max = 11,
void Function(double)? onChanged}) {
return _renderConfigCard(title: 'minimumWidth', children: <Widget>[
Slider(
label: value?.toString() ?? 'null',
value: value ?? 0,
min: min,
max: max,
secondaryTrackValue: actualMax,
onChanged: onChanged,
divisions: 10,
)
]);
Widget _renderMinimumWidthCard({
double? value,
double min = 0,
double actualMax = 10,
double max = 11,
void Function(double)? onChanged,
}) {
return _renderConfigCard(
title: 'minimumWidth',
children: <Widget>[
Slider(
label: value?.toString() ?? 'null',
value: value ?? 0,
min: min,
max: max,
secondaryTrackValue: actualMax,
onChanged: onChanged,
divisions: 10,
)
],
);
}

/// Renders a Config Card with the values of an Enum as radio buttons.
Widget _renderRadioListTileCard<T extends Enum>(
{required String title,
required List<T> values,
T? selected,
void Function(T?)? onChanged}) {
Widget _renderRadioListTileCard<T extends Enum>({
required String title,
required List<T> values,
T? selected,
void Function(T?)? onChanged,
}) {
return _renderConfigCard(
title: title,
children: values
Expand All @@ -150,29 +177,32 @@ Widget _renderRadioListTileCard<T extends Enum>(
}

/// Renders a Card where we render some `children` that change config.
Widget _renderConfigCard(
{required String title, required List<Widget> children}) {
return Container(
constraints: const BoxConstraints(maxWidth: 200),
child: Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text(
title,
style: const TextStyle(fontWeight: FontWeight.bold),
),
dense: true,
Widget _renderConfigCard({
required String title,
required List<Widget> children,
}) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text(
title,
style: const TextStyle(fontWeight: FontWeight.bold),
),
...children,
],
)));
dense: true,
),
...children,
],
),
);
}

/// Sets a `value` into an `old` configuration object.
GSIButtonConfiguration _copyConfigWith(
GSIButtonConfiguration? old, Object? value) {
GSIButtonConfiguration _copyConfigWith<T>(
GSIButtonConfiguration? old,
T? value,
) {
return GSIButtonConfiguration(
locale: value is String ? value : old?.locale,
minimumWidth:
Expand All @@ -188,11 +218,13 @@ GSIButtonConfiguration _copyConfigWith(

/// Returns a function that modifies the `current` configuration with a `value`, then calls `fn` with it.
void Function(T?)? _onChanged<T>(
GSIButtonConfiguration? current, OnWebConfigChangeFn? fn) {
GSIButtonConfiguration? current,
OnWebConfigChangeFn? fn,
) {
if (fn == null) {
return null;
}
return (T? value) {
fn(_copyConfigWith(current, value));
fn(_copyConfigWith<T>(current, value));
};
}