feat: custom appbar

This commit is contained in:
efrilm 2025-08-16 00:39:09 +07:00
parent d334bb8f17
commit d73cd1a574
16 changed files with 207 additions and 1062 deletions

View File

@ -0,0 +1,189 @@
import 'package:flutter/material.dart';
import 'dart:math' as math;
import '../../../../common/theme/theme.dart';
import '../../../common/painter/wave_painter.dart';
class CustomAppBar extends StatefulWidget {
final String title;
final bool isBack;
const CustomAppBar({super.key, required this.title, this.isBack = true});
@override
State<CustomAppBar> createState() => _CustomAppBarState();
}
class _CustomAppBarState extends State<CustomAppBar>
with TickerProviderStateMixin {
late AnimationController _particleController;
late AnimationController _waveController;
late AnimationController _breathController;
late Animation<double> _particleAnimation;
late Animation<double> _waveAnimation;
late Animation<double> _breathAnimation;
@override
void initState() {
super.initState();
_particleController = AnimationController(
duration: const Duration(seconds: 8),
vsync: this,
)..repeat();
_waveController = AnimationController(
duration: const Duration(seconds: 6),
vsync: this,
)..repeat();
_breathController = AnimationController(
duration: const Duration(seconds: 4),
vsync: this,
)..repeat(reverse: true);
_particleAnimation = Tween<double>(
begin: 0.0,
end: 2 * math.pi,
).animate(_particleController);
_waveAnimation = Tween<double>(
begin: 0.0,
end: 2 * math.pi,
).animate(_waveController);
_breathAnimation = Tween<double>(begin: 0.8, end: 1.2).animate(
CurvedAnimation(parent: _breathController, curve: Curves.easeInOut),
);
}
@override
void dispose() {
_particleController.dispose();
_waveController.dispose();
_breathController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: EdgeInsets.only(left: widget.isBack ? 50 : 20, bottom: 16),
title: Text(
widget.title,
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: AnimatedBuilder(
animation: Listenable.merge([
_particleController,
_waveController,
_breathController,
]),
builder: (context, child) {
return Stack(
children: [
// Animated background elements
_buildAnimatedBackground(context),
],
);
},
),
),
);
}
Widget _buildAnimatedBackground(BuildContext context) {
final size = MediaQuery.of(context).size;
return Stack(
children: [
// Floating particles with orbital motion
...List.generate(8, (index) {
final double radius = 40 + (index * 15);
final double angle = _particleAnimation.value + (index * 0.8);
final double centerX = size.width * 0.7;
final double centerY = 60;
return Positioned(
left: centerX + math.cos(angle) * radius - 3,
top: centerY + math.sin(angle) * (radius * 0.5) - 3,
child: Transform.scale(
scale: _breathAnimation.value * 0.5,
child: Container(
width: 4 + (index % 3),
height: 4 + (index % 3),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.textWhite.withOpacity(0.6),
boxShadow: [
BoxShadow(
color: AppColor.textWhite.withOpacity(0.3),
blurRadius: 6,
spreadRadius: 1,
),
],
),
),
),
);
}),
// Wave patterns
Positioned.fill(
child: CustomPaint(
painter: WavePainter(
animation: _waveAnimation.value,
color: AppColor.textWhite.withOpacity(0.1),
),
),
),
// Sparkle effects
...List.generate(4, (index) {
return Positioned(
left: (index * 90.0) % size.width,
top: 20 + (index * 25.0),
child: Transform.rotate(
angle: _particleAnimation.value * 2 + index,
child: Transform.scale(
scale: math.sin(_particleAnimation.value + index) * 0.5 + 1,
child: Icon(
Icons.auto_awesome,
size: 10 + (index % 3) * 3,
color: AppColor.textWhite.withOpacity(0.4),
),
),
),
);
}),
// Gradient overlay for depth
Container(
decoration: BoxDecoration(
gradient: RadialGradient(
center: const Alignment(0.3, -0.2),
radius: 1.2,
colors: [
Colors.transparent,
AppColor.primaryGradient.first.withOpacity(0.1),
Colors.transparent,
],
),
),
),
],
);
}
}

View File

