feat: update login page
This commit is contained in:
parent
ebfdb7274c
commit
9b398cabb6
@ -1,5 +1,6 @@
|
|||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import '../../../../common/extension/extension.dart';
|
import '../../../../common/extension/extension.dart';
|
||||||
import '../../../../common/theme/theme.dart';
|
import '../../../../common/theme/theme.dart';
|
||||||
@ -26,8 +27,13 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
|||||||
|
|
||||||
late AnimationController _fadeController;
|
late AnimationController _fadeController;
|
||||||
late AnimationController _slideController;
|
late AnimationController _slideController;
|
||||||
|
late AnimationController _backgroundController;
|
||||||
|
late AnimationController _floatingController;
|
||||||
|
|
||||||
late Animation<double> _fadeAnimation;
|
late Animation<double> _fadeAnimation;
|
||||||
late Animation<Offset> _slideAnimation;
|
late Animation<Offset> _slideAnimation;
|
||||||
|
late Animation<double> _backgroundAnimation;
|
||||||
|
late Animation<double> _floatingAnimation;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -43,6 +49,16 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
|||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_backgroundController = AnimationController(
|
||||||
|
duration: const Duration(seconds: 10),
|
||||||
|
vsync: this,
|
||||||
|
)..repeat();
|
||||||
|
|
||||||
|
_floatingController = AnimationController(
|
||||||
|
duration: const Duration(seconds: 6),
|
||||||
|
vsync: this,
|
||||||
|
)..repeat(reverse: true);
|
||||||
|
|
||||||
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
||||||
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
|
CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut),
|
||||||
);
|
);
|
||||||
@ -51,8 +67,19 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
|||||||
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
|
Tween<Offset>(begin: const Offset(0, 0.3), end: Offset.zero).animate(
|
||||||
CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic),
|
CurvedAnimation(parent: _slideController, curve: Curves.easeOutCubic),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_backgroundAnimation = Tween<double>(
|
||||||
|
begin: 0.0,
|
||||||
|
end: 2 * math.pi,
|
||||||
|
).animate(_backgroundController);
|
||||||
|
|
||||||
|
_floatingAnimation = Tween<double>(begin: -20.0, end: 20.0).animate(
|
||||||
|
CurvedAnimation(parent: _floatingController, curve: Curves.easeInOut),
|
||||||
|
);
|
||||||
|
|
||||||
_emailController.text = 'test@example.com';
|
_emailController.text = 'test@example.com';
|
||||||
_passwordController.text = 'password';
|
_passwordController.text = 'password';
|
||||||
|
|
||||||
_fadeController.forward();
|
_fadeController.forward();
|
||||||
_slideController.forward();
|
_slideController.forward();
|
||||||
}
|
}
|
||||||
@ -61,6 +88,8 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
_fadeController.dispose();
|
_fadeController.dispose();
|
||||||
_slideController.dispose();
|
_slideController.dispose();
|
||||||
|
_backgroundController.dispose();
|
||||||
|
_floatingController.dispose();
|
||||||
_emailController.dispose();
|
_emailController.dispose();
|
||||||
_passwordController.dispose();
|
_passwordController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@ -86,36 +115,164 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Container(
|
body: AnimatedBuilder(
|
||||||
decoration: const BoxDecoration(
|
animation: Listenable.merge([
|
||||||
gradient: LinearGradient(
|
_backgroundController,
|
||||||
begin: Alignment.topLeft,
|
_floatingController,
|
||||||
end: Alignment.bottomRight,
|
]),
|
||||||
colors: AppColor.primaryGradient,
|
builder: (context, child) {
|
||||||
),
|
return Container(
|
||||||
),
|
decoration: const BoxDecoration(
|
||||||
child: SafeArea(
|
gradient: LinearGradient(
|
||||||
child: Center(
|
begin: Alignment.topLeft,
|
||||||
child: SingleChildScrollView(
|
end: Alignment.bottomRight,
|
||||||
padding: EdgeInsets.symmetric(horizontal: AppValue.padding),
|
colors: AppColor.primaryGradient,
|
||||||
child: FadeTransition(
|
),
|
||||||
opacity: _fadeAnimation,
|
),
|
||||||
child: SlideTransition(
|
child: Stack(
|
||||||
position: _slideAnimation,
|
children: [
|
||||||
child: Column(
|
// Animated background elements
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
_buildAnimatedBackground(),
|
||||||
children: [
|
|
||||||
_buildLogo(context),
|
// Main content
|
||||||
SpaceHeight(48),
|
SafeArea(
|
||||||
_buildLoginCard(context),
|
child: Center(
|
||||||
],
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: AppValue.padding,
|
||||||
|
),
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: _fadeAnimation,
|
||||||
|
child: SlideTransition(
|
||||||
|
position: _slideAnimation,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildLogo(context),
|
||||||
|
SpaceHeight(48),
|
||||||
|
_buildLoginCard(context),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAnimatedBackground() {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
// Floating circles
|
||||||
|
...List.generate(6, (index) {
|
||||||
|
final double size = 80 + (index * 40);
|
||||||
|
final double left =
|
||||||
|
(index * 60.0) % MediaQuery.of(context).size.width;
|
||||||
|
final double top =
|
||||||
|
(index * 120.0) % MediaQuery.of(context).size.height;
|
||||||
|
|
||||||
|
return Positioned(
|
||||||
|
left: left + math.sin(_backgroundAnimation.value + index) * 30,
|
||||||
|
top: top + _floatingAnimation.value + (index * 10),
|
||||||
|
child: Container(
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.white.withOpacity(0.1),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.white.withOpacity(0.2),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Rotating geometric shapes
|
||||||
|
Positioned(
|
||||||
|
top: 100,
|
||||||
|
right: 50,
|
||||||
|
child: Transform.rotate(
|
||||||
|
angle: _backgroundAnimation.value,
|
||||||
|
child: Container(
|
||||||
|
width: 60,
|
||||||
|
height: 60,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.08),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.white.withOpacity(0.15),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
Positioned(
|
||||||
|
bottom: 150,
|
||||||
|
left: 30,
|
||||||
|
child: Transform.rotate(
|
||||||
|
angle: -_backgroundAnimation.value * 0.5,
|
||||||
|
child: Container(
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.06),
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.white.withOpacity(0.12),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Floating particles
|
||||||
|
...List.generate(8, (index) {
|
||||||
|
return Positioned(
|
||||||
|
left: (index * 45.0) % MediaQuery.of(context).size.width,
|
||||||
|
top: (index * 80.0) % MediaQuery.of(context).size.height,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(
|
||||||
|
math.sin(_backgroundAnimation.value + index * 0.5) * 20,
|
||||||
|
math.cos(_backgroundAnimation.value + index * 0.3) * 15,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: 4 + (index % 3) * 2,
|
||||||
|
height: 4 + (index % 3) * 2,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Colors.white.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Gradient overlay for better text readability
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: [
|
||||||
|
Colors.transparent,
|
||||||
|
Colors.black.withOpacity(0.1),
|
||||||
|
Colors.transparent,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,13 +284,29 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
|||||||
style: AppStyle.h1.copyWith(
|
style: AppStyle.h1.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: AppColor.white,
|
color: AppColor.white,
|
||||||
|
shadows: [
|
||||||
|
Shadow(
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
blurRadius: 10,
|
||||||
|
color: Colors.black.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SpaceHeight(8),
|
const SpaceHeight(8),
|
||||||
Text(
|
Text(
|
||||||
context.lang.login_desc,
|
context.lang.login_desc,
|
||||||
style: AppStyle.lg.copyWith(color: AppColor.textLight),
|
style: AppStyle.lg.copyWith(
|
||||||
|
color: AppColor.textLight,
|
||||||
|
shadows: [
|
||||||
|
Shadow(
|
||||||
|
offset: const Offset(0, 1),
|
||||||
|
blurRadius: 5,
|
||||||
|
color: Colors.black.withOpacity(0.2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -147,10 +320,17 @@ class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
|
|||||||
color: AppColor.white,
|
color: AppColor.white,
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: AppColor.black.withOpacity(0.15),
|
||||||
|
blurRadius: 40,
|
||||||
|
offset: const Offset(0, 20),
|
||||||
|
spreadRadius: 0,
|
||||||
|
),
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: AppColor.black.withOpacity(0.1),
|
color: AppColor.black.withOpacity(0.1),
|
||||||
blurRadius: 30,
|
blurRadius: 10,
|
||||||
offset: const Offset(0, 15),
|
offset: const Offset(0, 5),
|
||||||
|
spreadRadius: 0,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user