TIF_E41221079/lib/features/home/tabs/profile_tab.dart

303 lines
9.1 KiB
Dart

// lib/features/home/tabs/profile_tab.dart
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:smpn1_lengkong/core/constants/app_colors.dart';
import 'package:smpn1_lengkong/core/models/student_model.dart';
import 'package:smpn1_lengkong/features/home/widgets/profile_class_card.dart';
class ProfileTab extends StatelessWidget {
final StudentModel student;
final String currentViewingClass;
final Function(String, String) onClassTap;
final Future<void> Function() onRefresh; // Callback untuk refresh data dari parent
const ProfileTab({
super.key,
required this.student,
required this.currentViewingClass,
required this.onClassTap,
required this.onRefresh,
});
// Fungsi untuk menampilkan dialog konfirmasi sebelum pindah kelas
void _showSelectionDialog(
BuildContext context,
String className,
String academicYear,
) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.r),
),
title: const Text("Ganti Tampilan Kelas"),
content: Text(
"Apakah Anda ingin melihat riwayat data untuk Kelas $className (TA $academicYear)?",
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("Batal", style: TextStyle(color: Colors.grey[600])),
),
ElevatedButton(
onPressed: () {
Navigator.pop(context); // Tutup dialog
onClassTap(className, academicYear); // Jalankan perpindahan data
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryBlue,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
child: const Text("Ya, Lihat"),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.backgroundWhite,
// RefreshIndicator membungkus CustomScrollView
body: RefreshIndicator(
onRefresh: onRefresh,
color: AppColors.primaryBlue,
edgeOffset: 100, // Mengatur posisi munculnya loading spinner agar tidak tertutup AppBar
child: CustomScrollView(
// AlwaysScrollable wajib agar fitur refresh aktif walau konten sedikit
physics: const AlwaysScrollableScrollPhysics(
parent: BouncingScrollPhysics(),
),
slivers: [
// HEADER DENGAN BACKGROUND BIRU
SliverAppBar(
expandedHeight: 180.h,
pinned: true,
automaticallyImplyLeading: false,
backgroundColor: AppColors.primaryBlue,
flexibleSpace: FlexibleSpaceBar(
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [AppColors.primaryBlue, Color(0xFF2C64B8)],
),
),
child: Stack(
children: [
Positioned(
right: -20,
top: -20,
child: Icon(
Icons.person,
size: 150.sp,
color: Colors.white.withOpacity(0.1),
),
),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [SizedBox(height: 20.h), _buildAvatar()],
),
),
],
),
),
),
),
// CONTENT SECTION
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(24.w),
child: Column(
children: [
_buildNameSection(),
SizedBox(height: 32.h),
_buildDetailInfoSection(),
SizedBox(height: 32.h),
_buildHistorySection(context),
],
),
),
),
],
),
),
);
}
Widget _buildAvatar() {
return Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 4),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: CachedNetworkImage(
imageUrl: student.photoUrl,
imageBuilder: (context, imageProvider) =>
CircleAvatar(radius: 50.r, backgroundImage: imageProvider),
placeholder: (context, url) => CircleAvatar(
radius: 50.r,
backgroundColor: Colors.white,
child: const CircularProgressIndicator(),
),
errorWidget: (context, url, error) => CircleAvatar(
radius: 50.r,
backgroundColor: Colors.white,
child: Icon(
Icons.person,
size: 50.sp,
color: AppColors.primaryBlue,
),
),
),
);
}
Widget _buildNameSection() {
return Column(
children: [
Text(
student.name,
style: TextStyle(fontSize: 22.sp, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
SizedBox(height: 4.h),
Text(
"NISN: ${student.nisn}",
style: TextStyle(
color: Colors.grey,
fontSize: 14.sp,
fontWeight: FontWeight.w500,
),
),
],
);
}
Widget _buildDetailInfoSection() {
String genderFull = student.gender == "L"
? "Laki-laki"
: student.gender == "P"
? "Perempuan"
: "-";
return Container(
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.03),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
children: [
_infoRow("Kelas Aktif", student.className),
_infoRow("Jenis Kelamin", genderFull),
_infoRow("Status Siswa", student.statusSiswa, isStatus: true),
_infoRow("Angkatan", student.angkatan),
_infoRow("Tahun Masuk", student.tahunMasuk, isLast: true),
],
),
);
}
Widget _buildHistorySection(BuildContext context) {
final sortedHistory = List.from(student.history);
sortedHistory.sort((a, b) {
if (a.className == student.className) return -1;
if (b.className == student.className) return 1;
return b.academicYear.compareTo(a.academicYear);
});
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 4.w),
child: Text(
"RIWAYAT BELAJAR",
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 11.sp,
color: AppColors.textSecondary,
letterSpacing: 1.2,
),
),
),
SizedBox(height: 16.h),
...sortedHistory.map(
(h) => ProfileClassCard(
className: h.className,
academicYear: h.academicYear,
isSelected: currentViewingClass == h.className,
isCurrent: h.className == student.className,
onTap: () {
if (currentViewingClass != h.className) {
_showSelectionDialog(context, h.className, h.academicYear);
}
},
),
),
],
);
}
Widget _infoRow(
String label,
String val, {
bool isStatus = false,
bool isLast = false,
}) {
return Padding(
padding: EdgeInsets.only(bottom: isLast ? 0 : 16.h),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: TextStyle(color: Colors.grey[600], fontSize: 13.sp),
),
Text(
val,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.sp,
color:
isStatus ? AppColors.successGreen : AppColors.textPrimary,
),
),
],
),
if (!isLast) ...[
SizedBox(height: 12.h),
Divider(color: Colors.grey.shade100, height: 1),
],
],
),
);
}
}