Perbarui struktur dan referensi file di dashboard_view.dart dan detail_donatur_view.dart. Tambahkan dokumentasi pada kelas DateTimeHelper dan perkenalan fungsi baru untuk format tanggal relatif serta nama hari dan bulan. Hapus widget yang tidak digunakan seperti detail_penitipan_dialog.dart, loading_indicator.dart, navigation_button.dart, statistic_card.dart, dan status_pill.dart untuk menyederhanakan kode.

This commit is contained in:
Khafidh Fuadi
2025-03-16 16:30:23 +07:00
parent 5814b19546
commit 078d74aad3
22 changed files with 1639 additions and 509 deletions

View File

@ -0,0 +1,120 @@
import 'package:flutter/material.dart';
import 'package:penyaluran_app/app/theme/app_colors.dart';
/// Tombol navigasi yang digunakan untuk navigasi dalam aplikasi
///
/// Tombol ini memiliki label dan ikon, dan dapat dikonfigurasi untuk
/// berbagai ukuran dan warna.
class NavigationButton extends StatelessWidget {
/// Label yang ditampilkan pada tombol
final String label;
/// Ikon yang ditampilkan di sebelah label (opsional)
final IconData? icon;
/// Widget ikon kustom yang ditampilkan di sebelah label (opsional)
final Widget? iconWidget;
/// Fungsi yang dipanggil ketika tombol ditekan
final VoidCallback onPressed;
/// Warna latar belakang tombol
final Color? backgroundColor;
/// Warna teks dan ikon
final Color? foregroundColor;
/// Ukuran teks
final double fontSize;
/// Ukuran ikon
final double iconSize;
/// Konstruktor untuk NavigationButton
///
/// Salah satu dari [icon] atau [iconWidget] harus disediakan.
const NavigationButton({
super.key,
required this.label,
this.icon,
this.iconWidget,
required this.onPressed,
this.backgroundColor,
this.foregroundColor,
this.fontSize = 10,
this.iconSize = 12,
}) : assert(icon != null || iconWidget != null,
'Either icon or iconWidget must be provided');
@override
Widget build(BuildContext context) {
final Color bgColor = backgroundColor ?? AppColors.primary;
final Color fgColor = foregroundColor ?? const Color(0xFFAFF8FF);
return ConstrainedBox(
constraints: const BoxConstraints(minWidth: 70),
child: GestureDetector(
onTap: onPressed,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
label,
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.w500,
color: fgColor,
),
),
const SizedBox(width: 4),
if (icon != null)
Icon(
icon,
size: iconSize,
color: fgColor,
)
else if (iconWidget != null)
SizedBox(
width: iconSize,
height: iconSize,
child: iconWidget,
),
],
),
),
),
);
}
}
/// Data class untuk tombol navigasi
///
/// Digunakan untuk menyimpan data tombol navigasi yang akan digunakan
/// di beberapa tempat.
class NavigationButtonData {
/// Label yang ditampilkan pada tombol
final String label;
/// Ikon yang ditampilkan di sebelah label (opsional)
final IconData? icon;
/// Widget ikon kustom yang ditampilkan di sebelah label (opsional)
final Widget? iconWidget;
/// Konstruktor untuk NavigationButtonData
///
/// Salah satu dari [icon] atau [iconWidget] harus disediakan.
const NavigationButtonData({
required this.label,
this.icon,
this.iconWidget,
}) : assert(icon != null || iconWidget != null,
'Either icon or iconWidget must be provided');
}

View File

