import 'package:flutter/material.dart'; import 'package:mobile_monitoring/core/constants/colors.dart'; /// Loading Indicator - Widget untuk menampilkan loading state class LoadingIndicator extends StatelessWidget { final double size; final Color? color; final String? message; const LoadingIndicator({ super.key, this.size = 40, this.color, this.message, }); @override Widget build(BuildContext context) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( width: size, height: size, child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation( color ?? AppColors.primary, ), strokeWidth: 3, ), ), if (message != null) ...[ const SizedBox(height: 16), Text( message!, style: const TextStyle( fontSize: 14, color: AppColors.textSecondary, ), textAlign: TextAlign.center, ), ], ], ), ); } } /// Overlay Loading - Full screen loading dengan overlay class OverlayLoading extends StatelessWidget { final String? message; const OverlayLoading({ super.key, this.message, }); @override Widget build(BuildContext context) { return Container( color: Colors.black.withValues(alpha: 0.5), child: Center( child: Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(16), ), child: LoadingIndicator(message: message), ), ), ); } } /// Shimmer Loading - Shimmer effect untuk skeleton loading class ShimmerLoading extends StatefulWidget { final double width; final double height; final BorderRadius? borderRadius; const ShimmerLoading({ super.key, required this.width, required this.height, this.borderRadius, }); @override State createState() => _ShimmerLoadingState(); } class _ShimmerLoadingState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; @override void initState() { super.initState(); _controller = AnimationController( duration: const Duration(milliseconds: 1500), vsync: this, )..repeat(); _animation = Tween(begin: -1.0, end: 2.0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Container( width: widget.width, height: widget.height, decoration: BoxDecoration( borderRadius: widget.borderRadius ?? BorderRadius.circular(8), gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: const [ AppColors.lightGray, AppColors.white, AppColors.lightGray, ], stops: [ _animation.value - 0.3, _animation.value, _animation.value + 0.3, ], ), ), ); }, ); } } /// Linear Progress Indicator - Progress bar class CustomLinearProgress extends StatelessWidget { final double? value; final Color? backgroundColor; final Color? valueColor; final double height; final BorderRadius? borderRadius; const CustomLinearProgress({ super.key, this.value, this.backgroundColor, this.valueColor, this.height = 4, this.borderRadius, }); @override Widget build(BuildContext context) { return ClipRRect( borderRadius: borderRadius ?? BorderRadius.circular(height / 2), child: SizedBox( height: height, child: LinearProgressIndicator( value: value, backgroundColor: backgroundColor ?? AppColors.lightGray, valueColor: AlwaysStoppedAnimation( valueColor ?? AppColors.primary, ), ), ), ); } }