|
|
@@ -1,4 +1,5 @@
|
|
|
import 'package:flutter/material.dart';
|
|
|
+import 'package:url_launcher/url_launcher.dart';
|
|
|
import '../utils/colors.dart';
|
|
|
import '../utils/haptic_utils.dart';
|
|
|
import '../utils/settings_manager.dart';
|
|
|
@@ -136,13 +137,19 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|
|
|
|
|
const SizedBox(height: 30),
|
|
|
|
|
|
+ // Support Section
|
|
|
+ _buildSectionHeader('Support ZenTap'),
|
|
|
+ _buildDonationTile(),
|
|
|
+
|
|
|
+ const SizedBox(height: 30),
|
|
|
+
|
|
|
// About Section
|
|
|
Padding(
|
|
|
padding: const EdgeInsets.only(bottom: 20),
|
|
|
child: Column(
|
|
|
children: [
|
|
|
Text(
|
|
|
- 'ZenTap v1.0.1',
|
|
|
+ 'ZenTap v1.0.2',
|
|
|
style: TextStyle(
|
|
|
color: ZenColors.mutedText,
|
|
|
fontSize: 14,
|
|
|
@@ -364,6 +371,53 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ void _showDonationDialog() {
|
|
|
+ if (_hapticsEnabled) {
|
|
|
+ HapticUtils.vibrate(duration: 50);
|
|
|
+ }
|
|
|
+
|
|
|
+ showDialog(
|
|
|
+ context: context,
|
|
|
+ builder: (context) => _buildDonationDialog(),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Future<void> _openDonationLink(String url) async {
|
|
|
+ if (_hapticsEnabled) {
|
|
|
+ HapticUtils.vibrate(duration: 30);
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ final Uri uri = Uri.parse(url);
|
|
|
+ if (await canLaunchUrl(uri)) {
|
|
|
+ await launchUrl(uri, mode: LaunchMode.externalApplication);
|
|
|
+ Navigator.of(context).pop(); // Close dialog after opening link
|
|
|
+ } else {
|
|
|
+ // Show error if URL can't be launched
|
|
|
+ if (mounted) {
|
|
|
+ ScaffoldMessenger.of(context).showSnackBar(
|
|
|
+ SnackBar(
|
|
|
+ content: const Text('Could not open donation link'),
|
|
|
+ backgroundColor: ZenColors.mutedText,
|
|
|
+ behavior: SnackBarBehavior.floating,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ // Show error on exception
|
|
|
+ if (mounted) {
|
|
|
+ ScaffoldMessenger.of(context).showSnackBar(
|
|
|
+ SnackBar(
|
|
|
+ content: const Text('Error opening donation link'),
|
|
|
+ backgroundColor: ZenColors.mutedText,
|
|
|
+ behavior: SnackBarBehavior.floating,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Widget _buildTutorialDialog() {
|
|
|
return AlertDialog(
|
|
|
backgroundColor: ZenColors.uiElements,
|
|
|
@@ -499,4 +553,173 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ Widget _buildDonationTile() {
|
|
|
+ return _buildActionTile(
|
|
|
+ icon: Icons.favorite,
|
|
|
+ title: 'Support Development',
|
|
|
+ subtitle: 'Help keep ZenTap free and ad-free',
|
|
|
+ onTap: _showDonationDialog,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildDonationDialog() {
|
|
|
+ return AlertDialog(
|
|
|
+ backgroundColor: ZenColors.uiElements,
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ borderRadius: BorderRadius.circular(20),
|
|
|
+ ),
|
|
|
+ title: Row(
|
|
|
+ children: [
|
|
|
+ Icon(
|
|
|
+ Icons.favorite,
|
|
|
+ color: ZenColors.red,
|
|
|
+ size: 24,
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 12),
|
|
|
+ const Text(
|
|
|
+ 'Support ZenTap',
|
|
|
+ style: TextStyle(
|
|
|
+ color: ZenColors.primaryText,
|
|
|
+ fontSize: 22,
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ content: Column(
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ 'ZenTap is free and ad-free. If you enjoy using it, consider supporting development:',
|
|
|
+ style: TextStyle(
|
|
|
+ color: ZenColors.secondaryText,
|
|
|
+ fontSize: 14,
|
|
|
+ height: 1.4,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 20),
|
|
|
+
|
|
|
+ // Ko-fi Button
|
|
|
+ _buildDonationButton(
|
|
|
+ icon: Icons.coffee,
|
|
|
+ title: 'Buy me a coffee',
|
|
|
+ subtitle: 'Ko-fi (one-time)',
|
|
|
+ color: const Color(0xFF13C3FF),
|
|
|
+ onTap: () => _openDonationLink('https://ko-fi.com/fsociety_hu'),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 12),
|
|
|
+
|
|
|
+ // PayPal Button
|
|
|
+ _buildDonationButton(
|
|
|
+ icon: Icons.payment,
|
|
|
+ title: 'PayPal Donation',
|
|
|
+ subtitle: 'Direct donation',
|
|
|
+ color: const Color(0xFF0070BA),
|
|
|
+ onTap: () => _openDonationLink('https://paypal.me/fsocietyhu'),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 12),
|
|
|
+
|
|
|
+ // GitHub Sponsors Button
|
|
|
+ _buildDonationButton(
|
|
|
+ icon: Icons.code,
|
|
|
+ title: 'GitHub Sponsors',
|
|
|
+ subtitle: 'Monthly support',
|
|
|
+ color: const Color(0xFFEA4AAA),
|
|
|
+ onTap: () => _openDonationLink('https://github.com/sponsors/fszontagh'),
|
|
|
+ ),
|
|
|
+
|
|
|
+ const SizedBox(height: 16),
|
|
|
+
|
|
|
+ Text(
|
|
|
+ 'Thank you for supporting indie development! 💜',
|
|
|
+ style: TextStyle(
|
|
|
+ color: ZenColors.secondaryText,
|
|
|
+ fontSize: 12,
|
|
|
+ fontStyle: FontStyle.italic,
|
|
|
+ ),
|
|
|
+ textAlign: TextAlign.center,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ actions: [
|
|
|
+ TextButton(
|
|
|
+ onPressed: () => Navigator.of(context).pop(),
|
|
|
+ child: Text(
|
|
|
+ 'Maybe later',
|
|
|
+ style: TextStyle(
|
|
|
+ color: ZenColors.mutedText,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildDonationButton({
|
|
|
+ required IconData icon,
|
|
|
+ required String title,
|
|
|
+ required String subtitle,
|
|
|
+ required Color color,
|
|
|
+ required VoidCallback onTap,
|
|
|
+ }) {
|
|
|
+ return Material(
|
|
|
+ color: color.withValues(alpha: 0.1),
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ child: InkWell(
|
|
|
+ onTap: onTap,
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ child: Container(
|
|
|
+ padding: const EdgeInsets.all(12),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ borderRadius: BorderRadius.circular(12),
|
|
|
+ border: Border.all(
|
|
|
+ color: color.withValues(alpha: 0.3),
|
|
|
+ width: 1,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ Icon(
|
|
|
+ icon,
|
|
|
+ color: color,
|
|
|
+ size: 20,
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 12),
|
|
|
+ Expanded(
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ title,
|
|
|
+ style: TextStyle(
|
|
|
+ color: ZenColors.primaryText,
|
|
|
+ fontSize: 14,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ subtitle,
|
|
|
+ style: TextStyle(
|
|
|
+ color: ZenColors.secondaryText,
|
|
|
+ fontSize: 12,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Icon(
|
|
|
+ Icons.open_in_new,
|
|
|
+ color: color,
|
|
|
+ size: 16,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|