@ -1,11 +1,10 @@
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 'package:line_icons/line_icons.dart'; import 'package:line_icons/line_icons.dart';
import 'dart:math' as math;
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart'; import '../../components/button/button.dart';
import 'widgets/appbar.dart';
import 'widgets/customer_card.dart'; import 'widgets/customer_card.dart';
import 'widgets/customer_tile.dart'; import 'widgets/customer_tile.dart';
@ -102,27 +101,14 @@ class _CustomerPageState extends State<CustomerPage>
), ),
]; ];
// Animation
late AnimationController _rotationController;
late Animation<double> _rotationAnimation;
@override @override
initState() { initState() {
super.initState(); super.initState();
_rotationController = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
)..repeat();
_rotationAnimation = Tween<double>(
begin: 0,
end: 2 * math.pi,
).animate(_rotationController);
} }
@override @override
void dispose() { void dispose() {
_searchController.dispose(); _searchController.dispose();
_rotationController.dispose();
super.dispose(); super.dispose();
} }
@ -151,9 +137,7 @@ class _CustomerPageState extends State<CustomerPage>
floating: false, floating: false,
pinned: true, pinned: true,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
flexibleSpace: CustomerAppbar( flexibleSpace: CustomAppBar(title: 'Pelanggan'),
rotationAnimation: _rotationAnimation,
),
actions: [ActionIconButton(onTap: () {}, icon: LineIcons.search)], actions: [ActionIconButton(onTap: () {}, icon: LineIcons.search)],
), ),

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart'; import 'package:line_icons/line_icons.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import 'widgets/appbar.dart'; import '../../components/appbar/appbar.dart';
import 'widgets/cash_flow.dart'; import 'widgets/cash_flow.dart';
import 'widgets/category.dart'; import 'widgets/category.dart';
import 'widgets/profit_loss.dart'; import 'widgets/profit_loss.dart';
@ -22,14 +22,10 @@ class _FinancePageState extends State<FinancePage>
late AnimationController _slideController; late AnimationController _slideController;
late AnimationController _fadeController; late AnimationController _fadeController;
late AnimationController _scaleController; late AnimationController _scaleController;
late AnimationController _rotationController;
late AnimationController _floatingController;
late Animation<Offset> _slideAnimation; late Animation<Offset> _slideAnimation;
late Animation<double> _fadeAnimation; late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation; late Animation<double> _scaleAnimation;
late Animation<double> rotationAnimation;
late Animation<double> floatingAnimation;
String selectedPeriod = 'Hari ini'; String selectedPeriod = 'Hari ini';
final List<String> periods = [ final List<String> periods = [
@ -43,16 +39,6 @@ class _FinancePageState extends State<FinancePage>
void initState() { void initState() {
super.initState(); super.initState();
rotationAnimation = AnimationController(
duration: const Duration(seconds: 20),
vsync: this,
)..repeat();
floatingAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
)..repeat(reverse: true);
_slideController = AnimationController( _slideController = AnimationController(
duration: const Duration(milliseconds: 800), duration: const Duration(milliseconds: 800),
vsync: this, vsync: this,
@ -97,8 +83,6 @@ class _FinancePageState extends State<FinancePage>
_slideController.dispose(); _slideController.dispose();
_fadeController.dispose(); _fadeController.dispose();
_scaleController.dispose(); _scaleController.dispose();
_rotationController.dispose();
_floatingController.dispose();
super.dispose(); super.dispose();
} }
@ -115,10 +99,7 @@ class _FinancePageState extends State<FinancePage>
pinned: true, pinned: true,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
elevation: 0, elevation: 0,
flexibleSpace: FinanceAppbar( flexibleSpace: CustomAppBar(title: 'Keuangan'),
rotationAnimation: rotationAnimation,
floatingAnimation: floatingAnimation,
),
), ),
// Header dengan filter periode // Header dengan filter periode

View File

@ -1,201 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class FinanceAppbar extends StatelessWidget {
const FinanceAppbar({
super.key,
required this.rotationAnimation,
required this.floatingAnimation,
});
final Animation<double> rotationAnimation;
final Animation<double> floatingAnimation;
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 50, bottom: 16),
title: Text(
'Keuangan',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
// Animated geometric shapes
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: Listenable.merge([
rotationAnimation,
floatingAnimation,
]),
builder: (context, child) {
return Transform.translate(
offset: Offset(
floatingAnimation.value * 10,
floatingAnimation.value * 15,
),
child: Transform.rotate(
angle: rotationAnimation.value * 2 * 3.14159,
child: Container(
width: 120,
height: 120,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
AppColor.white.withOpacity(0.15),
AppColor.white.withOpacity(0.05),
],
),
boxShadow: [
BoxShadow(
color: AppColor.white.withOpacity(0.1),
blurRadius: 20,
spreadRadius: 5,
),
],
),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: Listenable.merge([
rotationAnimation,
floatingAnimation,
]),
builder: (context, child) {
return Transform.translate(
offset: Offset(
-floatingAnimation.value * 8,
-floatingAnimation.value * 12,
),
child: Transform.rotate(
angle: -rotationAnimation.value * 0.5 * 3.14159,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
AppColor.white.withOpacity(0.1),
AppColor.white.withOpacity(0.02),
],
),
),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: Listenable.merge([
rotationAnimation,
floatingAnimation,
]),
builder: (context, child) {
return Transform.translate(
offset: Offset(
floatingAnimation.value * 5,
-floatingAnimation.value * 8,
),
child: Transform.rotate(
angle: -rotationAnimation.value * 0.3 * 3.14159,
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
gradient: LinearGradient(
colors: [
AppColor.white.withOpacity(0.12),
AppColor.white.withOpacity(0.04),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
),
);
},
),
),
// Additional floating elements
Positioned(
left: 60,
top: 80,
child: AnimatedBuilder(
animation: floatingAnimation,
builder: (context, child) {
return Transform.translate(
offset: Offset(
floatingAnimation.value * 3,
floatingAnimation.value * 6,
),
child: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.08),
),
),
);
},
),
),
Positioned(
right: 40,
top: 120,
child: AnimatedBuilder(
animation: floatingAnimation,
builder: (context, child) {
return Transform.translate(
offset: Offset(
-floatingAnimation.value * 4,
floatingAnimation.value * 7,
),
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: AppColor.white.withOpacity(0.06),
),
),
);
},
),
),
],
),
),
);
}
}

