Tambahkan SVG ikon dan perbarui tampilan dashboard

- Integrasikan flutter_svg untuk ikon vektor
- Ganti ikon default dengan SVG dari aset
- Perbarui desain statistik dan daftar dengan tampilan baru
- Tambahkan daftar donasi dan donatur
- Modifikasi tata letak dan gaya komponen dashboard
This commit is contained in:
Khafidh Fuadi
2025-03-08 11:54:36 +07:00
parent b6b4d63802
commit eb80fb629a
3 changed files with 312 additions and 62 deletions

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:penyaluran_app/app/modules/dashboard/controllers/dashboard_controller.dart';
import 'package:google_fonts/google_fonts.dart';
@ -10,12 +11,14 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
Widget build(BuildContext context) {
final TextTheme textTheme =
GoogleFonts.dmSansTextTheme(Theme.of(context).textTheme);
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
return Theme(
data: Theme.of(context).copyWith(
textTheme: textTheme,
),
child: Scaffold(
key: _scaffoldKey,
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
@ -60,7 +63,12 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
),
),
ListTile(
leading: const Icon(Icons.home),
leading: SvgPicture.asset(
'assets/icons/home-icon.svg',
width: 24,
height: 24,
color: Colors.grey[700],
),
title: const Text('Beranda'),
onTap: () {
Get.back();
@ -110,6 +118,11 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// add drawer button
IconButton(
onPressed: () => _scaffoldKey.currentState?.openDrawer(),
icon: const Icon(Icons.menu),
),
// Header dengan greeting
_buildGreetingHeader(textTheme),
const SizedBox(height: 20),
@ -122,7 +135,7 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
dateTime: '15 April 2023, 13:00 - 14:00',
isToday: true,
),
const SizedBox(height: 10),
const SizedBox(height: 20),
// Jadwal penyaluran mendatang
_buildScheduleCard(
@ -144,6 +157,11 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
// Daftar penerima
_buildRecipientsList(textTheme),
// Daftar Donasi
_buildDonationList(textTheme),
// Daftar Donatur
_buildDonorsList(textTheme),
],
);
}),
@ -155,21 +173,37 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
type: BottomNavigationBarType.fixed,
selectedLabelStyle: textTheme.bodySmall,
unselectedLabelStyle: textTheme.bodySmall,
items: const [
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
icon: SvgPicture.asset(
'assets/icons/home-icon.svg',
width: 24,
height: 24,
),
label: 'Beranda',
),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today),
icon: SvgPicture.asset(
'assets/icons/jadwal-icon.svg',
width: 24,
height: 24,
),
label: 'Jadwal',
),
BottomNavigationBarItem(
icon: Icon(Icons.notifications),
icon: SvgPicture.asset(
'assets/icons/notif-icon.svg',
width: 24,
height: 24,
),
label: 'Notifikasi',
),
BottomNavigationBarItem(
icon: Icon(Icons.inventory),
icon: SvgPicture.asset(
'assets/icons/inventory-icon.svg',
width: 24,
height: 24,
),
label: 'Inventaris',
),
],
@ -272,11 +306,11 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
return Row(
children: [
Expanded(
child: _buildStatCard('Penerima', '3', 'Konfirmasi', textTheme),
child: _buildStatCard('Penitipan', '3', 'Konfirmasi', textTheme),
),
const SizedBox(width: 10),
Expanded(
child: _buildStatCard('Pengajuan', '1', 'Pengajuan', textTheme),
child: _buildStatCard('Penjadwalan', '1', 'Pengajuan', textTheme),
),
const SizedBox(width: 10),
Expanded(
@ -303,6 +337,13 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
color: Colors.white.withOpacity(0.8),
),
),
Text(
count,
style: textTheme.headlineSmall?.copyWith(
@ -325,48 +366,60 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
}
Widget _buildProgressSection(TextTheme textTheme) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Progress Penyaluran',
style: textTheme.titleMedium?.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
),
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFF2E5077), Color(0xFF5882B1)],
transform: GradientRotation(96.93 * 3.14159 / 180),
),
const SizedBox(height: 10),
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LinearProgressIndicator(
value: 0.7,
minHeight: 10,
backgroundColor: Colors.grey[300],
valueColor: const AlwaysStoppedAnimation<Color>(Color(0xFF2E5077)),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Progress Penyaluran',
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
color: Colors.white.withOpacity(0.8),
),
),
),
const SizedBox(height: 10),
Text(
'70% Selesai',
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
fontWeight: FontWeight.bold,
color: const Color(0xFF2E5077),
const SizedBox(height: 10),
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: LinearProgressIndicator(
value: 0.7,
minHeight: 10,
backgroundColor: Colors.white.withOpacity(0.3),
valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
const SizedBox(height: 10),
_buildProgressDetailRow('Telah Menerima', 70, textTheme),
_buildProgressDetailRow('Dijedwalkan', 20, textTheme),
_buildProgressDetailRow('Belum Dijadwalkan', 10, textTheme),
const SizedBox(height: 5),
Text(
'Total : 100 Penerima, Telah Disalurkan : 70 Penerima, Belum Disalurkan : 30',
style: textTheme.bodySmall?.copyWith(
fontSize: 12,
color: Colors.grey[600],
const SizedBox(height: 10),
Text(
'70% Selesai',
style: textTheme.bodyMedium?.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
const SizedBox(height: 10),
_buildProgressDetailRow('Telah Menerima', 70, textTheme),
_buildProgressDetailRow('Dijedwalkan', 20, textTheme),
_buildProgressDetailRow('Belum Dijadwalkan', 10, textTheme),
const SizedBox(height: 5),
Text(
'Total : 100 Penerima, Telah Disalurkan : 70 Penerima, Belum Disalurkan : 30',
style: textTheme.bodySmall?.copyWith(
fontSize: 12,
color: Colors.white.withOpacity(0.8),
),
),
],
),
);
}
@ -376,17 +429,17 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
child: Row(
children: [
Expanded(
flex: 3,
flex: 5,
child: Text(
label,
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
color: Colors.grey[700],
color: Colors.white,
),
),
),
Expanded(
flex: 7,
flex: 5,
child: Stack(
children: [
Container(
@ -402,7 +455,7 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
0.7 *
(value / 100),
decoration: BoxDecoration(
color: const Color(0xFF2E5077),
color: const Color(0xFFE4F1AC),
borderRadius: BorderRadius.circular(4),
),
),
@ -411,10 +464,11 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
),
const SizedBox(width: 10),
Text(
'$value',
'$value%',
style: textTheme.bodyMedium?.copyWith(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
@ -423,6 +477,31 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
}
Widget _buildRecipientsList(TextTheme textTheme) {
return _buildList(
textTheme: textTheme,
title: 'Daftar Penerima',
items: [
{
'title': 'Siti Rahayu',
'subtitle': '3201020107030010',
'status': 'Selesai'
},
{
'title': 'Siti Rahayu',
'subtitle': '3201020107030010',
'status': 'Selesai'
},
{
'title': 'Siti Rahayu',
'subtitle': '3201020107030010',
'status': 'Selesai'
},
],
idLabel: 'NIK',
);
}
Widget _buildDonorsList(TextTheme textTheme) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -430,7 +509,7 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Daftar Penerima',
'Daftar Donatur',
style: textTheme.titleMedium?.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
@ -457,18 +536,14 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
],
),
const SizedBox(height: 10),
_buildRecipientItem(
'Siti Rahayu', '3201020107030010', 'Selesai', textTheme),
_buildRecipientItem(
'Siti Rahayu', '3201020107030010', 'Selesai', textTheme),
_buildRecipientItem(
'Siti Rahayu', '3201020107030010', 'Selesai', textTheme),
_buildDonorItem('PT Sejahtera', 'D-2023-001', textTheme),
_buildDonorItem('Yayasan Peduli', 'D-2023-002', textTheme),
_buildDonorItem('CV Makmur', 'D-2023-003', textTheme),
],
);
}
Widget _buildRecipientItem(
String name, String nik, String status, TextTheme textTheme) {
Widget _buildDonorItem(String name, String id, TextTheme textTheme) {
return Container(
width: double.infinity,
margin: const EdgeInsets.only(bottom: 10),
@ -492,7 +567,117 @@ class PetugasDesaDashboardView extends GetView<DashboardController> {
),
),
subtitle: Text(
'NIK: $nik',
id,
style: textTheme.bodyMedium,
),
trailing: IconButton(
icon: const Icon(
Icons.chevron_right,
color: Colors.grey,
),
onPressed: () {},
),
),
);
}
//daftar donasi
Widget _buildDonationList(TextTheme textTheme) {
return _buildList(
textTheme: textTheme,
title: 'Daftar Donasi',
items: [
{
'title': 'Rp 100.000',
'subtitle': 'Siti Rahayu',
'status': 'Selesai',
},
{
'title': 'Rp 100.000',
'subtitle': 'Siti Rahayu',
'status': 'Selesai',
},
],
idLabel: '',
);
}
Widget _buildList({
required TextTheme textTheme,
required String title,
required List<Map<String, String>> items,
required String idLabel,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: textTheme.titleMedium?.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
TextButton(
onPressed: () {},
child: Row(
children: [
Text(
'Lihat Semua',
style: textTheme.bodyMedium?.copyWith(
color: const Color(0xFF2E5077),
),
),
Icon(
Icons.chevron_right,
size: 16,
color: const Color(0xFF2E5077),
),
],
),
),
],
),
const SizedBox(height: 10),
...items.map((item) => _buildItem(
item['title'] ?? '',
item['subtitle'] ?? '',
item['status'] ?? '',
textTheme,
)),
],
);
}
Widget _buildItem(
String title, String subtitle, String status, TextTheme textTheme) {
return Container(
width: double.infinity,
margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 3,
offset: const Offset(0, 1),
),
],
),
child: ListTile(
title: Text(
title,
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
subtitle,
style: textTheme.bodyMedium,
),
trailing: Row(

View File

@ -33,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
args:
dependency: transitive
description:
name: args
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
url: "https://pub.dev"
source: hosted
version: "2.6.0"
async:
dependency: transitive
description:
@ -134,6 +142,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.2.1"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b
url: "https://pub.dev"
source: hosted
version: "2.0.17"
flutter_test:
dependency: "direct dev"
description: flutter
@ -296,6 +312,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
path_provider:
dependency: transitive
description:
@ -344,6 +368,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "6.0.2"
platform:
dependency: transitive
description:
@ -597,6 +629,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.4"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de"
url: "https://pub.dev"
source: hosted
version: "1.1.18"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.13"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad"
url: "https://pub.dev"
source: hosted
version: "1.1.16"
vector_math:
dependency: transitive
description:
@ -645,6 +701,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
xml:
dependency: transitive
description:
name: xml
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.5.0"
yet_another_json_isolate:
dependency: transitive
description:

View File

@ -50,6 +50,7 @@ dependencies:
# Untuk tampilan loading
flutter_spinkit: ^5.2.0
google_fonts: ^6.2.1
flutter_svg: ^2.0.17
dev_dependencies:
flutter_test: