266 lines
6.9 KiB
Dart
266 lines
6.9 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../models/taxi_model.dart';
|
|
import '../../services/taxi_service.dart';
|
|
import '../../widgets/custom_app_bar.dart';
|
|
import '../../widgets/custom_bottom_bar.dart';
|
|
import './widgets/taxi_card_widget.dart';
|
|
import './widgets/taxi_empty_state_widget.dart';
|
|
import './widgets/taxi_filters_widget.dart';
|
|
|
|
/// Main taxi screen with filtering, search, and favorites functionality
|
|
class TaxiScreen extends StatefulWidget {
|
|
const TaxiScreen({super.key});
|
|
|
|
@override
|
|
State<TaxiScreen> createState() => _TaxiScreenState();
|
|
}
|
|
|
|
class _TaxiScreenState extends State<TaxiScreen> {
|
|
final TaxiService _taxiService = TaxiService.instance;
|
|
Timer? _searchDebouncer;
|
|
|
|
// State variables
|
|
List<String> _corregimientos = [];
|
|
List<String> _shifts = [];
|
|
List<TaxiModel> _taxis = [];
|
|
Set<String> _favoriteTaxiIds = {};
|
|
String? _selectedCorregimiento;
|
|
String? _selectedShift;
|
|
String _searchText = '';
|
|
bool _isLoading = true;
|
|
String? _error;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_loadInitialData();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_searchDebouncer?.cancel();
|
|
super.dispose();
|
|
}
|
|
|
|
/// Load corregimientos, shifts and initial taxi data
|
|
Future<void> _loadInitialData() async {
|
|
try {
|
|
setState(() {
|
|
_isLoading = true;
|
|
_error = null;
|
|
});
|
|
|
|
// Load corregimientos, shifts and favorites
|
|
final results = await Future.wait([
|
|
_taxiService.getCorregimientos(),
|
|
_taxiService.getFavoriteTaxiIds(),
|
|
]);
|
|
|
|
final corregimientos = results[0];
|
|
final favoriteIds = results[1];
|
|
|
|
setState(() {
|
|
_corregimientos = corregimientos;
|
|
_shifts = _taxiService.getShifts();
|
|
_favoriteTaxiIds = favoriteIds.toSet();
|
|
_isLoading = false;
|
|
});
|
|
|
|
// Load taxis for all corregimientos initially
|
|
await _searchTaxis();
|
|
} catch (e) {
|
|
setState(() {
|
|
_error = e.toString();
|
|
_isLoading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
/// Search taxis with current filters
|
|
Future<void> _searchTaxis() async {
|
|
try {
|
|
final taxis = await _taxiService.searchTaxis(
|
|
selectedCorregimiento: _selectedCorregimiento,
|
|
selectedShift: _selectedShift,
|
|
searchText: _searchText.isEmpty ? null : _searchText,
|
|
);
|
|
|
|
setState(() {
|
|
_taxis = taxis;
|
|
_error = null;
|
|
});
|
|
} catch (e) {
|
|
setState(() {
|
|
_error = e.toString();
|
|
});
|
|
}
|
|
}
|
|
|
|
/// Handle corregimiento selection change
|
|
void _onCorregimientoChanged(String? corregimiento) {
|
|
setState(() {
|
|
_selectedCorregimiento = corregimiento;
|
|
});
|
|
_searchTaxis();
|
|
}
|
|
|
|
/// Handle shift selection change
|
|
void _onShiftChanged(String? shift) {
|
|
setState(() {
|
|
_selectedShift = shift;
|
|
});
|
|
_searchTaxis();
|
|
}
|
|
|
|
/// Handle search text change with debouncing
|
|
void _onSearchChanged(String text) {
|
|
setState(() {
|
|
_searchText = text;
|
|
});
|
|
|
|
// Cancel previous timer
|
|
_searchDebouncer?.cancel();
|
|
|
|
// Start new timer for debounced search
|
|
_searchDebouncer = Timer(const Duration(milliseconds: 300), () {
|
|
_searchTaxis();
|
|
});
|
|
}
|
|
|
|
/// Clear all filters
|
|
void _onClearFilters() {
|
|
setState(() {
|
|
_selectedCorregimiento = null;
|
|
_selectedShift = null;
|
|
_searchText = '';
|
|
});
|
|
_searchTaxis();
|
|
}
|
|
|
|
/// Toggle favorite status for a taxi
|
|
Future<void> _onFavoriteToggle(String taxiId) async {
|
|
try {
|
|
final isFavorite = await _taxiService.toggleFavorite(taxiId);
|
|
|
|
setState(() {
|
|
if (isFavorite) {
|
|
_favoriteTaxiIds.add(taxiId);
|
|
} else {
|
|
_favoriteTaxiIds.remove(taxiId);
|
|
}
|
|
});
|
|
|
|
// Show feedback
|
|
if (mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(
|
|
isFavorite
|
|
? 'Taxi agregado a favoritos'
|
|
: 'Taxi removido de favoritos',
|
|
),
|
|
duration: const Duration(seconds: 2),
|
|
backgroundColor: isFavorite ? Colors.green : Colors.orange,
|
|
),
|
|
);
|
|
}
|
|
} catch (e) {
|
|
if (mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('Error al actualizar favoritos: $e'),
|
|
backgroundColor: Colors.red,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Handle pull to refresh
|
|
Future<void> _onRefresh() async {
|
|
await _loadInitialData();
|
|
}
|
|
|
|
/// Get current empty state widget based on context
|
|
Widget _getEmptyStateWidget() {
|
|
if (_error != null) {
|
|
return TaxiEmptyStateWidget.error(
|
|
error: _error!,
|
|
onRetry: _loadInitialData,
|
|
);
|
|
}
|
|
|
|
if (_selectedCorregimiento == null &&
|
|
_selectedShift == null &&
|
|
_searchText.isEmpty) {
|
|
return TaxiEmptyStateWidget.noFiltersSelected();
|
|
}
|
|
|
|
return TaxiEmptyStateWidget.noResultsFound(onClearFilters: _onClearFilters);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
|
|
return Scaffold(
|
|
backgroundColor: theme.colorScheme.surface,
|
|
appBar: const CustomAppBar(
|
|
title: 'Taxi Directory',
|
|
backgroundColor: Color(0xFF101820),
|
|
foregroundColor: Color(0xFFFEE715),
|
|
),
|
|
body: Column(
|
|
children: [
|
|
// Filters Section
|
|
TaxiFiltersWidget(
|
|
corregimientos: _corregimientos,
|
|
shifts: _shifts,
|
|
selectedCorregimiento: _selectedCorregimiento,
|
|
selectedShift: _selectedShift,
|
|
searchText: _searchText,
|
|
onCorregimientoChanged: _onCorregimientoChanged,
|
|
onShiftChanged: _onShiftChanged,
|
|
onSearchChanged: _onSearchChanged,
|
|
onClearFilters: _onClearFilters,
|
|
),
|
|
// Results Section
|
|
Expanded(
|
|
child:
|
|
_isLoading
|
|
? const Center(child: CircularProgressIndicator())
|
|
: _taxis.isEmpty
|
|
? _getEmptyStateWidget()
|
|
: RefreshIndicator(
|
|
onRefresh: _onRefresh,
|
|
child: ListView.builder(
|
|
itemCount: _taxis.length,
|
|
itemBuilder: (context, index) {
|
|
final taxi = _taxis[index];
|
|
return TaxiCardWidget(
|
|
taxi: taxi,
|
|
isFavorite: _favoriteTaxiIds.contains(taxi.id),
|
|
onFavoriteToggle: _onFavoriteToggle,
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
bottomNavigationBar: CustomBottomBar(
|
|
currentIndex: 3, // Taxi tab index
|
|
onTap: _onBottomNavTap,
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Handle bottom navigation tap
|
|
void _onBottomNavTap(int index) {
|
|
// Navigation is handled by CustomBottomBar
|
|
}
|
|
}
|