import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_svg/flutter_svg.dart'; import '../../../core/api/api_client.dart'; import '../../../core/theme/halo_tokens.dart'; /// Renders a payment-method brand mark fetched from the backend. /// /// `iconUrl` comes from `payment_methods.icon_url` on the catalog response. /// Relative paths (the common case — `/assets/payment-icons/.svg`) are /// resolved against [ApiClient.baseUrl]. Absolute URLs (operator override) /// are used as-is. /// /// First fetch hits the network; the file is then persisted to disk by /// [DefaultCacheManager] (30-day idle LRU) and served locally on subsequent /// renders. While the cache lookup is in flight or when [iconUrl] is null, /// the bundled placeholder is shown so the picker never displays a spinner. class PaymentIcon extends StatelessWidget { final String? iconUrl; final double size; final Color color; const PaymentIcon({ super.key, required this.iconUrl, this.size = 24, this.color = HaloTokens.brandDark, }); String? get _resolvedUrl { final raw = iconUrl; if (raw == null || raw.isEmpty) return null; if (raw.startsWith('http://') || raw.startsWith('https://')) return raw; return '${ApiClient.baseUrl}$raw'; } @override Widget build(BuildContext context) { final url = _resolvedUrl; if (url == null) return _placeholder(); return FutureBuilder( future: DefaultCacheManager().getFileFromCache(url), builder: (context, cachedSnap) { final cached = cachedSnap.data?.file; if (cached != null) { return SvgPicture.file(cached, width: size, height: size); } // Cache miss: render placeholder while the download lands, then swap // in. We fire the download in the same FutureBuilder body so the next // rebuild picks up the freshly-cached file. return FutureBuilder( future: DefaultCacheManager().getSingleFile(url), builder: (context, snap) { if (snap.hasData) { return SvgPicture.file(snap.data!, width: size, height: size); } return _placeholder(); }, ); }, ); } Widget _placeholder() => SvgPicture.asset( 'assets/payment_icons/placeholder.svg', width: size, height: size, colorFilter: ColorFilter.mode(color, BlendMode.srcIn), ); }