Perbarui DonaturController dan tampilan terkait untuk mendukung stok bantuan
- Tambahkan metode fetchStokBantuan di DonaturController untuk mengambil data stok bantuan - Perbarui tampilan DaftarDonaturView untuk navigasi ke detail donatur - Tambahkan rute dan tampilan detail donatur - Ganti beberapa warna ikon dan teks untuk konsistensi tampilan - Gunakan dialog DetailPenitipanDialog untuk menampilkan detail penitipan
This commit is contained in:
@ -2,11 +2,14 @@ import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/services/supabase_service.dart';
|
||||
import 'package:penyaluran_app/app/data/models/donatur_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penitipan_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/stok_bantuan_model.dart';
|
||||
|
||||
class DonaturController extends GetxController {
|
||||
final RxList<DonaturModel> daftarDonatur = <DonaturModel>[].obs;
|
||||
final RxMap<String, List<PenitipanBantuanModel>> penitipanPerDonatur =
|
||||
<String, List<PenitipanBantuanModel>>{}.obs;
|
||||
final RxMap<String, StokBantuanModel> stokBantuanMap =
|
||||
<String, StokBantuanModel>{}.obs;
|
||||
final RxBool isLoading = false.obs;
|
||||
final SupabaseService _supabaseService = SupabaseService.to;
|
||||
|
||||
@ -14,6 +17,7 @@ class DonaturController extends GetxController {
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
fetchDaftarDonatur();
|
||||
fetchStokBantuan();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -74,6 +78,25 @@ class DonaturController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchStokBantuan() async {
|
||||
try {
|
||||
final result = await _supabaseService.getStokBantuan();
|
||||
|
||||
if (result != null) {
|
||||
stokBantuanMap.clear();
|
||||
|
||||
for (var data in result) {
|
||||
final stokBantuan = StokBantuanModel.fromJson(data);
|
||||
if (stokBantuan.id != null) {
|
||||
stokBantuanMap[stokBantuan.id!] = stokBantuan;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error saat mengambil data stok bantuan: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Mendapatkan jumlah donasi untuk donatur tertentu
|
||||
int getJumlahDonasi(String? donaturId) {
|
||||
if (donaturId == null || !penitipanPerDonatur.containsKey(donaturId)) {
|
||||
@ -231,4 +254,39 @@ class DonaturController extends GetxController {
|
||||
|
||||
return penitipanList;
|
||||
}
|
||||
|
||||
String getStokBantuanSatuan(String? stokBantuanId) {
|
||||
if (stokBantuanId == null || !stokBantuanMap.containsKey(stokBantuanId)) {
|
||||
return 'item';
|
||||
}
|
||||
return stokBantuanMap[stokBantuanId]?.satuan ?? 'item';
|
||||
}
|
||||
|
||||
String getStokBantuanNama(String? stokBantuanId) {
|
||||
if (stokBantuanId == null || !stokBantuanMap.containsKey(stokBantuanId)) {
|
||||
return '';
|
||||
}
|
||||
return stokBantuanMap[stokBantuanId]?.nama ?? '';
|
||||
}
|
||||
|
||||
// Mendapatkan nama donatur berdasarkan ID
|
||||
String? getDonaturNama(String? donaturId) {
|
||||
if (donaturId == null) return null;
|
||||
|
||||
try {
|
||||
final donatur = daftarDonatur.firstWhere((d) => d.id == donaturId);
|
||||
return donatur.nama;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Mendapatkan nama petugas desa berdasarkan ID
|
||||
String? getPetugasDesaNama(String? petugasDesaId) {
|
||||
if (petugasDesaId == null) return null;
|
||||
|
||||
// Implementasi ini perlu disesuaikan dengan cara aplikasi menyimpan data petugas desa
|
||||
// Contoh sederhana:
|
||||
return 'Petugas Desa'; // Ganti dengan implementasi yang sesuai
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/donatur_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/data/models/donatur_model.dart';
|
||||
import 'package:penyaluran_app/app/routes/app_pages.dart';
|
||||
|
||||
class DaftarDonaturView extends GetView<DonaturController> {
|
||||
const DaftarDonaturView({super.key});
|
||||
@ -199,8 +200,8 @@ class DaftarDonaturView extends GetView<DonaturController> {
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// Navigasi ke halaman detail donatur (akan diimplementasikan nanti)
|
||||
// Get.toNamed('/daftar-donatur/detail', arguments: donatur.id);
|
||||
// Navigasi ke halaman detail donatur
|
||||
Get.toNamed(Routes.detailDonatur, arguments: donatur.id);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
@ -268,14 +269,14 @@ class DaftarDonaturView extends GetView<DonaturController> {
|
||||
const Icon(
|
||||
Icons.attach_money,
|
||||
size: 14,
|
||||
color: Color.fromARGB(255, 210, 158, 4),
|
||||
color: Colors.green,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'${jumlahDonasiUang}x Donasi Uang',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color.fromARGB(255, 210, 158, 4),
|
||||
color: Colors.green,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -287,14 +288,14 @@ class DaftarDonaturView extends GetView<DonaturController> {
|
||||
const Icon(
|
||||
Icons.inventory_2,
|
||||
size: 14,
|
||||
color: Colors.purple,
|
||||
color: Colors.orange,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'${jumlahDonasiBarang}x Donasi Barang',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.purple,
|
||||
color: Colors.orange,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -319,8 +320,8 @@ class DaftarDonaturView extends GetView<DonaturController> {
|
||||
|
||||
switch (status) {
|
||||
case 'AKTIF':
|
||||
backgroundColor = Colors.green.withOpacity(0.1);
|
||||
textColor = Colors.green;
|
||||
backgroundColor = Colors.blue.withOpacity(0.1);
|
||||
textColor = Colors.blue;
|
||||
label = 'Aktif';
|
||||
break;
|
||||
case 'NONAKTIF':
|
||||
@ -446,7 +447,7 @@ class DonaturSearchDelegate extends SearchDelegate {
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
close(context, null);
|
||||
// Get.toNamed('/daftar-donatur/detail', arguments: donatur.id);
|
||||
Get.toNamed(Routes.detailDonatur, arguments: donatur.id);
|
||||
},
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: AppTheme.primaryColor.withOpacity(0.1),
|
||||
|
553
lib/app/modules/petugas_desa/views/detail_donatur_view.dart
Normal file
553
lib/app/modules/petugas_desa/views/detail_donatur_view.dart
Normal file
@ -0,0 +1,553 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/donatur_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/data/models/donatur_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penitipan_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/widgets/detail_penitipan_dialog.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DetailDonaturView extends GetView<DonaturController> {
|
||||
const DetailDonaturView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final String donaturId = Get.arguments as String;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Detail Donatur'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: () {
|
||||
// Implementasi edit donatur (akan diimplementasikan nanti)
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: FutureBuilder<DonaturModel?>(
|
||||
future: controller.fetchDonaturById(donaturId),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text('Error: ${snapshot.error}'),
|
||||
);
|
||||
}
|
||||
|
||||
if (!snapshot.hasData || snapshot.data == null) {
|
||||
return const Center(
|
||||
child: Text('Data donatur tidak ditemukan'),
|
||||
);
|
||||
}
|
||||
|
||||
final donatur = snapshot.data!;
|
||||
return _buildDetailContent(context, donatur);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDetailContent(BuildContext context, DonaturModel donatur) {
|
||||
// Pilih ikon berdasarkan jenis donatur
|
||||
IconData jenisIcon;
|
||||
switch (donatur.jenis) {
|
||||
case 'Perusahaan':
|
||||
jenisIcon = Icons.business;
|
||||
break;
|
||||
case 'Organisasi':
|
||||
jenisIcon = Icons.groups;
|
||||
break;
|
||||
case 'Individu':
|
||||
jenisIcon = Icons.person;
|
||||
break;
|
||||
default:
|
||||
jenisIcon = Icons.help_outline;
|
||||
}
|
||||
|
||||
// Hitung jumlah donasi dan total nilai donasi
|
||||
final jumlahDonasi = controller.getJumlahDonasi(donatur.id);
|
||||
final jumlahDonasiUang = controller.getJumlahDonasiUang(donatur.id);
|
||||
final jumlahDonasiBarang = controller.getJumlahDonasiBarang(donatur.id);
|
||||
final totalNilaiDonasiUang = controller.getTotalNilaiDonasiUang(donatur.id);
|
||||
final totalNilaiDonasiUangFormatted =
|
||||
controller.formatRupiah(totalNilaiDonasiUang);
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Header dengan informasi utama donatur
|
||||
Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
// Avatar dan nama donatur
|
||||
Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: AppTheme.primaryColor.withOpacity(0.1),
|
||||
child: Icon(
|
||||
jenisIcon,
|
||||
size: 40,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
donatur.nama ?? 'Tanpa Nama',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: donatur.jenis == 'Perusahaan'
|
||||
? Colors.blue.withOpacity(0.1)
|
||||
: donatur.jenis == 'Organisasi'
|
||||
? Colors.green.withOpacity(0.1)
|
||||
: Colors.orange.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Text(
|
||||
donatur.jenis ?? 'Tidak Diketahui',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: donatur.jenis == 'Perusahaan'
|
||||
? Colors.blue
|
||||
: donatur.jenis == 'Organisasi'
|
||||
? Colors.green
|
||||
: Colors.orange,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: donatur.status == 'AKTIF'
|
||||
? Colors.green.withOpacity(0.1)
|
||||
: Colors.red.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
donatur.status == 'AKTIF'
|
||||
? Icons.check_circle
|
||||
: Icons.cancel,
|
||||
size: 12,
|
||||
color: donatur.status == 'AKTIF'
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
donatur.status ?? 'TIDAK AKTIF',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: donatur.status == 'AKTIF'
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Informasi kontak
|
||||
const Divider(),
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoItem(Icons.location_on, 'Alamat',
|
||||
donatur.alamat ?? 'Tidak ada alamat'),
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoItem(Icons.phone, 'Telepon',
|
||||
donatur.telepon ?? 'Tidak ada telepon'),
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoItem(
|
||||
Icons.email, 'Email', donatur.email ?? 'Tidak ada email'),
|
||||
const SizedBox(height: 8),
|
||||
_buildInfoItem(
|
||||
Icons.calendar_today,
|
||||
'Terdaftar Sejak',
|
||||
donatur.createdAt != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(donatur.createdAt!)
|
||||
: 'Tidak diketahui',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Ringkasan donasi
|
||||
Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Ringkasan Donasi',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildStatItem(
|
||||
'Total Donasi',
|
||||
'$jumlahDonasi',
|
||||
Icons.volunteer_activism,
|
||||
Colors.blue,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _buildStatItem(
|
||||
'Donasi Uang',
|
||||
'$jumlahDonasiUang',
|
||||
Icons.monetization_on,
|
||||
Colors.green,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _buildStatItem(
|
||||
'Donasi Barang',
|
||||
'$jumlahDonasiBarang',
|
||||
Icons.inventory_2,
|
||||
Colors.orange,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.monetization_on,
|
||||
color: Colors.green,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Total Nilai Donasi Uang:',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Text(
|
||||
totalNilaiDonasiUangFormatted,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.green,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Riwayat donasi
|
||||
Card(
|
||||
elevation: 2,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'Riwayat Donasi',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
// Navigasi ke halaman riwayat donasi lengkap
|
||||
},
|
||||
child: const Text('Lihat Semua'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildRiwayatDonasi(donatur.id),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInfoItem(IconData icon, String label, String value) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
size: 20,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatItem(
|
||||
String label, String value, IconData icon, Color color) {
|
||||
return Column(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 25,
|
||||
backgroundColor: color.withOpacity(0.1),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
value,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRiwayatDonasi(String? donaturId) {
|
||||
if (donaturId == null ||
|
||||
!controller.penitipanPerDonatur.containsKey(donaturId)) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Center(
|
||||
child: Text('Belum ada riwayat donasi'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final penitipanList = controller.penitipanPerDonatur[donaturId]!;
|
||||
|
||||
// Tampilkan maksimal 3 donasi terbaru
|
||||
final displayedPenitipan =
|
||||
penitipanList.length > 3 ? penitipanList.sublist(0, 3) : penitipanList;
|
||||
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: displayedPenitipan.length,
|
||||
itemBuilder: (context, index) {
|
||||
final penitipan = displayedPenitipan[index];
|
||||
return _buildDonasiItem(penitipan);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDonasiItem(PenitipanBantuanModel penitipan) {
|
||||
final isUang = penitipan.isUang == true;
|
||||
final tanggal = penitipan.createdAt != null
|
||||
? DateFormat('dd MMM yyyy', 'id_ID').format(penitipan.createdAt!)
|
||||
: 'Tanggal tidak diketahui';
|
||||
|
||||
String nilaiDonasi = '';
|
||||
if (isUang && penitipan.jumlah != null) {
|
||||
nilaiDonasi = controller.formatRupiah(penitipan.jumlah!);
|
||||
} else if (penitipan.jumlah != null) {
|
||||
final satuan = controller.getStokBantuanSatuan(penitipan.stokBantuanId);
|
||||
nilaiDonasi = '${penitipan.jumlah} $satuan';
|
||||
} else {
|
||||
nilaiDonasi = 'Jumlah tidak diketahui';
|
||||
}
|
||||
|
||||
return Card(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
elevation: 0,
|
||||
color: Colors.grey[100],
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
// Tampilkan dialog detail penitipan
|
||||
_showDetailPenitipan(penitipan);
|
||||
},
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: isUang
|
||||
? Colors.green.withOpacity(0.1)
|
||||
: Colors.orange.withOpacity(0.1),
|
||||
child: Icon(
|
||||
isUang ? Icons.monetization_on : Icons.inventory_2,
|
||||
color: isUang ? Colors.green : Colors.orange,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
isUang
|
||||
? 'Donasi Uang'
|
||||
: controller
|
||||
.getStokBantuanNama(penitipan.stokBantuanId)
|
||||
.isNotEmpty
|
||||
? controller
|
||||
.getStokBantuanNama(penitipan.stokBantuanId)
|
||||
: penitipan.deskripsi ?? 'Donasi Barang',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
tanggal,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
nilaiDonasi,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isUang ? Colors.green : Colors.orange,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
color: Colors.grey[400],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Metode untuk menampilkan dialog detail penitipan
|
||||
void _showDetailPenitipan(PenitipanBantuanModel penitipan) {
|
||||
// Dapatkan data yang diperlukan
|
||||
final donaturNama = penitipan.donatur?.nama ??
|
||||
controller.getDonaturNama(penitipan.donaturId) ??
|
||||
'Donatur tidak ditemukan';
|
||||
|
||||
final kategoriNama = penitipan.kategoriBantuan?.nama ??
|
||||
controller.getStokBantuanNama(penitipan.stokBantuanId);
|
||||
|
||||
final kategoriSatuan = penitipan.kategoriBantuan?.satuan ??
|
||||
controller.getStokBantuanSatuan(penitipan.stokBantuanId);
|
||||
|
||||
// Tampilkan dialog
|
||||
DetailPenitipanDialog.show(
|
||||
context: Get.context!,
|
||||
item: penitipan,
|
||||
donaturNama: donaturNama,
|
||||
kategoriNama: kategoriNama,
|
||||
kategoriSatuan: kategoriSatuan,
|
||||
getPetugasDesaNama: (String? id) =>
|
||||
controller.getPetugasDesaNama(id) ?? 'Petugas tidak diketahui',
|
||||
showFullScreenImage: (String imageUrl) {
|
||||
DetailPenitipanDialog.showFullScreenImage(Get.context!, imageUrl);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import 'package:penyaluran_app/app/data/models/penitipan_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penitipan_bantuan_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/utils/date_formatter.dart';
|
||||
import 'package:penyaluran_app/app/widgets/detail_penitipan_dialog.dart';
|
||||
import 'dart:io';
|
||||
|
||||
class PenitipanView extends GetView<PenitipanBantuanController> {
|
||||
@ -694,198 +695,18 @@ class PenitipanView extends GetView<PenitipanBantuanController> {
|
||||
final kategoriSatuan = item.kategoriBantuan?.satuan ??
|
||||
controller.getKategoriSatuan(item.stokBantuanId);
|
||||
|
||||
// Cek apakah penitipan berbentuk uang
|
||||
final isUang = item.isUang ?? false;
|
||||
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: const Text('Detail Penitipan'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildDetailItem('Donatur', donaturNama),
|
||||
_buildDetailItem('Status', item.status ?? 'Tidak diketahui'),
|
||||
_buildDetailItem('Kategori Bantuan', kategoriNama),
|
||||
_buildDetailItem(
|
||||
'Jumlah',
|
||||
isUang
|
||||
? 'Rp ${DateFormatter.formatNumber(item.jumlah)}'
|
||||
: '${DateFormatter.formatNumber(item.jumlah)} $kategoriSatuan'),
|
||||
if (isUang) _buildDetailItem('Jenis Bantuan', 'Uang (Rupiah)'),
|
||||
_buildDetailItem(
|
||||
'Deskripsi', item.deskripsi ?? 'Tidak ada deskripsi'),
|
||||
_buildDetailItem(
|
||||
'Tanggal Penitipan',
|
||||
DateFormatter.formatDateTime(item.tanggalPenitipan,
|
||||
defaultValue: 'Tidak ada tanggal'),
|
||||
),
|
||||
if (item.tanggalVerifikasi != null)
|
||||
_buildDetailItem(
|
||||
'Tanggal Verifikasi',
|
||||
DateFormatter.formatDateTime(item.tanggalVerifikasi),
|
||||
),
|
||||
if (item.status == 'TERVERIFIKASI' && item.petugasDesaId != null)
|
||||
_buildDetailItem(
|
||||
'Diverifikasi Oleh',
|
||||
controller.getPetugasDesaNama(item.petugasDesaId),
|
||||
),
|
||||
_buildDetailItem('Tanggal Dibuat',
|
||||
DateFormatter.formatDateTime(item.createdAt)),
|
||||
if (item.alasanPenolakan != null &&
|
||||
item.alasanPenolakan!.isNotEmpty)
|
||||
_buildDetailItem('Alasan Penolakan', item.alasanPenolakan!),
|
||||
|
||||
// Foto Bantuan
|
||||
if (!isUang &&
|
||||
item.fotoBantuan != null &&
|
||||
item.fotoBantuan!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Foto Bantuan:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: item.fotoBantuan!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_showFullScreenImage(
|
||||
context, item.fotoBantuan![index]);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
item.fotoBantuan![index],
|
||||
height: 100,
|
||||
width: 100,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Icon(Icons.error),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Bukti Transfer (untuk bantuan uang)
|
||||
if (isUang &&
|
||||
item.fotoBantuan != null &&
|
||||
item.fotoBantuan!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Bukti Transfer:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: item.fotoBantuan!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_showFullScreenImage(
|
||||
context, item.fotoBantuan![index]);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
item.fotoBantuan![index],
|
||||
height: 100,
|
||||
width: 100,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Icon(Icons.error),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Bukti Serah Terima
|
||||
if (item.fotoBuktiSerahTerima != null &&
|
||||
item.fotoBuktiSerahTerima!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Bukti Serah Terima:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_showFullScreenImage(
|
||||
context, item.fotoBuktiSerahTerima!);
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
item.fotoBuktiSerahTerima!,
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Icon(Icons.error),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: const Text('Tutup'),
|
||||
),
|
||||
],
|
||||
),
|
||||
// Gunakan dialog yang sudah dibuat
|
||||
DetailPenitipanDialog.show(
|
||||
context: context,
|
||||
item: item,
|
||||
donaturNama: donaturNama,
|
||||
kategoriNama: kategoriNama,
|
||||
kategoriSatuan: kategoriSatuan,
|
||||
getPetugasDesaNama: (String? id) =>
|
||||
controller.getPetugasDesaNama(id) ?? 'Tidak diketahui',
|
||||
showFullScreenImage: (String imageUrl) {
|
||||
DetailPenitipanDialog.showFullScreenImage(context, imageUrl);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,7 @@ class PetugasDesaView extends GetView<PetugasDesaController> {
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.volunteer_activism),
|
||||
leading: const Icon(Icons.volunteer_activism_outlined),
|
||||
title: const Text('Daftar Donatur'),
|
||||
onTap: () {
|
||||
Navigator.pop(context); // Tutup drawer terlebih dahulu
|
||||
|
@ -2,9 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penitipan_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/controllers/penitipan_bantuan_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/utils/date_formatter.dart';
|
||||
import 'dart:io';
|
||||
|
||||
class RiwayatPenitipanView extends GetView<PenitipanBantuanController> {
|
||||
const RiwayatPenitipanView({super.key});
|
||||
|
@ -10,6 +10,7 @@ import 'package:penyaluran_app/app/modules/petugas_desa/views/konfirmasi_penerim
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/pelaksanaan_penyaluran_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/riwayat_penitipan_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/daftar_donatur_view.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/views/detail_donatur_view.dart';
|
||||
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/bindings/penerima_binding.dart';
|
||||
import 'package:penyaluran_app/app/modules/petugas_desa/bindings/donatur_binding.dart';
|
||||
@ -81,5 +82,10 @@ class AppPages {
|
||||
page: () => const DaftarDonaturView(),
|
||||
binding: DonaturBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: _Paths.detailDonatur,
|
||||
page: () => const DetailDonaturView(),
|
||||
binding: DonaturBinding(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ abstract class Routes {
|
||||
static const profile = _Paths.profile;
|
||||
static const riwayatPenitipan = _Paths.riwayatPenitipan;
|
||||
static const daftarDonatur = _Paths.daftarDonatur;
|
||||
static const detailDonatur = _Paths.detailDonatur;
|
||||
}
|
||||
|
||||
abstract class _Paths {
|
||||
@ -38,4 +39,5 @@ abstract class _Paths {
|
||||
static const profile = '/profile';
|
||||
static const riwayatPenitipan = '/petugas-desa/riwayat-penitipan';
|
||||
static const daftarDonatur = '/daftar-donatur';
|
||||
static const detailDonatur = '/daftar-donatur/detail';
|
||||
}
|
||||
|
306
lib/app/widgets/detail_penitipan_dialog.dart
Normal file
306
lib/app/widgets/detail_penitipan_dialog.dart
Normal file
@ -0,0 +1,306 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penitipan_bantuan_model.dart';
|
||||
import 'package:penyaluran_app/app/utils/date_formatter.dart';
|
||||
|
||||
/// Dialog untuk menampilkan detail penitipan bantuan
|
||||
///
|
||||
/// Contoh penggunaan:
|
||||
/// ```dart
|
||||
/// // Di halaman lain
|
||||
/// void showDetailPenitipan(BuildContext context, PenitipanBantuanModel item) {
|
||||
/// // Dapatkan data yang diperlukan
|
||||
/// final donaturNama = item.donatur?.nama ?? 'Donatur tidak ditemukan';
|
||||
/// final kategoriNama = item.kategoriBantuan?.nama ?? 'Kategori tidak ditemukan';
|
||||
/// final kategoriSatuan = item.kategoriBantuan?.satuan ?? '';
|
||||
///
|
||||
/// // Tampilkan dialog
|
||||
/// DetailPenitipanDialog.show(
|
||||
/// context: context,
|
||||
/// item: item,
|
||||
/// donaturNama: donaturNama,
|
||||
/// kategoriNama: kategoriNama,
|
||||
/// kategoriSatuan: kategoriSatuan,
|
||||
/// getPetugasDesaNama: (String? id) => 'Nama Petugas', // Sesuaikan dengan cara mendapatkan nama petugas
|
||||
/// showFullScreenImage: (String imageUrl) {
|
||||
/// DetailPenitipanDialog.showFullScreenImage(context, imageUrl);
|
||||
/// },
|
||||
/// );
|
||||
/// }
|
||||
class DetailPenitipanDialog {
|
||||
static void show({
|
||||
required BuildContext context,
|
||||
required PenitipanBantuanModel item,
|
||||
required String donaturNama,
|
||||
required String kategoriNama,
|
||||
required String kategoriSatuan,
|
||||
required String Function(String?) getPetugasDesaNama,
|
||||
required Function(String) showFullScreenImage,
|
||||
}) {
|
||||
// Cek apakah penitipan berbentuk uang
|
||||
final isUang = item.isUang ?? false;
|
||||
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: const Text('Detail Penitipan'),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildDetailItem('Donatur', donaturNama),
|
||||
_buildDetailItem('Status', item.status ?? 'Tidak diketahui'),
|
||||
_buildDetailItem('Kategori Bantuan', kategoriNama),
|
||||
_buildDetailItem(
|
||||
'Jumlah',
|
||||
isUang
|
||||
? 'Rp ${DateFormatter.formatNumber(item.jumlah)}'
|
||||
: '${DateFormatter.formatNumber(item.jumlah)} $kategoriSatuan'),
|
||||
if (isUang) _buildDetailItem('Jenis Bantuan', 'Uang (Rupiah)'),
|
||||
_buildDetailItem(
|
||||
'Deskripsi', item.deskripsi ?? 'Tidak ada deskripsi'),
|
||||
_buildDetailItem(
|
||||
'Tanggal Penitipan',
|
||||
DateFormatter.formatDateTime(item.tanggalPenitipan,
|
||||
defaultValue: 'Tidak ada tanggal'),
|
||||
),
|
||||
if (item.tanggalVerifikasi != null)
|
||||
_buildDetailItem(
|
||||
'Tanggal Verifikasi',
|
||||
DateFormatter.formatDateTime(item.tanggalVerifikasi),
|
||||
),
|
||||
if (item.status == 'TERVERIFIKASI' && item.petugasDesaId != null)
|
||||
_buildDetailItem(
|
||||
'Diverifikasi Oleh',
|
||||
getPetugasDesaNama(item.petugasDesaId) ?? 'Tidak diketahui',
|
||||
),
|
||||
_buildDetailItem('Tanggal Dibuat',
|
||||
DateFormatter.formatDateTime(item.createdAt)),
|
||||
if (item.alasanPenolakan != null &&
|
||||
item.alasanPenolakan!.isNotEmpty)
|
||||
_buildDetailItem('Alasan Penolakan', item.alasanPenolakan!),
|
||||
|
||||
// Foto Bantuan
|
||||
if (!isUang &&
|
||||
item.fotoBantuan != null &&
|
||||
item.fotoBantuan!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Foto Bantuan:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: item.fotoBantuan!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
showFullScreenImage(item.fotoBantuan![index]);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
item.fotoBantuan![index],
|
||||
height: 100,
|
||||
width: 100,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Icon(Icons.error),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Bukti Transfer (untuk bantuan uang)
|
||||
if (isUang &&
|
||||
item.fotoBantuan != null &&
|
||||
item.fotoBantuan!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Bukti Transfer:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
height: 100,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: item.fotoBantuan!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
showFullScreenImage(item.fotoBantuan![index]);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
item.fotoBantuan![index],
|
||||
height: 100,
|
||||
width: 100,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Icon(Icons.error),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Bukti Serah Terima
|
||||
if (item.fotoBuktiSerahTerima != null &&
|
||||
item.fotoBuktiSerahTerima!.isNotEmpty)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Bukti Serah Terima:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
showFullScreenImage(item.fotoBuktiSerahTerima!);
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.network(
|
||||
item.fotoBuktiSerahTerima!,
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: 200,
|
||||
width: double.infinity,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Icon(Icons.error),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(),
|
||||
child: const Text('Tutup'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Widget _buildDetailItem(String label, String value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static void showFullScreenImage(BuildContext context, String imageUrl) {
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
insetPadding: EdgeInsets.zero,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
InteractiveViewer(
|
||||
panEnabled: true,
|
||||
minScale: 0.5,
|
||||
maxScale: 4,
|
||||
child: Image.network(
|
||||
imageUrl,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
color: Colors.grey.shade300,
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.error,
|
||||
size: 50,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 20,
|
||||
right: 20,
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user