Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 339 additions & 0 deletions lib/features/settings/presentation/pages/settings_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:package_info_plus/package_info_plus.dart';

import '../../../../core/constants/app_constants.dart';
import '../../../../services/preferences_service.dart';

class SettingsPage extends StatefulWidget {
final Function(Locale) onLanguageChanged;
final Function(ThemeMode) onThemeChanged;
final Locale currentLocale;
final ThemeMode currentTheme;

const SettingsPage({
super.key,
required this.onLanguageChanged,
required this.onThemeChanged,
required this.currentLocale,
required this.currentTheme,
});

@override
State<SettingsPage> createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
final PreferencesService _preferencesService = PreferencesService();
String _appVersion = '1.0.0';

@override
void initState() {
super.initState();
_loadAppVersion();
}

Future<void> _loadAppVersion() async {
try {
final packageInfo = await PackageInfo.fromPlatform();
if (mounted) {
setState(() {
_appVersion = packageInfo.version;
});
}
} catch (e) {
// Keep default version on error
}
}

@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;

return Scaffold(
backgroundColor: AppConstants.backgroundColor,
appBar: AppBar(
title: Text(l10n.settings),
backgroundColor: AppConstants.primaryColor,
foregroundColor: Colors.white,
elevation: 0,
),
body: ListView(
padding: const EdgeInsets.all(16.0),
children: [
_buildLanguageSection(context, l10n),
const SizedBox(height: 24),
_buildThemeSection(context, l10n),
const SizedBox(height: 24),
_buildGitHubSection(context, l10n),
const SizedBox(height: 24),
_buildVersionSection(context, l10n),
],
),
);
}

Widget _buildLanguageSection(BuildContext context, AppLocalizations l10n) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.language, color: AppConstants.primaryColor),
const SizedBox(width: 12),
Text(
l10n.language,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 16),
_buildLanguageOption(
context,
'English',
const Locale('en'),
widget.currentLocale,
),
const Divider(),
_buildLanguageOption(
context,
'Deutsch',
const Locale('de'),
widget.currentLocale,
),
const Divider(),
_buildLanguageOption(
context,
'Schwiizerdütsch',
const Locale('gsw'),
widget.currentLocale,
),
],
),
),
);
}

Widget _buildLanguageOption(
BuildContext context,
String label,
Locale locale,
Locale currentLocale,
) {
final isSelected = currentLocale.languageCode == locale.languageCode;

return InkWell(
onTap: () async {
widget.onLanguageChanged(locale);
await _preferencesService.setLanguage(locale.languageCode);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Language changed to $label'),
duration: const Duration(seconds: 2),
),
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
children: [
Expanded(
child: Text(
label,
style: TextStyle(
fontSize: 16,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
),
),
if (isSelected)
const Icon(
Icons.check,
color: AppConstants.primaryColor,
),
],
),
),
);
}

Widget _buildThemeSection(BuildContext context, AppLocalizations l10n) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(Icons.palette, color: AppConstants.primaryColor),
const SizedBox(width: 12),
Text(
l10n.theme,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 16),
_buildThemeOption(
context,
l10n.lightMode,
ThemeMode.light,
Icons.light_mode,
),
const Divider(),
_buildThemeOption(
context,
l10n.darkMode,
ThemeMode.dark,
Icons.dark_mode,
),
],
),
),
);
}

Widget _buildThemeOption(
BuildContext context,
String label,
ThemeMode themeMode,
IconData icon,
) {
final isSelected = widget.currentTheme == themeMode;

return InkWell(
onTap: () async {
widget.onThemeChanged(themeMode);
await _preferencesService.setTheme(
themeMode == ThemeMode.light ? 'light' : 'dark',
);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Theme changed to $label'),
duration: const Duration(seconds: 2),
),
);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Row(
children: [
Icon(icon, size: 20),
const SizedBox(width: 12),
Expanded(
child: Text(
label,
style: TextStyle(
fontSize: 16,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
),
),
if (isSelected)
const Icon(
Icons.check,
color: AppConstants.primaryColor,
),
],
),
),
);
}

Widget _buildGitHubSection(BuildContext context, AppLocalizations l10n) {
return Card(
child: InkWell(
onTap: () => _openGitHub(context),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
const Icon(Icons.code, color: AppConstants.primaryColor),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
l10n.githubContributors,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
l10n.githubContributorsDescription,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
],
),
),
const Icon(Icons.open_in_new),
],
),
),
),
);
}

Future<void> _openGitHub(BuildContext context) async {
final url = Uri.parse('https://github.com/tujii/angry_raphi_flutter');
try {
if (await canLaunchUrl(url)) {
await launchUrl(url, mode: LaunchMode.externalApplication);
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Could not open GitHub link'),
backgroundColor: Colors.red,
),
);
}
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error opening link: $e'),
backgroundColor: Colors.red,
),
);
}
}
}

Widget _buildVersionSection(BuildContext context, AppLocalizations l10n) {
return Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
l10n.version(_appVersion),
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
),
),
),
);
}
}
Loading
Loading