hwhub/lib/screens/about_screen.dart
2026-03-09 20:42:28 +01:00

233 lines
6.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import '../theme/app_colors.dart';
/// Full-page About screen with app info, version, and links.
class AboutScreen extends StatefulWidget {
const AboutScreen({super.key});
@override
State<AboutScreen> createState() => _AboutScreenState();
}
class _AboutScreenState extends State<AboutScreen> {
static const _supportEmail = 'support@car64.app';
static const _websiteUrl = 'https://www.car64.app/';
PackageInfo? _packageInfo;
@override
void initState() {
super.initState();
_loadPackageInfo();
}
Future<void> _loadPackageInfo() async {
final info = await PackageInfo.fromPlatform();
if (mounted) setState(() => _packageInfo = info);
}
Future<void> _contactSupport() async {
final uri = Uri(
scheme: 'mailto',
path: _supportEmail,
queryParameters: {
'subject': 'car64 Support Request',
},
);
final launched = await launchUrl(uri, mode: LaunchMode.externalApplication);
if (!launched && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Could not open mail app. Please email support@car64.app.'),
),
);
}
}
Future<void> _openWebsite() async {
final uri = Uri.parse(_websiteUrl);
final launched = await launchUrl(uri, mode: LaunchMode.externalApplication);
if (!launched && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Could not open website. Please visit https://www.car64.app/'),
),
);
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final version = _packageInfo != null
? 'v${_packageInfo!.version} (${_packageInfo!.buildNumber})'
: '';
return Scaffold(
appBar: AppBar(
title: const Text('About'),
),
body: ListView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
children: [
const SizedBox(height: 16),
// ── App icon + name ──
Center(
child: Container(
width: 96,
height: 96,
decoration: const BoxDecoration(
gradient: AppColors.brandGradient,
shape: BoxShape.circle,
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Image.asset(
'assets/img/icon_bg_removed.png',
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) => const Icon(
Icons.directions_car_filled,
color: Colors.white,
size: 52,
),
),
),
),
),
const SizedBox(height: 16),
Center(
child: Text(
'car64',
style: theme.textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 4),
Center(
child: Text(
version,
style: theme.textTheme.bodyMedium?.copyWith(
color: AppColors.textSecondary,
),
),
),
const SizedBox(height: 8),
Center(
child: Text(
'Track and manage your die-cast car collection.',
style: theme.textTheme.bodyMedium?.copyWith(
color: AppColors.textHint,
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 32),
const Divider(),
const SizedBox(height: 16),
// ── Technical details ──
Text(
'Technical',
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
color: AppColors.textSecondary,
),
),
const SizedBox(height: 8),
_InfoRow(label: 'Version', value: _packageInfo?.version ?? ''),
_InfoRow(
label: 'Build',
value: _packageInfo?.buildNumber ?? '',
),
_InfoRow(
label: 'Package',
value: _packageInfo?.packageName ?? '',
),
const SizedBox(height: 20),
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _openWebsite,
icon: const Icon(Icons.language),
label: const Text('Visit Website'),
),
),
const SizedBox(height: 10),
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _contactSupport,
icon: const Icon(Icons.support_agent),
label: const Text('Contact Support'),
),
),
const SizedBox(height: 32),
// ── Powered by ──
Center(
child: Column(
children: [
Text(
'Powered by Flutter & Supabase',
style: theme.textTheme.bodySmall?.copyWith(
color: AppColors.textHint,
),
),
const SizedBox(height: 4),
Text(
'© 2026 car64',
style: theme.textTheme.bodySmall?.copyWith(
color: AppColors.textHint,
),
),
],
),
),
const SizedBox(height: 24),
],
),
);
}
}
// ── Info row (label : value) ──────────────────────────────────────────
class _InfoRow extends StatelessWidget {
final String label;
final String value;
const _InfoRow({required this.label, required this.value});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
Text(
label,
style: const TextStyle(
color: AppColors.textSecondary,
fontWeight: FontWeight.w500,
),
),
const Spacer(),
Text(
value,
style: const TextStyle(color: AppColors.textHint),
),
],
),
);
}
}