import 'package:flutter/material.dart'; import '../theme/app_colors.dart'; /// 배경에 따라 자동으로 색상 대비를 조정하는 텍스트 위젯 class ThemedText extends StatelessWidget { final String text; final TextStyle? style; final TextAlign? textAlign; final TextOverflow? overflow; final int? maxLines; final bool softWrap; final bool forceLight; final bool forceDark; final double? opacity; final double? fontSize; final FontWeight? fontWeight; final double? letterSpacing; final Color? color; const ThemedText( this.text, { super.key, this.style, this.textAlign, this.overflow, this.maxLines, this.softWrap = true, this.forceLight = false, this.forceDark = false, this.opacity, this.fontSize, this.fontWeight, this.letterSpacing, this.color, }); /// 배경 밝기에 따른 텍스트 색상 결정 static Color getContrastColor(BuildContext context, { bool forceLight = false, bool forceDark = false, }) { if (forceLight) return Colors.white; if (forceDark) return AppColors.textPrimary; final brightness = Theme.of(context).brightness; // 글래스모피즘 환경에서는 보통 어두운 배경 위에 밝은 텍스트 if (_isGlassmorphicContext(context)) { return brightness == Brightness.dark ? Colors.white.withValues(alpha: 0.95) : AppColors.textPrimary; } // 일반 환경 return brightness == Brightness.dark ? Colors.white : AppColors.textPrimary; } /// 글래스모피즘 컨텍스트인지 확인 static bool _isGlassmorphicContext(BuildContext context) { // 부모 위젯 체인에서 글래스모피즘 카드가 있는지 확인 final glassmorphic = context.findAncestorWidgetOfExactType(); return glassmorphic != null; } @override Widget build(BuildContext context) { final textColor = color ?? getContrastColor( context, forceLight: forceLight, forceDark: forceDark, ); final finalColor = opacity != null ? textColor.withValues(alpha: opacity!) : textColor; final defaultStyle = DefaultTextStyle.of(context).style; // 개별 스타일 속성들을 병합 final baseStyle = TextStyle( fontSize: fontSize, fontWeight: fontWeight, letterSpacing: letterSpacing, color: finalColor, ); final effectiveStyle = defaultStyle.merge(baseStyle).merge(style); return Text( text, style: effectiveStyle, textAlign: textAlign, overflow: overflow, maxLines: maxLines, softWrap: softWrap, ); } /// 제목용 스타일 팩토리 static ThemedText headline({ required String text, TextStyle? style, bool forceLight = false, bool forceDark = false, }) { return ThemedText( text, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ).merge(style), forceLight: forceLight, forceDark: forceDark, ); } /// 부제목용 스타일 팩토리 static ThemedText subtitle({ required String text, TextStyle? style, bool forceLight = false, bool forceDark = false, double opacity = 0.8, }) { return ThemedText( text, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w500, ).merge(style), forceLight: forceLight, forceDark: forceDark, opacity: opacity, ); } /// 본문용 스타일 팩토리 static ThemedText body({ required String text, TextStyle? style, bool forceLight = false, bool forceDark = false, double opacity = 0.9, }) { return ThemedText( text, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.normal, ).merge(style), forceLight: forceLight, forceDark: forceDark, opacity: opacity, ); } /// 캡션용 스타일 팩토리 static ThemedText caption({ required String text, TextStyle? style, bool forceLight = false, bool forceDark = false, double opacity = 0.7, }) { return ThemedText( text, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.normal, ).merge(style), forceLight: forceLight, forceDark: forceDark, opacity: opacity, ); } } /// 글래스모피즘 컨텍스트를 표시하는 마커 위젯 class GlassmorphicIndicator extends InheritedWidget { const GlassmorphicIndicator({ super.key, required super.child, }); static GlassmorphicIndicator? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); } @override bool updateShouldNotify(GlassmorphicIndicator oldWidget) => false; } /// 글래스모피즘 환경에서 텍스트 색상을 자동 조정하는 래퍼 class GlassmorphicTextWrapper extends StatelessWidget { final Widget child; const GlassmorphicTextWrapper({ super.key, required this.child, }); @override Widget build(BuildContext context) { return GlassmorphicIndicator( child: DefaultTextStyle( style: DefaultTextStyle.of(context).style.copyWith( color: ThemedText.getContrastColor(context), ), child: child, ), ); } }