261 lines
8.0 KiB
Dart
261 lines
8.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:lba/res/colors.dart';
|
|
|
|
class LanguageSelectionOverlay extends StatefulWidget {
|
|
final String currentLanguage;
|
|
final Function(String language, String flag) onLanguageSelected;
|
|
final GlobalKey targetKey;
|
|
|
|
const LanguageSelectionOverlay({
|
|
super.key,
|
|
required this.currentLanguage,
|
|
required this.onLanguageSelected,
|
|
required this.targetKey,
|
|
});
|
|
|
|
@override
|
|
State<LanguageSelectionOverlay> createState() =>
|
|
_LanguageSelectionOverlayState();
|
|
}
|
|
|
|
class _LanguageSelectionOverlayState extends State<LanguageSelectionOverlay>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _animationController;
|
|
late Animation<double> _scaleAnimation;
|
|
late Animation<double> _opacityAnimation;
|
|
late String _selectedLanguage;
|
|
|
|
final List<Map<String, String>> languages = [
|
|
{
|
|
'name': '🇺🇲 English',
|
|
'code': 'en',
|
|
'flag': 'assets/icons/usa circle.svg',
|
|
},
|
|
{
|
|
'name': '🇦🇪 العربية',
|
|
'code': 'ar',
|
|
'flag': 'assets/icons/arab circle.svg',
|
|
},
|
|
{
|
|
'name': '🇮🇷 فارسی',
|
|
'code': 'fa',
|
|
'flag': 'assets/icons/iran circle.svg',
|
|
},
|
|
];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_selectedLanguage = widget.currentLanguage.isNotEmpty
|
|
? widget.currentLanguage
|
|
: '🇺🇲 English';
|
|
|
|
_animationController = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(milliseconds: 300),
|
|
);
|
|
|
|
_scaleAnimation = Tween<double>(begin: 0.8, end: 1.0).animate(
|
|
CurvedAnimation(parent: _animationController, curve: Curves.easeOutBack),
|
|
);
|
|
|
|
_opacityAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
|
|
CurvedAnimation(parent: _animationController, curve: Curves.easeOut),
|
|
);
|
|
|
|
_animationController.forward();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_animationController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _closeOverlay() async {
|
|
await _animationController.reverse();
|
|
if (mounted) {
|
|
Navigator.of(context).pop();
|
|
}
|
|
}
|
|
|
|
void _selectLanguage(String languageName, String languageCode, String flag) {
|
|
setState(() {
|
|
_selectedLanguage = languageName;
|
|
});
|
|
|
|
Future.delayed(const Duration(milliseconds: 150), () {
|
|
widget.onLanguageSelected(languageName, flag);
|
|
_closeOverlay();
|
|
});
|
|
}
|
|
|
|
Offset _getTargetPosition() {
|
|
final RenderBox? renderBox =
|
|
widget.targetKey.currentContext?.findRenderObject() as RenderBox?;
|
|
if (renderBox != null) {
|
|
final position = renderBox.localToGlobal(Offset.zero);
|
|
return position;
|
|
}
|
|
return Offset.zero;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final targetPosition = _getTargetPosition();
|
|
final screenWidth = MediaQuery.of(context).size.width;
|
|
|
|
final overlayWidth = screenWidth * 0.45;
|
|
|
|
double? leftPosition;
|
|
double? rightPosition;
|
|
|
|
if (targetPosition.dx > screenWidth * 0.7) {
|
|
rightPosition = 16;
|
|
} else {
|
|
rightPosition = 24;
|
|
}
|
|
|
|
return AnimatedBuilder(
|
|
animation: _animationController,
|
|
builder: (context, child) {
|
|
return Material(
|
|
color: Colors.transparent,
|
|
child: GestureDetector(
|
|
onTap: _closeOverlay,
|
|
behavior: HitTestBehavior.translucent,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
height: double.infinity,
|
|
child: Stack(
|
|
children: [
|
|
Positioned(
|
|
left: leftPosition,
|
|
right: rightPosition,
|
|
top: targetPosition.dy + 40,
|
|
child: Transform.scale(
|
|
scale: _scaleAnimation.value,
|
|
child: Opacity(
|
|
opacity: _opacityAnimation.value,
|
|
child: Container(
|
|
width: overlayWidth,
|
|
decoration: BoxDecoration(
|
|
color: AppColors.surface,
|
|
borderRadius: BorderRadius.only(
|
|
bottomLeft: Radius.circular(16),
|
|
bottomRight: Radius.circular(16),
|
|
topLeft: Radius.circular(16),
|
|
),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppColors.shadowColor,
|
|
blurRadius: 15,
|
|
spreadRadius: 3,
|
|
offset: const Offset(0, 5),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children:
|
|
languages.map((language) {
|
|
final isSelected =
|
|
_selectedLanguage == language['name'];
|
|
return _buildLanguageOption(
|
|
language['name']!,
|
|
language['code']!,
|
|
language['flag']!,
|
|
isSelected,
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildLanguageOption(
|
|
String name,
|
|
String code,
|
|
String flag,
|
|
bool isSelected,
|
|
) {
|
|
print('Building language option: $name with flag: $flag');
|
|
return Material(
|
|
color: Colors.transparent,
|
|
child: InkWell(
|
|
onTap: () => _selectLanguage(name, code, flag),
|
|
borderRadius: BorderRadius.circular(12),
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
name,
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
|
|
color:
|
|
isSelected ? AppColors.primary : AppColors.textPrimary,
|
|
),
|
|
textDirection:
|
|
(code == 'ar' || code == 'fa')
|
|
? TextDirection.rtl
|
|
: TextDirection.ltr,
|
|
),
|
|
),
|
|
|
|
if (isSelected)
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(8, 0, 0, 0),
|
|
child: Container(
|
|
padding: const EdgeInsets.all(2),
|
|
decoration: BoxDecoration(
|
|
color: AppColors.primary,
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Icon(Icons.check, color: AppColors.surface, size: 12),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void showLanguageSelectionOverlay(
|
|
BuildContext context,
|
|
String currentLanguage,
|
|
Function(String language, String flag) onLanguageSelected,
|
|
GlobalKey targetKey,
|
|
) {
|
|
showGeneralDialog(
|
|
context: context,
|
|
barrierDismissible: true,
|
|
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
|
|
barrierColor: Colors.transparent,
|
|
transitionDuration: const Duration(milliseconds: 300),
|
|
pageBuilder: (context, animation1, animation2) {
|
|
return LanguageSelectionOverlay(
|
|
currentLanguage: currentLanguage,
|
|
onLanguageSelected: onLanguageSelected,
|
|
targetKey: targetKey,
|
|
);
|
|
},
|
|
);
|
|
}
|