Perbarui model dan tampilan untuk menambahkan properti fotoProfil di DonaturModel, PetugasDesaModel, dan WargaModel. Modifikasi controller dan tampilan untuk mendukung pengambilan dan penampilan foto profil pengguna. Tambahkan fungsionalitas baru untuk menampilkan foto profil di berbagai tampilan, termasuk detail penerima dan dashboard warga. Perbarui rute aplikasi untuk mencakup halaman profil pengguna.

This commit is contained in:
Khafidh Fuadi
2025-03-25 12:21:37 +07:00
parent 8e9553d1fc
commit 32736be867
19 changed files with 2138 additions and 752 deletions

View File

@ -3,16 +3,24 @@ import 'package:get/get.dart';
import 'package:penyaluran_app/app/data/models/user_model.dart';
import 'package:penyaluran_app/app/services/supabase_service.dart';
import 'package:penyaluran_app/app/modules/auth/controllers/auth_controller.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
class ProfileController extends GetxController {
final SupabaseService _supabaseService = Get.find<SupabaseService>();
final AuthController _authController = Get.find<AuthController>();
final ImagePicker _imagePicker = ImagePicker();
final Rx<BaseUserModel?> user = Rx<BaseUserModel?>(null);
final RxBool isLoading = true.obs;
final RxBool isEditing = false.obs;
final Rx<Map<String, dynamic>?> roleData = Rx<Map<String, dynamic>?>(null);
// Untuk foto profil
final RxString fotoProfil = ''.obs;
final RxString fotoProfilPath = ''.obs;
final RxBool isUploadingFoto = false.obs;
// Form controllers
late TextEditingController nameController;
late TextEditingController emailController;
@ -51,10 +59,15 @@ class ProfileController extends GetxController {
if (userData['role_data'] != null) {
roleData.value = userData['role_data'] as Map<String, dynamic>?;
// Jika role adalah warga, ambil no telepon dari role data
if (user.value?.role?.toLowerCase() == 'warga' &&
roleData.value?['no_hp'] != null) {
if (roleData.value?['no_hp'] != null) {
phoneController.text = roleData.value?['no_hp'] ?? '';
}
// Ambil foto profil jika ada
if (roleData.value?['foto_profil'] != null) {
fotoProfil.value = roleData.value?['foto_profil'] ?? '';
print(fotoProfil.value);
}
}
}
} catch (e) {
@ -74,6 +87,86 @@ class ProfileController extends GetxController {
isEditing.value = !isEditing.value;
}
// Metode untuk memilih foto profil dari kamera
Future<void> pickFotoProfilFromCamera() async {
try {
final pickedFile = await _imagePicker.pickImage(
source: ImageSource.camera,
imageQuality: 80,
maxWidth: 1000,
maxHeight: 1000,
);
if (pickedFile != null) {
fotoProfilPath.value = pickedFile.path;
}
} catch (e) {
print('Error mengambil foto dari kamera: $e');
Get.snackbar(
'Error',
'Gagal mengambil foto: ${e.toString()}',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
}
// Metode untuk memilih foto profil dari galeri
Future<void> pickFotoProfilFromGallery() async {
try {
final pickedFile = await _imagePicker.pickImage(
source: ImageSource.gallery,
imageQuality: 80,
maxWidth: 1000,
maxHeight: 1000,
);
if (pickedFile != null) {
fotoProfilPath.value = pickedFile.path;
}
} catch (e) {
print('Error mengambil foto dari galeri: $e');
Get.snackbar(
'Error',
'Gagal mengambil foto: ${e.toString()}',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red,
colorText: Colors.white,
);
}
}
// Metode untuk menghapus foto profil
void clearFotoProfil() {
fotoProfilPath.value = '';
}
// Metode untuk mengupload foto profil
Future<String?> _uploadFotoProfil() async {
if (fotoProfilPath.isEmpty) return null;
try {
isUploadingFoto.value = true;
final userData = user.value;
if (userData == null) throw 'Data user tidak ditemukan';
// Upload foto ke Supabase storage
final fotoUrl = await _supabaseService.uploadFile(
fotoProfilPath.value,
'profiles', // bucket name
'profile_photos/${userData.id}', // folder path
);
return fotoUrl;
} catch (e) {
print('Error upload foto profil: $e');
throw e.toString();
} finally {
isUploadingFoto.value = false;
}
}
Future<void> updateProfile() async {
if (nameController.text.isEmpty) {
Get.snackbar(
@ -91,6 +184,15 @@ class ProfileController extends GetxController {
final userData = user.value;
if (userData == null) throw 'Data user tidak ditemukan';
// Upload foto profil jika ada
String? fotoProfilUrl;
if (fotoProfilPath.isNotEmpty) {
fotoProfilUrl = await _uploadFotoProfil();
if (fotoProfilUrl == null) {
throw 'Gagal mengupload foto profil';
}
}
// Update data sesuai role
switch (userData.role?.toLowerCase() ?? 'unknown') {
case 'warga':
@ -99,6 +201,7 @@ class ProfileController extends GetxController {
namaLengkap: nameController.text,
noHp: phoneController.text,
email: emailController.text,
fotoProfil: fotoProfilUrl,
);
break;
case 'donatur':
@ -107,6 +210,7 @@ class ProfileController extends GetxController {
nama: nameController.text,
noHp: phoneController.text,
email: emailController.text,
fotoProfil: fotoProfilUrl,
);
break;
case 'petugas_desa':
@ -115,6 +219,7 @@ class ProfileController extends GetxController {
nama: nameController.text,
noHp: phoneController.text,
email: emailController.text,
fotoProfil: fotoProfilUrl,
);
break;
default:
@ -127,6 +232,9 @@ class ProfileController extends GetxController {
// Refresh data di AuthController untuk menyebarkan perubahan ke seluruh aplikasi
await _authController.refreshUserData();
// Reset path foto setelah update
fotoProfilPath.value = '';
// Keluar dari mode edit
isEditing.value = false;