refactor ui

This commit is contained in:
2025-09-04 15:21:43 -05:00
parent 8797134903
commit 5f92801860

View File

@@ -0,0 +1,141 @@
import 'package:flutter/material.dart';
import 'package:repertory/constants.dart' as constants;
import 'package:repertory/helpers.dart';
class AppDropdownFormField<T> extends StatelessWidget {
const AppDropdownFormField({
super.key,
required this.values,
required this.labelOf,
this.value,
this.onChanged,
this.validator,
this.labelText,
this.prefixIcon,
this.enabled = true,
this.constrainToIntrinsic = false,
this.widthMultiplier = 1.0,
this.maxWidth,
this.isExpanded = false,
this.dropdownColor,
this.textStyle,
this.contentPadding,
this.fillColor,
});
final List<T> values;
final String Function(T value) labelOf;
final T? value;
final ValueChanged<T?>? onChanged;
final FormFieldValidator<T>? validator;
final String? labelText;
final IconData? prefixIcon;
final bool enabled;
final bool constrainToIntrinsic;
final double widthMultiplier;
final double? maxWidth;
final bool isExpanded;
final Color? dropdownColor;
final TextStyle? textStyle;
final EdgeInsetsGeometry? contentPadding;
final Color? fillColor;
double _measureTextWidth(
BuildContext context,
String text,
TextStyle? style,
) {
final tp = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: 1,
textDirection: Directionality.of(context),
)..layout();
return tp.width;
}
double? _computedMaxWidth(BuildContext context) {
if (!constrainToIntrinsic) return maxWidth;
final theme = Theme.of(context);
final scheme = theme.colorScheme;
final effectiveStyle =
textStyle ??
theme.textTheme.bodyMedium?.copyWith(
color: scheme.onSurface.withValues(alpha: 0.96),
);
final longest = values.isEmpty
? ''
: values
.map((v) => labelOf(v))
.reduce((a, b) => a.length >= b.length ? a : b);
final labelW = _measureTextWidth(context, longest, effectiveStyle);
final prefixW = prefixIcon == null ? 0.0 : 48.0;
const arrowW = 32.0;
final pad = contentPadding ?? const EdgeInsets.all(constants.paddingSmall);
final padW = (pad is EdgeInsets)
? (pad.left + pad.right)
: constants.paddingSmall * 2;
final base = labelW + prefixW + arrowW + padW;
final cap =
maxWidth ?? (MediaQuery.of(context).size.width - constants.padding * 2);
return (base * widthMultiplier).clamp(0.0, cap);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scheme = theme.colorScheme;
final effectiveFill =
fillColor ?? scheme.primary.withValues(alpha: constants.primaryAlpha);
final effectiveTextStyle =
textStyle ??
theme.textTheme.bodyMedium?.copyWith(
color: scheme.onSurface.withValues(alpha: 0.96),
);
final items = values.map((v) {
return DropdownMenuItem<T>(
value: v,
child: Text(
labelOf(v),
style: effectiveTextStyle,
overflow: TextOverflow.ellipsis,
),
);
}).toList();
final field = DropdownButtonFormField<T>(
decoration: createCommonDecoration(scheme, labelText ?? ""),
dropdownColor: dropdownColor ?? effectiveFill,
iconEnabledColor: scheme.onSurface.withValues(alpha: 0.90),
initialValue: value,
isExpanded: isExpanded,
items: items,
onChanged: enabled ? onChanged : null,
style: effectiveTextStyle,
validator: validator,
);
final maxW = _computedMaxWidth(context);
final wrapped = maxW == null
? field
: ConstrainedBox(
constraints: BoxConstraints(maxWidth: maxW),
child: field,
);
return Align(
alignment: Alignment.centerLeft,
heightFactor: 1.0,
child: wrapped,
);
}
}