import 'package:flutter/material.dart'; import 'package:clarity_flutter/clarity_flutter.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/theme/colors.dart'; class CustomButton extends StatefulWidget { final String text; final String? icon; final VoidCallback? onPressed; final Color backgroundColor; final Color borderColor; final Color textColor; final double? borderRadius; final double borderWidth; final EdgeInsetsGeometry padding; final double? fontSize; final String? fontFamily; final FontWeight fontWeight; final bool isDisabled; final Color? iconColor; final double? height; final double? width; final double? iconSize; final TextOverflow? textOverflow; final BorderSide? borderSide; final bool applyThemeColor; final bool isBold; const CustomButton({ super.key, required this.text, required this.onPressed, this.backgroundColor = const Color(0xFFED1C2B), this.borderColor = const Color(0xFFED1C2B), this.textColor = Colors.white, this.borderRadius, this.borderWidth = 2, this.padding = const EdgeInsets.fromLTRB(8, 10, 8, 10), this.fontSize, this.fontFamily, this.fontWeight = FontWeight.w700, this.isDisabled = false, this.isBold = false, this.icon, this.iconColor = Colors.white, this.height, this.width, this.iconSize, this.textOverflow, this.borderSide, this.applyThemeColor = true, }); @override State createState() => _CustomButtonState(); } class _CustomButtonState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _scaleAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 80), vsync: this, ); _scaleAnimation = Tween(begin: 1.0, end: 0.95).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); } @override void dispose() { _animationController.dispose(); super.dispose(); } Future _playTapAnimation() async { if (!widget.isDisabled && widget.onPressed != null) { await _animationController.forward(); _animationController.reverse(); } } @override Widget build(BuildContext context) { final radius = widget.borderRadius ?? (12.r); final iconS = widget.iconSize ?? (24.h); final fontS = widget.fontSize ?? (16.f); final isButtonDisabled = widget.isDisabled || widget.onPressed == null; return Semantics( button: true, enabled: !isButtonDisabled, label: widget.text, hint: isButtonDisabled ? 'Button is disabled' : 'Tap to ${widget.text}', child: GestureDetector( onTap: isButtonDisabled ? null : () async { // Play tap animation and wait for it to complete await _playTapAnimation(); // Log button tap to Clarity before executing callback try { Clarity.setCustomTag('button_text', widget.text.length > 100 ? widget.text.substring(0, 100) : widget.text); Clarity.setCustomTag('button_action', 'tap'); Clarity.setCustomTag('button_disabled', 'false'); Clarity.sendCustomEvent('button_tapped'); } catch (e) { // Silence Clarity errors to not interrupt user flow } // Execute the actual button callback widget.onPressed?.call(); }, child: AnimatedBuilder( animation: _scaleAnimation, builder: (context, child) => Transform.scale( scale: _scaleAnimation.value, child: child, ), child: Container( height: widget.height == null ? 56.h : (isFoldable || isTablet) ? widget.height! + 10.h : widget.height, width: widget.width, padding: widget.padding, decoration: RoundedRectangleBorder().toSmoothCornerDecoration( color: isButtonDisabled ? AppColors.inputLabelTextColor.withValues(alpha: 0.3) : widget.backgroundColor, borderRadius: radius, customBorder: BorderRadius.circular(radius), side: widget.borderSide ?? BorderSide(width: widget.borderWidth.h, color: isButtonDisabled ? Colors.transparent : widget.borderColor)), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ if (widget.icon != null) Padding( padding: widget.text.isNotEmpty ? EdgeInsets.only(right: 6.w, left: 6.w) : EdgeInsets.zero, child: Utils.buildSvgWithAssets( icon: widget.icon!, iconColor: isButtonDisabled ? AppColors.greyTextColor : widget.iconColor, isDisabled: isButtonDisabled, width: iconS, height: iconS, applyThemeColor: widget.applyThemeColor), ), if (widget.text.isNotEmpty && widget.icon != null) Flexible( child: Text( widget.text, overflow: widget.textOverflow ?? TextOverflow.ellipsis, maxLines: 1, textAlign: TextAlign.center, style: context.dynamicTextStyle( fontSize: fontS, color: isButtonDisabled ? AppColors.greyTextColor : widget.textColor, letterSpacing: 0, fontWeight: widget.isBold ? FontWeight.w700 : widget.fontWeight, ), ), ), if (widget.text.isNotEmpty && widget.icon == null) Text( widget.text, overflow: widget.textOverflow ?? TextOverflow.ellipsis, maxLines: 1, textAlign: TextAlign.center, style: context.dynamicTextStyle( fontSize: fontS, color: isButtonDisabled ? AppColors.greyTextColor : widget.textColor, letterSpacing: 0, fontWeight: widget.isBold ? FontWeight.w700 : widget.fontWeight, ), ), ], ), )), )); } }