Initial commit: SIBU 2.0 MISSION

This commit is contained in:
2026-02-21 09:53:31 -05:00
commit 0c7aa53c8b
400 changed files with 67708 additions and 0 deletions

View File

@ -0,0 +1,265 @@
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
}
}