HydroTrack: Aplikasi yang Bikin Lo Auto Rajin Minum Air! ๐Ÿ’ง

 Hai guys! Jadi gue nemu satu app yang literally ngebantu gue buat stay hydrated tanpa perlu diingetin berkali-kali kayak emak-emak. Namanya HydroTrack—dan trust me, ini bukan aplikasi biasa. Desainnya bikin lo gamau berenti scroll, fungsinya juara, dan yang paling penting, bikin lo nggak lupa minum air lagi! Let’s dive in! ๐Ÿš€


Apa Itu HydroTrack? ๐Ÿค”

Bayangin lo punya personal hydration assistant yang:

  • Ngingetin lo buat minum air tanpa sounding annoying.

  • Nampilin progress lo dengan visual yang memuaskan banget.

  • Bikin lo semangat ngejar daily goal karena UI-nya aesthetic af! ๐ŸŒˆ

Yap, HydroTrack doing all that without being extra.


Desain UI yang Bikin Betah ๐ŸŽจ

Gue gaspolin dikit ya soal desainnya, soalnya ini worth it banget dibahas:

1. Warna-warna Pastel & Gradient yang Eye Candy ๐Ÿฌ
App ini pilih warna biru, ungu, cyan—kayak lihat langit senja tapi di HP. Smooth banget gradiennya, kayak liquid effect. Bikin mata adem, terus pengen minum air. Mission passed, respect! ๐Ÿ‘

2. Animasi Air yang Ngalir & Gelembung-gelembung ๐Ÿ’ฆ
Background-nya ada wave animation yang geraknya pelan-pelan, plus gelembung air yang naik turun. Kecil tapi impactful—bikin app feel alive dan nggak monoton.

3. Tombol-tombol Cuy! Yang Bikin Pengen Di-klik ๐Ÿ”ฅ
Tombol Google, Facebook, Apple—warnanya vibrant, shadow-nya subtle, dan bentuknya rounded. Kelihatan premium tapi tetap funky.

4. Input Fields yang Clean Tapi Colorful ๐ŸŽฏ
Tempat isi nama, email, password—di sini dikasih sentuhan gradient border dan icon warna-warni. Biasa kan formnya boring? Nah, ini nggak!


Fitur-fitur yang Bikin Lo Gamau Uninstall ๐Ÿ“ฒ

  • Auto Tracking: Lo cuma input berapa gelas yang diminum, nanti app hitung sendiri progressnya.

  • Custom Reminder: Bisa set waktu notif sesuai jadwal lo. Mau dikirimin notif pas lagi meeting? Sure thing!

  • Weekly Report: Lo bisa liat progress hydrasi lo dalam bentuk grafik yang easy to understand.

  • Reward System: Kalo lo berhasil mencapai target, dapetin badge atau icon lucu. Siapa yang nggak suka dikasih reward? ๐Ÿ˜


Why HydroTrack Is So Gen Z? ๐Ÿค

  1. Visual Over Everything—Desainnya Instagrammable, bisa jadi konten TikTok atau story WhatsApp.

  2. Ga Ribet—Cukup input data sekali, terus tinggal pantau progress. No complicated steps!

  3. Fun & Functional—Ada element game-like (progress bar, reward) yang bikin lo engaged.

  4. Relatable—Bukan cuma buat olahragawan atau fitness freak, tapi buat semua orang yang suka lupa minum—which is most of us.



Untuk codenya bisa dicheck di sini ya bro:

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;
}

Kesimpulan: Should You Try It? ๐Ÿ’‍♂️

Gue kasih rating:

  • Fungsi: 9/10 — works like a charm.

  • Desain: 10/10 — mood booster.

  • Kepraktisan: 10/10 — nggak makan storage, nggak bikin pusing.

Jadi, kalo lo:

  • Suka lupa minum air padahal udah diemin botol di meja.

  • Pengen punya hydration tracker yang aesthetically pleasing.

  • Mau punya alasan buat screenshot trus dikirim ke pacar/gebetan ๐Ÿ˜…

HydroTrack is for you!

Coba deh, dan thank me later. Tubuh lo bakal lebih segar, kulit makin glowing, dan lo akhirnya nggak deh dikatain "kok kering?" ๐Ÿ˜‚

Made By: Reihan Novalendra H XI RPL 2



Gue tantang lo:
Coba HydroTrack hari ini, set target 3 hari berturut-turut—and see if you feel the difference! ✌️

Btw, lo punya app favorite buat health tracking? Share di comments! ๐Ÿ‘‡


Komentar

Postingan populer dari blog ini

๐Ÿš€ Bikin Aplikasi Jadwal Penerbangan Offline Keren dengan Flutter Web (Pakai zapp.run) ✈️

Jenis jenis sistem operasi mobile