@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:penyaluran_app/app/theme/app_colors.dart';
/// Tombol utama yang digunakan di seluruh aplikasi
///
/// Tombol ini memiliki warna latar belakang utama dan teks putih.
/// Dapat dikonfigurasi untuk berbagai ukuran dan dapat dinonaktifkan.
class PrimaryButton extends StatelessWidget {
/// Teks yang ditampilkan pada tombol
final String text;
/// Fungsi yang dipanggil ketika tombol ditekan
final VoidCallback? onPressed;
/// Ikon yang ditampilkan di sebelah kiri teks (opsional)
final IconData? icon;
/// Apakah tombol mengisi lebar penuh
final bool fullWidth;
/// Ukuran tombol (kecil, sedang, besar)
final ButtonSize size;
/// Apakah tombol sedang memuat
final bool isLoading;
const PrimaryButton({
super.key,
required this.text,
this.onPressed,
this.icon,
this.fullWidth = false,
this.size = ButtonSize.medium,
this.isLoading = false,
});
@override
Widget build(BuildContext context) {
// Tentukan padding berdasarkan ukuran
final EdgeInsetsGeometry padding = _getPadding();
// Tentukan ukuran teks berdasarkan ukuran tombol
final double fontSize = _getFontSize();
return SizedBox(
width: fullWidth ? double.infinity : null,
child: ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
foregroundColor: Colors.white,
padding: padding,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 0,
),
child: isLoading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (icon != null) ...[
Icon(icon, size: fontSize + 2),
const SizedBox(width: 8),
],
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
}
/// Mendapatkan padding berdasarkan ukuran tombol
EdgeInsetsGeometry _getPadding() {
switch (size) {
case ButtonSize.small:
return const EdgeInsets.symmetric(horizontal: 12, vertical: 8);
case ButtonSize.medium:
return const EdgeInsets.symmetric(horizontal: 16, vertical: 12);
case ButtonSize.large:
return const EdgeInsets.symmetric(horizontal: 24, vertical: 16);
}
}
/// Mendapatkan ukuran font berdasarkan ukuran tombol
double _getFontSize() {
switch (size) {
case ButtonSize.small:
return 12;
case ButtonSize.medium:
return 14;
case ButtonSize.large:
return 16;
}
}
}
/// Enum untuk ukuran tombol
enum ButtonSize {
small,
medium,
large,
}

View File

@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:penyaluran_app/app/theme/app_colors.dart';
import 'package:penyaluran_app/app/widgets/buttons/primary_button.dart';
/// Tombol sekunder yang digunakan di seluruh aplikasi
///
/// Tombol ini memiliki warna latar belakang putih dengan border dan teks berwarna utama.
/// Dapat dikonfigurasi untuk berbagai ukuran dan dapat dinonaktifkan.
class SecondaryButton extends StatelessWidget {
/// Teks yang ditampilkan pada tombol
final String text;
/// Fungsi yang dipanggil ketika tombol ditekan
final VoidCallback? onPressed;
/// Ikon yang ditampilkan di sebelah kiri teks (opsional)
final IconData? icon;
/// Apakah tombol mengisi lebar penuh
final bool fullWidth;
/// Ukuran tombol (kecil, sedang, besar)
final ButtonSize size;
/// Apakah tombol sedang memuat
final bool isLoading;
const SecondaryButton({
super.key,
required this.text,
this.onPressed,
this.icon,
this.fullWidth = false,
this.size = ButtonSize.medium,
this.isLoading = false,
});
@override
Widget build(BuildContext context) {
// Tentukan padding berdasarkan ukuran
final EdgeInsetsGeometry padding = _getPadding();
// Tentukan ukuran teks berdasarkan ukuran tombol
final double fontSize = _getFontSize();
return SizedBox(
width: fullWidth ? double.infinity : null,
child: OutlinedButton(
onPressed: isLoading ? null : onPressed,
style: OutlinedButton.styleFrom(
foregroundColor: AppColors.primary,
side: BorderSide(color: AppColors.primary),
padding: padding,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: isLoading
? SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(AppColors.primary),
),
)
: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (icon != null) ...[
Icon(icon, size: fontSize + 2),
const SizedBox(width: 8),
],
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.w500,
),
),
],
),
),
);
}
/// Mendapatkan padding berdasarkan ukuran tombol
EdgeInsetsGeometry _getPadding() {
switch (size) {
case ButtonSize.small:
return const EdgeInsets.symmetric(horizontal: 12, vertical: 8);
case ButtonSize.medium:
return const EdgeInsets.symmetric(horizontal: 16, vertical: 12);
case ButtonSize.large:
return const EdgeInsets.symmetric(horizontal: 24, vertical: 16);
}
}
/// Mendapatkan ukuran font berdasarkan ukuran tombol
double _getFontSize() {
switch (size) {
case ButtonSize.small:
return 12;
case ButtonSize.medium:
return 14;
case ButtonSize.large:
return 16;
}
}
}