diff --git a/README.md b/README.md index ad8462f..fe0072f 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,39 @@ -# apskel_owner_flutter +# Apskel Owner App -A new Flutter project. +A Flutter-based Point of Sale (POS) application designed specifically for business owners. +Helps manage sales, products, inventory, and business reports in real-time with a simple, easy-to-use interface. -## Getting Started +## ๐Ÿš€ Getting Started -This project is a starting point for a Flutter application. +### โœ… Prerequisites -A few resources to get you started if this is your first Flutter project: +- [Flutter](https://flutter.dev/docs/get-started/install) 3.32.8 or newer +- Dart 3.8.1 or newer -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) +### ๐Ÿ›  Installation -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +```bash +git clone https://github.com/efrilm/frl-movie.git +``` + +```bash +cd app-path +``` + +```bash +flutter pub get +``` + +```bash +flutter pub run build_runner build --delete-conflicting-outputs +``` + +--- + +## ๐Ÿงช Running + +```bash +flutter run +``` + +--- diff --git a/analysis_options.yaml b/analysis_options.yaml index c4d2cef..1d331a6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -13,6 +13,7 @@ analyzer: sort_unnamed_constructors_first: ignore invalid_annotation_target: ignore use_build_context_synchronously: ignore + deprecated_member_use: ignore exclude: - test/generated/** - "**/**.g.dart" diff --git a/lib/common/theme/app_color.dart b/lib/common/theme/app_color.dart index 63dd90f..c2b1798 100644 --- a/lib/common/theme/app_color.dart +++ b/lib/common/theme/app_color.dart @@ -1,5 +1,66 @@ part of 'theme.dart'; class AppColor { - // TODO: define color + // Primary Colors + static const Color primary = Color(0xFF36175e); + static const Color primaryLight = Color(0xFF5a2d85); + static const Color primaryDark = Color(0xFF1e0d35); + + // Secondary Colors + static const Color secondary = Color(0xFF4CAF50); + static const Color secondaryLight = Color(0xFF81C784); + static const Color secondaryDark = Color(0xFF388E3C); + + // Background Colors + static const Color background = Color(0xFFF5F5F5); + static const Color backgroundLight = Color(0xFFFFFFFF); + static const Color backgroundDark = Color(0xFF1A1A1A); + static const Color surface = Color(0xFFFFFFFF); + static const Color surfaceDark = Color(0xFF2D2D2D); + + // Text Colors + static const Color textPrimary = Color(0xFF212121); + static const Color textSecondary = Color(0xFF757575); + static const Color textLight = Color(0xFFBDBDBD); + static const Color textWhite = Color(0xFFFFFFFF); + + // Status Colors + static const Color success = Color(0xFF4CAF50); + static const Color error = Color(0xFFE53E3E); + static const Color warning = Color(0xFFFF9800); + static const Color info = Color(0xFF2196F3); + + // Border Colors + static const Color border = Color(0xFFE0E0E0); + static const Color borderLight = Color(0xFFF0F0F0); + static const Color borderDark = Color(0xFFBDBDBD); + + // Basic Color + static const Color white = Color(0xFFFFFFFF); + static const Color black = Color(0xFF000000); + + // Gradient Colors + static const List primaryGradient = [ + Color(0xFF36175e), + Color(0xFF5a2d85), + ]; + + static const List successGradient = [ + Color(0xFF4CAF50), + Color(0xFF81C784), + ]; + + static const List backgroundGradient = [ + Color(0xFFF5F5F5), + Color(0xFFE8E8E8), + ]; + + // Opacity Variations + static Color primaryWithOpacity(double opacity) => + primary.withOpacity(opacity); + static Color successWithOpacity(double opacity) => + success.withOpacity(opacity); + static Color errorWithOpacity(double opacity) => error.withOpacity(opacity); + static Color warningWithOpacity(double opacity) => + warning.withOpacity(opacity); } diff --git a/lib/common/theme/app_style.dart b/lib/common/theme/app_style.dart index 5c422cc..822a346 100644 --- a/lib/common/theme/app_style.dart +++ b/lib/common/theme/app_style.dart @@ -1,5 +1,27 @@ part of 'theme.dart'; class AppStyle { - // TODO: define style + static TextStyle xs = TextStyle(color: AppColor.textPrimary, fontSize: 11); + + static TextStyle sm = TextStyle(color: AppColor.textPrimary, fontSize: 12); + + static TextStyle md = TextStyle(color: AppColor.textPrimary, fontSize: 14); + + static TextStyle lg = TextStyle(color: AppColor.textPrimary, fontSize: 18); + + static TextStyle xl = TextStyle(color: AppColor.textPrimary, fontSize: 20); + + static TextStyle xxl = TextStyle(color: AppColor.textPrimary, fontSize: 22); + + static TextStyle h6 = TextStyle(color: AppColor.textPrimary, fontSize: 24); + + static TextStyle h5 = TextStyle(color: AppColor.textPrimary, fontSize: 26); + + static TextStyle h4 = TextStyle(color: AppColor.textPrimary, fontSize: 28); + + static TextStyle h3 = TextStyle(color: AppColor.textPrimary, fontSize: 30); + + static TextStyle h2 = TextStyle(color: AppColor.textPrimary, fontSize: 32); + + static TextStyle h1 = TextStyle(color: AppColor.textPrimary, fontSize: 34); } diff --git a/lib/common/theme/app_value.dart b/lib/common/theme/app_value.dart index d76dbcc..1a2d8d8 100644 --- a/lib/common/theme/app_value.dart +++ b/lib/common/theme/app_value.dart @@ -1,5 +1,7 @@ part of 'theme.dart'; class AppValue { - // TODO: define value + static const double padding = 16.0; + static const double radius = 8.0; + static const double elevation = 4.0; } diff --git a/lib/presentation/pages/splash_page.dart b/lib/presentation/pages/splash_page.dart index 12c890a..f838bf4 100644 --- a/lib/presentation/pages/splash_page.dart +++ b/lib/presentation/pages/splash_page.dart @@ -1,6 +1,9 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; +import '../../common/theme/theme.dart'; +import '../components/assets/assets.gen.dart'; + @RoutePage() class SplashPage extends StatefulWidget { const SplashPage({super.key}); @@ -9,12 +12,160 @@ class SplashPage extends StatefulWidget { State createState() => _SplashPageState(); } -class _SplashPageState extends State { +class _SplashPageState extends State with TickerProviderStateMixin { + late AnimationController _logoController; + late AnimationController _versionController; + late AnimationController _backgroundController; + + late Animation _logoAnimation; + late Animation _versionAnimation; + late Animation _backgroundAnimation; + + @override + void initState() { + super.initState(); + + // Initialize animation controllers + _logoController = AnimationController( + duration: const Duration(milliseconds: 1200), + vsync: this, + ); + + _versionController = AnimationController( + duration: const Duration(milliseconds: 800), + vsync: this, + ); + + _backgroundController = AnimationController( + duration: const Duration(milliseconds: 1500), + vsync: this, + ); + + // Create animations + _logoAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _logoController, curve: Curves.elasticOut), + ); + + _versionAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _versionController, curve: Curves.easeInOut), + ); + + _backgroundAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _backgroundController, curve: Curves.easeInOut), + ); + + // Start animations + _startAnimations(); + } + + void _startAnimations() async { + // Start background animation immediately + _backgroundController.forward(); + + // Wait a bit, then start logo animation + await Future.delayed(const Duration(milliseconds: 300)); + if (mounted) _logoController.forward(); + + // Start version animation after logo starts + await Future.delayed(const Duration(milliseconds: 600)); + if (mounted) _versionController.forward(); + + // Navigate to home screen after all animations complete + await Future.delayed(const Duration(milliseconds: 2000)); + if (mounted) { + _navigateToHome(); + } + } + + void _navigateToHome() { + // Uncomment dan sesuaikan dengan route yang ada + // context.router.replace(const HomeRoute()); + } + + @override + void dispose() { + _logoController.dispose(); + _versionController.dispose(); + _backgroundController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( - body: Center( - child: Text("Splash Page"), + body: AnimatedBuilder( + animation: Listenable.merge([ + _logoController, + _versionController, + _backgroundController, + ]), + builder: (context, child) { + // Clamp values to prevent opacity errors + final logoOpacity = _logoAnimation.value.clamp(0.0, 1.0); + final versionOpacity = _versionAnimation.value.clamp(0.0, 1.0); + final backgroundOpacity = _backgroundAnimation.value.clamp(0.0, 1.0); + + return Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + AppColor.primaryWithOpacity(backgroundOpacity), + AppColor.primaryWithOpacity(backgroundOpacity * 0.8), + ], + ), + ), + child: Stack( + children: [ + // Logo di tengah + Center( + child: Transform.scale( + scale: logoOpacity, + child: Opacity( + opacity: logoOpacity, + child: Container( + width: 150, + height: 150, + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 30, + offset: const Offset(0, 15), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(AppValue.radius), + child: Assets.images.logo.image(fit: BoxFit.cover), + ), + ), + ), + ), + ), + + // Version di bagian bawah + Positioned( + bottom: 60, + left: 0, + right: 0, + child: Transform.translate( + offset: Offset(0, 20 * (1 - versionOpacity)), + child: Opacity( + opacity: versionOpacity, + child: Text( + 'Version 1.0.0', + style: AppStyle.md.copyWith(color: AppColor.textLight), + textAlign: TextAlign.center, + ), + ), + ), + ), + ], + ), + ); + }, ), ); }