View File

@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import 'widgets/appbar.dart'; import '../../components/appbar/appbar.dart';
import 'widgets/ingredient_tile.dart'; import 'widgets/ingredient_tile.dart';
import 'widgets/product_tile.dart'; import 'widgets/product_tile.dart';
import 'widgets/stat_card.dart'; import 'widgets/stat_card.dart';
@ -64,10 +64,8 @@ class _InventoryPageState extends State<InventoryPage>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late AnimationController _fadeAnimationController; late AnimationController _fadeAnimationController;
late AnimationController _slideAnimationController; late AnimationController _slideAnimationController;
late AnimationController _rotationAnimationController;
late Animation<double> _fadeAnimation; late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation; late Animation<Offset> _slideAnimation;
late Animation<double> rotationAnimation;
late TabController _tabController; late TabController _tabController;
final List<ProductItem> productItems = [ final List<ProductItem> productItems = [
@ -188,10 +186,6 @@ class _InventoryPageState extends State<InventoryPage>
duration: const Duration(milliseconds: 800), duration: const Duration(milliseconds: 800),
vsync: this, vsync: this,
); );
_rotationAnimationController = AnimationController(
duration: const Duration(seconds: 20),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate( _fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation( CurvedAnimation(
@ -208,21 +202,14 @@ class _InventoryPageState extends State<InventoryPage>
), ),
); );
rotationAnimation = Tween<double>(
begin: 0.0,
end: 2 * 3.14159,
).animate(_rotationAnimationController);
_fadeAnimationController.forward(); _fadeAnimationController.forward();
_slideAnimationController.forward(); _slideAnimationController.forward();
_rotationAnimationController.repeat();
} }
@override @override
void dispose() { void dispose() {
_fadeAnimationController.dispose(); _fadeAnimationController.dispose();
_slideAnimationController.dispose(); _slideAnimationController.dispose();
_rotationAnimationController.dispose();
_tabController.dispose(); _tabController.dispose();
super.dispose(); super.dispose();
} }
@ -356,7 +343,7 @@ class _InventoryPageState extends State<InventoryPage>
pinned: true, pinned: true,
elevation: 0, elevation: 0,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
flexibleSpace: InventoryAppBar(rotationAnimation: rotationAnimation), flexibleSpace: CustomAppBar(title: 'Inventaris'),
); );
} }

