HydroNutrify_Ari_e41221567/lib/data/services/users_service.dart

157 lines
5.3 KiB
Dart

import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:image/image.dart' as img;
import 'package:path_provider/path_provider.dart';
/// Service untuk mengelola data user (profile, foto, password)
class UsersService {
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
static const String collectionName = 'users';
User? get currentUser => _auth.currentUser;
String get userId => currentUser?.uid ?? '';
/// Inisiasi profil saat pertama kali register
Future<void> createUserDocument(String uid, String name, String email) async {
try {
await _firestore.collection(collectionName).doc(uid).set({
'user_id': uid,
'display_name': name.trim(),
'email': email.trim(),
'created_at': FieldValue.serverTimestamp(),
'updated_at': FieldValue.serverTimestamp(),
});
} catch (e) {
throw Exception('Gagal inisiasi dokumen user: $e');
}
}
/// Update nama user di Firebase Auth dan Firestore
Future<void> updateName(String name) async {
try {
await currentUser?.updateDisplayName(name.trim());
await _firestore.collection(collectionName).doc(userId).set(
{
'user_id': userId,
'display_name': name.trim(),
'updated_at': FieldValue.serverTimestamp(),
},
SetOptions(merge: true),
);
await currentUser?.reload();
} catch (e) {
throw Exception('Gagal update nama: $e');
}
}
/// Kompresi gambar ke 800x800px dengan quality 75%
Future<File> _compressImage(File imageFile) async {
try {
final bytes = await imageFile.readAsBytes();
final image = img.decodeImage(bytes);
if (image == null) throw Exception('Gagal decode gambar');
final resized = img.copyResize(image, width: 800, height: 800, maintainAspect: true);
final compressed = img.encodeJpg(resized, quality: 75);
final dir = await getApplicationDocumentsDirectory();
final compressedFile = File('${dir.path}/profile_compressed.jpg');
await compressedFile.writeAsBytes(compressed);
return compressedFile;
} catch (e) {
throw Exception('Gagal kompresi foto: $e');
}
}
/// Simpan foto profil ke lokal storage dengan kompresi
Future<String> saveProfilePhotoLocal(File imageFile) async {
try {
if (userId.isEmpty) throw Exception('User tidak terautentikasi');
if (!await imageFile.exists()) throw Exception('File gambar tidak ditemukan');
final compressedFile = await _compressImage(imageFile);
final appDocDir = await getApplicationDocumentsDirectory();
final photosDir = Directory('${appDocDir.path}/HydroNutrify/photos');
if (!await photosDir.exists()) {
await photosDir.create(recursive: true);
}
final fileName = 'profile_${DateTime.now().millisecondsSinceEpoch}.jpg';
final localPath = '${photosDir.path}/$fileName';
await compressedFile.copy(localPath);
await _firestore.collection(collectionName).doc(userId).set({
'user_id': userId,
'profile_photo_filename': fileName,
'profile_photo_path': localPath,
'updated_at': FieldValue.serverTimestamp(),
}, SetOptions(merge: true));
return localPath;
} catch (e) {
throw Exception('Gagal simpan foto lokal: $e');
}
}
/// Get path foto profil dari lokal storage
Future<String?> getProfilePhotoPath() async {
try {
final profile = await getUserProfile();
if (profile != null) {
final filePath = profile['profile_photo_path'] as String?;
if (filePath != null && await File(filePath).exists()) {
return filePath;
}
}
return null;
} catch (e) {
return null;
}
}
/// Update password dengan re-authentication
Future<void> reauthenticateAndUpdatePassword(String oldPassword, String newPassword) async {
try {
if (currentUser == null) throw Exception('User tidak ditemukan');
final email = currentUser!.email;
if (email == null) throw Exception('Email tidak ditemukan');
final credential = EmailAuthProvider.credential(email: email, password: oldPassword);
await currentUser!.reauthenticateWithCredential(credential);
await currentUser!.updatePassword(newPassword);
} on FirebaseAuthException catch (e) {
if (e.code == 'wrong-password') {
throw Exception('Password lama salah');
} else if (e.code == 'weak-password') {
throw Exception('Password baru terlalu lemah');
}
throw Exception('Gagal update password: ${e.message}');
}
}
/// Get data profile user dari Firestore
Future<Map<String, dynamic>?> getUserProfile() async {
try {
if (userId.isEmpty) return null;
final doc = await _firestore.collection(collectionName).doc(userId).get();
return doc.data();
} catch (e) {
return null;
}
}
/// Stream perubahan profile user real-time
Stream<DocumentSnapshot?> getUserProfileStream() {
if (userId.isEmpty) return Stream.value(null);
return _firestore.collection(collectionName).doc(userId).snapshots().handleError((e) {
debugPrint('[UsersService] Stream error: $e');
return null;
});
}
}