import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_cupertino.dart'; import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_fluent.dart'; import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_material.dart'; import 'package:info_tren/models.dart'; import 'package:info_tren/providers.dart'; class SelectTrainSuggestions extends ConsumerWidget { final List choices; final String? currentInput; final void Function(String trainNumber) onTrainSelected; const SelectTrainSuggestions({required this.choices, this.currentInput, required this.onTrainSelected, super.key, }); @override Widget build(BuildContext context, WidgetRef ref) { final uiDesign = ref.watch(uiDesignProvider); switch(uiDesign) { case UiDesign.MATERIAL: return SelectTrainSuggestionsMaterial( choices: choices, onTrainSelected: onTrainSelected, currentInput: currentInput, ); case UiDesign.CUPERTINO: return SelectTrainSuggestionsCupertino( choices: choices, onTrainSelected: onTrainSelected, currentInput: currentInput, ); case UiDesign.FLUENT: return SelectTrainSuggestionsFluent( choices: choices, onTrainSelected: onTrainSelected, currentInput: currentInput, ); default: throw UnmatchedUiDesignException(uiDesign); } } } abstract class SelectTrainSuggestionsShared extends StatelessWidget { String getUseCurrentInputWidgetText(String currentInput) => 'Caută trenul cu numărul $currentInput'; Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected); final List choices; final String? currentInput; final void Function(String trainNumber) onTrainSelected; const SelectTrainSuggestionsShared({ required this.choices, this.currentInput, required this.onTrainSelected, super.key, }); @override Widget build(BuildContext context) { var slivers = choices.map((c) => c.company).toSet().map((operator) => OperatorAutocompleteSliver( operatorName: operator, trains: choices.where((c) => c.company == operator).toList(), onTrainSelected: onTrainSelected, )).toList(); return CustomScrollView( slivers: [ ...slivers, SliverToBoxAdapter( child: currentInput != null && int.tryParse(currentInput!) != null ? getUseCurrentInputWidget(currentInput!, onTrainSelected) : Container(), ), SliverToBoxAdapter( child: Container( height: MediaQuery.of(context).viewPadding.bottom, ), ), ], ); } } class OperatorAutocompleteSliver extends ConsumerWidget { final String operatorName; final List trains; final void Function(String) onTrainSelected; const OperatorAutocompleteSliver({ super.key, required this.operatorName, required this.trains, required this.onTrainSelected, }); Widget mapTrainToItem(TrainsResult train, UiDesign uiDesign) { switch (uiDesign) { case UiDesign.MATERIAL: return OperatorAutocompleteTileMaterial( onTrainSelected: onTrainSelected, operatorName: operatorName, train: train, ); case UiDesign.CUPERTINO: return OperatorAutocompleteTileCupertino( onTrainSelected: onTrainSelected, operatorName: operatorName, train: train, ); case UiDesign.FLUENT: return OperatorAutocompleteTileFluent( onTrainSelected: onTrainSelected, operatorName: operatorName, train: train, ); default: throw UnmatchedUiDesignException(uiDesign); } } @override Widget build(BuildContext context, WidgetRef ref) { final uiDesign = ref.watch(uiDesignProvider); if (trains.isEmpty) { return SliverToBoxAdapter(child: Container(),); } return SliverPrototypeExtentList( prototypeItem: Column( children: [ mapTrainToItem(const TrainsResult(company: 'Company', number: '123', rank: 'R'), uiDesign), ], ), delegate: SliverChildBuilderDelegate( (context, index) { return Column( children: [ mapTrainToItem(trains[index], uiDesign), ], ); }, childCount: trains.length, addSemanticIndexes: true, ), ); } } abstract class OperatorAutocompleteTile extends StatelessWidget { final String operatorName; final TrainsResult train; final void Function(String) onTrainSelected; const OperatorAutocompleteTile({ Key? key, required this.onTrainSelected, required this.operatorName, required this.train }) : super(key: key); }