import 'package:flutter/material.dart'; extension TextExt on Text { /// Single-line width as rendered in [context] (honours the text scaler). /// Memoised: chat bubbles measure the same few names and times over and /// over, and every measurement is a full paragraph layout. double measuredWidth(BuildContext context) { final scaler = MediaQuery.textScalerOf(context); final key = (data, style, scaler); final cached = _widthCache[key]; if (cached != null) return cached; final painter = TextPainter( text: TextSpan(text: data, style: style), maxLines: 1, textDirection: TextDirection.ltr, textScaler: scaler, )..layout(); final width = painter.width; painter.dispose(); if (_widthCache.length >= 512) _widthCache.clear(); return _widthCache[key] = width; } } final Map<(String?, TextStyle?, TextScaler), double> _widthCache = {}; /// Returns the first non-empty (after trim) entry, or '' if none match. String firstNonEmpty(List values) { for (final v in values) { if (v != null && v.trim().isNotEmpty) return v; } return ''; }