Compare commits

...

1 Commits

Author SHA1 Message Date
AlexisDanlos
d92767bda1 feat: add accessibility option to home page menu
All checks were successful
/ mirror (push) Successful in 4s
/ build (push) Successful in 8m23s
/ build-stealth (push) Successful in 8m29s
2025-03-22 23:42:47 +01:00
2 changed files with 470 additions and 0 deletions

View File

@ -0,0 +1,459 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AccessibilityPage extends StatefulWidget {
const AccessibilityPage({Key? key}) : super(key: key);
@override
_AccessibilityPageState createState() => _AccessibilityPageState();
}
class _AccessibilityPageState extends State<AccessibilityPage> {
// Font size setting
double _fontSize = 1.0;
// Toggle settings
bool _highContrastMode = false;
bool _reduceAnimations = false;
bool _enableVibration = true;
bool _enableScreenReader = false;
bool _useSimpleLayout = false;
bool _autoAnswerCalls = false;
// Call display timeout
int _callDisplayTimeout = 30; // seconds
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadSettings();
}
Future<void> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_fontSize = prefs.getDouble('accessibility_font_size') ?? 1.0;
_highContrastMode = prefs.getBool('accessibility_high_contrast') ?? false;
_reduceAnimations = prefs.getBool('accessibility_reduce_animations') ?? false;
_enableVibration = prefs.getBool('accessibility_vibration') ?? true;
_enableScreenReader = prefs.getBool('accessibility_screen_reader') ?? false;
_useSimpleLayout = prefs.getBool('accessibility_simple_layout') ?? false;
_autoAnswerCalls = prefs.getBool('accessibility_auto_answer') ?? false;
_callDisplayTimeout = prefs.getInt('accessibility_call_timeout') ?? 30;
_isLoading = false;
});
}
Future<void> _saveSettings() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setDouble('accessibility_font_size', _fontSize);
await prefs.setBool('accessibility_high_contrast', _highContrastMode);
await prefs.setBool('accessibility_reduce_animations', _reduceAnimations);
await prefs.setBool('accessibility_vibration', _enableVibration);
await prefs.setBool('accessibility_screen_reader', _enableScreenReader);
await prefs.setBool('accessibility_simple_layout', _useSimpleLayout);
await prefs.setBool('accessibility_auto_answer', _autoAnswerCalls);
await prefs.setInt('accessibility_call_timeout', _callDisplayTimeout);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Accessibility settings saved')),
);
}
String _getFontSizeLabel() {
if (_fontSize <= 0.8) return 'Small';
if (_fontSize <= 1.0) return 'Default';
if (_fontSize <= 1.2) return 'Large';
if (_fontSize <= 1.4) return 'Extra Large';
return 'Maximum';
}
String _getCallTimeoutLabel() {
if (_callDisplayTimeout <= 15) return '15 seconds';
if (_callDisplayTimeout <= 30) return '30 seconds';
if (_callDisplayTimeout <= 45) return '45 seconds';
if (_callDisplayTimeout <= 60) return '1 minute';
return '${_callDisplayTimeout} seconds';
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Accessibility'),
backgroundColor: Colors.black,
elevation: 0,
actions: [
TextButton(
onPressed: _saveSettings,
child: const Text('Save', style: TextStyle(color: Colors.blue)),
),
],
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header with icon
Center(
child: Column(
children: [
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(20),
),
child: const Icon(
Icons.accessibility_new,
size: 50,
color: Colors.white,
),
),
const SizedBox(height: 16),
const Text(
'Accessibility Settings',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 8),
Text(
'Customize your experience',
style: TextStyle(
color: Colors.grey[400],
fontSize: 14,
),
),
],
),
),
const SizedBox(height: 32),
// Text Size Settings
const _SectionHeader(title: 'Display Settings'),
_ContentCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Text Size',
style: TextStyle(color: Colors.white, fontSize: 16),
),
Text(
_getFontSizeLabel(),
style: TextStyle(color: Colors.blue, fontSize: 16),
),
],
),
const SizedBox(height: 8),
Slider(
value: _fontSize,
min: 0.8,
max: 1.6,
divisions: 4,
label: _getFontSizeLabel(),
onChanged: (value) {
setState(() {
_fontSize = value;
});
},
),
const SizedBox(height: 16),
_ToggleOption(
title: 'High Contrast Mode',
subtitle: 'Increase color contrast for better visibility',
value: _highContrastMode,
onChanged: (value) {
setState(() {
_highContrastMode = value;
});
},
),
_ToggleOption(
title: 'Reduce Animations',
subtitle: 'Minimize motion effects throughout the app',
value: _reduceAnimations,
onChanged: (value) {
setState(() {
_reduceAnimations = value;
});
},
),
_ToggleOption(
title: 'Simple Layout',
subtitle: 'Use a simplified interface with larger touch targets',
value: _useSimpleLayout,
onChanged: (value) {
setState(() {
_useSimpleLayout = value;
});
},
),
],
),
),
const SizedBox(height: 24),
// Assistive Technology
const _SectionHeader(title: 'Assistive Technology'),
_ContentCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ToggleOption(
title: 'Enable Screen Reader',
subtitle: 'Works with TalkBack and VoiceOver',
value: _enableScreenReader,
onChanged: (value) {
setState(() {
_enableScreenReader = value;
});
},
),
_ToggleOption(
title: 'Haptic Feedback',
subtitle: 'Vibration feedback for interactions',
value: _enableVibration,
onChanged: (value) {
setState(() {
_enableVibration = value;
});
},
),
],
),
),
const SizedBox(height: 24),
// Call Settings
const _SectionHeader(title: 'Call Settings'),
_ContentCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ToggleOption(
title: 'Auto-Answer Calls',
subtitle: 'Answer incoming calls automatically after timeout',
value: _autoAnswerCalls,
onChanged: (value) {
setState(() {
_autoAnswerCalls = value;
});
},
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Call Display Timeout',
style: TextStyle(color: Colors.white, fontSize: 16),
),
Text(
_getCallTimeoutLabel(),
style: TextStyle(color: Colors.blue, fontSize: 16),
),
],
),
const SizedBox(height: 8),
Slider(
value: _callDisplayTimeout.toDouble(),
min: 15,
max: 60,
divisions: 3,
label: _getCallTimeoutLabel(),
onChanged: (value) {
setState(() {
_callDisplayTimeout = value.toInt();
});
},
),
],
),
),
const SizedBox(height: 24),
// Additional Resources
const _SectionHeader(title: 'Additional Resources'),
_ContentCard(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_LinkButton(
icon: Icons.help_outline,
text: 'Accessibility Help',
onTap: () {
// Add navigation or link to help page
},
),
const SizedBox(height: 12),
_LinkButton(
icon: Icons.feedback_outlined,
text: 'Send Accessibility Feedback',
onTap: () {
// Add feedback functionality
},
),
],
),
),
const SizedBox(height: 40),
],
),
),
);
}
}
class _SectionHeader extends StatelessWidget {
final String title;
const _SectionHeader({Key? key, required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
title,
style: const TextStyle(
color: Colors.blue,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
);
}
}
class _ContentCard extends StatelessWidget {
final Widget child;
const _ContentCard({Key? key, required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[900],
borderRadius: BorderRadius.circular(12),
),
child: child,
);
}
}
class _ToggleOption extends StatelessWidget {
final String title;
final String subtitle;
final bool value;
final ValueChanged<bool> onChanged;
const _ToggleOption({
Key? key,
required this.title,
required this.subtitle,
required this.value,
required this.onChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
),
const SizedBox(height: 4),
Text(
subtitle,
style: const TextStyle(
color: Colors.white70,
fontSize: 14,
),
),
],
),
),
Switch(
value: value,
onChanged: onChanged,
activeColor: Colors.blue,
),
],
),
);
}
}
class _LinkButton extends StatelessWidget {
final IconData icon;
final String text;
final VoidCallback onTap;
const _LinkButton({
Key? key,
required this.icon,
required this.text,
required this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
children: [
Icon(icon, color: Colors.blue),
const SizedBox(width: 16),
Text(
text,
style: const TextStyle(color: Colors.white),
),
const Spacer(),
const Icon(
Icons.arrow_forward_ios,
color: Colors.white70,
size: 16,
),
],
),
),
);
}
}

View File

@ -9,6 +9,7 @@ import 'package:dialer/features/settings/settings.dart';
import '../../services/contact_service.dart';
import 'package:dialer/features/voicemail/voicemail_page.dart';
import '../contacts/widgets/contact_modal.dart';
import 'package:dialer/features/accessibility/accessibility.dart'; // Add this import
class _MyHomePageState extends State<MyHomePage>
@ -233,6 +234,10 @@ class _MyHomePageState extends State<MyHomePage>
value: 'settings',
child: Text('Settings'),
),
const PopupMenuItem<String>(
value: 'accessibility',
child: Text('Accessibility'),
),
],
onSelected: (String value) {
if (value == 'settings') {
@ -241,6 +246,12 @@ class _MyHomePageState extends State<MyHomePage>
MaterialPageRoute(
builder: (context) => const SettingsPage()),
);
} else if (value == 'accessibility') {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AccessibilityPage()),
);
}
},
),