[verified] Publish ReelBox source under GPLv3

This commit is contained in:
Hermes committed 2026-11-12 23:41:13 +00:00
commit db2b505ca3
445 files changed
+105274

No files matched your search

+159
View File
@@ -0,0 +1,159 @@
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<List<HomeBanner>> future;
Future<void> _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<List<HomeBanner>>(
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,
),
],
),
),
],
),
),
);
}
}