h-1 lebaran
This commit is contained in:
@ -1,16 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/data/models/pengaduan_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/tindakan_pengaduan_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/theme/app_theme.dart';
|
||||
import 'package:penyaluran_app/app/utils/format_helper.dart';
|
||||
import 'package:timeline_tile/timeline_tile.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:penyaluran_app/app/widgets/indicators/status_pill.dart';
|
||||
import 'package:penyaluran_app/app/widgets/section_header.dart';
|
||||
import 'package:penyaluran_app/app/widgets/cards/info_card.dart';
|
||||
import 'dart:io';
|
||||
import 'package:penyaluran_app/app/widgets/widgets.dart';
|
||||
|
||||
class WargaDetailPengaduanView extends GetView<WargaDashboardController> {
|
||||
const WargaDetailPengaduanView({super.key});
|
||||
@ -670,8 +670,7 @@ class WargaDetailPengaduanView extends GetView<WargaDashboardController> {
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
pengaduan.tanggalPengaduan != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(pengaduan.tanggalPengaduan!)
|
||||
? FormatHelper.formatDateTime(pengaduan.tanggalPengaduan!)
|
||||
: '-',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
@ -1309,8 +1308,8 @@ class WargaDetailPengaduanView extends GetView<WargaDashboardController> {
|
||||
child: Row(
|
||||
children: tindakan.buktiTindakan!.map((bukti) {
|
||||
return GestureDetector(
|
||||
onTap: () =>
|
||||
showFullScreenImage(context, bukti),
|
||||
onTap: () => ShowImageDialog.showFullScreen(
|
||||
context, bukti),
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
@ -1407,8 +1406,8 @@ class WargaDetailPengaduanView extends GetView<WargaDashboardController> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
tindakan.tanggalTindakan != null
|
||||
? DateFormat('dd MMM yyyy HH:mm', 'id_ID')
|
||||
.format(tindakan.tanggalTindakan!)
|
||||
? FormatHelper.formatDateTime(
|
||||
tindakan.tanggalTindakan!)
|
||||
: '-',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
@ -1429,183 +1428,8 @@ class WargaDetailPengaduanView extends GetView<WargaDashboardController> {
|
||||
);
|
||||
}
|
||||
|
||||
void showFullScreenImage(BuildContext context, String imageUrl) {
|
||||
// Buat controller untuk InteractiveViewer
|
||||
final TransformationController transformationController =
|
||||
TransformationController();
|
||||
|
||||
Get.dialog(
|
||||
Dialog(
|
||||
insetPadding: EdgeInsets.zero,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
Container(
|
||||
color: Colors.black,
|
||||
child: InteractiveViewer(
|
||||
panEnabled: true,
|
||||
minScale: 0.5,
|
||||
maxScale: 4,
|
||||
transformationController: transformationController,
|
||||
child: Center(
|
||||
child: Hero(
|
||||
tag: imageUrl,
|
||||
child: imageUrl.startsWith('http')
|
||||
? Image.network(
|
||||
imageUrl,
|
||||
fit: BoxFit.contain,
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) return child;
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Colors.white),
|
||||
value: loadingProgress.expectedTotalBytes !=
|
||||
null
|
||||
? loadingProgress.cumulativeBytesLoaded /
|
||||
loadingProgress.expectedTotalBytes!
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.broken_image,
|
||||
size: 60,
|
||||
color: Colors.red,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Gagal memuat gambar',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: Image.file(
|
||||
File(imageUrl),
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.broken_image,
|
||||
size: 60,
|
||||
color: Colors.red,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Gagal memuat gambar',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 20,
|
||||
right: 20,
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.back(),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.6),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 20,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
_buildImageControlButton(
|
||||
icon: Icons.zoom_out,
|
||||
onTap: () {
|
||||
// Zoom out
|
||||
final Matrix4 matrix =
|
||||
transformationController.value.clone();
|
||||
matrix.scale(0.75);
|
||||
transformationController.value = matrix;
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
_buildImageControlButton(
|
||||
icon: Icons.refresh,
|
||||
onTap: () {
|
||||
// Reset
|
||||
transformationController.value = Matrix4.identity();
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
_buildImageControlButton(
|
||||
icon: Icons.zoom_in,
|
||||
onTap: () {
|
||||
// Zoom in
|
||||
final Matrix4 matrix =
|
||||
transformationController.value.clone();
|
||||
matrix.scale(1.5);
|
||||
transformationController.value = matrix;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImageControlButton({
|
||||
required IconData icon,
|
||||
required Function() onTap,
|
||||
}) {
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withOpacity(0.6),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
);
|
||||
void _showFullScreenImage(BuildContext context, String imagePath) {
|
||||
ShowImageDialog.showFullScreen(context, imagePath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2056,8 +1880,7 @@ class _TambahTindakanPengaduanViewState
|
||||
}
|
||||
|
||||
void _showFullScreenImage(BuildContext context, String imagePath) {
|
||||
final wargaDetailView = Get.find<WargaDetailPengaduanView>();
|
||||
wargaDetailView.showFullScreenImage(context, imagePath);
|
||||
ShowImageDialog.showFullScreen(context, imagePath);
|
||||
}
|
||||
|
||||
Future<void> _simpanTindakan() async {
|
||||
@ -2078,22 +1901,6 @@ class _TambahTindakanPengaduanViewState
|
||||
});
|
||||
|
||||
try {
|
||||
// Di sini kita baru melakukan upload file ke server
|
||||
// Contoh implementasi:
|
||||
|
||||
// 1. Upload semua file bukti tindakan
|
||||
// final List<String> buktiTindakanUrls = await uploadMultipleFiles(buktiTindakanPaths);
|
||||
|
||||
// 2. Simpan data tindakan ke database
|
||||
// await saveTindakanPengaduan(
|
||||
// pengaduanId: widget.pengaduanId,
|
||||
// kategoriTindakan: selectedKategori!,
|
||||
// prioritas: selectedPrioritas!,
|
||||
// tindakan: tindakanController.text,
|
||||
// catatan: catatanController.text,
|
||||
// buktiTindakanUrls: buktiTindakanUrls,
|
||||
// );
|
||||
|
||||
// Tampilkan pesan sukses
|
||||
Get.back(); // Kembali ke halaman sebelumnya
|
||||
Get.snackbar(
|
||||
|
@ -11,12 +11,12 @@ class FormPengaduanView extends StatefulWidget {
|
||||
final List<File>? selectedImages;
|
||||
|
||||
const FormPengaduanView({
|
||||
Key? key,
|
||||
super.key,
|
||||
required this.uidPenerimaan,
|
||||
this.judul,
|
||||
this.deskripsi,
|
||||
this.selectedImages,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<FormPengaduanView> createState() => _FormPengaduanViewState();
|
||||
@ -219,7 +219,7 @@ class _FormPengaduanViewState extends State<FormPengaduanView> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
SizedBox(
|
||||
height: 120,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/utils/format_helper.dart';
|
||||
import 'package:penyaluran_app/app/widgets/section_header.dart';
|
||||
|
||||
class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
@ -23,6 +23,54 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Header DisalurKita dengan logo dan slogan
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.blue.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/logo-disalurkita.png',
|
||||
width: 50,
|
||||
height: 50,
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'DisalurKita',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF1565C0),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
'Salurkan dengan Pasti, Pantau dengan Bukti',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
_buildWelcomeSection(),
|
||||
const SizedBox(height: 24),
|
||||
_buildStatisticSection(),
|
||||
@ -90,10 +138,17 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
? NetworkImage(controller.profilePhotoUrl!)
|
||||
: null,
|
||||
child: controller.profilePhotoUrl == null
|
||||
? Icon(
|
||||
Icons.person,
|
||||
color: Colors.blue.shade700,
|
||||
size: 30,
|
||||
? Text(
|
||||
controller.nama.isNotEmpty
|
||||
? controller.nama
|
||||
.substring(0, 1)
|
||||
.toUpperCase()
|
||||
: '?',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.blue.shade700,
|
||||
fontSize: 24,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@ -417,12 +472,6 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
}
|
||||
|
||||
Widget _buildPenerimaanSummary() {
|
||||
final currencyFormat = NumberFormat.currency(
|
||||
locale: 'id',
|
||||
symbol: 'Rp ',
|
||||
decimalDigits: 0,
|
||||
);
|
||||
|
||||
double totalUang = 0;
|
||||
Map<String, double> totalNonUang = {};
|
||||
|
||||
@ -494,7 +543,7 @@ class WargaDashboardView extends GetView<WargaDashboardController> {
|
||||
icon: Icons.attach_money,
|
||||
color: Colors.green,
|
||||
title: 'Total Bantuan Uang',
|
||||
value: currencyFormat.format(totalUang),
|
||||
value: FormatHelper.formatRupiah(totalUang),
|
||||
),
|
||||
if (totalNonUang.isNotEmpty) ...[
|
||||
if (totalUang > 0)
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
|
||||
import 'package:penyaluran_app/app/data/models/pengaduan_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/utils/format_helper.dart';
|
||||
import 'package:penyaluran_app/app/widgets/status_badge.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
@ -131,17 +131,11 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
}
|
||||
|
||||
Widget _buildHeaderSection(PenerimaPenyaluranModel penyaluran) {
|
||||
final currencyFormat = NumberFormat.currency(
|
||||
locale: 'id',
|
||||
symbol: 'Rp ',
|
||||
decimalDigits: 0,
|
||||
);
|
||||
|
||||
// Format jumlah bantuan berdasarkan tipe (uang atau bukan)
|
||||
String formattedJumlah = '';
|
||||
if (penyaluran.jumlahBantuan != null) {
|
||||
if (penyaluran.isUang == true) {
|
||||
formattedJumlah = currencyFormat.format(penyaluran.jumlahBantuan);
|
||||
formattedJumlah = FormatHelper.formatRupiah(penyaluran.jumlahBantuan);
|
||||
} else {
|
||||
formattedJumlah =
|
||||
'${penyaluran.jumlahBantuan} ${penyaluran.satuan ?? ''}';
|
||||
@ -390,8 +384,7 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
icon: Icons.calendar_today,
|
||||
title: 'Tanggal Penerimaan',
|
||||
value: penyaluran.tanggalPenerimaan != null
|
||||
? DateFormat('dd MMMM yyyy', 'id_ID')
|
||||
.format(penyaluran.tanggalPenerimaan!)
|
||||
? FormatHelper.formatDateTime(penyaluran.tanggalPenerimaan!)
|
||||
: 'Belum diterima',
|
||||
statusColor: null,
|
||||
),
|
||||
@ -400,8 +393,7 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
icon: Icons.access_time,
|
||||
title: 'Waktu Penerimaan',
|
||||
value: penyaluran.tanggalPenerimaan != null
|
||||
? DateFormat('HH:mm', 'id_ID')
|
||||
.format(penyaluran.tanggalPenerimaan!)
|
||||
? FormatHelper.formatDateTime(penyaluran.tanggalPenerimaan!)
|
||||
: 'Belum diterima',
|
||||
statusColor: null,
|
||||
),
|
||||
@ -758,8 +750,7 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
icon: Icons.update,
|
||||
title: 'Terakhir Diperbarui',
|
||||
value: penyaluran.tanggalPenerimaan != null
|
||||
? DateFormat('dd MMMM yyyy HH:mm', 'id_ID')
|
||||
.format(penyaluran.tanggalPenerimaan!)
|
||||
? FormatHelper.formatDateTime(penyaluran.tanggalPenerimaan!)
|
||||
: 'Tidak tersedia',
|
||||
statusColor: null,
|
||||
),
|
||||
@ -1394,7 +1385,7 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Pengaduan Terdaftar',
|
||||
'Pengaduan',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
@ -1547,8 +1538,7 @@ class WargaDetailPenerimaanView extends GetView<WargaDashboardController> {
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
pengaduan.tanggalPengaduan != null
|
||||
? DateFormat('dd MMMM yyyy HH:mm', 'id_ID')
|
||||
.format(pengaduan.tanggalPengaduan!)
|
||||
? FormatHelper.formatDateTime(pengaduan.tanggalPengaduan!)
|
||||
: 'Tanggal tidak tersedia',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
|
@ -1,12 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:penyaluran_app/app/data/models/penerima_penyaluran_model.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/controllers/warga_dashboard_controller.dart';
|
||||
import 'package:penyaluran_app/app/modules/warga/views/form_pengaduan_view.dart';
|
||||
import 'package:penyaluran_app/app/utils/format_helper.dart';
|
||||
import 'dart:io';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
class WargaPengaduanView extends GetView<WargaDashboardController> {
|
||||
const WargaPengaduanView({super.key});
|
||||
@ -380,7 +375,7 @@ class WargaPengaduanView extends GetView<WargaDashboardController> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.tanggalPengaduan != null
|
||||
? DateTimeHelper.formatDateTime(
|
||||
? FormatHelper.formatDateTime(
|
||||
item.tanggalPengaduan!)
|
||||
: '-',
|
||||
style: TextStyle(
|
||||
|
@ -20,13 +20,13 @@ class WargaView extends GetView<WargaDashboardController> {
|
||||
title: Obx(() {
|
||||
switch (controller.activeTabIndex.value) {
|
||||
case 0:
|
||||
return const Text('Dashboard Warga');
|
||||
return const Text('Dashboard');
|
||||
case 1:
|
||||
return const Text('Penerimaan Bantuan');
|
||||
case 2:
|
||||
return const Text('Pengaduan');
|
||||
default:
|
||||
return const Text('Dashboard Warga');
|
||||
return const Text('Dashboard');
|
||||
}
|
||||
}),
|
||||
leading: IconButton(
|
||||
@ -164,16 +164,19 @@ class WargaView extends GetView<WargaDashboardController> {
|
||||
child: CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.white70,
|
||||
backgroundImage: controller.profilePhotoUrl != null &&
|
||||
controller.profilePhotoUrl!.isNotEmpty
|
||||
? NetworkImage(controller.profilePhotoUrl!)
|
||||
backgroundImage: controller.fotoProfil.value.isNotEmpty
|
||||
? NetworkImage(controller.fotoProfil.value)
|
||||
: null,
|
||||
child: controller.profilePhotoUrl == null ||
|
||||
controller.profilePhotoUrl!.isEmpty
|
||||
? Icon(
|
||||
Icons.person,
|
||||
color: Colors.white,
|
||||
size: 40,
|
||||
child: controller.fotoProfil.isEmpty
|
||||
? Text(
|
||||
controller.nama.isNotEmpty
|
||||
? controller.nama.substring(0, 1).toUpperCase()
|
||||
: '?',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontSize: 24,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
@ -292,6 +295,15 @@ class WargaView extends GetView<WargaDashboardController> {
|
||||
controller.refreshData();
|
||||
},
|
||||
),
|
||||
_buildMenuItem(
|
||||
icon: Icons.info_outline,
|
||||
activeIcon: Icons.info,
|
||||
title: 'Tentang Kami',
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
Get.toNamed('/about');
|
||||
},
|
||||
),
|
||||
_buildMenuItem(
|
||||
icon: Icons.logout,
|
||||
title: 'Keluar',
|
||||
@ -307,7 +319,7 @@ class WargaView extends GetView<WargaDashboardController> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Text(
|
||||
'© ${DateTime.now().year} Aplikasi Penyaluran Bantuan',
|
||||
'© ${DateTime.now().year} DisalurKita',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey,
|
||||
|
Reference in New Issue
Block a user