MIF_E31230910_MP-HRIS-MOBILE/lib/widgets/molecules/presensi_card.dart

190 lines
5.4 KiB
Dart

import 'package:flutter/material.dart';
import '../../core/theme.dart';
import '../atoms/marquee_text.dart';
enum PresensiType { datang, pulang }
enum PresensiStatus { belumWaktunya, waktunya, sudahAbsen, adaMasalah }
class PresensiCard extends StatefulWidget {
final PresensiType type;
final String? time;
final PresensiStatus status;
final String? statusText;
final VoidCallback? onTap;
const PresensiCard({
Key? key,
required this.type,
this.time,
this.status = PresensiStatus.belumWaktunya,
this.statusText,
this.onTap,
}) : super(key: key);
@override
State<PresensiCard> createState() => _PresensiCardState();
}
class _PresensiCardState extends State<PresensiCard> with SingleTickerProviderStateMixin {
AnimationController? _pulseController;
Animation<double>? _pulseAnimation;
@override
void initState() {
super.initState();
_setupPulse();
}
@override
void didUpdateWidget(PresensiCard oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.status != widget.status) {
_pulseController?.dispose();
_pulseController = null;
_setupPulse();
}
}
void _setupPulse() {
if (widget.status == PresensiStatus.waktunya) {
_pulseController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
);
_pulseAnimation = Tween<double>(begin: 0.6, end: 1.0).animate(
CurvedAnimation(parent: _pulseController!, curve: Curves.easeInOut),
);
_pulseController!.repeat(reverse: true);
}
}
@override
void dispose() {
_pulseController?.dispose();
super.dispose();
}
Color get _accentColor {
switch (widget.status) {
case PresensiStatus.belumWaktunya:
return AppTheme.textTertiary;
case PresensiStatus.waktunya:
return AppTheme.primaryBlue;
case PresensiStatus.sudahAbsen:
return AppTheme.statusGreen;
case PresensiStatus.adaMasalah:
return AppTheme.statusRed;
}
}
String get _statusLabel {
if (widget.status == PresensiStatus.sudahAbsen || widget.status == PresensiStatus.adaMasalah) {
if (widget.statusText != null && widget.statusText!.isNotEmpty) {
return widget.statusText!;
}
}
switch (widget.status) {
case PresensiStatus.belumWaktunya:
return "Belum Waktunya";
case PresensiStatus.waktunya:
return "Waktunya Absen!";
case PresensiStatus.sudahAbsen:
return "Tepat Waktu ✓";
case PresensiStatus.adaMasalah:
final isDatang = widget.type == PresensiType.datang;
return isDatang ? "Terlambat" : "Pulang Awal";
}
}
@override
Widget build(BuildContext context) {
final isDatang = widget.type == PresensiType.datang;
final icon = isDatang ? Icons.login : Icons.logout;
final label = isDatang ? "Presensi Datang" : "Presensi Pulang";
final displayTime = widget.time ?? "--:--";
Widget card = Container(
padding: const EdgeInsets.all(AppTheme.spacingMd),
decoration: BoxDecoration(
color: AppTheme.bgWhite,
borderRadius: BorderRadius.circular(AppTheme.radiusLg),
boxShadow: AppTheme.shadowMd,
),
child: Row(
children: [
Container(
width: 6,
height: 50,
decoration: BoxDecoration(
color: _accentColor,
borderRadius: BorderRadius.circular(3),
),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(icon, size: 14, color: _accentColor),
const SizedBox(width: 4),
Expanded(
child: ScrollableText(
text: label,
style: AppTheme.bodySmall.copyWith(color: AppTheme.textSecondary),
),
),
],
),
const SizedBox(height: 4),
Text(
displayTime,
style: AppTheme.heading2.copyWith(fontSize: 20, color: _accentColor),
),
const SizedBox(height: 2),
ScrollableText(
text: _statusLabel,
style: AppTheme.bodySmall.copyWith(
fontSize: 10,
color: _accentColor,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
);
if (widget.status == PresensiStatus.waktunya && _pulseAnimation != null) {
card = AnimatedBuilder(
animation: _pulseAnimation!,
builder: (context, child) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(AppTheme.radiusLg),
boxShadow: [
BoxShadow(
color: AppTheme.primaryBlue.withOpacity(_pulseAnimation!.value * 0.3),
blurRadius: 16,
spreadRadius: 2,
),
],
),
child: child,
);
},
child: card,
);
}
return GestureDetector(
onTap: widget.onTap,
child: card,
);
}
}