diff --git a/lib/screens/servers_screen.dart b/lib/screens/servers_screen.dart index 75a2206..b57338e 100644 --- a/lib/screens/servers_screen.dart +++ b/lib/screens/servers_screen.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:flutter/material.dart'; import '../models.dart'; @@ -27,6 +29,15 @@ class _ServersScreenState extends State { List? _servers; String? _error; final _busy = {}; + final _imgCache = {}; + + Future _image(GameServer s) async { + if (!s.hasImage) return null; + if (_imgCache.containsKey(s.id)) return _imgCache[s.id]; + final b = await widget.api.imageBytes(s.id).catchError((_) => null); + _imgCache[s.id] = b; + return b; + } @override void initState() { @@ -41,6 +52,7 @@ class _ServersScreenState extends State { if (mounted) setState(() { _servers = servers; _error = null; + _imgCache.clear(); // recharge les images (elles ont pu changer) }); } on UnauthorizedException { await widget.auth.logout(); @@ -191,11 +203,12 @@ class _ServersScreenState extends State { Widget _card(GameServer s) => Padding( padding: const EdgeInsets.only(bottom: 14), - child: FutureBuilder( - future: widget.api.iconUrl(s.id), + child: FutureBuilder( + future: _image(s), builder: (_, snap) => ServerCard( server: s, - iconUrl: snap.data ?? '', + iconUrl: '', + imageBytes: snap.data, busy: _busy.contains(s.id), onToggle: () => _toggle(s), onTap: () => _openDetail(s), diff --git a/lib/widgets/server_card.dart b/lib/widgets/server_card.dart index 6b09186..cd5b016 100644 --- a/lib/widgets/server_card.dart +++ b/lib/widgets/server_card.dart @@ -1,3 +1,5 @@ +import 'dart:typed_data'; + import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -11,6 +13,7 @@ class ServerCard extends StatelessWidget { required this.busy, required this.onToggle, this.onTap, + this.imageBytes, }); final GameServer server; @@ -18,31 +21,49 @@ class ServerCard extends StatelessWidget { final bool busy; final VoidCallback onToggle; final VoidCallback? onTap; + final Uint8List? imageBytes; @override Widget build(BuildContext context) { final t = server.theme; final badge = server.statusBadge; + final hasImg = imageBytes != null; return Card( clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, + child: Ink( + decoration: hasImg + ? BoxDecoration( + image: DecorationImage(image: MemoryImage(imageBytes!), fit: BoxFit.cover), + ) + : BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [t.start, t.end], + ), + ), child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [t.start, t.end], - ), - ), + decoration: hasImg + ? const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Color(0x66000000), Color(0xCC000000)], + ), + ) + : null, padding: const EdgeInsets.all(18), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ - _Icon(server: server, iconUrl: iconUrl, fallback: t.icon), - const SizedBox(width: 14), + if (!hasImg) ...[ + _Icon(server: server, iconUrl: iconUrl, fallback: t.icon), + const SizedBox(width: 14), + ], Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -107,6 +128,7 @@ class ServerCard extends StatelessWidget { ), ), ), + ), ); } } @@ -124,7 +146,7 @@ class _Icon extends StatelessWidget { child: SizedBox( width: 52, height: 52, - child: (server.hasIcon) + child: (server.hasIcon && iconUrl.isNotEmpty) ? Image.network(iconUrl, fit: BoxFit.cover, errorBuilder: (_, __, ___) => _fallbackBox())