View File

@ -1,96 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class InventoryAppBar extends StatelessWidget {
const InventoryAppBar({super.key, required this.rotationAnimation});
final Animation<double> rotationAnimation;
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 50, bottom: 16),
title: Text(
'Inventaris',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: rotationAnimation.value,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.textWhite.withOpacity(0.1),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.5,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.textWhite.withOpacity(0.05),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.2,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: AppColor.textWhite.withOpacity(0.08),
),
),
);
},
),
),
],
),
),
);
}
}

View File

@ -1,12 +1,10 @@
import 'dart:math' as math;
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 'package:line_icons/line_icons.dart'; import 'package:line_icons/line_icons.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart'; import '../../components/button/button.dart';
import 'widgets/appbar.dart';
import 'widgets/category_delegate.dart'; import 'widgets/category_delegate.dart';
import 'widgets/product_tile.dart'; import 'widgets/product_tile.dart';
@ -26,10 +24,6 @@ class _ProductPageState extends State<ProductPage>
List<String> categories = ['Semua', 'Makanan', 'Minuman', 'Snack', 'Dessert']; List<String> categories = ['Semua', 'Makanan', 'Minuman', 'Snack', 'Dessert'];
ViewType currentViewType = ViewType.grid; ViewType currentViewType = ViewType.grid;
// Animation
late AnimationController _rotationController;
late Animation<double> _rotationAnimation;
// Sample product data // Sample product data
List<Product> products = [ List<Product> products = [
Product( Product(
@ -135,19 +129,10 @@ class _ProductPageState extends State<ProductPage>
@override @override
initState() { initState() {
super.initState(); super.initState();
_rotationController = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
)..repeat();
_rotationAnimation = Tween<double>(
begin: 0,
end: 2 * math.pi,
).animate(_rotationController);
} }
@override @override
void dispose() { void dispose() {
_rotationController.dispose();
super.dispose(); super.dispose();
} }
@ -172,7 +157,7 @@ class _ProductPageState extends State<ProductPage>
floating: false, floating: false,
pinned: true, pinned: true,
elevation: 0, elevation: 0,
flexibleSpace: ProductAppbar(rotationAnimation: _rotationAnimation), flexibleSpace: CustomAppBar(title: 'Produk'),
actions: [ actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.search), ActionIconButton(onTap: () {}, icon: LineIcons.search),
ActionIconButton(onTap: _showAddProductDialog, icon: LineIcons.plus), ActionIconButton(onTap: _showAddProductDialog, icon: LineIcons.plus),

View File

@ -1,96 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class ProductAppbar extends StatelessWidget {
final Animation<double> rotationAnimation;
const ProductAppbar({super.key, required this.rotationAnimation});
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 50, bottom: 16),
title: Text(
'Produk',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: rotationAnimation.value,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.1),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.5,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.05),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.2,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: AppColor.white.withOpacity(0.08),
),
),
);
},
),
),
],
),
),
);
}
}

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:line_icons/line_icons.dart'; import 'package:line_icons/line_icons.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import 'widgets/appbar.dart'; import '../../components/appbar/appbar.dart';
import 'widgets/purchase_tile.dart'; import 'widgets/purchase_tile.dart';
import 'widgets/stat_card.dart'; import 'widgets/stat_card.dart';
import 'widgets/status_chip.dart'; import 'widgets/status_chip.dart';
@ -18,9 +18,7 @@ class PurchasePage extends StatefulWidget {
class _PurchasePageState extends State<PurchasePage> class _PurchasePageState extends State<PurchasePage>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late AnimationController rotationAnimation;
late AnimationController cardAnimation; late AnimationController cardAnimation;
late AnimationController floatingAnimation;
String selectedFilter = 'Semua'; String selectedFilter = 'Semua';
final List<String> filterOptions = [ final List<String> filterOptions = [
'Semua', 'Semua',
@ -67,29 +65,18 @@ class _PurchasePageState extends State<PurchasePage>
@override @override
void initState() { void initState() {
super.initState(); super.initState();
rotationAnimation = AnimationController(
duration: const Duration(seconds: 20),
vsync: this,
)..repeat();
cardAnimation = AnimationController( cardAnimation = AnimationController(
duration: const Duration(milliseconds: 1200), duration: const Duration(milliseconds: 1200),
vsync: this, vsync: this,
); );
floatingAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
)..repeat(reverse: true);
cardAnimation.forward(); cardAnimation.forward();
} }
@override @override
void dispose() { void dispose() {
rotationAnimation.dispose();
cardAnimation.dispose(); cardAnimation.dispose();
floatingAnimation.dispose();
super.dispose(); super.dispose();
} }
@ -106,10 +93,7 @@ class _PurchasePageState extends State<PurchasePage>
elevation: 0, elevation: 0,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
flexibleSpace: PurchaseAppbar( flexibleSpace: CustomAppBar(title: 'Pembelian'),
rotationAnimation: rotationAnimation,
floatingAnimation: floatingAnimation,
),
), ),
// Stats Cards // Stats Cards

