[verified] Publish ReelBox source under GPLv3
This commit is contained in:
commit
db2b505ca3
445 files changed
+105274
No files matched your search
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user