MIF_E31222846/lib/views/siswa/siswaDashboard.dart

414 lines
14 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'dart:math' as math;
import 'dart:math' show Random;
import 'package:ui/routes/app_routes.dart';
import 'package:ui/views/siswa/controllers/notifikasi_count_controller.dart';
import 'package:ui/views/siswa/controllers/siswa_controller.dart';
import 'package:ui/widgets/my_text.dart';
class AnimatedBackground extends StatefulWidget {
const AnimatedBackground({super.key});
@override
State<AnimatedBackground> createState() => _AnimatedBackgroundState();
}
class _AnimatedBackgroundState extends State<AnimatedBackground>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
final List<Shape> _shapes = [];
final int _numberOfShapes = 4;
final Random _random = Random();
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 15),
)..repeat();
// Initialize shapes with random angles and distances
for (int i = 0; i < _numberOfShapes; i++) {
_shapes.add(Shape(
angle: _random.nextDouble() * math.pi * 2,
distance: 150 + _random.nextDouble() * 250,
baseSize: 150 + _random.nextDouble() * 200,
speed: 0.1 + _random.nextDouble() * 0.2,
type: _random.nextBool() ? ShapeType.curve : ShapeType.triangle,
opacity: 0.1,
opacitySpeed: 0.1 + _random.nextDouble() * 0.3,
sizeSpeed: 0.2 + _random.nextDouble() * 0.3,
angleSpeed: 0.05 + _random.nextDouble() * 0.2,
));
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return CustomPaint(
painter: BackgroundPainter(
shapes: _shapes,
animation: _controller.value,
),
child: Container(),
);
},
);
}
}
class Shape {
double angle;
double distance;
double size;
final double baseSize;
final double speed;
final ShapeType type;
double opacity;
double opacitySpeed;
double sizeSpeed;
double angleSpeed;
Shape({
required this.angle,
required this.distance,
required this.baseSize,
required this.speed,
required this.type,
required this.opacity,
required this.opacitySpeed,
required this.sizeSpeed,
required this.angleSpeed,
}) : size = baseSize;
}
enum ShapeType {
curve,
triangle,
}
class BackgroundPainter extends CustomPainter {
final List<Shape> shapes;
final double animation;
BackgroundPainter({
required this.shapes,
required this.animation,
});
@override
void paint(Canvas canvas, Size size) {
if (size.isEmpty) return;
final centerX = size.width / 2;
final centerY = size.height / 2;
for (var shape in shapes) {
try {
// Update opacity with sine wave for smooth fading
shape.opacity = 0.1 +
(math.sin(animation * math.pi * 2 * shape.opacitySpeed) * 0.15);
shape.opacity =
shape.opacity.clamp(0.0, 1.0); // Ensure opacity is between 0 and 1
// Update size with sine wave for pulsing effect
shape.size = shape.baseSize *
(0.8 + (math.sin(animation * math.pi * 2 * shape.sizeSpeed) * 0.3));
shape.size =
shape.size.clamp(1.0, double.infinity); // Ensure size is positive
// Update angle for rotation with varying speed
shape.angle += shape.angleSpeed * 0.02;
final paint = Paint()
..color = Colors.green.withOpacity(shape.opacity)
..style = PaintingStyle.fill
..isAntiAlias = true;
// Calculate position based on angle and distance from center
final x = centerX + math.cos(shape.angle) * shape.distance;
final y = centerY + math.sin(shape.angle) * shape.distance;
// Ensure coordinates are within bounds
if (x.isFinite && y.isFinite) {
// Draw shape based on type
final path = Path();
if (shape.type == ShapeType.curve) {
path
..moveTo(x, y)
..quadraticBezierTo(
x + shape.size * 0.5,
y - shape.size * 0.5,
x + shape.size,
y,
)
..quadraticBezierTo(
x + shape.size * 1.5,
y + shape.size * 0.5,
x,
y,
);
} else {
// Triangle
final triangleSize = shape.size * 1.2;
path
..moveTo(x, y - triangleSize)
..lineTo(x + triangleSize, y + triangleSize * 0.5)
..lineTo(x - triangleSize, y + triangleSize * 0.5)
..close();
}
canvas.drawPath(path, paint);
}
} catch (e) {
debugPrint('Error painting shape: $e');
}
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
class SiswaDashboardPage extends StatelessWidget {
const SiswaDashboardPage({super.key});
@override
Widget build(BuildContext context) {
final siswaC = Get.find<SiswaController>();
final notifC = Get.find<NotifikasiCountController>();
final List<_DashboardMenu> menuItems = [
_DashboardMenu(
title: "Mata Pelajaran",
icon: Icons.menu_book_rounded,
color: Colors.teal.shade300,
onTap: () => Get.toNamed(AppRoutes.kelasmatapelajarans),
),
_DashboardMenu(
title: "#1 Ranking",
icon: Icons.emoji_events_rounded,
color: Colors.indigo.shade200,
onTap: () => Get.toNamed(AppRoutes.matpelRankQuiz),
),
_DashboardMenu(
title: "Quiz",
icon: Icons.quiz_rounded,
color: Colors.green.shade300,
onTap: () => Get.toNamed(AppRoutes.matpelQuiz),
),
_DashboardMenu(
title: "Profil",
icon: Icons.person_rounded,
color: Colors.amber.shade200,
onTap: () => Get.toNamed(AppRoutes.profileSiswa),
),
_DashboardMenu(
title: "Tugas",
icon: Icons.assignment_rounded,
color: Colors.teal.shade400,
onTap: () => Get.toNamed(AppRoutes.tugasSiswa),
),
_DashboardMenu(
title: "Notifikasi",
icon: Icons.notifications_active_rounded,
color: Colors.pink.shade200,
onTap: () => Get.toNamed(AppRoutes.notifikasiSiswa)?.then((_) {
siswaC.getMe();
notifC.getNotifCount();
}),
),
];
// return WillPopScope(
// onWillPop: () async {
// return snackbarAlert("a", "Klik 2x untuk keluar", Colors.black);
// final shouldLogout = await showDialog(
// context: context,
// builder: (context) => AlertDialog(
// title: const Text('Konfirmasi Logout'),
// content: const Text('Apakah anda ingin Logout?'),
// actions: [
// TextButton(
// onPressed: () => Navigator.of(context).pop(false),
// child: const Text('Batal'),
// ),
// TextButton(
// onPressed: () => Navigator.of(context).pop(true),
// child: const Text(
// 'Logout',
// style: TextStyle(color: Colors.red),
// ),
// ),
// ],
// ),
// );
// if (shouldLogout == true) {
// siswaC.logout(role: "siswa");
// }
// return false;
// },
return Scaffold(
backgroundColor: Colors.grey[100],
body: Stack(
children: [
const AnimatedBackground(),
SafeArea(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Obx(() {
if (siswaC.isLoading.value) {
return const CircularProgressIndicator();
}
var user = siswaC.dataUser['user'];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"E-Learning",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.w600),
),
Text(
"Hi, ${user?['nama'] ?? 'Siswa'}",
style: const TextStyle(
fontSize: 28, fontWeight: FontWeight.bold),
),
Text(
"Kelas : ${user?['kelas']}",
style: const TextStyle(
fontSize: 15, fontWeight: FontWeight.bold),
),
],
);
}),
const SizedBox(height: 30),
// Menu Grid
Obx(
() {
if (notifC.isLoading.value) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Expanded(
child: RefreshIndicator(
onRefresh: () {
notifC.getNotifCount();
siswaC.getMe();
return Future.value();
},
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: menuItems.map((item) {
return GestureDetector(
onTap: item.onTap,
child: Stack(
fit: StackFit.expand,
clipBehavior: Clip.none,
children: [
Positioned(
child: Container(
decoration: BoxDecoration(
color: item.color,
borderRadius:
BorderRadius.circular(20),
),
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(item.icon,
size: 40, color: Colors.white),
const SizedBox(height: 12),
Text(
item.title,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
if (item.title == "Notifikasi" &&
notifC.notifCount.value > 0)
Positioned(
top: -7,
right: -5,
child: Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: Colors.red,
borderRadius:
BorderRadius.circular(20),
),
child: Center(
child: MyText(
text: notifC.notifCount.value
.toString(),
textAlign: TextAlign.center,
fontSize: 13,
color: Colors.white,
fontWeight: FontWeight.w900,
),
),
),
),
],
),
);
}).toList(),
),
),
);
},
),
],
),
),
),
// ),
],
),
);
}
}
class _DashboardMenu {
final String title;
final IconData icon;
final Color color;
final VoidCallback onTap;
_DashboardMenu({
required this.title,
required this.icon,
required this.color,
required this.onTap,
});
}