import 'package:flutter/material.dart'; class FontConstants { /// ── The app's typeface ── /// /// Poppins: geometric, OFL-licensed, and the one every screen now reads from. /// It replaced Manrope, which was itself a stand-in for Uber Move. /// /// **Read this before changing it.** The family was already declared in /// `pubspec.yaml` as `poppins`, with a lowercase path on every one of its /// seven assets, while the files on disk are `assets/fonts/Poppins/Poppins-*`. /// Asset bundling is case-sensitive on both platforms, so not one of them /// resolved: anything asking for the family fell back to Roboto and no error /// was raised anywhere. The declaration is fixed and all seven static weights /// are registered — Poppins ships as separate files rather than a variable /// font, and without explicit 800/900 entries Flutter synthesises them by /// smearing SemiBold, which is what makes a heading look muddy at exactly the /// size it is meant to be read from. /// ── The weight scale is calibrated for THIS family ── /// /// Poppins runs optically heavier than Manrope at every grade: it is /// geometric, its bowls are wide and its stems thick, so `w800` here is far /// darker on the page than `w800` was in a variable Manrope. The whole scale /// was tuned against Manrope and came across a grade too heavy — headings /// read as shouting and body copy as bold. /// /// Every weight in `lib/` (outside `lib/xpress`, which is Proxima Nova) was /// stepped down one grade: 900→800, 800→700, 700→600, 600→500. The *relative* /// hierarchy is untouched — each level is still one step from its neighbour — /// so nothing lost its rank; the whole run just sits where it should for this /// typeface. /// /// **If the family changes again, re-tune this.** A weight is a number, not a /// design: what it looks like belongs to the font. static const String fontFamily = 'Poppins'; /// Only ever reached for a glyph Poppins does not carry. Manrope covers the /// Latin and currency sets the app uses, so this is a safety net rather than /// a second typeface in the design. static String fontFamilyFallback = 'Manrope'; // Typography scale static const double displayLg = 32.0; static const double headlineMd = 24.0; static const double headlineSm = 20.0; static const double bodyLg = 18.0; static const double bodyMd = 16.0; static const double labelBold = 14.0; static const double labelSm = 12.0; static TextStyle displayLgStyle = const TextStyle( fontSize: 32, fontWeight: FontWeight.w600, letterSpacing: -0.64, fontFamily: fontFamily, ); static TextStyle headlineMdStyle = const TextStyle( fontSize: 24, fontWeight: FontWeight.w600, letterSpacing: -0.24, fontFamily: fontFamily, ); static TextStyle headlineSmStyle = const TextStyle( fontSize: 20, fontWeight: FontWeight.w500, letterSpacing: -0.2, fontFamily: fontFamily, ); static TextStyle bodyLgStyle = const TextStyle( fontSize: 18, fontWeight: FontWeight.w500, fontFamily: fontFamily, ); static TextStyle bodyMdStyle = const TextStyle( fontSize: 16, fontWeight: FontWeight.w400, fontFamily: fontFamily, ); static TextStyle labelBoldStyle = const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, fontFamily: fontFamily, ); static TextStyle labelSmStyle = const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, fontFamily: fontFamily, ); static double getResponsiveFontSize(BuildContext context, double baseSize) { return baseSize; } static double extraSmall(BuildContext context) => getResponsiveFontSize(context, 10); static double small(BuildContext context) => getResponsiveFontSize(context, labelSm); static double medium(BuildContext context) => getResponsiveFontSize(context, bodyMd); static double regular(BuildContext context) => getResponsiveFontSize(context, bodyLg); static double large(BuildContext context) => getResponsiveFontSize(context, headlineSm); static double xLarge(BuildContext context) => getResponsiveFontSize(context, headlineMd); static double xxLarge(BuildContext context) => getResponsiveFontSize(context, 28); static double xxxLarge(BuildContext context) => getResponsiveFontSize(context, 30); static double huge(BuildContext context) => getResponsiveFontSize(context, displayLg); } class ReusableTextWidget extends StatelessWidget { final String text; final double? fontSize; final double? textHeight; final String? fontFamily; final FontWeight? fontWeight; final FontStyle? fontStyle; final Color? color; final TextAlign? textAlign; final int? maxLines; final TextDecoration? isUnderText; const ReusableTextWidget({ super.key, required this.text, this.fontSize, this.textHeight, this.fontFamily, this.fontWeight, this.fontStyle, this.color, this.textAlign, this.maxLines, this.isUnderText, }); @override Widget build(BuildContext context) { return Text( text, softWrap: true, style: TextStyle( fontSize: fontSize ?? FontConstants.medium(context), decoration: isUnderText, fontFamily: fontFamily ?? FontConstants.fontFamily, decorationColor: color, fontWeight: fontWeight ?? FontWeight.normal, fontStyle: fontStyle ?? FontStyle.normal, color: color ?? Colors.grey.shade900, overflow: TextOverflow.ellipsis, decorationStyle: TextDecorationStyle.solid, decorationThickness: 1, height: textHeight, ), maxLines: maxLines, textAlign: textAlign ?? TextAlign.start, ); } }