Perbarui tampilan DetailPengaduanView dan PengaduanView untuk meningkatkan konsistensi dan pengalaman pengguna. Tambahkan konstanta warna untuk status pengaduan dan modifikasi penggunaan warna di seluruh tampilan. Ganti metode filter dengan PopupMenuButton untuk kemudahan akses dan tambahkan informasi waktu terakhir update pada PengaduanView.

This commit is contained in:
Khafidh Fuadi
2025-03-17 20:44:21 +07:00
parent aa73508108
commit 9eb2c5ac1a
8 changed files with 918 additions and 227 deletions

View File

@ -9,30 +9,62 @@ class PengaduanView extends GetView<PengaduanController> {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Ringkasan pengaduan
_buildPengaduanSummary(context),
return RefreshIndicator(
onRefresh: controller.refreshData,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Ringkasan pengaduan
_buildPengaduanSummary(context),
const SizedBox(height: 24),
const SizedBox(height: 24),
// Filter dan pencarian
_buildFilterSearch(context),
// Filter dan pencarian
_buildFilterSearch(context),
const SizedBox(height: 20),
// Informasi terakhir update
_buildLastUpdateInfo(context),
// Daftar pengaduan
_buildPengaduanList(context),
],
const SizedBox(height: 20),
// Daftar pengaduan
_buildPengaduanList(context),
],
),
),
),
);
}
// Tambahkan widget untuk menampilkan waktu terakhir update
Widget _buildLastUpdateInfo(BuildContext context) {
final lastUpdate = DateTime
.now(); // Gunakan waktu saat ini atau dari controller jika tersedia
final formattedDate = DateTimeHelper.formatDateTimeWithHour(lastUpdate);
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
children: [
Icon(Icons.update, size: 16, color: Colors.grey[600]),
const SizedBox(width: 4),
Text(
'Data terupdate: $formattedDate',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
fontStyle: FontStyle.italic,
),
),
],
),
);
}
Widget _buildPengaduanSummary(BuildContext context) {
return Obx(() {
return Container(
@ -160,75 +192,36 @@ class PengaduanView extends GetView<PengaduanController> {
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: IconButton(
onPressed: () {
// Tampilkan dialog filter
_showFilterDialog(context);
},
child: PopupMenuButton<int>(
icon: const Icon(Icons.filter_list),
tooltip: 'Filter',
onSelected: (index) {
controller.changeCategory(index);
},
itemBuilder: (context) => [
const PopupMenuItem(
value: 0,
child: Text('Semua'),
),
const PopupMenuItem(
value: 1,
child: Text('Diproses'),
),
const PopupMenuItem(
value: 2,
child: Text('Tindakan'),
),
const PopupMenuItem(
value: 3,
child: Text('Selesai'),
),
],
),
),
],
);
}
void _showFilterDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Filter Pengaduan'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Obx(() => RadioListTile<int>(
title: const Text('Semua'),
value: 0,
groupValue: controller.selectedCategoryIndex.value,
onChanged: (value) {
controller.changeCategory(value!);
Navigator.pop(context);
},
)),
Obx(() => RadioListTile<int>(
title: const Text('Diproses'),
value: 1,
groupValue: controller.selectedCategoryIndex.value,
onChanged: (value) {
controller.changeCategory(value!);
Navigator.pop(context);
},
)),
Obx(() => RadioListTile<int>(
title: const Text('Tindakan'),
value: 2,
groupValue: controller.selectedCategoryIndex.value,
onChanged: (value) {
controller.changeCategory(value!);
Navigator.pop(context);
},
)),
Obx(() => RadioListTile<int>(
title: const Text('Selesai'),
value: 3,
groupValue: controller.selectedCategoryIndex.value,
onChanged: (value) {
controller.changeCategory(value!);
Navigator.pop(context);
},
)),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Batal'),
),
],
),
);
}
Widget _buildPengaduanList(BuildContext context) {
return Obx(() {
if (controller.isLoading.value) {
@ -248,16 +241,16 @@ class PengaduanView extends GetView<PengaduanController> {
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
const Icon(
Icon(
Icons.inbox_outlined,
size: 80,
color: Colors.grey,
color: Colors.grey.shade400,
),
const SizedBox(height: 16),
Text(
'Belum ada pengaduan',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Colors.grey,
color: Colors.grey.shade600,
),
),
],
@ -278,10 +271,11 @@ class PengaduanView extends GetView<PengaduanController> {
fontWeight: FontWeight.bold,
),
),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () => controller.refreshData(),
tooltip: 'Refresh',
Text(
'${DateTimeHelper.formatNumber(filteredPengaduan.length)} item',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey,
),
),
],
),
@ -344,6 +338,7 @@ class PengaduanView extends GetView<PengaduanController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
@ -352,9 +347,10 @@ class PengaduanView extends GetView<PengaduanController> {
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
overflow: TextOverflow.ellipsis,
// overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 12),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
@ -383,63 +379,6 @@ class PengaduanView extends GetView<PengaduanController> {
),
],
),
const SizedBox(height: 4),
Text(
'NIK: ${item.warga?['nik'] ?? ''}',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.grey,
),
),
const SizedBox(height: 12),
if (item.penerimaPenyaluran != null) ...[
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Penyaluran: ${item.namaPenyaluran}',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Jenis: ${item.jenisBantuan}',
style: Theme.of(context).textTheme.bodySmall,
),
),
),
const SizedBox(width: 8),
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.green.shade50,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Jumlah: ${item.jumlahBantuan}',
style: Theme.of(context).textTheme.bodySmall,
),
),
),
],
),
],
const SizedBox(height: 8),
Text(
item.deskripsi ?? '',
@ -447,24 +386,72 @@ class PengaduanView extends GetView<PengaduanController> {
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
const SizedBox(height: 12),
Row(
children: [
Icon(
Icons.calendar_today,
size: 14,
color: Colors.grey,
Expanded(
child: _buildItemDetail(
context,
icon: Icons.person,
label: 'Pelapor',
value: item.warga?['nama_lengkap'] ?? '',
),
),
const SizedBox(width: 4),
Text(
formattedDate,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.grey,
),
Expanded(
child: _buildItemDetail(
context,
icon: Icons.numbers,
label: 'NIK',
value: item.warga?['nik'] ?? '',
),
),
],
),
const SizedBox(height: 12),
if (item.penerimaPenyaluran != null) ...[
Row(
children: [
Expanded(
child: _buildItemDetail(
context,
icon: Icons.shopping_bag,
label: 'Jumlah',
value:
'${item.jumlahBantuan} ${item.stokBantuan['satuan']}',
)),
Expanded(
child: _buildItemDetail(
context,
icon: Icons.inventory,
label: 'Stok Bantuan',
value: item.stokBantuan['nama'] ?? '',
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: _buildItemDetail(
context,
icon: Icons.category,
label: 'Nama Penyaluran',
value: item.namaPenyaluran ?? '',
),
),
Expanded(
child: _buildItemDetail(
context,
icon: Icons.calendar_today,
label: 'Tanggal',
value: formattedDate,
),
),
],
),
],
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: _buildActionButtons(context, item),
@ -475,6 +462,42 @@ class PengaduanView extends GetView<PengaduanController> {
);
}
Widget _buildItemDetail(
BuildContext context, {
required IconData icon,
required String label,
required String value,
}) {
return Row(
children: [
Icon(
icon,
size: 16,
color: Colors.grey,
),
const SizedBox(width: 4),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Colors.grey,
),
),
Text(
value,
style: Theme.of(context).textTheme.bodyMedium,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
);
}
List<Widget> _buildActionButtons(BuildContext context, dynamic item) {
final status = item.status?.toUpperCase();