Yap, HydroTrack doing all that without being extra.
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'HydroTrack',
theme: ThemeData(
primarySwatch: Colors.blue,
fontFamily: 'Poppins',
),
home: const LoginPage(),
debugShowCheckedModeBanner: false,
);
}
}
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
late Animation<double> _fadeAnimation;
late Animation<Color?> _colorAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 2000),
);
_animation = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(parent: _controller, curve: Curves.fastOutSlowIn),
);
_fadeAnimation = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
_colorAnimation = ColorTween(
begin: const Color(0xFF2D68FF),
end: const Color(0xFF00B4D8),
).animate(_controller);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
// Animated Background with more colors
AnimatedBackground(),
// Content
SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 40.0),
// Animated Water Drop Logo with more colors
ScaleTransition(
scale: _animation,
child: Stack(
alignment: Alignment.center,
children: [
// Outer glow with multiple colors
Container(
width: 160,
height: 160,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
const Color(0xFF2D68FF).withOpacity(0.2),
const Color(0xFF00B4D8).withOpacity(0.2),
const Color(0xFF6A11CB).withOpacity(0.1),
Colors.transparent,
],
stops: const [0.1, 0.4, 0.8, 1.0],
),
),
),
Container(
width: 140,
height: 140,
decoration: BoxDecoration(
color: const Color(0xFF6A11CB).withOpacity(0.15),
shape: BoxShape.circle,
),
),
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [
Color(0xFF6A11CB), // Purple
Color(0xFF2575FC), // Blue
Color(0xFF2D68FF), // Light Blue
Color(0xFF00B4D8), // Cyan
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: const Color(0xFF2575FC).withOpacity(0.5),
blurRadius: 25,
spreadRadius: 3,
offset: const Offset(0, 10),
)
],
),
child: const Icon(
Icons.water_drop,
size: 70,
color: Colors.white,
),
),
],
),
),
const SizedBox(height: 25.0),
// App Title with Multi-color Gradient
FadeTransition(
opacity: _fadeAnimation,
child: ShaderMask(
shaderCallback: (bounds) => const LinearGradient(
colors: [
Color(0xFF6A11CB), // Purple
Color(0xFF2575FC), // Blue
Color(0xFF2D68FF), // Light Blue
Color(0xFF00B4D8), // Cyan
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
).createShader(bounds),
child: const Text(
'HydroTrack',
style: TextStyle(
fontSize: 38.0,
fontWeight: FontWeight.w800,
color: Colors.white,
letterSpacing: 1.2,
),
),
),
),
const SizedBox(height: 8.0),
FadeTransition(
opacity: _fadeAnimation,
child: const Text(
'Stay hydrated, stay healthy',
style: TextStyle(
fontSize: 16.0,
color: Colors.white70,
fontWeight: FontWeight.w500,
),
),
),
const SizedBox(height: 50.0),
// Social Login Buttons with more vibrant colors
FadeTransition(
opacity: _fadeAnimation,
child: _buildSocialButton(
icon: Icons.mail_outline,
text: 'Continue With Google',
color: const Color(0xFF4285F4),
textColor: Colors.white,
iconColor: Colors.white,
),
),
const SizedBox(height: 16.0),
FadeTransition(
opacity: _fadeAnimation,
child: _buildSocialButton(
icon: Icons.facebook,
text: 'Continue with Facebook',
color: const Color(0xFF4267B2),
textColor: Colors.white,
iconColor: Colors.white,
),
),
const SizedBox(height: 16.0),
FadeTransition(
opacity: _fadeAnimation,
child: _buildSocialButton(
icon: Icons.apple,
text: 'Continue with Apple',
color: Colors.black,
textColor: Colors.white,
iconColor: Colors.white,
),
),
const SizedBox(height: 40.0),
// Colorful Divider with text
FadeTransition(
opacity: _fadeAnimation,
child: Row(
children: [
Expanded(
child: Container(
height: 2.0,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.transparent,
const Color(0xFF6A11CB).withOpacity(0.7),
const Color(0xFF2575FC).withOpacity(0.7),
Colors.transparent,
],
),
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
'or continue with email',
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 14.0,
fontWeight: FontWeight.w600,
shadows: [
Shadow(
color: const Color(0xFF00B4D8).withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0, 0),
)
],
),
),
),
Expanded(
child: Container(
height: 2.0,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.transparent,
const Color(0xFF2575FC).withOpacity(0.7),
const Color(0xFF6A11CB).withOpacity(0.7),
Colors.transparent,
],
),
),
),
),
],
),
),
const SizedBox(height: 40.0),
// Input Fields with colorful borders
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.5),
end: Offset.zero,
).animate(_controller),
child: FadeTransition(
opacity: _fadeAnimation,
child: _buildInputField(
label: 'Full Name',
hint: 'Enter your full name',
icon: Icons.person_outline,
iconColor: const Color(0xFF6A11CB),
),
),
),
const SizedBox(height: 20.0),
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.5),
end: Offset.zero,
).animate(_controller),
child: FadeTransition(
opacity: _fadeAnimation,
child: _buildInputField(
label: 'Email Address',
hint: 'Enter your email',
icon: Icons.email_outlined,
iconColor: const Color(0xFF2575FC),
),
),
),
const SizedBox(height: 20.0),
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.5),
end: Offset.zero,
).animate(_controller),
child: FadeTransition(
opacity: _fadeAnimation,
child: _buildInputField(
label: 'Password',
hint: 'Create a password',
isPassword: true,
icon: Icons.lock_outline,
iconColor: const Color(0xFF2D68FF),
),
),
),
const SizedBox(height: 30.0),
// Create Account Button with multi-color gradient
ScaleTransition(
scale: Tween<double>(begin: 0.9, end: 1.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.elasticOut),
),
child: FadeTransition(
opacity: _fadeAnimation,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
gradient: const LinearGradient(
colors: [
Color(0xFF6A11CB), // Purple
Color(0xFF2575FC), // Blue
Color(0xFF2D68FF), // Light Blue
Color(0xFF00B4D8), // Cyan
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
boxShadow: [
BoxShadow(
color: const Color(0xFF2575FC).withOpacity(0.6),
blurRadius: 25,
spreadRadius: 3,
offset: const Offset(0, 10),
)
],
),
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
minimumSize: const Size(double.infinity, 60),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
child: const Text(
'Create Account',
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.w700,
),
),
),
),
),
),
const SizedBox(height: 30.0),
// Sign In Link with color animation
FadeTransition(
opacity: _fadeAnimation,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Already have an account? ',
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 14.0,
),
),
AnimatedBuilder(
animation: _colorAnimation,
builder: (context, child) {
return GestureDetector(
onTap: () {},
child: Text(
'Sign in',
style: TextStyle(
color: _colorAnimation.value,
fontSize: 14.0,
fontWeight: FontWeight.w700,
decoration: TextDecoration.underline,
shadows: [
Shadow(
color: _colorAnimation.value!.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 0),
)
],
),
),
);
},
),
],
),
),
const SizedBox(height: 40.0),
],
),
),
),
],
),
);
}
Widget _buildSocialButton({
required IconData icon,
required String text,
required Color color,
required Color textColor,
required Color iconColor,
}) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
boxShadow: [
BoxShadow(
color: color.withOpacity(0.4),
blurRadius: 15,
spreadRadius: 1,
offset: const Offset(0, 5),
)
],
),
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
foregroundColor: textColor,
backgroundColor: color,
minimumSize: const Size(double.infinity, 60),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: iconColor, size: 24),
const SizedBox(width: 12.0),
Text(
text,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.w600,
color: textColor,
),
),
],
),
),
);
}
Widget _buildInputField({
required String label,
required String hint,
bool isPassword = false,
IconData? icon,
Color? iconColor,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: Colors.white,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 2,
offset: const Offset(0, 1),
)
],
),
),
const SizedBox(height: 8.0),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
blurRadius: 15,
spreadRadius: 1,
offset: const Offset(0, 5),
)
],
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.white,
const Color(0xFFE6F7FF),
],
),
),
child: TextField(
obscureText: isPassword,
style: const TextStyle(color: Colors.black87),
decoration: InputDecoration(
hintText: hint,
hintStyle: TextStyle(color: Colors.grey[500]),
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 18.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
borderSide: BorderSide(color: iconColor ?? const Color(0xFF2D68FF), width: 2.0),
),
suffixIcon: icon != null
? Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Icon(
icon,
color: iconColor,
size: 22,
),
)
: null,
),
),
),
],
);
}
}
class AnimatedBackground extends StatefulWidget {
const AnimatedBackground({super.key});
@override
State<AnimatedBackground> createState() => _AnimatedBackgroundState();
}
class _AnimatedBackgroundState extends State<AnimatedBackground> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 15),
)..repeat(reverse: true);
_animation = Tween<double>(begin: 0, end: 1).animate(_controller);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
const Color(0xFF6A11CB).withOpacity(0.2), // Purple
const Color(0xFF2575FC).withOpacity(0.3), // Blue
const Color(0xFF2D68FF).withOpacity(0.4), // Light Blue
const Color(0xFF00B4D8).withOpacity(0.5), // Cyan
],
stops: [0.1, 0.4, 0.7, 1.0],
transform: GradientRotation(_animation.value * 2 * pi),
),
),
child: CustomPaint(
painter: _BackgroundPainter(animation: _animation.value),
),
);
},
);
}
}
class _BackgroundPainter extends CustomPainter {
final double animation;
_BackgroundPainter({required this.animation});
@override
void paint(Canvas canvas, Size size) {
final random = Random(123);
// Draw colorful bubbles
for (int i = 0; i < 20; i++) {
final x = size.width * random.nextDouble();
final y = size.height * random.nextDouble();
final radius = 5 + 15 * random.nextDouble();
final bubbleColor = Color.lerp(
const Color(0xFF6A11CB).withOpacity(0.15),
const Color(0xFF00B4D8).withOpacity(0.15),
random.nextDouble(),
);
final paint = Paint()
..color = bubbleColor!
..style = PaintingStyle.fill;
canvas.drawCircle(
Offset(x, y),
radius,
paint,
);
// Add highlight to bubbles
canvas.drawCircle(
Offset(x - radius/3, y - radius/3),
radius/4,
Paint()..color = Colors.white.withOpacity(0.3),
);
}
// Draw colorful waves
final waveColors = [
const Color(0xFF6A11CB).withOpacity(0.15),
const Color(0xFF2575FC).withOpacity(0.15),
const Color(0xFF2D68FF).withOpacity(0.15),
const Color(0xFF00B4D8).withOpacity(0.15),
];
for (int i = 0; i < waveColors.length; i++) {
final wavePaint = Paint()
..color = waveColors[i]
..style = PaintingStyle.fill;
final path = Path();
final waveHeight = 15 + i * 5;
final baseHeight = 0.7 + i * 0.05;
path.moveTo(0, size.height * baseHeight);
for (double x = 0; x <= size.width; x += 10) {
final y = size.height * baseHeight + sin(x * 0.01 + animation * 2 * pi + i) * waveHeight;
path.lineTo(x, y);
}
path.lineTo(size.width, size.height);
path.lineTo(0, size.height);
path.close();
canvas.drawPath(path, wavePaint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
Coba deh, dan thank me later. Tubuh lo bakal lebih segar, kulit makin glowing, dan lo akhirnya nggak deh dikatain "kok kering?" ๐
Komentar
Posting Komentar