View File

@ -1,201 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class PurchaseAppbar extends StatelessWidget {
const PurchaseAppbar({
super.key,
required this.rotationAnimation,
required this.floatingAnimation,
});
final AnimationController rotationAnimation;
final AnimationController floatingAnimation;
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 50, bottom: 16),
title: Text(
'Pembelian',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
// Animated geometric shapes with enhanced effects
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: Listenable.merge([
rotationAnimation,
floatingAnimation,
]),
builder: (context, child) {
return Transform.translate(
offset: Offset(
floatingAnimation.value * 10,
floatingAnimation.value * 15,
),
child: Transform.rotate(
angle: rotationAnimation.value * 2 * 3.14159,
child: Container(
width: 120,
height: 120,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
AppColor.white.withOpacity(0.15),
AppColor.white.withOpacity(0.05),
],
),
boxShadow: [
BoxShadow(
color: AppColor.white.withOpacity(0.1),
blurRadius: 20,
spreadRadius: 5,
),
],
),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: Listenable.merge([
rotationAnimation,
floatingAnimation,
]),
builder: (context, child) {
return Transform.translate(
offset: Offset(
-floatingAnimation.value * 8,
-floatingAnimation.value * 12,
),
child: Transform.rotate(
angle: -rotationAnimation.value * 0.5 * 3.14159,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
AppColor.white.withOpacity(0.1),
AppColor.white.withOpacity(0.02),
],
),
),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: Listenable.merge([
rotationAnimation,
floatingAnimation,
]),
builder: (context, child) {
return Transform.translate(
offset: Offset(
floatingAnimation.value * 5,
-floatingAnimation.value * 8,
),
child: Transform.rotate(
angle: -rotationAnimation.value * 0.3 * 3.14159,
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
gradient: LinearGradient(
colors: [
AppColor.white.withOpacity(0.12),
AppColor.white.withOpacity(0.04),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
),
);
},
),
),
// Additional floating elements
Positioned(
left: 60,
top: 80,
child: AnimatedBuilder(
animation: floatingAnimation,
builder: (context, child) {
return Transform.translate(
offset: Offset(
floatingAnimation.value * 3,
floatingAnimation.value * 6,
),
child: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.08),
),
),
);
},
),
),
Positioned(
right: 40,
top: 120,
child: AnimatedBuilder(
animation: floatingAnimation,
builder: (context, child) {
return Transform.translate(
offset: Offset(
-floatingAnimation.value * 4,
floatingAnimation.value * 7,
),
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: AppColor.white.withOpacity(0.06),
),
),
);
},
),
),
],
),
),
);
}
}

View File

