import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hmg_patient_app_new/core/app_assets.dart'; import 'package:hmg_patient_app_new/core/app_export.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart'; import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart'; import 'package:provider/provider.dart'; enum VisualMode { off, invert, dim, highContrast } class AccessibilityPage extends StatefulWidget { const AccessibilityPage({super.key}); @override State createState() => _AccessibilityPageState(); } class _AccessibilityPageState extends State { late ProfileSettingsViewModel profileSettingsViewModel; int _currentFontSizeStep = 2; // 0: Small, 1: Small-Medium, 2: Medium (default), 3: Medium-Large, 4: Large VisualMode _selectedMode = VisualMode.off; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { profileSettingsViewModel = Provider.of(context, listen: false); // Load saved settings from ViewModel _loadSavedSettings(); } }); } void _loadSavedSettings() { setState(() { _currentFontSizeStep = profileSettingsViewModel.fontSizeStep; _selectedMode = _visualModeFromString(profileSettingsViewModel.visualMode); }); } VisualMode _visualModeFromString(String mode) { switch (mode) { case 'off': return VisualMode.off; case 'invert': return VisualMode.invert; case 'dim': return VisualMode.dim; case 'highContrast': return VisualMode.highContrast; default: return VisualMode.off; } } String _visualModeToString(VisualMode mode) { switch (mode) { case VisualMode.off: return 'off'; case VisualMode.invert: return 'invert'; case VisualMode.dim: return 'dim'; case VisualMode.highContrast: return 'highContrast'; } } @override void dispose() { super.dispose(); } double _getFontSizeForStep(int step) { const double mediumSize = 40.0; // Medium is baseline switch (step) { case 0: return mediumSize * 0.5; // Small: 20.0 case 1: return mediumSize * 0.75; // Small-Medium: 30.0 case 2: return mediumSize; // Medium (default): 40.0 case 3: return mediumSize * 1.5; // Medium-Large: 60.0 case 4: return mediumSize * 1.75; // Large: 70.0 default: return mediumSize; } } @override Widget build(BuildContext context) { profileSettingsViewModel = Provider.of(context, listen: false); return CollapsingListView( title: LocaleKeys.accessibility.tr(context: context), isClose: true, bottomChild: Container( padding: EdgeInsets.all(24.w), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false, ), child: CustomButton( height: 56.h, icon: AppAssets.checkmark_icon, iconColor: AppColors.whiteColor, text: LocaleKeys.saveChanges.tr(context: context), backgroundColor: AppColors.primaryRedColor, borderColor: AppColors.primaryRedColor, textColor: AppColors.whiteColor, fontSize: 16.f, isBold: true, onPressed: () { // Save accessibility settings to ViewModel profileSettingsViewModel.setFontSizeStep(_currentFontSizeStep); profileSettingsViewModel.setVisualMode(_visualModeToString(_selectedMode)); // Show success message ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: LocaleKeys.settingsSavedSuccessfully.tr(context: context).toText14( color: AppColors.whiteColor, ), backgroundColor: AppColors.successColor, duration: const Duration(seconds: 2), ), ); // Pop the page Navigator.pop(context); }, ), ), child: SingleChildScrollView( padding: EdgeInsets.only(top: 16.h, bottom: 24.h, left: 24.w, right: 24.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Font Size Card _buildFontSizeCard(), SizedBox(height: 24.h), // Mode for Partially Blind Card _buildVisualModeCard(), ], ), ), ); } Widget _buildFontSizeCard() { return Container( padding: EdgeInsets.all(24.w), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Card Label LocaleKeys.fontSize.tr(context: context).toText18(isBold: true), SizedBox(height: 24.h), // Center Aa heading that changes size Container( height: 70.h, child: Center( child: AnimatedDefaultTextStyle( duration: const Duration(milliseconds: 300), style: TextStyle( fontSize: _getFontSizeForStep(_currentFontSizeStep), fontWeight: FontWeight.bold, color: AppColors.blackBgColor, ), child: const Text("Aa"), ), ), ), SizedBox(height: 32.h), // Stepped slider Column( children: [ // Stack to position circles on top of the bar Stack( alignment: Alignment.center, children: [ // Grey bar Container( height: 4.h, decoration: BoxDecoration( color: AppColors.greyTextColor.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(2.r), ), ), // Step indicator with dots positioned on top of the bar Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate(5, (index) { bool isSelected = index == _currentFontSizeStep; return GestureDetector( onTap: () { setState(() { _currentFontSizeStep = index; }); }, behavior: HitTestBehavior.opaque, child: Padding( padding: EdgeInsets.all(8.w), // Increased tap zone child: Container( width: isSelected ? 20.w : 12.w, height: isSelected ? 20.w : 12.w, decoration: BoxDecoration( color: isSelected ? AppColors.primaryRedColor : Colors.transparent, shape: BoxShape.circle, border: Border.all( color: isSelected ? AppColors.primaryRedColor : AppColors.greyTextColor.withValues(alpha: 0.3), width: 2.w, ), ), ), ), ); }), ), ], ), SizedBox(height: 12.h), // Labels Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ LocaleKeys.fontSizeSmall.tr(context: context).toText12(color: AppColors.greyTextColor), LocaleKeys.fontSizeMedium.tr(context: context).toText12(color: AppColors.greyTextColor), LocaleKeys.fontSizeLarge.tr(context: context).toText12(color: AppColors.greyTextColor), ], ), ], ), ], ), ); } Widget _buildVisualModeCard() { return Container( padding: EdgeInsets.all(24.w), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 24.r, hasShadow: false, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Card Label LocaleKeys.blindModes.tr(context: context).toText18(isBold: true), SizedBox(height: 24.h), // Two columns layout Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Left Column - Radio buttons Expanded( flex: 2, child: Column( children: [ _buildRadioOption(VisualMode.off, LocaleKeys.offTheme.tr(context: context)), SizedBox(height: 12.h), _buildRadioOption(VisualMode.invert, LocaleKeys.invertTheme.tr(context: context)), SizedBox(height: 12.h), _buildRadioOption(VisualMode.dim, LocaleKeys.dimTheme.tr(context: context)), SizedBox(height: 12.h), _buildRadioOption(VisualMode.highContrast, LocaleKeys.highContrastTheme.tr(context: context)), ], ), ), SizedBox(width: 16.w), // Right Column - Preview Card Expanded( flex: 3, child: _buildPreviewCard(), ), ], ), ], ), ); } Widget _buildRadioOption(VisualMode mode, String label) { bool isSelected = _selectedMode == mode; return GestureDetector( onTap: () { setState(() { _selectedMode = mode; }); }, child: Row( children: [ Container( width: 20.w, height: 20.w, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: isSelected ? AppColors.primaryRedColor : AppColors.greyTextColor, width: 2.w, ), color: Colors.transparent, ), child: isSelected ? Center( child: Container( width: 10.w, height: 10.w, decoration: BoxDecoration( shape: BoxShape.circle, color: AppColors.primaryRedColor, ), ), ) : null, ), SizedBox(width: 8.w), label.toText14( isBold: isSelected, color: isSelected ? AppColors.blackBgColor : AppColors.greyTextColor, ), ], ), ); } Widget _buildPreviewCard() { // Always build preview content with base "Off" mode colors Widget previewContent = Container( padding: EdgeInsets.all(16.w), decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: AppColors.whiteColor, borderRadius: 20.r, isCustomShadow: [ BoxShadow( color: const Color(0xff000000).withValues(alpha: 0.1), blurRadius: 16, spreadRadius: 16 * 0.1, // 10% of blur radius offset: const Offset(0, 0), // Uniform shadow on all sides ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Top row with heading and arrow Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ LocaleKeys.cardHeading.tr(context: context).toText14( isBold: true, color: AppColors.blackBgColor, // Always use base color ), Transform.scale( scaleX: Utils.appState.isArabic() ? -1 : 1, child: Utils.buildSvgWithAssets( icon: AppAssets.arrow_forward, iconColor: AppColors.blackBgColor, // Always use base color ), ), ], ), SizedBox(height: 16.h), // Price with SAR symbol Row( children: [ "1234".toText24( isBold: true, color: AppColors.blackBgColor, // Always use base color ), SizedBox(width: 4.w), LocaleKeys.riyal.tr(context: context).toText14( color: AppColors.blackBgColor, // Always use base color ), SizedBox(width: 4.w), Utils.buildSvgWithAssets( icon: AppAssets.saudi_riyal_icon, iconColor: AppColors.blackBgColor, // Always use base color width: 16.w, height: 16.w, ), ], ), SizedBox(height: 16.h), // Button - always show with base "Off" colors CustomButton( height: 44.h, icon: AppAssets.add_icon, iconColor: AppColors.whiteColor, // Always use base color text: LocaleKeys.buttonText.tr(context: context), backgroundColor: AppColors.primaryRedColor, // Always use base color borderColor: AppColors.primaryRedColor, // Always use base color textColor: AppColors.whiteColor, // Always use base color fontSize: 14.f, onPressed: () {}, ), ], ), ); // Apply visual mode filters to preview switch (_selectedMode) { case VisualMode.invert: return ColorFiltered( colorFilter: const ColorFilter.matrix([ -1, 0, 0, 0, 255, // Red channel inverted 0, -1, 0, 0, 255, // Green channel inverted 0, 0, -1, 0, 255, // Blue channel inverted 0, 0, 0, 1, 0, // Alpha channel unchanged ]), child: previewContent, ); case VisualMode.dim: return Stack( children: [ previewContent, Positioned.fill( child: IgnorePointer( child: Container( decoration: BoxDecoration( color: AppColors.blackBgColor.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(20.r), ), ), ), ), ], ); case VisualMode.highContrast: return ColorFiltered( colorFilter: const ColorFilter.matrix([ 0.2126, 0.7152, 0.0722, 0, 0, // Red channel (grayscale) 0.2126, 0.7152, 0.0722, 0, 0, // Green channel (grayscale) 0.2126, 0.7152, 0.0722, 0, 0, // Blue channel (grayscale) 0, 0, 0, 1, 0, // Alpha channel unchanged ]), child: previewContent, ); case VisualMode.off: return previewContent; } } }