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:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import 'dart:math' as math;
import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart';
import 'widgets/appbar.dart';
import 'widgets/customer_card.dart';
import 'widgets/customer_tile.dart';
@ -102,27 +101,14 @@ class _CustomerPageState extends State<CustomerPage>
),
];
// Animation
late AnimationController _rotationController;
late Animation<double> _rotationAnimation;
@override
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
void dispose() {
_searchController.dispose();
_rotationController.dispose();
super.dispose();
}
@ -151,9 +137,7 @@ class _CustomerPageState extends State<CustomerPage>
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: CustomerAppbar(
rotationAnimation: _rotationAnimation,
),
flexibleSpace: CustomAppBar(title: 'Pelanggan'),
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 '../../../common/theme/theme.dart';
import 'widgets/appbar.dart';
import '../../components/appbar/appbar.dart';
import 'widgets/cash_flow.dart';
import 'widgets/category.dart';
import 'widgets/profit_loss.dart';
@ -22,14 +22,10 @@ class _FinancePageState extends State<FinancePage>
late AnimationController _slideController;
late AnimationController _fadeController;
late AnimationController _scaleController;
late AnimationController _rotationController;
late AnimationController _floatingController;
late Animation<Offset> _slideAnimation;
late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation;
late Animation<double> rotationAnimation;
late Animation<double> floatingAnimation;
String selectedPeriod = 'Hari ini';
final List<String> periods = [
@ -43,16 +39,6 @@ class _FinancePageState extends State<FinancePage>
void 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(
duration: const Duration(milliseconds: 800),
vsync: this,
@ -97,8 +83,6 @@ class _FinancePageState extends State<FinancePage>
_slideController.dispose();
_fadeController.dispose();
_scaleController.dispose();
_rotationController.dispose();
_floatingController.dispose();
super.dispose();
}
@ -115,10 +99,7 @@ class _FinancePageState extends State<FinancePage>
pinned: true,
backgroundColor: AppColor.primary,
elevation: 0,
flexibleSpace: FinanceAppbar(
rotationAnimation: rotationAnimation,
floatingAnimation: floatingAnimation,
),
flexibleSpace: CustomAppBar(title: 'Keuangan'),
),
// 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 '../../../common/theme/theme.dart';
import 'widgets/appbar.dart';
import '../../components/appbar/appbar.dart';
import 'widgets/ingredient_tile.dart';
import 'widgets/product_tile.dart';
import 'widgets/stat_card.dart';
@ -64,10 +64,8 @@ class _InventoryPageState extends State<InventoryPage>
with TickerProviderStateMixin {
late AnimationController _fadeAnimationController;
late AnimationController _slideAnimationController;
late AnimationController _rotationAnimationController;
late Animation<double> _fadeAnimation;
late Animation<Offset> _slideAnimation;
late Animation<double> rotationAnimation;
late TabController _tabController;
final List<ProductItem> productItems = [
@ -188,10 +186,6 @@ class _InventoryPageState extends State<InventoryPage>
duration: const Duration(milliseconds: 800),
vsync: this,
);
_rotationAnimationController = AnimationController(
duration: const Duration(seconds: 20),
vsync: this,
);
_fadeAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
@ -208,21 +202,14 @@ class _InventoryPageState extends State<InventoryPage>
),
);
rotationAnimation = Tween<double>(
begin: 0.0,
end: 2 * 3.14159,
).animate(_rotationAnimationController);
_fadeAnimationController.forward();
_slideAnimationController.forward();
_rotationAnimationController.repeat();
}
@override
void dispose() {
_fadeAnimationController.dispose();
_slideAnimationController.dispose();
_rotationAnimationController.dispose();
_tabController.dispose();
super.dispose();
}
@ -356,7 +343,7 @@ class _InventoryPageState extends State<InventoryPage>
pinned: true,
elevation: 0,
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:flutter/material.dart';
import 'package:line_icons/line_icons.dart';
import '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart';
import 'widgets/appbar.dart';
import 'widgets/category_delegate.dart';
import 'widgets/product_tile.dart';
@ -26,10 +24,6 @@ class _ProductPageState extends State<ProductPage>
List<String> categories = ['Semua', 'Makanan', 'Minuman', 'Snack', 'Dessert'];
ViewType currentViewType = ViewType.grid;
// Animation
late AnimationController _rotationController;
late Animation<double> _rotationAnimation;
// Sample product data
List<Product> products = [
Product(
@ -135,19 +129,10 @@ class _ProductPageState extends State<ProductPage>
@override
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
void dispose() {
_rotationController.dispose();
super.dispose();
}
@ -172,7 +157,7 @@ class _ProductPageState extends State<ProductPage>
floating: false,
pinned: true,
elevation: 0,
flexibleSpace: ProductAppbar(rotationAnimation: _rotationAnimation),
flexibleSpace: CustomAppBar(title: 'Produk'),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.search),
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 '../../../common/theme/theme.dart';
import 'widgets/appbar.dart';
import '../../components/appbar/appbar.dart';
import 'widgets/purchase_tile.dart';
import 'widgets/stat_card.dart';
import 'widgets/status_chip.dart';
@ -18,9 +18,7 @@ class PurchasePage extends StatefulWidget {
class _PurchasePageState extends State<PurchasePage>
with TickerProviderStateMixin {
late AnimationController rotationAnimation;
late AnimationController cardAnimation;
late AnimationController floatingAnimation;
String selectedFilter = 'Semua';
final List<String> filterOptions = [
'Semua',
@ -67,29 +65,18 @@ class _PurchasePageState extends State<PurchasePage>
@override
void initState() {
super.initState();
rotationAnimation = AnimationController(
duration: const Duration(seconds: 20),
vsync: this,
)..repeat();
cardAnimation = AnimationController(
duration: const Duration(milliseconds: 1200),
vsync: this,
);
floatingAnimation = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
)..repeat(reverse: true);
cardAnimation.forward();
}
@override
void dispose() {
rotationAnimation.dispose();
cardAnimation.dispose();
floatingAnimation.dispose();
super.dispose();
}
@ -106,10 +93,7 @@ class _PurchasePageState extends State<PurchasePage>
elevation: 0,
backgroundColor: AppColor.primary,
flexibleSpace: PurchaseAppbar(
rotationAnimation: rotationAnimation,
floatingAnimation: floatingAnimation,
),
flexibleSpace: CustomAppBar(title: 'Pembelian'),
),
// 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 '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/button/button.dart';
import '../../components/spacer/spacer.dart';
import 'widgets/appbar.dart';
import 'widgets/quick_stats.dart';
import 'widgets/report_action.dart';
import 'widgets/revenue_summary.dart';
@ -80,14 +80,13 @@ class _ReportPageState extends State<ReportPage> with TickerProviderStateMixin {
backgroundColor: AppColor.background,
body: CustomScrollView(
slivers: [
// Custom App Bar with Hero Effect
SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
centerTitle: false,
flexibleSpace: ReportAppBar(rotationAnimation: _rotationAnimation),
flexibleSpace: CustomAppBar(title: 'Laporan', isBack: false),
actions: [
ActionIconButton(onTap: () {}, icon: LineIcons.download),
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 '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
import '../../components/spacer/spacer.dart';
import 'widgets/appbar.dart';
import 'widgets/summary_card.dart';
// Data Models
@ -70,9 +70,6 @@ class SalesPage extends StatefulWidget {
}
class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
late AnimationController rotationAnimationController;
late Animation<double> rotationAnimation;
late AnimationController slideAnimationController;
late Animation<Offset> slideAnimation;
@ -82,23 +79,6 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
void 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
slideAnimationController = AnimationController(
duration: const Duration(milliseconds: 800),
@ -130,7 +110,6 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
@override
void dispose() {
rotationAnimationController.dispose();
slideAnimationController.dispose();
fadeAnimationController.dispose();
super.dispose();
@ -187,7 +166,7 @@ class _SalesPageState extends State<SalesPage> with TickerProviderStateMixin {
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
flexibleSpace: SalesAppbar(rotationAnimation: rotationAnimation),
flexibleSpace: CustomAppBar(title: 'Penjualan'),
),
// 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 '../../../common/theme/theme.dart';
import '../../components/appbar/appbar.dart';
// Schedule model dengan optimasi
class Schedule {
@ -212,107 +213,7 @@ class _SchedulePageState extends State<SchedulePage>
floating: false,
pinned: true,
backgroundColor: AppColor.primary,
actions: [
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),
),
),
);
},
),
),
],
),
),
),
flexibleSpace: CustomAppBar(title: 'Jadwal'),
);
}
@ -639,47 +540,6 @@ class _SchedulePageState extends State<SchedulePage>
_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) {
showModalBottomSheet(
context: context,

View File

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