feat: add donation info

This commit is contained in:
cogwheel0
2025-10-02 15:14:34 +05:30
parent afd3231ae9
commit 089eb48bd7
10 changed files with 276 additions and 0 deletions

View File

@@ -35,6 +35,9 @@ import '../../../shared/widgets/model_avatar.dart';
/// Profile page (You tab) showing user info and main actions
/// Enhanced with production-grade design tokens for better cohesion
class ProfilePage extends ConsumerWidget {
static const _githubSponsorsUrl = 'https://github.com/sponsors/cogwheel0';
static const _buyMeACoffeeUrl = 'https://www.buymeacoffee.com/cogwheel0';
const ProfilePage({super.key});
@override
@@ -161,11 +164,123 @@ class ProfilePage extends ConsumerWidget {
end: 0,
curve: AnimationCurves.pageTransition,
),
const SizedBox(height: Spacing.sectionGap),
_buildSupportSection(context)
.animate()
.fadeIn(
delay: AnimationDelay.medium,
duration: AnimationDuration.pageTransition,
)
.slideY(
begin: 0.08,
end: 0,
curve: AnimationCurves.pageTransition,
),
],
),
);
}
Widget _buildSupportSection(BuildContext context) {
final theme = context.conduitTheme;
final textTheme =
theme.bodySmall?.copyWith(color: theme.textSecondary) ??
TextStyle(color: theme.textSecondary);
final supportTiles = [
_buildSupportOption(
context,
icon: UiUtils.platformIcon(
ios: CupertinoIcons.heart,
android: Icons.favorite_border,
),
title: AppLocalizations.of(context)!.githubSponsorsTitle,
subtitle: AppLocalizations.of(context)!.githubSponsorsSubtitle,
url: _githubSponsorsUrl,
color: theme.success,
),
_buildSupportOption(
context,
icon: UiUtils.platformIcon(
ios: CupertinoIcons.gift,
android: Icons.coffee,
),
title: AppLocalizations.of(context)!.buyMeACoffeeTitle,
subtitle: AppLocalizations.of(context)!.buyMeACoffeeSubtitle,
url: _buyMeACoffeeUrl,
color: theme.warning,
),
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context)!.supportConduit,
style: theme.headingSmall?.copyWith(color: theme.textPrimary),
),
const SizedBox(height: Spacing.xs),
Text(
AppLocalizations.of(context)!.supportConduitSubtitle,
style: textTheme,
),
const SizedBox(height: Spacing.sm),
for (var i = 0; i < supportTiles.length; i++) ...[
supportTiles[i],
if (i != supportTiles.length - 1) const SizedBox(height: Spacing.md),
],
],
);
}
Widget _buildSupportOption(
BuildContext context, {
required IconData icon,
required String title,
required String subtitle,
required String url,
required Color color,
}) {
final theme = context.conduitTheme;
return _ProfileSettingTile(
onTap: () => _openExternalLink(context, url),
isDestructive: false,
leading: _buildIconBadge(context, icon, color: color),
title: title,
subtitle: subtitle,
trailing: Icon(
UiUtils.platformIcon(
ios: CupertinoIcons.arrow_up_right,
android: Icons.open_in_new,
),
color: theme.iconSecondary,
size: IconSize.small,
),
);
}
Future<void> _openExternalLink(BuildContext context, String url) async {
try {
final launched = await launchUrlString(
url,
mode: LaunchMode.externalApplication,
);
if (!launched && context.mounted) {
UiUtils.showMessage(
context,
AppLocalizations.of(context)!.errorMessage,
);
}
} on PlatformException catch (_) {
if (!context.mounted) return;
UiUtils.showMessage(context, AppLocalizations.of(context)!.errorMessage);
} catch (_) {
if (!context.mounted) return;
UiUtils.showMessage(context, AppLocalizations.of(context)!.errorMessage);
}
}
Widget _buildProfileHeader(
BuildContext context,
dynamic user,