Initial commit: SIBU 2.0 MISSION
This commit is contained in:
202
old/lib/widgets/custom_bottom_bar.dart
Normal file
202
old/lib/widgets/custom_bottom_bar.dart
Normal file
@ -0,0 +1,202 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// Custom bottom navigation bar implementing adaptive tab persistence
|
||||
/// with contextual badge indicators for the transit app
|
||||
class CustomBottomBar extends StatefulWidget {
|
||||
final int currentIndex;
|
||||
final Function(int) onTap;
|
||||
|
||||
const CustomBottomBar({
|
||||
super.key,
|
||||
required this.currentIndex,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CustomBottomBar> createState() => _CustomBottomBarState();
|
||||
}
|
||||
|
||||
class _CustomBottomBarState extends State<CustomBottomBar> {
|
||||
// Navigation items with routes and icons
|
||||
final List<BottomNavigationBarItem> _navigationItems = [
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.map_outlined),
|
||||
activeIcon: Icon(Icons.map),
|
||||
label: 'Mapa',
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.schedule_outlined),
|
||||
activeIcon: Icon(Icons.schedule),
|
||||
label: 'Horarios',
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.local_offer_outlined),
|
||||
activeIcon: Icon(Icons.local_offer),
|
||||
label: 'Cupones',
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.local_taxi_outlined),
|
||||
activeIcon: Icon(Icons.local_taxi),
|
||||
label: 'Taxi',
|
||||
),
|
||||
];
|
||||
|
||||
final List<String> _routes = [
|
||||
'/map-screen',
|
||||
'/schedules-screen',
|
||||
'/coupons-screen',
|
||||
'/taxi-screen',
|
||||
];
|
||||
|
||||
void _handleTap(int index) {
|
||||
if (index != widget.currentIndex) {
|
||||
// Haptic feedback for tab selection
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
// Navigate to selected route
|
||||
Navigator.pushNamed(context, _routes[index]);
|
||||
|
||||
// Call the onTap callback
|
||||
widget.onTap(index);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildNavigationItem(BottomNavigationBarItem item, int index) {
|
||||
final bool isSelected = index == widget.currentIndex;
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Expanded(
|
||||
child: InkWell(
|
||||
onTap: () => _handleTap(index),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Icon with micro-interaction confirmation
|
||||
AnimatedScale(
|
||||
scale: isSelected ? 1.1 : 1.0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
curve: Curves.easeInOut,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? theme.colorScheme.secondary.withValues(alpha: 0.1)
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: _buildIconWithBadge(
|
||||
isSelected ? item.activeIcon : item.icon,
|
||||
index,
|
||||
isSelected,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
// Label with smooth transition
|
||||
AnimatedDefaultTextStyle(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
style: theme.textTheme.labelSmall!.copyWith(
|
||||
color: isSelected
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
|
||||
),
|
||||
child: Text(item.label!),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildIconWithBadge(Widget icon, int index, bool isSelected) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
// Smart notification badges - contextual indicators
|
||||
bool showBadge = false;
|
||||
String? badgeText;
|
||||
|
||||
switch (index) {
|
||||
case 0: // Map
|
||||
// Show badge when there are nearby bus updates
|
||||
showBadge = false; // Would be dynamic based on app state
|
||||
break;
|
||||
case 1: // Schedules
|
||||
// Show badge when there are schedule changes
|
||||
showBadge = false; // Would be dynamic based on app state
|
||||
break;
|
||||
case 2: // Coupons
|
||||
// Show badge when there are new coupons available
|
||||
showBadge = true; // Example: new coupons available
|
||||
badgeText = '3';
|
||||
break;
|
||||
case 3: // Taxi
|
||||
// Show badge for new taxi services or favorites
|
||||
showBadge = false; // Would be dynamic based on app state
|
||||
break;
|
||||
}
|
||||
|
||||
if (!showBadge) {
|
||||
return IconTheme(
|
||||
data: IconThemeData(
|
||||
color: isSelected
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
size: 24,
|
||||
),
|
||||
child: icon,
|
||||
);
|
||||
}
|
||||
|
||||
return Badge(
|
||||
label: badgeText != null ? Text(badgeText) : null,
|
||||
backgroundColor: theme.colorScheme.error,
|
||||
textColor: theme.colorScheme.onError,
|
||||
smallSize: badgeText == null ? 8 : null,
|
||||
child: IconTheme(
|
||||
data: IconThemeData(
|
||||
color: isSelected
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
size: 24,
|
||||
),
|
||||
child: icon,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surface,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: theme.shadowColor.withValues(alpha: 0.1),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
height: 72,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Row(
|
||||
children: List.generate(
|
||||
_navigationItems.length,
|
||||
(index) => _buildNavigationItem(_navigationItems[index], index),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user