MIF_E31222846/lib/views/siswa/profile.dart

709 lines
23 KiB
Dart

// ignore_for_file: must_be_immutable
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:ui/routes/app_routes.dart';
import 'package:ui/views/siswa/controllers/siswa_controller.dart';
class ProfileSiswa extends StatelessWidget {
ProfileSiswa({super.key});
SiswaController siswaC = Get.find<SiswaController>();
@override
Widget build(BuildContext context) {
siswaC.getAnalysis();
final size = MediaQuery.of(context).size;
final isTablet = size.width > 600;
return Scaffold(
backgroundColor: const Color(0xFFF8FAFC),
appBar: AppBar(
title: const Text(
'Profil Siswa',
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 20,
color: Colors.white,
fontFamily: 'Poppins',
),
),
centerTitle: true,
elevation: 0,
backgroundColor: Colors.transparent,
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF667EEA),
Color(0xFF764BA2),
],
),
),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.white),
onPressed: () => Get.back(),
),
),
body: RefreshIndicator(
onRefresh: () async {
await siswaC.getAnalysis();
},
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [
// Header profil dengan gradient
_buildProfileHeader(isTablet),
// Konten utama
Padding(
padding: EdgeInsets.symmetric(
horizontal: isTablet ? size.width * 0.1 : 20, vertical: 20),
child: Column(
children: [
// Card untuk konten analisis
_buildAnalysisCard(context, isTablet),
SizedBox(height: isTablet ? 32 : 24),
// Tombol-tombol aksi
_buildActionButtons(context, isTablet),
],
),
),
],
),
),
),
);
}
Widget _buildProfileHeader(bool isTablet) {
return Container(
padding: EdgeInsets.symmetric(
vertical: isTablet ? 40 : 30, horizontal: isTablet ? 40 : 20),
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF667EEA),
Color(0xFF764BA2),
],
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
boxShadow: [
BoxShadow(
color: Color(0xFF667EEA),
blurRadius: 20,
offset: Offset(0, 10),
),
],
),
child: Obx(
() => Column(
children: [
// Avatar dengan animasi
Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white,
width: 3,
),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 15,
offset: const Offset(0, 8),
),
],
),
child: CircleAvatar(
radius: isTablet ? 70 : 60,
backgroundColor: Colors.white,
child: Icon(
Icons.person,
size: isTablet ? 70 : 60,
color: const Color(0xFF667EEA),
),
),
),
const SizedBox(height: 20),
Text(
siswaC.dataUser['user']['nama'],
style: TextStyle(
fontSize: isTablet ? 28 : 24,
fontWeight: FontWeight.w700,
color: Colors.white,
fontFamily: 'Poppins',
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: Colors.white.withOpacity(0.3),
width: 1,
),
),
child: Text(
'Kelas ${siswaC.dataUser['user']['kelas']}',
style: TextStyle(
fontSize: isTablet ? 18 : 16,
color: Colors.white,
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
),
),
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(
Icons.email_outlined,
color: Colors.white,
size: 18,
),
),
const SizedBox(width: 12),
Text(
siswaC.dataUser['user']['user']['email'].toString(),
style: TextStyle(
fontSize: isTablet ? 16 : 14,
color: Colors.white,
fontWeight: FontWeight.w500,
fontFamily: 'Poppins',
),
),
],
),
],
),
),
);
}
Widget _buildAnalysisCard(BuildContext context, bool isTablet) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Padding(
padding: EdgeInsets.all(isTablet ? 24 : 20),
child: Obx(
() {
if (siswaC.isLoadingAnalysis.value) {
return Container(
height: 200,
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFF6366F1),
),
strokeWidth: 3,
),
),
const SizedBox(height: 20),
const Text(
'Memuat data analisis...',
style: TextStyle(
color: Colors.grey,
fontSize: 16,
fontFamily: 'Poppins',
),
)
],
),
);
}
var kelebihan = siswaC.dataAnalysis['kelebihan'];
var kekurangan = siswaC.dataAnalysis['kekurangan'];
return Column(
children: [
if (siswaC.kelebihanIsEmpty.value)
const SizedBox()
else
Column(children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFF10B981).withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(
Icons.quiz,
color: Color(0xFF10B981),
size: 24,
),
),
const SizedBox(width: 12),
const Text(
'Rata rata Kuis',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: 'Poppins',
),
),
],
),
const SizedBox(height: 16),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: siswaC.dataAnalysis['kelebihan'].length,
itemBuilder: (context, index) {
return AnimatedProgressItem(
title: kelebihan[index]['mapel'],
percentage: kelebihan[index]['persentase'],
color: const Color(0xFF10B981),
isTablet: isTablet,
animationDelay: (index * 200),
);
},
),
]),
if (siswaC.kekuranganIsEmpty.value)
const SizedBox()
else
Column(children: [
const SizedBox(height: 24),
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFFEF4444).withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(
Icons.trending_down,
color: Color(0xFFEF4444),
size: 24,
),
),
const SizedBox(width: 12),
const Text(
'Perlu Perbaikan',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.black87,
fontFamily: 'Poppins',
),
),
],
),
const SizedBox(height: 16),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: siswaC.dataAnalysis['kekurangan'].length,
itemBuilder: (context, index) {
return AnimatedProgressItem(
title: kekurangan[index]['mapel'],
percentage: kekurangan[index]['persentase'],
color: const Color(0xFFEF4444),
isTablet: isTablet,
animationDelay: (index * 200) + 500,
);
},
),
]),
if (siswaC.kelebihanIsEmpty.value &&
siswaC.kekuranganIsEmpty.value)
Container(
padding: const EdgeInsets.all(40),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: const Color(0xFF6366F1).withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
),
child: const Icon(
Icons.analytics_outlined,
size: 60,
color: Color(0xFF6366F1),
),
),
const SizedBox(height: 20),
const Text(
'Belum ada data analisis',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.grey,
fontFamily: 'Poppins',
),
),
const SizedBox(height: 8),
const Text(
'Data akan muncul setelah mengerjakan kuis',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
fontFamily: 'Poppins',
),
textAlign: TextAlign.center,
),
],
),
),
],
);
},
),
),
);
}
Widget _buildActionButtons(BuildContext context, bool isTablet) {
return Column(
children: [
// Tombol Ubah Password
GestureDetector(
onTap: () {
Get.toNamed(AppRoutes.ubahPassord);
},
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 18),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF6366F1), Color(0xFF8B5CF6)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: const Color(0xFF6366F1).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(
Icons.lock_reset,
color: Colors.white,
size: 20,
),
),
const SizedBox(width: 12),
Text(
'Ubah Password',
style: TextStyle(
fontSize: isTablet ? 18 : 16,
fontWeight: FontWeight.w600,
color: Colors.white,
fontFamily: 'Poppins',
),
),
],
),
),
),
SizedBox(height: isTablet ? 20 : 16),
// Tombol Logout
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: const Text(
'Konfirmasi Logout',
style: TextStyle(
fontWeight: FontWeight.w600,
fontFamily: 'Poppins',
),
),
content: const Text(
'Apakah Anda yakin ingin logout?',
style: TextStyle(
fontFamily: 'Poppins',
),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: const Text(
'Batal',
style: TextStyle(
color: Colors.grey,
fontFamily: 'Poppins',
),
),
),
ElevatedButton(
onPressed: () {
siswaC.logout(role: "siswa");
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFEF4444),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
child: const Text(
'Logout',
style: TextStyle(
fontFamily: 'Poppins',
),
),
),
],
),
);
},
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 18),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFFEF4444), Color(0xFFDC2626)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: const Color(0xFFEF4444).withOpacity(0.3),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(
Icons.logout,
color: Colors.white,
size: 20,
),
),
const SizedBox(width: 12),
Text(
'Logout',
style: TextStyle(
fontSize: isTablet ? 18 : 16,
fontWeight: FontWeight.w600,
color: Colors.white,
fontFamily: 'Poppins',
),
),
],
),
),
),
],
);
}
}
// Widget untuk progress item dengan animasi
class AnimatedProgressItem extends StatefulWidget {
final String title;
final int percentage;
final Color color;
final bool isTablet;
final int animationDelay;
const AnimatedProgressItem({
super.key,
required this.title,
required this.percentage,
required this.color,
required this.isTablet,
this.animationDelay = 0,
});
@override
State<AnimatedProgressItem> createState() => _AnimatedProgressItemState();
}
class _AnimatedProgressItemState extends State<AnimatedProgressItem>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
_animation = Tween<double>(begin: 0, end: widget.percentage / 100)
.animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeOutQuart,
));
// Tunda animasi sesuai dengan delay yang diberikan
Future.delayed(Duration(milliseconds: widget.animationDelay), () {
if (mounted) {
_controller.forward();
}
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final textStyle = TextStyle(
fontSize: widget.isTablet ? 16 : 14,
fontWeight: FontWeight.w500,
color: Colors.black87,
fontFamily: 'Poppins',
);
return Container(
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: widget.color.withOpacity(0.1),
width: 1,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
widget.title,
style: textStyle.copyWith(
fontWeight: FontWeight.w600,
),
),
),
AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: widget.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'${(_animation.value * 100).toInt()}%',
style: textStyle.copyWith(
color: widget.color,
fontWeight: FontWeight.w700,
fontSize: 12,
),
),
);
},
),
],
),
const SizedBox(height: 12),
AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: LinearProgressIndicator(
value: _animation.value,
backgroundColor: widget.color.withOpacity(0.1),
color: widget.color,
minHeight: widget.isTablet ? 12 : 10,
),
);
},
),
],
),
);
}
}