proxybuy-flutter/lib/components/dialogs/language_selection_dialog.dart

253 lines
9.5 KiB
Dart

import 'package:flutter/material.dart';
void showLanguageSelectionOverlay(
BuildContext context,
String currentLanguage,
Function(String, String) onLanguageSelected,
GlobalKey languageTileKey,
) {
final overlay = Overlay.of(context);
late OverlayEntry overlayEntry;
final RenderBox renderBox = languageTileKey.currentContext?.findRenderObject() as RenderBox;
final position = renderBox.localToGlobal(Offset.zero);
final size = renderBox.size;
overlayEntry = OverlayEntry(
builder: (context) => LanguageSelectionOverlay(
onLanguageSelected: (language, flag) {
onLanguageSelected(language, flag);
overlayEntry.remove();
},
onDismiss: () {
overlayEntry.remove();
},
currentLanguage: currentLanguage,
position: position,
triggerSize: size,
),
);
overlay.insert(overlayEntry);
}
class LanguageSelectionOverlay extends StatefulWidget {
final Function(String, String) onLanguageSelected;
final VoidCallback onDismiss;
final String currentLanguage;
final Offset position;
final Size triggerSize;
const LanguageSelectionOverlay({
super.key,
required this.onLanguageSelected,
required this.onDismiss,
required this.currentLanguage,
required this.position,
required this.triggerSize,
});
@override
State<LanguageSelectionOverlay> createState() => _LanguageSelectionOverlayState();
}
class _LanguageSelectionOverlayState extends State<LanguageSelectionOverlay>
with TickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _scaleAnimation;
late Animation<double> _opacityAnimation;
final List<Map<String, String>> languages = [
{'name': 'English', 'flag': 'assets/icons/usa circle.svg'},
{'name': 'العربية', 'flag': 'assets/icons/arab circle.svg'},
{'name': 'فارسی', 'flag': 'assets/icons/iran circle.svg'},
];
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 200),
vsync: this,
);
_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();
}
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
final overlayWidth = screenSize.width * 0.45;
const overlayHeight = 180.0;
double left = widget.position.dx;
double top = widget.position.dy + widget.triggerSize.height + 8;
if (left + overlayWidth > screenSize.width) {
left = screenSize.width - overlayWidth - 16;
}
if (left < 16) {
left = 16;
}
if (top + overlayHeight > screenSize.height) {
top = widget.position.dy - overlayHeight - 8;
}
return GestureDetector(
onTap: widget.onDismiss,
child: Material(
color: Colors.transparent,
child: Stack(
children: [
Container(
width: screenSize.width,
height: screenSize.height,
color: Colors.transparent,
),
Positioned(
left: left,
top: top,
child: AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Transform.scale(
scale: _scaleAnimation.value,
child: Opacity(
opacity: _opacityAnimation.value,
child: Container(
width: overlayWidth,
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: languages.map((language) {
final isSelected = language['name'] == widget.currentLanguage;
final isRTL = language['name'] == 'العربية' || language['name'] == 'فارسی';
return GestureDetector(
onTap: () {
widget.onLanguageSelected(
language['name']!,
language['flag']!,
);
},
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 12,
),
decoration: BoxDecoration(
color: isSelected
? Theme.of(context).primaryColor.withOpacity(0.1)
: Colors.transparent,
borderRadius: languages.indexOf(language) == 0
? const BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
)
: languages.indexOf(language) == languages.length - 1
? const BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
)
: null,
),
child: Row(
textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.asset(
language['flag']!,
width: 24,
height: 18,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 24,
height: 18,
decoration: BoxDecoration(
color: Theme.of(context).dividerColor,
borderRadius: BorderRadius.circular(4),
),
child: Icon(
Icons.flag,
color: Theme.of(context).textTheme.bodyMedium?.color,
size: 12,
),
);
},
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
language['name']!,
textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
style: TextStyle(
fontSize: 15,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
color: isSelected
? Theme.of(context).primaryColor
: Theme.of(context).textTheme.bodyLarge?.color,
),
),
),
if (isSelected)
Icon(
Icons.check,
color: Theme.of(context).primaryColor,
size: 18,
),
],
),
),
);
}).toList(),
),
),
),
);
},
),
),
],
),
),
);
}
}