// ignore_for_file: deprecated_member_use import 'package:didvan/config/design_config.dart'; import 'package:didvan/config/theme_data.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; class SearchField extends StatefulWidget { final String title; final FocusNode focusNode; final bool? isFiltered; final void Function(String value) onChanged; final VoidCallback? onFilterButtonPressed; final VoidCallback? onGoBack; final String? value; final String? extraIconPath; final VoidCallback? onExtraIconPressed; const SearchField({ Key? key, required this.title, required this.onChanged, required this.focusNode, this.onFilterButtonPressed, this.isFiltered, this.onGoBack, this.value, this.extraIconPath, this.onExtraIconPressed, }) : super(key: key); @override State createState() => _SearchFieldState(); } class _SearchFieldState extends State with TickerProviderStateMixin { late AnimationController _pulseController; late Animation _pulseAnimation; late AnimationController _rotationController; late Animation _rotationAnimation; @override void initState() { super.initState(); _pulseController = AnimationController( duration: const Duration(milliseconds: 1500), vsync: this, )..repeat(reverse: true); _pulseAnimation = Tween(begin: 1.0, end: 1.1).animate( CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut), ); _rotationController = AnimationController( duration: const Duration(seconds: 4), vsync: this, )..repeat(); _rotationAnimation = Tween(begin: 0, end: 1).animate( CurvedAnimation(parent: _rotationController, curve: Curves.linear), ); widget.focusNode.addListener(() { if (mounted) { setState(() {}); } }); } @override Widget build(BuildContext context) { return SizedBox( height: 47, child: Row( children: [ Expanded( child: Container( decoration: BoxDecoration( color: DesignConfig.isDark ? const Color.fromARGB(255, 188, 188, 188) : const Color.fromARGB(255, 235, 235, 235), borderRadius: BorderRadius.circular(40), ), child: TextFormField( initialValue: widget.value, focusNode: widget.focusNode, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Colors.black, ), textAlignVertical: TextAlignVertical.center, onChanged: widget.onChanged, keyboardType: TextInputType.text, textInputAction: TextInputAction.search, decoration: InputDecoration( suffixIcon: widget.onFilterButtonPressed != null ? SizedBox( width: 48, child: Align( alignment: Alignment.centerLeft, child: Padding( padding: const EdgeInsets.only(left: 8), child: Row( mainAxisSize: MainAxisSize.min, children: [ Stack( children: [ GestureDetector( onTap: widget.onFilterButtonPressed!, child: Container( width: 27, height: 27, padding: const EdgeInsets.all(4), child: SvgPicture.asset( "lib/assets/icons/search sort.svg", ), ), ), if (widget.isFiltered!) Positioned( child: Container( width: 10, height: 10, decoration: BoxDecoration( shape: BoxShape.circle, color: Theme.of(context) .colorScheme .secondary, ), ), ), ], ), ], ), ), ), ) : null, focusedBorder: OutlineInputBorder( borderRadius: const BorderRadius.all( Radius.circular(35), ), borderSide: BorderSide( color: Theme.of(context).colorScheme.primary, ), ), prefixIcon: GestureDetector( onTap: widget.onGoBack, child: Padding( padding: const EdgeInsets.all(11.0), child: SvgPicture.asset( widget.onGoBack == null ? 'lib/assets/icons/search.svg' : 'lib/assets/icons/search.svg', width: 23, height: 23, ), ), ), prefixIconColor: Theme.of(context).colorScheme.inputText, enabledBorder: OutlineInputBorder( borderRadius: const BorderRadius.all( Radius.circular(20), ), borderSide: BorderSide( color: Theme.of(context).colorScheme.border, ), ), fillColor: Colors.red, contentPadding: const EdgeInsets.only( left: 12, right: 12, ), border: InputBorder.none, hintText: 'جست‌وجو در ${widget.title}', hintStyle: TextStyle( color: DesignConfig.isDark ? const Color.fromARGB(255, 98, 98, 98) : const Color.fromARGB(255, 122, 122, 122), fontSize: 13, ), ), ), ), ), if (widget.extraIconPath != null && widget.onExtraIconPressed != null) ...[ const SizedBox(width: 12), AnimatedBuilder( animation: Listenable.merge([_pulseAnimation, _rotationAnimation]), builder: (context, child) { return Transform.scale( scale: _pulseAnimation.value, child: GestureDetector( onTap: widget.onExtraIconPressed, child: CustomPaint( painter: RotatingBorderPainter( rotation: _rotationAnimation.value, color1: const Color(0xFFB20436), color2: const Color(0xFFFFC8D7), ), child: Container( width: 50, height: 50, decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Color(0xFF0066AA), Color(0xFF00AAFF), ], ), shape: BoxShape.circle, // border: Border.all( // color: Colors.white.withOpacity(0.5), // width: 2.5, // ), ), child: Stack( alignment: Alignment.center, children: [ Container( width: 50, height: 50, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ Colors.white.withOpacity(0.3), Colors.transparent, ], ), ), ), Padding( padding: const EdgeInsets.all(4.0), child: SvgPicture.asset( "lib/assets/icons/fluent_bot-sparkle-16-regular.svg", width: 27, height: 27, colorFilter: const ColorFilter.mode( Colors.white, BlendMode.srcIn, ), ), ), ], ), ), ), ), ); }, ), ], ], ), ); } @override void dispose() { _pulseController.dispose(); _rotationController.dispose(); widget.focusNode.removeListener(() {}); super.dispose(); } } class RotatingBorderPainter extends CustomPainter { final double rotation; final Color color1; final Color color2; RotatingBorderPainter({ required this.rotation, required this.color1, required this.color2, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = size.width / 2; // 0.0 -> 0.5: fade in // 0.5 -> 1.0: fade out final fadeProgress = rotation < 0.5 ? rotation * 2 : (1 - rotation) * 2; final opacity = fadeProgress.clamp(0.0, 1.0); final paint = Paint() ..shader = SweepGradient( colors: [ Colors.transparent, color1.withOpacity(0.3 * opacity), color1.withOpacity(0.7 * opacity), color1.withOpacity(0.9 * opacity), color1.withOpacity(0.7 * opacity), color1.withOpacity(0.3 * opacity), Colors.transparent, ], stops: const [0.0, 0.15, 0.3, 0.5, 0.7, 0.85, 1.0], transform: GradientRotation(rotation * 6.28318), ).createShader(Rect.fromCircle(center: center, radius: radius)) ..style = PaintingStyle.stroke ..strokeWidth = 2 ..strokeCap = StrokeCap.round; canvas.drawCircle( center, radius + 0.5, paint, ); } @override bool shouldRepaint(RotatingBorderPainter oldDelegate) { return oldDelegate.rotation != rotation; } }