197 lines
No EOL
10 KiB
Dart
197 lines
No EOL
10 KiB
Dart
// ===========================================================================
|
|
// FILE: lib/ui/admin/admin_screen.dart
|
|
// ===========================================================================
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../../core/theme_manager.dart';
|
|
|
|
class AdminScreen extends StatelessWidget {
|
|
const AdminScreen({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = context.watch<ThemeManager>().currentColors;
|
|
|
|
return Scaffold(
|
|
backgroundColor: theme.background,
|
|
appBar: AppBar(
|
|
title: Text("DASHBOARD ADMIN 🕵️♂️", style: TextStyle(color: theme.text, fontWeight: FontWeight.w900, letterSpacing: 2)),
|
|
backgroundColor: theme.background,
|
|
iconTheme: IconThemeData(color: theme.text),
|
|
elevation: 0,
|
|
),
|
|
body: StreamBuilder<QuerySnapshot>(
|
|
stream: FirebaseFirestore.instance.collection('leaderboard').orderBy('lastActive', descending: true).snapshots(),
|
|
builder: (context, snapshot) {
|
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
return Center(child: CircularProgressIndicator(color: theme.playerBlue));
|
|
}
|
|
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
|
|
return Center(child: Text("Nessun giocatore trovato nel database.", style: TextStyle(color: theme.text)));
|
|
}
|
|
|
|
final docs = snapshot.data!.docs;
|
|
|
|
return ListView.builder(
|
|
padding: const EdgeInsets.all(16),
|
|
itemCount: docs.length,
|
|
itemBuilder: (context, index) {
|
|
var data = docs[index].data() as Map<String, dynamic>;
|
|
|
|
String name = data['name'] ?? 'Fantasma';
|
|
int level = data['level'] ?? 1;
|
|
int xp = data['xp'] ?? 0;
|
|
int wins = data['wins'] ?? 0;
|
|
|
|
String platform = data['platform'] ?? 'Sconosciuta';
|
|
String ip = data['ip'] ?? 'N/D';
|
|
String city = data['city'] ?? 'N/D';
|
|
String appVersion = data['appVersion'] ?? 'N/D';
|
|
String deviceModel = data['deviceModel'] ?? 'N/D';
|
|
|
|
int playtimeSec = data['playtime'] ?? 0;
|
|
int hours = playtimeSec ~/ 3600;
|
|
int minutes = (playtimeSec % 3600) ~/ 60;
|
|
String playtimeStr = "${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}";
|
|
|
|
// Recupero della data di creazione dell'account
|
|
DateTime? created;
|
|
if (data['accountCreated'] != null) created = (data['accountCreated'] as Timestamp).toDate();
|
|
|
|
DateTime? lastActive;
|
|
if (data['lastActive'] != null) lastActive = (data['lastActive'] as Timestamp).toDate();
|
|
|
|
String createdStr = created != null ? DateFormat('dd MMM yyyy - HH:mm').format(created) : 'N/D';
|
|
String lastActiveStr = lastActive != null ? DateFormat('dd MMM yyyy - HH:mm').format(lastActive) : 'N/D';
|
|
|
|
IconData platformIcon = Icons.device_unknown;
|
|
if (platform == 'iOS' || platform == 'macOS') platformIcon = Icons.apple;
|
|
if (platform == 'Android') platformIcon = Icons.android;
|
|
if (platform == 'Windows') platformIcon = Icons.window;
|
|
|
|
return Card(
|
|
color: theme.text.withOpacity(0.05),
|
|
elevation: 0,
|
|
margin: const EdgeInsets.only(bottom: 12),
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(15),
|
|
side: BorderSide(color: theme.gridLine.withOpacity(0.3))
|
|
),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(name, style: TextStyle(color: theme.playerBlue, fontSize: 22, fontWeight: FontWeight.w900)),
|
|
|
|
GestureDetector(
|
|
onTap: () {
|
|
showDialog(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
backgroundColor: theme.background,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(20),
|
|
side: BorderSide(color: theme.playerBlue, width: 2),
|
|
),
|
|
title: Text("Info Connessione", style: TextStyle(color: theme.text, fontWeight: FontWeight.bold)),
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text("🌐 IP: $ip", style: TextStyle(color: theme.text, fontSize: 16)),
|
|
const SizedBox(height: 10),
|
|
Text("📍 Città: $city", style: TextStyle(color: theme.text, fontSize: 16)),
|
|
const SizedBox(height: 10),
|
|
Text("📱 OS: $platform", style: TextStyle(color: theme.text, fontSize: 16)),
|
|
const SizedBox(height: 10),
|
|
Text("💻 Hardware: $deviceModel", style: TextStyle(color: theme.text, fontSize: 16)),
|
|
],
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(ctx),
|
|
child: Text("CHIUDI", style: TextStyle(color: theme.playerRed, fontWeight: FontWeight.bold)),
|
|
)
|
|
],
|
|
),
|
|
);
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: theme.text.withOpacity(0.1),
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(platformIcon, color: theme.text.withOpacity(0.8), size: 24),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
children: [
|
|
Text("Liv. $level", style: TextStyle(color: theme.playerRed, fontWeight: FontWeight.bold, fontSize: 14)),
|
|
const SizedBox(width: 10),
|
|
Text("$xp XP", style: TextStyle(color: theme.text.withOpacity(0.7), fontSize: 12)),
|
|
const SizedBox(width: 10),
|
|
Text("Vittorie: $wins", style: TextStyle(color: Colors.amber.shade700, fontWeight: FontWeight.bold, fontSize: 12)),
|
|
const Spacer(),
|
|
Icon(Icons.timer, color: theme.text.withOpacity(0.6), size: 16),
|
|
const SizedBox(width: 4),
|
|
Text(playtimeStr, style: TextStyle(color: theme.text, fontWeight: FontWeight.bold, fontSize: 14)),
|
|
],
|
|
),
|
|
const Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 8.0),
|
|
child: Divider(),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
FittedBox(fit: BoxFit.scaleDown, child: Text("Registrato il:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
|
|
FittedBox(fit: BoxFit.scaleDown, child: Text(createdStr, style: TextStyle(color: theme.text, fontSize: 12, fontWeight: FontWeight.bold))),
|
|
],
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
FittedBox(fit: BoxFit.scaleDown, child: Text("Versione App:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
|
|
FittedBox(fit: BoxFit.scaleDown, child: Text("v. $appVersion", style: TextStyle(color: theme.playerBlue, fontSize: 12, fontWeight: FontWeight.bold))),
|
|
],
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
FittedBox(fit: BoxFit.scaleDown, child: Text("Ultimo Accesso:", style: TextStyle(color: theme.text.withOpacity(0.5), fontSize: 10))),
|
|
FittedBox(fit: BoxFit.scaleDown, child: Text(lastActiveStr, style: TextStyle(color: Colors.green, fontSize: 12, fontWeight: FontWeight.bold))),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
),
|
|
);
|
|
}
|
|
} |