Refactor order creation and edit UI for consistency
Refactored BLoC and widget code for order creation flows to improve code style, readability, and consistency. Unified the edit order bottom sheet to follow the Unified Order Flow prototype, supporting multiple positions, review, and confirmation steps. Updated UI components to use more concise widget tree structures and standardized button implementations.
This commit is contained in:
@@ -8,7 +8,7 @@ import 'client_create_order_state.dart';
|
||||
class ClientCreateOrderBloc
|
||||
extends Bloc<ClientCreateOrderEvent, ClientCreateOrderState> {
|
||||
ClientCreateOrderBloc(this._getOrderTypesUseCase)
|
||||
: super(const ClientCreateOrderInitial()) {
|
||||
: super(const ClientCreateOrderInitial()) {
|
||||
on<ClientCreateOrderTypesRequested>(_onTypesRequested);
|
||||
}
|
||||
final GetOrderTypesUseCase _getOrderTypesUseCase;
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'one_time_order_state.dart';
|
||||
/// BLoC for managing the multi-step one-time order creation form.
|
||||
class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||
OneTimeOrderBloc(this._createOneTimeOrderUseCase)
|
||||
: super(OneTimeOrderState.initial()) {
|
||||
: super(OneTimeOrderState.initial()) {
|
||||
on<OneTimeOrderDateChanged>(_onDateChanged);
|
||||
on<OneTimeOrderLocationChanged>(_onLocationChanged);
|
||||
on<OneTimeOrderPositionAdded>(_onPositionAdded);
|
||||
@@ -37,13 +37,14 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||
Emitter<OneTimeOrderState> emit,
|
||||
) {
|
||||
final List<OneTimeOrderPosition> newPositions =
|
||||
List<OneTimeOrderPosition>.from(state.positions)
|
||||
..add(const OneTimeOrderPosition(
|
||||
List<OneTimeOrderPosition>.from(state.positions)..add(
|
||||
const OneTimeOrderPosition(
|
||||
role: '',
|
||||
count: 1,
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
));
|
||||
),
|
||||
);
|
||||
emit(state.copyWith(positions: newPositions));
|
||||
}
|
||||
|
||||
@@ -83,10 +84,12 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||
await _createOneTimeOrderUseCase(OneTimeOrderArguments(order: order));
|
||||
emit(state.copyWith(status: OneTimeOrderStatus.success));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
status: OneTimeOrderStatus.failure,
|
||||
errorMessage: e.toString(),
|
||||
));
|
||||
emit(
|
||||
state.copyWith(
|
||||
status: OneTimeOrderStatus.failure,
|
||||
errorMessage: e.toString(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,7 @@ class OneTimeOrderState extends Equatable {
|
||||
date: DateTime.now(),
|
||||
location: '',
|
||||
positions: const <OneTimeOrderPosition>[
|
||||
OneTimeOrderPosition(
|
||||
role: '',
|
||||
count: 1,
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
),
|
||||
OneTimeOrderPosition(role: '', count: 1, startTime: '', endTime: ''),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -50,10 +45,10 @@ class OneTimeOrderState extends Equatable {
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[
|
||||
date,
|
||||
location,
|
||||
positions,
|
||||
status,
|
||||
errorMessage,
|
||||
];
|
||||
date,
|
||||
location,
|
||||
positions,
|
||||
status,
|
||||
errorMessage,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ import 'rapid_order_state.dart';
|
||||
/// BLoC for managing the rapid (urgent) order creation flow.
|
||||
class RapidOrderBloc extends Bloc<RapidOrderEvent, RapidOrderState> {
|
||||
RapidOrderBloc(this._createRapidOrderUseCase)
|
||||
: super(
|
||||
const RapidOrderInitial(
|
||||
examples: <String>[
|
||||
'"We had a call out. Need 2 cooks ASAP"',
|
||||
'"Need 5 bartenders ASAP until 5am"',
|
||||
'"Emergency! Need 3 servers right now till midnight"',
|
||||
],
|
||||
),
|
||||
) {
|
||||
: super(
|
||||
const RapidOrderInitial(
|
||||
examples: <String>[
|
||||
'"We had a call out. Need 2 cooks ASAP"',
|
||||
'"Need 5 bartenders ASAP until 5am"',
|
||||
'"Emergency! Need 3 servers right now till midnight"',
|
||||
],
|
||||
),
|
||||
) {
|
||||
on<RapidOrderMessageChanged>(_onMessageChanged);
|
||||
on<RapidOrderVoiceToggled>(_onVoiceToggled);
|
||||
on<RapidOrderSubmitted>(_onSubmitted);
|
||||
@@ -68,7 +68,8 @@ class RapidOrderBloc extends Bloc<RapidOrderEvent, RapidOrderState> {
|
||||
|
||||
try {
|
||||
await _createRapidOrderUseCase(
|
||||
RapidOrderArguments(description: message));
|
||||
RapidOrderArguments(description: message),
|
||||
);
|
||||
emit(const RapidOrderSuccess());
|
||||
} catch (e) {
|
||||
emit(RapidOrderFailure(e.toString()));
|
||||
|
||||
@@ -17,8 +17,9 @@ class ClientCreateOrderPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<ClientCreateOrderBloc>(
|
||||
create: (BuildContext context) => Modular.get<ClientCreateOrderBloc>()
|
||||
..add(const ClientCreateOrderTypesRequested()),
|
||||
create: (BuildContext context) =>
|
||||
Modular.get<ClientCreateOrderBloc>()
|
||||
..add(const ClientCreateOrderTypesRequested()),
|
||||
child: const CreateOrderView(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,59 +65,58 @@ class CreateOrderView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child:
|
||||
BlocBuilder<ClientCreateOrderBloc, ClientCreateOrderState>(
|
||||
child: BlocBuilder<ClientCreateOrderBloc, ClientCreateOrderState>(
|
||||
builder:
|
||||
(BuildContext context, ClientCreateOrderState state) {
|
||||
if (state is ClientCreateOrderLoadSuccess) {
|
||||
return GridView.builder(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: UiConstants.space4,
|
||||
crossAxisSpacing: UiConstants.space4,
|
||||
childAspectRatio: 1,
|
||||
),
|
||||
itemCount: state.orderTypes.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final OrderType type = state.orderTypes[index];
|
||||
final OrderTypeUiMetadata ui =
|
||||
OrderTypeUiMetadata.fromId(id: type.id);
|
||||
if (state is ClientCreateOrderLoadSuccess) {
|
||||
return GridView.builder(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: UiConstants.space4,
|
||||
crossAxisSpacing: UiConstants.space4,
|
||||
childAspectRatio: 1,
|
||||
),
|
||||
itemCount: state.orderTypes.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final OrderType type = state.orderTypes[index];
|
||||
final OrderTypeUiMetadata ui =
|
||||
OrderTypeUiMetadata.fromId(id: type.id);
|
||||
|
||||
return OrderTypeCard(
|
||||
icon: ui.icon,
|
||||
title: _getTranslation(key: type.titleKey),
|
||||
description: _getTranslation(
|
||||
key: type.descriptionKey,
|
||||
),
|
||||
backgroundColor: ui.backgroundColor,
|
||||
borderColor: ui.borderColor,
|
||||
iconBackgroundColor: ui.iconBackgroundColor,
|
||||
iconColor: ui.iconColor,
|
||||
textColor: ui.textColor,
|
||||
descriptionColor: ui.descriptionColor,
|
||||
onTap: () {
|
||||
switch (type.id) {
|
||||
case 'rapid':
|
||||
Modular.to.pushRapidOrder();
|
||||
break;
|
||||
case 'one-time':
|
||||
Modular.to.pushOneTimeOrder();
|
||||
break;
|
||||
case 'recurring':
|
||||
Modular.to.pushRecurringOrder();
|
||||
break;
|
||||
case 'permanent':
|
||||
Modular.to.pushPermanentOrder();
|
||||
break;
|
||||
}
|
||||
return OrderTypeCard(
|
||||
icon: ui.icon,
|
||||
title: _getTranslation(key: type.titleKey),
|
||||
description: _getTranslation(
|
||||
key: type.descriptionKey,
|
||||
),
|
||||
backgroundColor: ui.backgroundColor,
|
||||
borderColor: ui.borderColor,
|
||||
iconBackgroundColor: ui.iconBackgroundColor,
|
||||
iconColor: ui.iconColor,
|
||||
textColor: ui.textColor,
|
||||
descriptionColor: ui.descriptionColor,
|
||||
onTap: () {
|
||||
switch (type.id) {
|
||||
case 'rapid':
|
||||
Modular.to.pushRapidOrder();
|
||||
break;
|
||||
case 'one-time':
|
||||
Modular.to.pushOneTimeOrder();
|
||||
break;
|
||||
case 'recurring':
|
||||
Modular.to.pushRecurringOrder();
|
||||
break;
|
||||
case 'permanent':
|
||||
Modular.to.pushPermanentOrder();
|
||||
break;
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
}
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -54,9 +54,7 @@ class OneTimeOrderHeader extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(
|
||||
title,
|
||||
style: UiTypography.headline3m.copyWith(
|
||||
color: UiColors.white,
|
||||
),
|
||||
style: UiTypography.headline3m.copyWith(color: UiColors.white),
|
||||
),
|
||||
Text(
|
||||
subtitle,
|
||||
|
||||
@@ -99,8 +99,10 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
isExpanded: true,
|
||||
hint:
|
||||
Text(roleLabel, style: UiTypography.body2r.textPlaceholder),
|
||||
hint: Text(
|
||||
roleLabel,
|
||||
style: UiTypography.body2r.textPlaceholder,
|
||||
),
|
||||
value: position.role.isEmpty ? null : position.role,
|
||||
icon: const Icon(
|
||||
UiIcons.chevronDown,
|
||||
@@ -112,26 +114,27 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
onUpdated(position.copyWith(role: val));
|
||||
}
|
||||
},
|
||||
items: <String>[
|
||||
'Server',
|
||||
'Bartender',
|
||||
'Cook',
|
||||
'Busser',
|
||||
'Host',
|
||||
'Barista',
|
||||
'Dishwasher',
|
||||
'Event Staff'
|
||||
].map((String role) {
|
||||
// Mock rates for UI matching
|
||||
final int rate = _getMockRate(role);
|
||||
return DropdownMenuItem<String>(
|
||||
value: role,
|
||||
child: Text(
|
||||
'$role - \$$rate/hr',
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
items:
|
||||
<String>[
|
||||
'Server',
|
||||
'Bartender',
|
||||
'Cook',
|
||||
'Busser',
|
||||
'Host',
|
||||
'Barista',
|
||||
'Dishwasher',
|
||||
'Event Staff',
|
||||
].map((String role) {
|
||||
// Mock rates for UI matching
|
||||
final int rate = _getMockRate(role);
|
||||
return DropdownMenuItem<String>(
|
||||
value: role,
|
||||
child: Text(
|
||||
'$role - \$$rate/hr',
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -153,7 +156,8 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
);
|
||||
if (picked != null && context.mounted) {
|
||||
onUpdated(
|
||||
position.copyWith(startTime: picked.format(context)));
|
||||
position.copyWith(startTime: picked.format(context)),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -172,7 +176,8 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
);
|
||||
if (picked != null && context.mounted) {
|
||||
onUpdated(
|
||||
position.copyWith(endTime: picked.format(context)));
|
||||
position.copyWith(endTime: picked.format(context)),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -198,10 +203,13 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () => onUpdated(position.copyWith(
|
||||
onTap: () => onUpdated(
|
||||
position.copyWith(
|
||||
count: (position.count > 1)
|
||||
? position.count - 1
|
||||
: 1)),
|
||||
: 1,
|
||||
),
|
||||
),
|
||||
child: const Icon(UiIcons.minus, size: 12),
|
||||
),
|
||||
Text(
|
||||
@@ -210,7 +218,8 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => onUpdated(
|
||||
position.copyWith(count: position.count + 1)),
|
||||
position.copyWith(count: position.count + 1),
|
||||
),
|
||||
child: const Icon(UiIcons.add, size: 12),
|
||||
),
|
||||
],
|
||||
@@ -249,11 +258,16 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.mapPin,
|
||||
size: 14, color: UiColors.iconSecondary),
|
||||
const Icon(
|
||||
UiIcons.mapPin,
|
||||
size: 14,
|
||||
color: UiColors.iconSecondary,
|
||||
),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
t.client_create_order.one_time
|
||||
t
|
||||
.client_create_order
|
||||
.one_time
|
||||
.different_location_title,
|
||||
style: UiTypography.footnote1m.textSecondary,
|
||||
),
|
||||
@@ -283,10 +297,7 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
|
||||
// Lunch Break
|
||||
Text(
|
||||
lunchLabel,
|
||||
style: UiTypography.footnote2r.textSecondary,
|
||||
),
|
||||
Text(lunchLabel, style: UiTypography.footnote2r.textSecondary),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Container(
|
||||
height: 44,
|
||||
@@ -312,38 +323,45 @@ class OneTimeOrderPositionCard extends StatelessWidget {
|
||||
items: <DropdownMenuItem<int>>[
|
||||
DropdownMenuItem<int>(
|
||||
value: 0,
|
||||
child: Text(t.client_create_order.one_time.no_break,
|
||||
style: UiTypography.body2r.textPrimary),
|
||||
child: Text(
|
||||
t.client_create_order.one_time.no_break,
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
DropdownMenuItem<int>(
|
||||
value: 10,
|
||||
child: Text(
|
||||
'10 ${t.client_create_order.one_time.paid_break}',
|
||||
style: UiTypography.body2r.textPrimary),
|
||||
'10 ${t.client_create_order.one_time.paid_break}',
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
DropdownMenuItem<int>(
|
||||
value: 15,
|
||||
child: Text(
|
||||
'15 ${t.client_create_order.one_time.paid_break}',
|
||||
style: UiTypography.body2r.textPrimary),
|
||||
'15 ${t.client_create_order.one_time.paid_break}',
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
DropdownMenuItem<int>(
|
||||
value: 30,
|
||||
child: Text(
|
||||
'30 ${t.client_create_order.one_time.unpaid_break}',
|
||||
style: UiTypography.body2r.textPrimary),
|
||||
'30 ${t.client_create_order.one_time.unpaid_break}',
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
DropdownMenuItem<int>(
|
||||
value: 45,
|
||||
child: Text(
|
||||
'45 ${t.client_create_order.one_time.unpaid_break}',
|
||||
style: UiTypography.body2r.textPrimary),
|
||||
'45 ${t.client_create_order.one_time.unpaid_break}',
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
DropdownMenuItem<int>(
|
||||
value: 60,
|
||||
child: Text(
|
||||
'60 ${t.client_create_order.one_time.unpaid_break}',
|
||||
style: UiTypography.body2r.textPrimary),
|
||||
'60 ${t.client_create_order.one_time.unpaid_break}',
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -27,14 +27,28 @@ class OneTimeOrderSectionHeader extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Text(title, style: UiTypography.headline4m.textPrimary),
|
||||
if (actionLabel != null && onAction != null)
|
||||
UiButton.text(
|
||||
TextButton(
|
||||
onPressed: onAction,
|
||||
leadingIcon: UiIcons.add,
|
||||
text: actionLabel!,
|
||||
iconSize: 16,
|
||||
style: TextButton.styleFrom(
|
||||
minimumSize: const Size(0, 24),
|
||||
maximumSize: const Size(0, 24),
|
||||
padding: EdgeInsets.zero,
|
||||
minimumSize: Size.zero,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.add, size: 16, color: Color(0xFF0032A0)),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Text(
|
||||
actionLabel!,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF0032A0),
|
||||
fontSize: 14,
|
||||
fontWeight:
|
||||
FontWeight.w500, // Added to match typical button text
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -58,8 +58,9 @@ class OneTimeOrderView extends StatelessWidget {
|
||||
? labels.creating
|
||||
: labels.create_order,
|
||||
isLoading: state.status == OneTimeOrderStatus.loading,
|
||||
onPressed: () => BlocProvider.of<OneTimeOrderBloc>(context)
|
||||
.add(const OneTimeOrderSubmitted()),
|
||||
onPressed: () => BlocProvider.of<OneTimeOrderBloc>(
|
||||
context,
|
||||
).add(const OneTimeOrderSubmitted()),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -90,34 +91,34 @@ class _OneTimeOrderForm extends StatelessWidget {
|
||||
OneTimeOrderDatePicker(
|
||||
label: labels.date_label,
|
||||
value: state.date,
|
||||
onChanged: (DateTime date) =>
|
||||
BlocProvider.of<OneTimeOrderBloc>(context)
|
||||
.add(OneTimeOrderDateChanged(date)),
|
||||
onChanged: (DateTime date) => BlocProvider.of<OneTimeOrderBloc>(
|
||||
context,
|
||||
).add(OneTimeOrderDateChanged(date)),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
OneTimeOrderLocationInput(
|
||||
label: labels.location_label,
|
||||
value: state.location,
|
||||
onChanged: (String location) =>
|
||||
BlocProvider.of<OneTimeOrderBloc>(context)
|
||||
.add(OneTimeOrderLocationChanged(location)),
|
||||
onChanged: (String location) => BlocProvider.of<OneTimeOrderBloc>(
|
||||
context,
|
||||
).add(OneTimeOrderLocationChanged(location)),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
|
||||
OneTimeOrderSectionHeader(
|
||||
title: labels.positions_title,
|
||||
actionLabel: labels.add_position,
|
||||
onAction: () => BlocProvider.of<OneTimeOrderBloc>(context)
|
||||
.add(const OneTimeOrderPositionAdded()),
|
||||
onAction: () => BlocProvider.of<OneTimeOrderBloc>(
|
||||
context,
|
||||
).add(const OneTimeOrderPositionAdded()),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
|
||||
// Positions List
|
||||
...state.positions
|
||||
.asMap()
|
||||
.entries
|
||||
.map((MapEntry<int, OneTimeOrderPosition> entry) {
|
||||
...state.positions.asMap().entries.map((
|
||||
MapEntry<int, OneTimeOrderPosition> entry,
|
||||
) {
|
||||
final int index = entry.key;
|
||||
final OneTimeOrderPosition position = entry.value;
|
||||
return Padding(
|
||||
@@ -133,13 +134,14 @@ class _OneTimeOrderForm extends StatelessWidget {
|
||||
endLabel: labels.end_label,
|
||||
lunchLabel: labels.lunch_break_label,
|
||||
onUpdated: (OneTimeOrderPosition updated) {
|
||||
BlocProvider.of<OneTimeOrderBloc>(context).add(
|
||||
OneTimeOrderPositionUpdated(index, updated),
|
||||
);
|
||||
BlocProvider.of<OneTimeOrderBloc>(
|
||||
context,
|
||||
).add(OneTimeOrderPositionUpdated(index, updated));
|
||||
},
|
||||
onRemoved: () {
|
||||
BlocProvider.of<OneTimeOrderBloc>(context)
|
||||
.add(OneTimeOrderPositionRemoved(index));
|
||||
BlocProvider.of<OneTimeOrderBloc>(
|
||||
context,
|
||||
).add(OneTimeOrderPositionRemoved(index));
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -73,16 +73,14 @@ class OrderTypeCard extends StatelessWidget {
|
||||
),
|
||||
child: Icon(icon, color: iconColor, size: 24),
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
style: UiTypography.body2b.copyWith(color: textColor),
|
||||
),
|
||||
Text(title, style: UiTypography.body2b.copyWith(color: textColor)),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Expanded(
|
||||
child: Text(
|
||||
description,
|
||||
style:
|
||||
UiTypography.footnote1r.copyWith(color: descriptionColor),
|
||||
style: UiTypography.footnote1r.copyWith(
|
||||
color: descriptionColor,
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
||||
@@ -47,10 +47,7 @@ class RapidOrderExampleCard extends StatelessWidget {
|
||||
text: TextSpan(
|
||||
style: UiTypography.body2r.textPrimary,
|
||||
children: <InlineSpan>[
|
||||
TextSpan(
|
||||
text: label,
|
||||
style: UiTypography.body2b.textPrimary,
|
||||
),
|
||||
TextSpan(text: label, style: UiTypography.body2b.textPrimary),
|
||||
TextSpan(text: ' $example'),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -74,11 +74,7 @@ class RapidOrderHeader extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
const Icon(
|
||||
UiIcons.zap,
|
||||
color: UiColors.accent,
|
||||
size: 18,
|
||||
),
|
||||
const Icon(UiIcons.zap, color: UiColors.accent, size: 18),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Text(
|
||||
title,
|
||||
|
||||
@@ -42,8 +42,9 @@ class RapidOrderSuccessView extends StatelessWidget {
|
||||
child: SafeArea(
|
||||
child: Center(
|
||||
child: Container(
|
||||
margin:
|
||||
const EdgeInsets.symmetric(horizontal: UiConstants.space10),
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space10,
|
||||
),
|
||||
padding: const EdgeInsets.all(UiConstants.space8),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.white,
|
||||
@@ -75,10 +76,7 @@ class RapidOrderSuccessView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: UiConstants.space6),
|
||||
Text(
|
||||
title,
|
||||
style: UiTypography.headline1m.textPrimary,
|
||||
),
|
||||
Text(title, style: UiTypography.headline1m.textPrimary),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Text(
|
||||
message,
|
||||
|
||||
@@ -153,27 +153,27 @@ class _RapidOrderFormState extends State<_RapidOrderForm> {
|
||||
|
||||
// Examples
|
||||
if (initialState != null)
|
||||
...initialState.examples
|
||||
.asMap()
|
||||
.entries
|
||||
.map((MapEntry<int, String> entry) {
|
||||
...initialState.examples.asMap().entries.map((
|
||||
MapEntry<int, String> entry,
|
||||
) {
|
||||
final int index = entry.key;
|
||||
final String example = entry.value;
|
||||
final bool isHighlighted = index == 0;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: UiConstants.space2),
|
||||
bottom: UiConstants.space2,
|
||||
),
|
||||
child: RapidOrderExampleCard(
|
||||
example: example,
|
||||
isHighlighted: isHighlighted,
|
||||
label: labels.example,
|
||||
onTap: () =>
|
||||
BlocProvider.of<RapidOrderBloc>(
|
||||
context)
|
||||
.add(
|
||||
RapidOrderExampleSelected(example),
|
||||
),
|
||||
context,
|
||||
).add(
|
||||
RapidOrderExampleSelected(example),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
@@ -184,9 +184,9 @@ class _RapidOrderFormState extends State<_RapidOrderForm> {
|
||||
controller: _messageController,
|
||||
maxLines: 4,
|
||||
onChanged: (String value) {
|
||||
BlocProvider.of<RapidOrderBloc>(context).add(
|
||||
RapidOrderMessageChanged(value),
|
||||
);
|
||||
BlocProvider.of<RapidOrderBloc>(
|
||||
context,
|
||||
).add(RapidOrderMessageChanged(value));
|
||||
},
|
||||
hintText: labels.hint,
|
||||
),
|
||||
@@ -197,7 +197,8 @@ class _RapidOrderFormState extends State<_RapidOrderForm> {
|
||||
labels: labels,
|
||||
isSubmitting: isSubmitting,
|
||||
isListening: initialState?.isListening ?? false,
|
||||
isMessageEmpty: initialState != null &&
|
||||
isMessageEmpty:
|
||||
initialState != null &&
|
||||
initialState.message.trim().isEmpty,
|
||||
),
|
||||
],
|
||||
@@ -242,11 +243,7 @@ class _AnimatedZapIcon extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Icon(
|
||||
UiIcons.zap,
|
||||
color: UiColors.white,
|
||||
size: 32,
|
||||
),
|
||||
child: const Icon(UiIcons.zap, color: UiColors.white, size: 32),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -271,9 +268,9 @@ class _RapidOrderActions extends StatelessWidget {
|
||||
child: UiButton.secondary(
|
||||
text: isListening ? labels.listening : labels.speak,
|
||||
leadingIcon: UiIcons.bell, // Placeholder for mic
|
||||
onPressed: () => BlocProvider.of<RapidOrderBloc>(context).add(
|
||||
const RapidOrderVoiceToggled(),
|
||||
),
|
||||
onPressed: () => BlocProvider.of<RapidOrderBloc>(
|
||||
context,
|
||||
).add(const RapidOrderVoiceToggled()),
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: isListening
|
||||
? UiColors.destructive.withValues(alpha: 0.05)
|
||||
@@ -291,9 +288,9 @@ class _RapidOrderActions extends StatelessWidget {
|
||||
trailingIcon: UiIcons.arrowRight,
|
||||
onPressed: isSubmitting || isMessageEmpty
|
||||
? null
|
||||
: () => BlocProvider.of<RapidOrderBloc>(context).add(
|
||||
const RapidOrderSubmitted(),
|
||||
),
|
||||
: () => BlocProvider.of<RapidOrderBloc>(
|
||||
context,
|
||||
).add(const RapidOrderSubmitted()),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user