feat: ajout de serveurs depuis l'app + charte flamme sombre
Build APK / build (push) Successful in 2m49s

- backend: GET /api/containers (liste lisible), POST/DELETE /api/servers
  (serveurs custom persistés en /data/servers.json, mergés aux intégrés),
  champ custom dans le statut.
- app: écran AddServer (form + sélecteur multi-conteneurs filtrable), FAB
  Ajouter, suppression depuis le détail (serveurs custom only).
- thème: palette flamme/chaud sombre (anthracite + orange→rouge), remplace le
  Material violet/teal par défaut (scaffold, appbar, tabs, boutons, FAB, champs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
neckfire
2026-07-13 13:33:22 +02:00
co-authored by Claude Opus 4.8
parent fb4ab95f13
commit 30786f9706
7 changed files with 441 additions and 14 deletions
+41
View File
@@ -45,6 +45,47 @@ class ApiService {
return GameServer.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
}
Future<List<DockerContainer>> containers() async {
final base = await baseUrl;
final res = await http.get(Uri.parse('$base/api/containers'), headers: await _headers());
if (res.statusCode == 401) throw UnauthorizedException();
if (res.statusCode != 200) throw ApiException('Erreur ${res.statusCode}');
return (jsonDecode(res.body) as List)
.map((e) => DockerContainer.fromJson(e as Map<String, dynamic>))
.toList();
}
Future<GameServer> createServer(Map<String, dynamic> payload) async {
final base = await baseUrl;
final res = await http.post(
Uri.parse('$base/api/servers'),
headers: {...await _headers(), 'Content-Type': 'application/json'},
body: jsonEncode(payload),
);
if (res.statusCode == 401) throw UnauthorizedException();
if (res.statusCode >= 400) {
throw ApiException(_msg(res.body) ?? 'Création refusée (${res.statusCode})');
}
return GameServer.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
}
Future<void> deleteServer(String id) async {
final base = await baseUrl;
final res = await http.delete(Uri.parse('$base/api/servers/$id'), headers: await _headers());
if (res.statusCode == 401) throw UnauthorizedException();
if (res.statusCode >= 400) {
throw ApiException(_msg(res.body) ?? 'Suppression refusée (${res.statusCode})');
}
}
String? _msg(String body) {
try {
return (jsonDecode(body) as Map<String, dynamic>)['detail'] as String?;
} catch (_) {
return null;
}
}
Future<void> start(String id) => _action(id, 'start');
Future<void> stop(String id) => _action(id, 'stop');