import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:ntp/ntp.dart'; import 'package:ui/routes/app_routes.dart'; import 'package:ui/views/siswa/tugas/controllers/tugas_controller.dart'; import 'package:ui/widgets/my_date_format.dart'; import 'package:ui/widgets/my_snackbar.dart'; import 'package:ui/widgets/my_text.dart'; import 'dart:developer'; class TugasDetail extends StatefulWidget { const TugasDetail({super.key}); @override State createState() => _TugasDetailState(); } class _TugasDetailState extends State { TugasController tugasC = Get.find(); var isActive = "belum"; DateTime? dateNow; @override void initState() { super.initState(); log("TugasDetail initState called"); log("Arguments received: " + Get.arguments.toString()); log("Arguments type: " + Get.arguments.runtimeType.toString()); dynamic arg = Get.arguments; String? tugasId; if (arg is String) { tugasId = arg; } else if (arg is Map && arg['id'] != null) { tugasId = arg['id'].toString(); } else if (arg is int) { tugasId = arg.toString(); } print( '[DETAIL] ID diterima di detail: $tugasId ( [36m${tugasId.runtimeType} [0m)'); if (tugasId != null) { tugasC.getTugas(id: tugasId, type: "belum"); } } Future getCurrentTime() async { DateTime now = await NTP.now(); dateNow = DateTime(now.year, now.month, now.day); setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF3F4F6), appBar: AppBar( title: Row( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(12), ), child: const Icon( Icons.assignment, color: Colors.white, size: 24, ), ), const SizedBox(width: 10), Expanded( child: Text( "Detail Tugas", style: const TextStyle( fontWeight: FontWeight.w800, fontSize: 20, color: Colors.white, letterSpacing: 0.5, ), overflow: TextOverflow.ellipsis, ), ), ], ), backgroundColor: Colors.transparent, elevation: 0, flexibleSpace: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Color(0xFF6366F1), Color(0xFF8B5CF6), Color(0xFFEC4899), ], ), ), ), centerTitle: false, ), body: SafeArea( child: Column( children: [ Padding( padding: const EdgeInsets.all(20), child: buttonTab(), ), Expanded( child: Container( margin: const EdgeInsets.symmetric(horizontal: 20), decoration: BoxDecoration( color: Colors.white, borderRadius: const BorderRadius.only( topLeft: Radius.circular(25), topRight: Radius.circular(25), ), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, -5), ), ], ), child: ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(25), topRight: Radius.circular(25), ), child: Column( children: [ if (isActive == "belum") Expanded(child: tugasBelum()), if (isActive == "selesai") Expanded(child: tugasSelesai()), ], ), ), ), ), ], ), ), ); } Widget buttonTab() { return Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(25), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Row( children: [ Expanded( child: GestureDetector( onTap: () { log("Tab 'Belum' tapped"); setState(() { isActive = "belum"; }); log("Calling getTugas with id: ${Get.arguments}, type: belum"); tugasC.getTugas(id: Get.arguments, type: "belum"); }, child: Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), decoration: BoxDecoration( gradient: isActive == "belum" ? const LinearGradient( colors: [Color(0xFF6366F1), Color(0xFF8B5CF6)], begin: Alignment.topLeft, end: Alignment.bottomRight, ) : null, color: isActive == "belum" ? null : Colors.transparent, borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.pending_actions, color: isActive == "belum" ? Colors.white : Colors.grey.shade600, size: 18, ), const SizedBox(width: 6), Text( "Belum", style: TextStyle( fontWeight: FontWeight.w600, color: isActive == "belum" ? Colors.white : Colors.grey.shade600, fontSize: 14, ), ), ], ), ), ), ), Expanded( child: GestureDetector( onTap: () { log("Tab 'Selesai' tapped"); setState(() { isActive = "selesai"; }); log("Calling getTugas with id: ${Get.arguments}, type: selesai"); tugasC.getTugas(id: Get.arguments, type: "selesai"); }, child: Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), decoration: BoxDecoration( gradient: isActive == "selesai" ? const LinearGradient( colors: [Color(0xFF10B981), Color(0xFF059669)], begin: Alignment.topLeft, end: Alignment.bottomRight, ) : null, color: isActive == "selesai" ? null : Colors.transparent, borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.check_circle_outline, color: isActive == "selesai" ? Colors.white : Colors.grey.shade600, size: 18, ), const SizedBox(width: 6), Text( "Selesai", style: TextStyle( fontWeight: FontWeight.w600, color: isActive == "selesai" ? Colors.white : Colors.grey.shade600, fontSize: 14, ), ), ], ), ), ), ), ], ), ); } Widget tugasBelum() { return Obx( () { log("tugasBelum widget rebuilt"); log("isLoading: ${tugasC.isLoading.value}"); log("tugasM: ${tugasC.tugasM}"); log("data length: ${tugasC.tugasM?.data.length ?? 0}"); log("data isEmpty: ${tugasC.tugasM?.data.isEmpty ?? true}"); if (tugasC.isLoading.value) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, 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(0xFF6366F1), ), strokeWidth: 3, ), ), const SizedBox(height: 20), const Text( "Memuat tugas...", style: TextStyle( fontSize: 16, color: Colors.grey, fontFamily: 'Poppins', ), ), ], ), ); } else if (tugasC.tugasM?.data.isEmpty ?? true) { log("Showing empty data widget"); return emptyData(); } log("Showing data list with ${tugasC.tugasM?.data.length ?? 0} items"); return ListView.builder( padding: const EdgeInsets.all(20), itemCount: tugasC.tugasM?.data.length ?? 0, itemBuilder: (context, index) { var data = tugasC.tugasM?.data[index]; return data?.submitTugas != null ? const SizedBox.shrink() : Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.blue.shade50, Colors.blue.shade100, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.blue.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(20), onTap: () async { var tenggat = data!.tenggat; int year = int.parse(tenggat.getYear()); int month = int.parse(tenggat.getMonthNumber()); int day = int.parse(tenggat.getTgl()); await getCurrentTime(); DateTime batasTanggal = DateTime(year, month, day); if (dateNow!.isAfter(batasTanggal)) { snackbarfailed( "Batas waktu sudah lewat, tidak bisa mengumpulkan tugas."); } else { Get.toNamed( AppRoutes.tugasCommitSiswa, arguments: { "id": data.id, "tipe_tugas": "belum", "title": data.nama, "deskripsi": data.deskripsi, "submitTugas": null }, )?.then( (value) { if (value == true) { tugasC.getTugas( id: Get.arguments.toString(), type: "belum"); } }, ); } }, child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.blue.shade500, borderRadius: BorderRadius.circular(15), ), child: const Icon( Icons.assignment, color: Colors.white, size: 24, ), ), const SizedBox(width: 15), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( data!.nama, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), const SizedBox(height: 8), Text( data!.deskripsi ?.toString() .isNotEmpty == true ? data!.deskripsi.toString() : 'Tidak ada deskripsi tugas.', style: const TextStyle( fontSize: 15, color: Colors.black54, fontStyle: FontStyle.italic, ), ), const SizedBox(height: 6), // Hapus created_at dan updated_at untuk tugas belum Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.calendar_today, size: 16, color: Colors.blue), const SizedBox(width: 6), Text( 'Tanggal dibuat:', style: TextStyle( fontSize: 12, color: Colors.blue, fontWeight: FontWeight.w600), ), ], ), Padding( padding: const EdgeInsets.only( left: 22.0, top: 2, bottom: 6), child: (() { final t = data.createdAt; final dt = t is! DateTime ? DateTime.parse( t.toString()) : t; return Text( dt.fullDateTime(), style: TextStyle( fontSize: 12, color: Colors.blue.shade800, fontWeight: FontWeight.w600), ); })(), ), Row( children: [ Icon(Icons.schedule, size: 16, color: Colors.red), const SizedBox(width: 6), Text( 'Tenggat tugas:', style: TextStyle( fontSize: 12, color: Colors.red, fontWeight: FontWeight.w600), ), ], ), Padding( padding: const EdgeInsets.only( left: 22.0, top: 2), child: Text( data.tenggat.fullDateTime(), style: TextStyle( fontSize: 12, color: Colors.red.shade800, fontWeight: FontWeight.w600), ), ), ], ), ], ), ), Icon( Icons.arrow_forward_ios, color: Colors.blue.shade500, size: 16, ), ], ), const SizedBox(height: 15), Row( children: [ Expanded( child: Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 6, ), decoration: BoxDecoration( color: Colors.white.withOpacity(0.7), borderRadius: BorderRadius.circular(10), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.calendar_today, size: 14, color: Colors.blue.shade600, ), const SizedBox(width: 4), Flexible( child: Text( data.tanggal.fullDateTime(), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.blue.shade600, ), overflow: TextOverflow.ellipsis, ), ), ], ), ), ), const SizedBox(width: 6), Expanded( child: Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 6, ), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(10), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.schedule, size: 14, color: Colors.red.shade600, ), const SizedBox(width: 4), Flexible( child: Text( data.tenggat.fullDateTime(), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.red.shade600, ), overflow: TextOverflow.ellipsis, ), ), ], ), ), ), ], ), ], ), ), ), ), ); }, ); }, ); } Widget emptyData() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(30), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(25), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 10), ), ], ), child: Column( children: [ Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: const Color(0xFF6366F1).withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Icon( isActive == "belum" ? Icons.pending_actions : Icons.check_circle_outline, size: 60, color: const Color(0xFF6366F1), ), ), const SizedBox(height: 20), Text( isActive == "belum" ? "Tidak Ada Tugas" : "Tidak Ada Tugas Selesai", style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, fontFamily: 'Poppins', ), ), const SizedBox(height: 8), Text( isActive == "belum" ? "Belum ada tugas yang perlu dikerjakan" : "Belum ada tugas yang telah selesai dikerjakan", style: const TextStyle( fontSize: 14, color: Colors.grey, fontFamily: 'Poppins', ), textAlign: TextAlign.center, ), ], ), ), ], ), ); } Widget tugasSelesai() { return Obx( () { log("tugasSelesai widget rebuilt"); log("isLoading: ${tugasC.isLoading.value}"); log("tugasM: ${tugasC.tugasM}"); log("data length: ${tugasC.tugasM?.data.length ?? 0}"); log("data isEmpty: ${tugasC.tugasM?.data.isEmpty ?? true}"); if (tugasC.isLoading.value) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, 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(0xFF10B981), ), strokeWidth: 3, ), ), const SizedBox(height: 20), const Text( "Memuat tugas...", style: TextStyle( fontSize: 16, color: Colors.grey, fontFamily: 'Poppins', ), ), ], ), ); } else if (tugasC.tugasM?.data.isEmpty ?? true) { log("Showing empty data widget"); return emptyData(); } log("Showing data list with ${tugasC.tugasM?.data.length ?? 0} items"); return ListView.builder( padding: const EdgeInsets.all(20), itemCount: tugasC.tugasM?.data.length ?? 0, itemBuilder: (context, index) { var data = tugasC.tugasM?.data[index]; return data?.submitTugas == null ? const SizedBox.shrink() : Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( gradient: LinearGradient( colors: [ Colors.green.shade50, Colors.green.shade100, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.green.withOpacity(0.1), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(20), onTap: () async { Get.toNamed( AppRoutes.tugasCommitSiswa, arguments: { "id": data!.submitTugas!.id, "tipe_tugas": "selesai", "title": data.nama, "deskripsi": data.deskripsi, "submitTugas": { "id": data.submitTugas!.id, "tanggal": data.submitTugas!.tanggal, "nisn": data.submitTugas!.nisn, "tugas_id": data.submitTugas!.tugasId, "text": data.submitTugas?.text, "file": data.submitTugas?.file, } }, ); }, child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.green.shade500, borderRadius: BorderRadius.circular(15), ), child: const Icon( Icons.check_circle, color: Colors.white, size: 24, ), ), const SizedBox(width: 15), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( data!.nama, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87, ), ), const SizedBox(height: 8), Text( data!.deskripsi ?.toString() .isNotEmpty == true ? data!.deskripsi.toString() : 'Tidak ada deskripsi tugas.', style: const TextStyle( fontSize: 15, color: Colors.black54, fontStyle: FontStyle.italic, ), ), const SizedBox(height: 4), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 4, ), decoration: BoxDecoration( color: Colors.green.shade100, borderRadius: BorderRadius.circular(12), ), child: Text( "Sudah Dikerjakan", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.green.shade700, ), ), ), ], ), ), Icon( Icons.arrow_forward_ios, color: Colors.green.shade500, size: 16, ), ], ), const SizedBox(height: 15), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(Icons.calendar_today, size: 16, color: Colors.blue), const SizedBox(width: 6), Text( 'Tanggal dibuat:', style: TextStyle( fontSize: 12, color: Colors.blue, fontWeight: FontWeight.w600), ), ], ), Padding( padding: const EdgeInsets.only( left: 22.0, top: 2, bottom: 6), child: (() { final t = data.createdAt; final dt = t is! DateTime ? DateTime.parse(t.toString()) : t; return Text( dt.fullDateTime(), style: TextStyle( fontSize: 12, color: Colors.blue.shade800, fontWeight: FontWeight.w600), ); })(), ), Row( children: [ Icon(Icons.schedule, size: 16, color: Colors.red), const SizedBox(width: 6), Text( 'Tenggat tugas:', style: TextStyle( fontSize: 12, color: Colors.red, fontWeight: FontWeight.w600), ), ], ), Padding( padding: const EdgeInsets.only( left: 22.0, top: 2, bottom: 6), child: Text( data.tenggat.fullDateTime(), style: TextStyle( fontSize: 12, color: Colors.red.shade800, fontWeight: FontWeight.w600), ), ), if (data.submitTugas != null) ...[ Row( children: [ Icon(Icons.done_all, size: 16, color: Colors.green), const SizedBox(width: 6), Text( 'Waktu submit:', style: TextStyle( fontSize: 12, color: Colors.green, fontWeight: FontWeight.w600), ), ], ), Padding( padding: const EdgeInsets.only( left: 22.0, top: 2, bottom: 6), child: (() { final t = data.submitTugas!.createdAt; final dt = t is! DateTime ? DateTime.parse(t.toString()) : t; return Text( dt.fullDateTime(), style: TextStyle( fontSize: 12, color: Colors.green.shade800, fontWeight: FontWeight.w600), ); })(), ), Row( children: [ Icon(Icons.update, size: 16, color: Colors.orange), const SizedBox(width: 6), Text( 'Diperbarui:', style: TextStyle( fontSize: 12, color: Colors.orange, fontWeight: FontWeight.w600), ), ], ), Padding( padding: const EdgeInsets.only( left: 22.0, top: 2), child: (() { final t = data.submitTugas!.updatedAt; final dt = t is! DateTime ? DateTime.parse(t.toString()) : t; return Text( dt.fullDateTime(), style: TextStyle( fontSize: 12, color: Colors.orange.shade800, fontWeight: FontWeight.w600), ); })(), ), ], ], ), const SizedBox(height: 10), Container( width: double.infinity, padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8, ), decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( Icons.upload_file, size: 16, color: Colors.blue.shade600, ), const SizedBox(width: 8), Text( "Dikumpulkan:", style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Colors.blue.shade600, ), ), ], ), Padding( padding: const EdgeInsets.only( left: 24.0, top: 4), child: Text( (() { final t = data.submitTugas!.updatedAt; final dt = t is! DateTime ? DateTime.parse(t.toString()) : t; return dt.fullDateTime(); })(), style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Colors.blue.shade600, ), ), ), ], ), ), ], ), ), ), ), ); }, ); }, ); } }