diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart index 1f3f564f..52b942b3 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/blocs/personal_info_bloc.dart @@ -56,9 +56,9 @@ class PersonalInfoBloc extends Bloc 'email': staff.email, 'phone': staff.phone, 'preferredLocations': - staff.address != null - ? [staff.address!] - : [], // TODO: Map correctly when Staff entity supports list + staff.preferredLocations != null + ? List.from(staff.preferredLocations!) + : [], 'avatar': staff.avatar, }; @@ -111,8 +111,8 @@ class PersonalInfoBloc extends Bloc 'email': updatedStaff.email, 'phone': updatedStaff.phone, 'preferredLocations': - updatedStaff.address != null - ? [updatedStaff.address!] + updatedStaff.preferredLocations != null + ? List.from(updatedStaff.preferredLocations!) : [], 'avatar': updatedStaff.avatar, }; diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/pages/preferred_locations_page.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/pages/preferred_locations_page.dart index 32629cd0..29024f42 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/pages/preferred_locations_page.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/pages/preferred_locations_page.dart @@ -4,13 +4,15 @@ import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; -import 'package:google_places_flutter/google_places_flutter.dart'; import 'package:google_places_flutter/model/prediction.dart'; import 'package:krow_core/core.dart'; import '../blocs/personal_info_bloc.dart'; import '../blocs/personal_info_event.dart'; import '../blocs/personal_info_state.dart'; +import '../widgets/preferred_locations_page/places_search_field.dart'; +import '../widgets/preferred_locations_page/locations_list.dart'; +import '../widgets/preferred_locations_page/empty_locations_state.dart'; /// The maximum number of preferred locations a staff member can add. const int _kMaxLocations = 5; @@ -80,7 +82,6 @@ class _PreferredLocationsPageState extends State { message: i18n.preferred_locations.save_success, type: UiSnackbarType.success, ); - Navigator.of(context).pop(); } else if (state.status == PersonalInfoStatus.error) { UiSnackbar.show( context, @@ -98,25 +99,14 @@ class _PreferredLocationsPageState extends State { return Scaffold( backgroundColor: UiColors.background, - appBar: AppBar( - backgroundColor: UiColors.bgPopup, - elevation: 0, - leading: IconButton( - icon: const Icon(UiIcons.chevronLeft, color: UiColors.textSecondary), - onPressed: () => Navigator.of(context).pop(), - tooltip: MaterialLocalizations.of(context).backButtonTooltip, - ), - title: Text( - i18n.preferred_locations.title, - style: UiTypography.title1m.textPrimary, - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: UiColors.border, height: 1.0), - ), + appBar: UiAppBar( + title: i18n.preferred_locations.title, + showBackButton: true, ), - body: SafeArea( - child: Column( + body: Stack( + children: [ + SafeArea( + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ── Description @@ -138,7 +128,7 @@ class _PreferredLocationsPageState extends State { padding: const EdgeInsets.symmetric( horizontal: UiConstants.space5, ), - child: _PlacesSearchField( + child: PlacesSearchField( controller: _searchController, focusNode: _searchFocusNode, hint: i18n.preferred_locations.search_hint, @@ -187,11 +177,11 @@ class _PreferredLocationsPageState extends State { const SizedBox(height: UiConstants.space3), - // ── Locations list / empty state + // Locations list / empty state Expanded( child: locations.isEmpty - ? _EmptyLocationsState(message: i18n.preferred_locations.empty_state) - : _LocationsList( + ? EmptyLocationsState(message: i18n.preferred_locations.empty_state) + : LocationsList( locations: locations, isSaving: isSaving, removeTooltip: i18n.preferred_locations.remove_tooltip, @@ -199,19 +189,42 @@ class _PreferredLocationsPageState extends State { ), ), - // ── Save button + // Save button Padding( padding: const EdgeInsets.all(UiConstants.space5), child: UiButton.primary( - text: i18n.preferred_locations.save_button, + text: isSaving ? null : i18n.preferred_locations.save_button, fullWidth: true, onPressed: isSaving ? null : () => _save(context, bloc, state), + child: isSaving + ? const SizedBox( + height: UiConstants.iconMd, + width: UiConstants.iconMd, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation( + UiColors.white, + ), + ), + ) + : null, ), ), ], ), ), - ); + if (isSaving) + Container( + color: UiColors.black.withValues(alpha: 0.3), + child: const Center( + child: CircularProgressIndicator( + color: UiColors.primary, + ), + ), + ), + ], + ), + ); }, ), ); @@ -225,291 +238,3 @@ class _PreferredLocationsPageState extends State { } } -// ───────────────────────────────────────────────────────────────────────────── -// Subwidgets -// ───────────────────────────────────────────────────────────────────────────── - -/// Google Places autocomplete search field, locked to US results. -class _PlacesSearchField extends StatelessWidget { - const _PlacesSearchField({ - required this.controller, - required this.focusNode, - required this.hint, - required this.onSelected, - this.enabled = true, - }); - - final TextEditingController controller; - final FocusNode focusNode; - final String hint; - final bool enabled; - final void Function(Prediction) onSelected; - - @override - Widget build(BuildContext context) { - return GooglePlaceAutoCompleteTextField( - textEditingController: controller, - focusNode: focusNode, - googleAPIKey: AppConfig.googleMapsApiKey, - debounceTime: 400, - countries: const ['us'], - isLatLngRequired: false, - getPlaceDetailWithLatLng: onSelected, - itemClick: (Prediction prediction) { - controller.text = prediction.description ?? ''; - controller.selection = TextSelection.fromPosition( - TextPosition(offset: controller.text.length), - ); - onSelected(prediction); - }, - inputDecoration: InputDecoration( - hintText: hint, - hintStyle: UiTypography.body2r.textSecondary, - prefixIcon: const Icon(UiIcons.search, color: UiColors.iconSecondary, size: 20), - suffixIcon: controller.text.isNotEmpty - ? IconButton( - icon: const Icon(UiIcons.close, size: 18, color: UiColors.iconSecondary), - onPressed: controller.clear, - ) - : null, - contentPadding: const EdgeInsets.symmetric( - horizontal: UiConstants.space3, - vertical: UiConstants.space3, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), - borderSide: const BorderSide(color: UiColors.border), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), - borderSide: const BorderSide(color: UiColors.border), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), - borderSide: const BorderSide(color: UiColors.primary, width: 1.5), - ), - disabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), - borderSide: BorderSide(color: UiColors.border.withValues(alpha: 0.5)), - ), - fillColor: enabled ? UiColors.bgPopup : UiColors.bgSecondary, - filled: true, - ), - textStyle: UiTypography.body2r.textPrimary, - itemBuilder: (BuildContext context, int index, Prediction prediction) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: UiConstants.space3, - vertical: UiConstants.space2, - ), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(UiConstants.space2), - decoration: BoxDecoration( - color: UiColors.primary.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(4.0), - ), - child: const Icon(UiIcons.mapPin, size: 16, color: UiColors.primary), - ), - const SizedBox(width: UiConstants.space3), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - _mainText(prediction.description ?? ''), - style: UiTypography.body2m.textPrimary, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - if (_subText(prediction.description ?? '').isNotEmpty) - Text( - _subText(prediction.description ?? ''), - style: UiTypography.footnote1r.textSecondary, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - ], - ), - ); - }, - ); - } - - /// Extracts text before first comma as the primary line. - String _mainText(String description) { - final int commaIndex = description.indexOf(','); - return commaIndex > 0 ? description.substring(0, commaIndex) : description; - } - - /// Extracts text after first comma as the secondary line. - String _subText(String description) { - final int commaIndex = description.indexOf(','); - return commaIndex > 0 ? description.substring(commaIndex + 1).trim() : ''; - } -} - -/// The scrollable list of location chips. -class _LocationsList extends StatelessWidget { - const _LocationsList({ - required this.locations, - required this.isSaving, - required this.removeTooltip, - required this.onRemove, - }); - - final List locations; - final bool isSaving; - final String removeTooltip; - final void Function(String) onRemove; - - @override - Widget build(BuildContext context) { - return ListView.separated( - padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5), - itemCount: locations.length, - separatorBuilder: (_, __) => const SizedBox(height: UiConstants.space2), - itemBuilder: (BuildContext context, int index) { - final String location = locations[index]; - return _LocationChip( - label: location, - index: index + 1, - total: locations.length, - isSaving: isSaving, - removeTooltip: removeTooltip, - onRemove: () => onRemove(location), - ); - }, - ); - } -} - -/// A single location row with pin icon, label, and remove button. -class _LocationChip extends StatelessWidget { - const _LocationChip({ - required this.label, - required this.index, - required this.total, - required this.isSaving, - required this.removeTooltip, - required this.onRemove, - }); - - final String label; - final int index; - final int total; - final bool isSaving; - final String removeTooltip; - final VoidCallback onRemove; - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric( - horizontal: UiConstants.space4, - vertical: UiConstants.space3, - ), - decoration: BoxDecoration( - color: UiColors.bgPopup, - borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), - border: Border.all(color: UiColors.border), - ), - child: Row( - children: [ - // Index badge - Container( - width: 28, - height: 28, - alignment: Alignment.center, - decoration: BoxDecoration( - color: UiColors.primary.withValues(alpha: 0.1), - shape: BoxShape.circle, - ), - child: Text( - '$index', - style: UiTypography.footnote1m.copyWith(color: UiColors.primary), - ), - ), - const SizedBox(width: UiConstants.space3), - - // Pin icon - const Icon(UiIcons.mapPin, size: 16, color: UiColors.iconSecondary), - const SizedBox(width: UiConstants.space2), - - // Location text - Expanded( - child: Text( - label, - style: UiTypography.body2m.textPrimary, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - - // Remove button - if (!isSaving) - Tooltip( - message: removeTooltip, - child: GestureDetector( - onTap: onRemove, - behavior: HitTestBehavior.opaque, - child: Padding( - padding: const EdgeInsets.all(UiConstants.space1), - child: Container( - padding: const EdgeInsets.all(4), - decoration: const BoxDecoration( - color: UiColors.bgSecondary, - shape: BoxShape.circle, - ), - child: const Icon(UiIcons.close, size: 14, color: UiColors.iconSecondary), - ), - ), - ), - ), - ], - ), - ); - } -} - -/// Shows when no locations have been added yet. -class _EmptyLocationsState extends StatelessWidget { - const _EmptyLocationsState({required this.message}); - - final String message; - - @override - Widget build(BuildContext context) { - return Center( - child: Padding( - padding: const EdgeInsets.all(UiConstants.space8), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - color: UiColors.primary.withValues(alpha: 0.08), - shape: BoxShape.circle, - ), - child: const Icon(UiIcons.mapPin, size: 28, color: UiColors.primary), - ), - const SizedBox(height: UiConstants.space4), - Text( - message, - textAlign: TextAlign.center, - style: UiTypography.body2r.textSecondary, - ), - ], - ), - ), - ); - } -} - diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/personal_info_page/personal_info_form.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/personal_info_page/personal_info_form.dart index 38c774b7..cd0ad51d 100644 --- a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/personal_info_page/personal_info_form.dart +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/personal_info_page/personal_info_form.dart @@ -80,7 +80,9 @@ class PersonalInfoForm extends StatelessWidget { enabled: enabled, keyboardType: TextInputType.phone, ), - const SizedBox(height: UiConstants.space4), + const SizedBox(height: UiConstants.space6), + const Divider(), + const SizedBox(height: UiConstants.space6), TappableRow( value: locationSummary, hint: i18n.locations_hint, diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/empty_locations_state.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/empty_locations_state.dart new file mode 100644 index 00000000..c4dced31 --- /dev/null +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/empty_locations_state.dart @@ -0,0 +1,38 @@ +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; + +/// Shows when no locations have been added yet. +class EmptyLocationsState extends StatelessWidget { + const EmptyLocationsState({super.key, required this.message}); + + final String message; + + @override + Widget build(BuildContext context) { + return Center( + child: Padding( + padding: const EdgeInsets.all(UiConstants.space8), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 64, + height: 64, + decoration: BoxDecoration( + color: UiColors.primary.withValues(alpha: 0.08), + shape: BoxShape.circle, + ), + child: const Icon(UiIcons.mapPin, size: 28, color: UiColors.primary), + ), + const SizedBox(height: UiConstants.space4), + Text( + message, + textAlign: TextAlign.center, + style: UiTypography.body2r.textSecondary, + ), + ], + ), + ), + ); + } +} diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/location_chip.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/location_chip.dart new file mode 100644 index 00000000..673f49c6 --- /dev/null +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/location_chip.dart @@ -0,0 +1,95 @@ +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; + +/// A single location row with pin icon, label, and remove button. +class LocationChip extends StatelessWidget { + const LocationChip({ + super.key, + required this.label, + required this.index, + required this.total, + required this.isSaving, + required this.removeTooltip, + required this.onRemove, + }); + + final String label; + final int index; + final int total; + final bool isSaving; + final String removeTooltip; + final VoidCallback onRemove; + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric( + horizontal: UiConstants.space4, + vertical: UiConstants.space3, + ), + decoration: BoxDecoration( + color: UiColors.bgPopup, + borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), + border: Border.all(color: UiColors.border), + ), + child: Row( + children: [ + // Index badge + Container( + width: 28, + height: 28, + alignment: Alignment.center, + decoration: BoxDecoration( + color: UiColors.primary.withValues(alpha: 0.1), + shape: BoxShape.circle, + ), + child: Text( + '$index', + style: UiTypography.footnote1m.copyWith(color: UiColors.primary), + ), + ), + const SizedBox(width: UiConstants.space3), + + // Pin icon + const Icon(UiIcons.mapPin, size: 16, color: UiColors.iconSecondary), + const SizedBox(width: UiConstants.space2), + + // Location text + Expanded( + child: Text( + label, + style: UiTypography.body2m.textPrimary, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + + // Remove button + if (!isSaving) + Tooltip( + message: removeTooltip, + child: GestureDetector( + onTap: onRemove, + behavior: HitTestBehavior.opaque, + child: Padding( + padding: const EdgeInsets.all(UiConstants.space1), + child: Container( + padding: const EdgeInsets.all(4), + decoration: const BoxDecoration( + color: UiColors.bgSecondary, + shape: BoxShape.circle, + ), + child: const Icon( + UiIcons.close, + size: 14, + color: UiColors.iconSecondary, + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/locations_list.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/locations_list.dart new file mode 100644 index 00000000..2f888d35 --- /dev/null +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/locations_list.dart @@ -0,0 +1,40 @@ +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; + +import 'location_chip.dart'; + +/// The scrollable list of location chips. +class LocationsList extends StatelessWidget { + const LocationsList({ + super.key, + required this.locations, + required this.isSaving, + required this.removeTooltip, + required this.onRemove, + }); + + final List locations; + final bool isSaving; + final String removeTooltip; + final void Function(String) onRemove; + + @override + Widget build(BuildContext context) { + return ListView.separated( + padding: const EdgeInsets.symmetric(horizontal: UiConstants.space5), + itemCount: locations.length, + separatorBuilder: (_, _) => const SizedBox(height: UiConstants.space2), + itemBuilder: (BuildContext context, int index) { + final String location = locations[index]; + return LocationChip( + label: location, + index: index + 1, + total: locations.length, + isSaving: isSaving, + removeTooltip: removeTooltip, + onRemove: () => onRemove(location), + ); + }, + ); + } +} diff --git a/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/places_search_field.dart b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/places_search_field.dart new file mode 100644 index 00000000..bbe7fe5e --- /dev/null +++ b/apps/mobile/packages/features/staff/profile_sections/onboarding/profile_info/lib/src/presentation/widgets/preferred_locations_page/places_search_field.dart @@ -0,0 +1,143 @@ +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:google_places_flutter/google_places_flutter.dart'; +import 'package:google_places_flutter/model/prediction.dart'; +import 'package:krow_core/core.dart'; + +/// Google Places autocomplete search field, locked to US results. +class PlacesSearchField extends StatelessWidget { + const PlacesSearchField({ + super.key, + required this.controller, + required this.focusNode, + required this.hint, + required this.onSelected, + this.enabled = true, + }); + + final TextEditingController controller; + final FocusNode focusNode; + final String hint; + final bool enabled; + final void Function(Prediction) onSelected; + + /// Extracts text before first comma as the primary line. + String _mainText(String description) { + final int commaIndex = description.indexOf(','); + return commaIndex > 0 ? description.substring(0, commaIndex) : description; + } + + /// Extracts text after first comma as the secondary line. + String _subText(String description) { + final int commaIndex = description.indexOf(','); + return commaIndex > 0 ? description.substring(commaIndex + 1).trim() : ''; + } + + @override + Widget build(BuildContext context) { + return GooglePlaceAutoCompleteTextField( + textEditingController: controller, + focusNode: focusNode, + googleAPIKey: AppConfig.googleMapsApiKey, + debounceTime: 400, + countries: const ['us'], + isLatLngRequired: false, + getPlaceDetailWithLatLng: onSelected, + itemClick: (Prediction prediction) { + controller.text = prediction.description ?? ''; + controller.selection = TextSelection.fromPosition( + TextPosition(offset: controller.text.length), + ); + onSelected(prediction); + }, + inputDecoration: InputDecoration( + hintText: hint, + hintStyle: UiTypography.body2r.textSecondary, + prefixIcon: const Icon( + UiIcons.search, + color: UiColors.iconSecondary, + size: 20, + ), + suffixIcon: controller.text.isNotEmpty + ? IconButton( + icon: const Icon( + UiIcons.close, + size: 18, + color: UiColors.iconSecondary, + ), + onPressed: controller.clear, + ) + : null, + contentPadding: const EdgeInsets.symmetric( + horizontal: UiConstants.space3, + vertical: UiConstants.space3, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), + borderSide: const BorderSide(color: UiColors.border), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), + borderSide: const BorderSide(color: UiColors.border), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), + borderSide: const BorderSide(color: UiColors.primary, width: 1.5), + ), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(UiConstants.radiusMdValue), + borderSide: BorderSide(color: UiColors.border.withValues(alpha: 0.5)), + ), + fillColor: enabled ? UiColors.bgPopup : UiColors.bgSecondary, + filled: true, + ), + textStyle: UiTypography.body2r.textPrimary, + itemBuilder: (BuildContext context, int index, Prediction prediction) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: UiConstants.space3, + vertical: UiConstants.space2, + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(UiConstants.space2), + decoration: BoxDecoration( + color: UiColors.primary.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(4.0), + ), + child: const Icon( + UiIcons.mapPin, + size: 16, + color: UiColors.primary, + ), + ), + const SizedBox(width: UiConstants.space3), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + _mainText(prediction.description ?? ''), + style: UiTypography.body2m.textPrimary, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + if (_subText(prediction.description ?? '').isNotEmpty) + Text( + _subText(prediction.description ?? ''), + style: UiTypography.footnote1r.textSecondary, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ], + ), + ); + }, + ); + } +}