import 'package:flutter/material.dart'; /// Un serveur de jeu tel que renvoyé par l'API `/api/servers`. class GameServer { final String id; final String name; final String game; final String? subtitle; final String? connect; final bool onDemand; final String env; // prod | preprod final bool web; // jeu web → bouton « Ouvrir » final String? openUrl; final String status; // stopped | starting | running | online | partial final int? players; final int? maxPlayers; final String? motd; final bool hasIcon; final bool hasImage; final bool custom; const GameServer({ required this.id, required this.name, required this.game, this.subtitle, this.connect, this.onDemand = false, this.env = 'prod', this.web = false, this.openUrl, required this.status, this.players, this.maxPlayers, this.motd, this.hasIcon = false, this.hasImage = false, this.custom = false, }); factory GameServer.fromJson(Map json) => GameServer( id: json['id'] as String, name: json['name'] as String, game: json['game'] as String, subtitle: json['subtitle'] as String?, connect: json['connect'] as String?, onDemand: json['on_demand'] as bool? ?? false, env: json['env'] as String? ?? 'prod', web: json['web'] as bool? ?? false, openUrl: json['open_url'] as String?, status: json['status'] as String? ?? 'stopped', players: json['players'] as int?, maxPlayers: json['max_players'] as int?, motd: json['motd'] as String?, hasIcon: json['has_icon'] as bool? ?? false, hasImage: json['has_image'] as bool? ?? false, custom: json['custom'] as bool? ?? false, ); bool get isUp => status == 'online' || status == 'running'; bool get isBusy => status == 'starting' || status == 'partial'; bool get isPreprod => env == 'preprod'; /// Couleur d'accent thématique par jeu (visuel sans dépendance externe). ({Color start, Color end, IconData icon}) get theme { final g = game.toLowerCase(); if (g.contains('minecraft')) { final medieval = name.toLowerCase().contains('mmc') || name.toLowerCase().contains('medieval'); return medieval ? (start: const Color(0xFF7B5E3B), end: const Color(0xFF3E2C1A), icon: Icons.castle) : (start: const Color(0xFF4CAF50), end: const Color(0xFF1B5E20), icon: Icons.grass); } if (g.contains('cycle')) { return (start: const Color(0xFF00BCD4), end: const Color(0xFF1A237E), icon: Icons.rocket_launch); } if (g.contains('swarm') || g.contains('ants')) { return (start: const Color(0xFFF9A825), end: const Color(0xFF6D4C00), icon: Icons.bug_report); } return (start: const Color(0xFF7E57C2), end: const Color(0xFF311B92), icon: Icons.sports_esports); } ({String label, Color color}) get statusBadge => switch (status) { 'online' => (label: 'En ligne', color: const Color(0xFF34C759)), 'running' => (label: 'Démarré', color: const Color(0xFF30B0C7)), 'starting' => (label: 'Démarrage…', color: const Color(0xFFFF9F0A)), 'partial' => (label: 'Partiel', color: const Color(0xFFFF9F0A)), _ => (label: 'Éteint', color: const Color(0xFF8E8E93)), }; } /// Conteneur Docker (pour lier un serveur depuis l'app). class DockerContainer { DockerContainer({required this.name, required this.image, required this.state}); final String name; final String image; final String state; factory DockerContainer.fromJson(Map j) => DockerContainer( name: j['name'] as String, image: (j['image'] as String?) ?? '', state: (j['state'] as String?) ?? '', ); bool get running => state == 'running'; /// Image sans le registre ni le digest, pour la lisibilité. /// ex: git.nfteam.ovh/neckfire/the-cycle:preprod → the-cycle:preprod String get prettyImage { var s = image.split('/').last; if (s.length > 34) s = '${s.substring(0, 33)}…'; return s; } }