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 createState() => _LanguageSelectionOverlayState(); } class _LanguageSelectionOverlayState extends State with TickerProviderStateMixin { late AnimationController _animationController; late Animation _scaleAnimation; late Animation _opacityAnimation; final List> 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( begin: 0.8, end: 1.0, ).animate(CurvedAnimation( parent: _animationController, curve: Curves.easeOutBack, )); _opacityAnimation = Tween( 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(), ), ), ), ); }, ), ), ], ), ), ); } }