import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import '../data/home_banners.dart'; import '../state/app_state.dart'; import 'common.dart'; /// Independent of home metadata loading/error UI so the official channel stays /// visible and usable even before configuration has arrived. class HomeBanners extends StatelessWidget { const HomeBanners({super.key, required this.future}); final Future> future; Future _open(BuildContext context, Uri target) async { try { if (await launchUrl(target, mode: LaunchMode.externalApplication)) return; } catch (_) { // Do not expose platform exceptions, configuration values or URLs. } if (context.mounted) { toast( context, tr(context, 'Could not open this link', 'باز کردن پیوند ممکن نشد'), kind: ToastKind.error, ); } } @override Widget build(BuildContext context) => FutureBuilder>( future: future, builder: (context, snapshot) { final banners = [ HomeBanner.telegram, if (!snapshot.hasError) ...?snapshot.data?.where((item) => item.isAdvertisement).take(5), ]; return Padding( padding: const EdgeInsets.fromLTRB(20, 12, 20, 0), child: Column( children: [ for (var i = 0; i < banners.length; i++) Padding( padding: EdgeInsets.only( bottom: i == banners.length - 1 ? 0 : 12, ), child: _BannerCard( banner: banners[i], tapKey: Key( banners[i].isAdvertisement ? 'home-banner-ad-$i' : 'home-banner-telegram', ), onTap: () => _open(context, banners[i].target), ), ), ], ), ); }, ); } class _BannerCard extends StatelessWidget { const _BannerCard({ required this.banner, required this.tapKey, required this.onTap, }); final HomeBanner banner; final Key tapKey; final VoidCallback onTap; @override Widget build(BuildContext context) { final state = AppScope.of(context); final persian = state.locale == 'fa'; final colors = Theme.of(context).colorScheme; final subtitle = banner.subtitle(persian); return Material( color: colors.primary.withValues(alpha: .08), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide(color: colors.primary.withValues(alpha: .22)), ), clipBehavior: Clip.antiAlias, child: InkWell( key: tapKey, onTap: onTap, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (banner.image != null && !state.prefs.dataSaver) Image.network( banner.image.toString(), height: 112, fit: BoxFit.cover, cacheWidth: 700, excludeFromSemantics: true, errorBuilder: (_, _, _) => const SizedBox.shrink(), ), Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Icon( banner.isAdvertisement ? Icons.ad_units_outlined : Icons.campaign_outlined, color: colors.primary, size: 18, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (banner.isAdvertisement) ...[ Text( tr(context, 'Advertisement', 'تبلیغات'), style: Theme.of(context).textTheme.labelSmall ?.copyWith( color: colors.primary, fontWeight: FontWeight.w500, ), ), const SizedBox(height: 4), ], Text( banner.title(persian), style: Theme.of(context).textTheme.titleSmall ?.copyWith(fontWeight: FontWeight.w600), ), if (subtitle.isNotEmpty) ...[ const SizedBox(height: 4), Text( subtitle, style: Theme.of(context).textTheme.bodySmall ?.copyWith(color: colors.onSurfaceVariant), ), ], ], ), ), const SizedBox(width: 8), Icon( Icons.open_in_new_rounded, color: colors.primary, size: 18, ), ], ), ), ], ), ), ); } }