MIF_E31222389/lib/stats_page.dart

325 lines
13 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flame/game.dart';
import 'utils/audio_manager.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
class StatsPage extends StatefulWidget {
const StatsPage({Key? key}) : super(key: key);
@override
State<StatsPage> createState() => _StatsPageState();
}
class _StatsPageState extends State<StatsPage> {
Future<List<Map<String, dynamic>>> _getScores() async {
final user = FirebaseAuth.instance.currentUser;
if (user == null) {
print('No user logged in');
return [];
}
try {
final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('scores').get();
print('Raw Firebase response: ${snapshot.value}');
if (snapshot.exists && snapshot.value != null) {
List<Map<String, dynamic>> scores = [];
final values = snapshot.value as Map;
values.forEach((key, value) {
if (value is Map && value['userId'] == user.uid) {
scores.add({
'level': value['level'] ?? '-',
'category': value['category'] ?? '-',
'time': value['time'] ?? '-',
'score': value['score'] ?? 0,
'timestamp': value['timestamp'] ?? '',
});
}
});
print('Processed scores: $scores');
// Sort by timestamp descending
scores.sort(
(a, b) => (b['timestamp'] ?? '').compareTo(a['timestamp'] ?? ''));
return scores;
}
print('No data found in snapshot');
return [];
} catch (e) {
print('Error fetching scores: $e');
return [];
}
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/background.jpg'),
fit: BoxFit.cover,
),
),
child: Stack(
children: [
// Tombol X untuk kembali
Positioned(
top: 10,
right: 10,
child: IconButton(
icon: Image.asset(
'assets/icons/exit.png',
width: 40,
height: 40,
),
onPressed: () {
AudioManager.playClickSound();
Navigator.pop(context);
},
),
),
// Konten Utama
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/icons/title.png'),
fit: BoxFit.cover,
),
borderRadius: BorderRadius.circular(10),
),
padding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 15),
child: const Text(
'STATISTIK',
style: TextStyle(
fontSize: 25,
fontFamily: 'Bestime',
color: Color.fromARGB(225, 193, 138, 83),
),
),
),
const SizedBox(height: 40),
// Tabel Statistik
Container(
margin: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Color.fromARGB(255, 182, 134, 86).withOpacity(0.9),
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Color.fromARGB(255, 65, 44, 23),
width: 2,
),
),
child: FutureBuilder<List<Map<String, dynamic>>>(
future: _getScores(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(
color: Color.fromARGB(255, 65, 44, 23),
),
);
}
if (snapshot.hasError) {
print('Error in FutureBuilder: ${snapshot.error}');
return Center(
child: Text(
'Terjadi kesalahan saat memuat data',
style: TextStyle(
fontFamily: 'Bestime',
fontSize: 14,
color: Color.fromARGB(255, 65, 44, 23),
),
),
);
}
final List<Map<String, dynamic>> data =
snapshot.data ?? [];
print('Data in builder: $data'); // Debug print
// Daftar atribut yang akan jadi baris (header vertikal)
final List<String> attributes = [
'Level',
'Kategori',
'Waktu',
'Skor'
];
// Key mapping ke data
final List<String> keys = [
'level',
'category',
'time',
'score'
];
// Jika tidak ada data, tampilkan pesan kosong
if (data.isEmpty) {
return Center(
child: Text(
'Tidak ada data',
style: TextStyle(
fontFamily: 'Bestime',
fontSize: 14,
color: Color.fromARGB(255, 103, 75, 47),
),
),
);
}
// Responsive width
double cellWidth = 110;
double headerWidth = 90;
double tableWidth =
headerWidth + (data.length * cellWidth);
double maxWidth =
MediaQuery.of(context).size.width - 32; // padding
if (tableWidth < maxWidth) tableWidth = maxWidth;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Container(
width: tableWidth,
child: Table(
border: TableBorder.all(
color: Color.fromARGB(255, 65, 44, 23),
width: 1,
),
defaultVerticalAlignment:
TableCellVerticalAlignment.middle,
columnWidths: {
0: FixedColumnWidth(headerWidth),
for (int i = 1; i <= data.length; i++)
i: FixedColumnWidth(cellWidth),
},
children: [
// Baris judul (No, User 1, User 2, ...)
TableRow(
decoration: BoxDecoration(
color: Color.fromARGB(255, 65, 44, 23),
),
children: [
TableCell(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'',
style: TextStyle(
color: Colors.white,
fontFamily: 'Bestime',
fontSize: 14,
),
),
),
),
...List.generate(
data.length,
(i) => TableCell(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'${i + 1}',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontFamily: 'Bestime',
fontSize: 14,
),
),
),
),
),
],
),
// Baris-baris atribut
...List.generate(
attributes.length,
(rowIdx) => TableRow(
children: [
// Header baris (atribut)
TableCell(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
attributes[rowIdx],
style: TextStyle(
fontFamily: 'Bestime',
fontSize: 14,
color: Color.fromARGB(
255, 65, 44, 23),
),
),
),
),
// Data user untuk atribut ini
...List.generate(data.length, (colIdx) {
final value =
data[colIdx][keys[rowIdx]] ?? '-';
return TableCell(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
value.toString(),
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Bestime',
fontSize: 14,
color: Color.fromARGB(
255, 103, 75, 47),
),
),
),
);
}),
],
),
),
],
),
),
);
},
),
),
],
),
),
],
),
),
);
}
}
// Game kosong sebagai background
class BackgroundGame extends FlameGame {
@override
Color backgroundColor() => Color.fromARGB(255, 255, 255, 255);
@override
Future<void> onLoad() async {
// Bisa ditambahkan komponen lain jika diperlukan
}
}