Enhance UI button and order card features

Added fullWidth support to UiButton and updated usages to ensure buttons span container width. Improved ViewOrderCard with expanded worker details, avatar stack, formatted date/time, and an order edit bottom sheet. Introduced new icons and typography style in the design system.
This commit is contained in:
Achintha Isuru
2026-01-23 11:53:36 -05:00
parent 960b21ec8c
commit 868688fb02
7 changed files with 543 additions and 100 deletions

View File

@@ -27,6 +27,9 @@ class UiButton extends StatelessWidget {
/// The size of the button.
final UiButtonSize size;
/// Whether the button should take up the full width of its container.
final bool fullWidth;
/// The button widget to use (ElevatedButton, OutlinedButton, or TextButton).
final Widget Function(
BuildContext context,
@@ -48,6 +51,7 @@ class UiButton extends StatelessWidget {
this.style,
this.iconSize = 20,
this.size = UiButtonSize.medium,
this.fullWidth = false,
}) : assert(
text != null || child != null,
'Either text or child must be provided',
@@ -64,6 +68,7 @@ class UiButton extends StatelessWidget {
this.style,
this.iconSize = 20,
this.size = UiButtonSize.medium,
this.fullWidth = false,
}) : buttonBuilder = _elevatedButtonBuilder,
assert(
text != null || child != null,
@@ -81,6 +86,7 @@ class UiButton extends StatelessWidget {
this.style,
this.iconSize = 20,
this.size = UiButtonSize.medium,
this.fullWidth = false,
}) : buttonBuilder = _outlinedButtonBuilder,
assert(
text != null || child != null,
@@ -98,6 +104,25 @@ class UiButton extends StatelessWidget {
this.style,
this.iconSize = 20,
this.size = UiButtonSize.medium,
this.fullWidth = false,
}) : buttonBuilder = _textButtonBuilder,
assert(
text != null || child != null,
'Either text or child must be provided',
);
/// Creates a ghost button (transparent background).
UiButton.ghost({
super.key,
this.text,
this.child,
this.onPressed,
this.leadingIcon,
this.trailingIcon,
this.style,
this.iconSize = 20,
this.size = UiButtonSize.medium,
this.fullWidth = false,
}) : buttonBuilder = _textButtonBuilder,
assert(
text != null || child != null,
@@ -107,7 +132,18 @@ class UiButton extends StatelessWidget {
@override
/// Builds the button UI.
Widget build(BuildContext context) {
return buttonBuilder(context, onPressed, style, _buildButtonContent());
final Widget button = buttonBuilder(
context,
onPressed,
style,
_buildButtonContent(),
);
if (fullWidth) {
return SizedBox(width: double.infinity, child: button);
}
return button;
}
/// Builds the button content with optional leading and trailing icons.
@@ -116,27 +152,40 @@ class UiButton extends StatelessWidget {
return child!;
}
// Single icon or text case
final String buttonText = text ?? '';
// Optimization: If no icons, return plain text to avoid Row layout overhead
if (leadingIcon == null && trailingIcon == null) {
return Text(text!);
return Text(buttonText, textAlign: TextAlign.center);
}
if (leadingIcon != null && text == null && trailingIcon == null) {
return Icon(leadingIcon, size: iconSize);
}
// Multiple elements case
// Multiple elements case: Use a Row with MainAxisSize.min
final List<Widget> children = [];
if (leadingIcon != null) {
children.add(Icon(leadingIcon, size: iconSize));
children.add(const SizedBox(width: UiConstants.space2));
}
children.add(Text(text!));
if (buttonText.isNotEmpty) {
if (leadingIcon != null) {
children.add(const SizedBox(width: UiConstants.space2));
}
// Use flexible to ensure text doesn't force infinite width in flex parents
children.add(
Flexible(
child: Text(
buttonText,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
),
);
}
if (trailingIcon != null) {
children.add(const SizedBox(width: UiConstants.space2));
if (buttonText.isNotEmpty || leadingIcon != null) {
children.add(const SizedBox(width: UiConstants.space2));
}
children.add(Icon(trailingIcon, size: iconSize));
}