@ -4,9 +4,9 @@ import 'package:line_icons/line_icons.dart';
import 'dart:math' as math; import 'dart:math' as math;
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart'; import '../../components/button/button.dart';
import '../../components/spacer/spacer.dart'; import '../../components/spacer/spacer.dart';
import 'widgets/appbar.dart';
import 'widgets/quick_stats.dart'; import 'widgets/quick_stats.dart';
import 'widgets/report_action.dart'; import 'widgets/report_action.dart';
import 'widgets/revenue_summary.dart'; import 'widgets/revenue_summary.dart';
@ -80,14 +80,13 @@ class _ReportPageState extends State<ReportPage> with TickerProviderStateMixin {
backgroundColor: AppColor.background, backgroundColor: AppColor.background,
body: CustomScrollView( body: CustomScrollView(
slivers: [ slivers: [
// Custom App Bar with Hero Effect
SliverAppBar( SliverAppBar(
expandedHeight: 120, expandedHeight: 120,
floating: false, floating: false,
pinned: true, pinned: true,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
centerTitle: false, centerTitle: false,
flexibleSpace: ReportAppBar(rotationAnimation: _rotationAnimation), flexibleSpace: CustomAppBar(title: 'Laporan', isBack: false),
actions: [ actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.download), ActionIconButton(onTap: () {}, icon: LineIcons.download),
ActionIconButton(onTap: () {}, icon: LineIcons.filter), ActionIconButton(onTap: () {}, icon: LineIcons.filter),

View File

@ -1,96 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class ReportAppBar extends StatelessWidget {
final Animation<double> rotationAnimation;
const ReportAppBar({super.key, required this.rotationAnimation});
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 20, bottom: 16),
title: Text(
'Laporan Bisnis',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: rotationAnimation.value,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.1),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.5,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.05),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.2,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: AppColor.white.withOpacity(0.08),
),
),
);
},
),
),
],
),
),
);
}
}

View File

