140 lines
3.7 KiB
Dart
140 lines
3.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../services/auth_service.dart';
|
|
import '../theme/app_theme.dart';
|
|
|
|
class GoogleSignInButton extends StatefulWidget {
|
|
const GoogleSignInButton({
|
|
super.key,
|
|
this.label = 'Continue with Google',
|
|
this.compact = false,
|
|
this.onSignedIn,
|
|
this.onError,
|
|
});
|
|
|
|
final String label;
|
|
final bool compact;
|
|
final VoidCallback? onSignedIn;
|
|
final void Function(Object error)? onError;
|
|
|
|
@override
|
|
State<GoogleSignInButton> createState() => _GoogleSignInButtonState();
|
|
}
|
|
|
|
class _GoogleSignInButtonState extends State<GoogleSignInButton> {
|
|
bool _isLoading = false;
|
|
|
|
Future<void> _signIn() async {
|
|
setState(() => _isLoading = true);
|
|
try {
|
|
await AuthService.instance.signInWithGoogle();
|
|
widget.onSignedIn?.call();
|
|
} catch (error) {
|
|
widget.onError?.call(error);
|
|
} finally {
|
|
if (mounted) {
|
|
setState(() => _isLoading = false);
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final double verticalPadding = widget.compact ? 14 : 16;
|
|
|
|
return SizedBox(
|
|
width: double.infinity,
|
|
child: FilledButton(
|
|
onPressed: _isLoading ? null : _signIn,
|
|
style: FilledButton.styleFrom(
|
|
backgroundColor: Colors.white,
|
|
foregroundColor: const Color(0xFF1F2937),
|
|
disabledBackgroundColor: Colors.white.withValues(alpha: 0.7),
|
|
padding: EdgeInsets.symmetric(vertical: verticalPadding),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
elevation: 0,
|
|
),
|
|
child: _isLoading
|
|
? const SizedBox(
|
|
width: 22,
|
|
height: 22,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2.5,
|
|
color: AppColors.background,
|
|
),
|
|
)
|
|
: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
const _GoogleLogo(size: 22),
|
|
const SizedBox(width: 12),
|
|
Flexible(
|
|
child: Text(
|
|
widget.label,
|
|
style: const TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: Color(0xFF1F2937),
|
|
),
|
|
textAlign: TextAlign.center,
|
|
overflow: TextOverflow.ellipsis,
|
|
maxLines: 1,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _GoogleLogo extends StatelessWidget {
|
|
const _GoogleLogo({required this.size});
|
|
|
|
final double size;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SizedBox(
|
|
width: size,
|
|
height: size,
|
|
child: CustomPaint(painter: _GoogleLogoPainter()),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _GoogleLogoPainter extends CustomPainter {
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
final double w = size.width;
|
|
final double h = size.height;
|
|
final Offset center = Offset(w / 2, h / 2);
|
|
final double r = w * 0.42;
|
|
|
|
void arc(Color color, double start, double sweep) {
|
|
final Paint paint = Paint()
|
|
..color = color
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = w * 0.18
|
|
..strokeCap = StrokeCap.round;
|
|
canvas.drawArc(
|
|
Rect.fromCircle(center: center, radius: r),
|
|
start,
|
|
sweep,
|
|
false,
|
|
paint,
|
|
);
|
|
}
|
|
|
|
arc(const Color(0xFF4285F4), -0.4, 1.6);
|
|
arc(const Color(0xFFEA4335), 1.2, 1.3);
|
|
arc(const Color(0xFFFBBC05), 2.5, 1.3);
|
|
arc(const Color(0xFF34A853), 3.8, 1.3);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
|
|
}
|