@ -2,8 +2,8 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/spacer/spacer.dart'; import '../../components/spacer/spacer.dart';
import 'widgets/appbar.dart';
import 'widgets/summary_card.dart'; import 'widgets/summary_card.dart';
// Data Models // Data Models
@ -70,9 +70,6 @@ class SalesPage extends StatefulWidget {
} }
class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin { class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
late AnimationController rotationAnimationController;
late Animation<double> rotationAnimation;
late AnimationController slideAnimationController; late AnimationController slideAnimationController;
late Animation<Offset> slideAnimation; late Animation<Offset> slideAnimation;
@ -82,23 +79,6 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
void initState() { void initState() {
super.initState(); super.initState();
// Rotation Animation
rotationAnimationController = AnimationController(
duration: const Duration(seconds: 20),
vsync: this,
);
rotationAnimation =
Tween<double>(
begin: 0,
end: 6.28, // 2 * PI
).animate(
CurvedAnimation(
parent: rotationAnimationController,
curve: Curves.linear,
),
);
rotationAnimationController.repeat();
// Slide Animation // Slide Animation
slideAnimationController = AnimationController( slideAnimationController = AnimationController(
duration: const Duration(milliseconds: 800), duration: const Duration(milliseconds: 800),
@ -130,7 +110,6 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
@override @override
void dispose() { void dispose() {
rotationAnimationController.dispose();
slideAnimationController.dispose(); slideAnimationController.dispose();
fadeAnimationController.dispose(); fadeAnimationController.dispose();
super.dispose(); super.dispose();
@ -187,7 +166,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
floating: false, floating: false,
pinned: true, pinned: true,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
flexibleSpace: SalesAppbar(rotationAnimation: rotationAnimation), flexibleSpace: CustomAppBar(title: 'Penjualan'),
), ),
// Date Range Header // Date Range Header

View File

@ -1,96 +0,0 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class SalesAppbar extends StatelessWidget {
const SalesAppbar({super.key, required this.rotationAnimation});
final Animation<double> rotationAnimation;
@override
Widget build(BuildContext context) {
return FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 50, bottom: 16),
title: Text(
'Penjualan',
style: AppStyle.xl.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: rotationAnimation.value,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.1),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.5,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.05),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.2,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: AppColor.white.withOpacity(0.08),
),
),
);
},
),
),
],
),
),
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
// Schedule model dengan optimasi // Schedule model dengan optimasi
class Schedule { class Schedule {
@ -212,107 +213,7 @@ class _SchedulePageState extends State<SchedulePage>
floating: false, floating: false,
pinned: true, pinned: true,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
actions: [ flexibleSpace: CustomAppBar(title: 'Jadwal'),
Container(
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColor.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: IconButton(
onPressed: () => _showCalendarOptions(),
icon: Icon(
Icons.calendar_view_week,
color: AppColor.white,
size: 24,
),
),
),
],
flexibleSpace: FlexibleSpaceBar(
titlePadding: const EdgeInsets.only(left: 50, bottom: 16),
title: Text(
'My Schedule',
style: TextStyle(
color: AppColor.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
background: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [AppColor.primary, AppColor.primary.withOpacity(0.8)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: rotationAnimation.value,
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.1),
),
),
);
},
),
),
Positioned(
left: -30,
bottom: -30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.5,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.white.withOpacity(0.05),
),
),
);
},
),
),
Positioned(
right: 80,
bottom: 30,
child: AnimatedBuilder(
animation: rotationAnimation,
builder: (context, child) {
return Transform.rotate(
angle: -rotationAnimation.value * 0.2,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: AppColor.white.withOpacity(0.08),
),
),
);
},
),
),
],
),
),
),
); );
} }
@ -639,47 +540,6 @@ class _SchedulePageState extends State<SchedulePage>
_slideController.forward(); _slideController.forward();
} }
void _showCalendarOptions() {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (context) => Container(
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
margin: const EdgeInsets.only(top: 12),
width: 40,
height: 4,
decoration: BoxDecoration(
color: AppColor.border,
borderRadius: BorderRadius.circular(2),
),
),
Padding(
padding: const EdgeInsets.all(24),
child: Text(
'Calendar Options',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
color: AppColor.textPrimary,
),
),
),
],
),
),
);
}
void _showModernScheduleDetails(Schedule schedule) { void _showModernScheduleDetails(Schedule schedule) {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,

View File

@ -1,13 +1,11 @@
import 'dart:math' as math;
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 'package:line_icons/line_icons.dart'; import 'package:line_icons/line_icons.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart'; import '../../components/button/button.dart';
import '../../components/spacer/spacer.dart'; import '../../components/spacer/spacer.dart';
import 'widgets/appbar.dart';
import 'widgets/status_tile.dart'; import 'widgets/status_tile.dart';
import 'widgets/transaction_tile.dart'; import 'widgets/transaction_tile.dart';
@ -23,10 +21,8 @@ class _TransactionPageState extends State<TransactionPage>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late AnimationController _fadeController; late AnimationController _fadeController;
late AnimationController _slideController; late AnimationController _slideController;
late AnimationController _rotationController;
late Animation<double> _fadeAnimation; late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation; late Animation<Offset> _slideAnimation;
late Animation<double> _rotationAnimation;
// Filter state // Filter state
String selectedFilter = 'All'; String selectedFilter = 'All';
@ -51,11 +47,6 @@ class _TransactionPageState extends State<TransactionPage>
vsync: this, vsync: this,
); );
_rotationController = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
)..repeat();
_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),
); );
@ -65,11 +56,6 @@ class _TransactionPageState extends State<TransactionPage>
CurvedAnimation(parent: _slideController, curve: Curves.elasticOut), CurvedAnimation(parent: _slideController, curve: Curves.elasticOut),
); );
_rotationAnimation = Tween<double>(
begin: 0,
end: 2 * math.pi,
).animate(_rotationController);
_fadeController.forward(); _fadeController.forward();
_slideController.forward(); _slideController.forward();
} }
@ -78,7 +64,6 @@ class _TransactionPageState extends State<TransactionPage>
void dispose() { void dispose() {
_fadeController.dispose(); _fadeController.dispose();
_slideController.dispose(); _slideController.dispose();
_rotationController.dispose();
super.dispose(); super.dispose();
} }
@ -154,9 +139,7 @@ class _TransactionPageState extends State<TransactionPage>
pinned: true, pinned: true,
backgroundColor: AppColor.primary, backgroundColor: AppColor.primary,
centerTitle: false, centerTitle: false,
flexibleSpace: TransactionAppBar( flexibleSpace: CustomAppBar(title: 'Transaction', isBack: false),
rotationAnimation: _rotationAnimation,
),
actions: [ actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.filter), ActionIconButton(onTap: () {}, icon: LineIcons.filter),
SpaceWidth(8), SpaceWidth(8),