environment_monitoring_app/lib/home_page.dart

299 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:environment_monitoring_app/auth_provider.dart';
import 'package:environment_monitoring_app/collapsible_sidebar.dart';
// Define a breakpoint for switching to a persistent sidebar or a mobile drawer
const double kDrawerBreakpoint = 800.0;
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// isCollapsed is only relevant for the persistent (desktop) layout
bool _isSidebarCollapsed = false;
String _currentSelectedRoute = '/home';
// Helper method used by both the persistent sidebar and the drawer
void _handleNavigation(String route) {
setState(() {
_currentSelectedRoute = route;
});
Navigator.pushNamed(context, route);
// If using the drawer (mobile layout), close it after navigation
if (MediaQuery.of(context).size.width < kDrawerBreakpoint) {
// NOTE: This pop needs the proper context, which is available inside the Builder.
// We will handle the pop inside the onPressed function.
}
}
// A simplified toggle for the persistent sidebar's state
void _toggleSidebarState() {
setState(() {
_isSidebarCollapsed = !_isSidebarCollapsed;
});
}
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthProvider>(context);
final colorScheme = Theme.of(context).colorScheme;
final screenWidth = MediaQuery.of(context).size.width;
// --- Determine Layout Type ---
final bool isMobileLayout = screenWidth < kDrawerBreakpoint;
// --- Responsive Size Calculations ---
final double collapsedWidth = (screenWidth * 0.08).clamp(55.0, 75.0);
// --- MODIFICATION START: Increased Expanded Width for Drawer ---
final double expandedWidth = (screenWidth * 0.3).clamp(250.0, 350.0); // Increased factor to 30% and max to 350px
// --- MODIFICATION END ---
final double sidebarWidth = _isSidebarCollapsed ? collapsedWidth : expandedWidth;
// Grid properties are set based on whether the persistent sidebar is open OR if it's the mobile layout
final double effectiveContentWidth = isMobileLayout ? screenWidth : screenWidth - sidebarWidth;
final bool useCompactLayout = effectiveContentWidth < 600.0 && !isMobileLayout && !_isSidebarCollapsed;
final int crossAxisCount = useCompactLayout ? 1 : 2;
final double childAspectRatio = useCompactLayout ? 4.0 : 1.6;
final double iconSize = (screenWidth * 0.05).clamp(26.0, 40.0);
final double textSize = (screenWidth * 0.03).clamp(13.0, 18.0);
// --------------------------------------------------------------------------
final sidebar = CollapsibleSidebar(
isCollapsed: _isSidebarCollapsed,
onToggle: _toggleSidebarState,
onNavigate: _handleNavigation,
);
// Calculate required top padding for the Drawer content
final double statusBarHeight = MediaQuery.of(context).padding.top;
final double appBarHeight = kToolbarHeight;
final double totalDrawerTopPadding = statusBarHeight + appBarHeight;
return Scaffold(
appBar: AppBar(
leading: Builder(
builder: (BuildContext innerContext) {
return IconButton(
icon: Icon(
isMobileLayout
? Icons.menu
: (_isSidebarCollapsed ? Icons.menu : Icons.close),
color: Colors.white
),
onPressed: () {
if (isMobileLayout) {
Scaffold.of(innerContext).openDrawer();
} else {
_toggleSidebarState();
}
},
);
},
),
title: const Text("MMS Version 3.12.01"),
actions: [
IconButton(
icon: const Icon(Icons.person),
onPressed: () {
Navigator.pushNamed(context, '/profile');
},
),
],
),
drawer: isMobileLayout ? Drawer(
width: expandedWidth,
child: Padding(
padding: EdgeInsets.only(top: totalDrawerTopPadding),
child: sidebar,
),
) : null,
body: Row(
children: [
if (!isMobileLayout)
sidebar,
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Welcome, ${auth.userEmail ?? 'User'}",
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: colorScheme.onBackground,
),
),
const SizedBox(height: 4),
Text(
"Select a Department:",
style: Theme.of(context).textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.onBackground,
),
),
const SizedBox(height: 4),
GridView.count(
crossAxisCount: crossAxisCount,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
childAspectRatio: childAspectRatio,
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
children: [
_buildMiniCategoryCard(
context,
title: "Air",
icon: Icons.air,
color: Colors.blue.shade700,
route: '/air/home',
iconSize: iconSize,
textSize: textSize,
),
_buildMiniCategoryCard(
context,
title: "River",
icon: Icons.water,
color: Colors.teal.shade700,
route: '/river/home',
iconSize: iconSize,
textSize: textSize,
),
_buildMiniCategoryCard(
context,
title: "Marine",
icon: Icons.sailing,
color: Colors.indigo.shade700,
route: '/marine/home',
iconSize: iconSize,
textSize: textSize,
),
_buildMiniSettingsCard(
context,
iconSize: iconSize,
textSize: textSize,
),
],
),
],
),
),
),
],
),
);
}
Widget _buildMiniCategoryCard(
BuildContext context, {
required String title,
required IconData icon,
required Color color,
required String route,
required double iconSize,
required double textSize,
}) {
return Card(
elevation: 1,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: InkWell(
borderRadius: BorderRadius.circular(6),
onTap: () => Navigator.pushNamed(context, route),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [color.withOpacity(0.9), color],
),
),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: iconSize, color: Colors.white),
const SizedBox(height: 2),
Text(
title,
style: TextStyle(
color: Colors.white,
fontSize: textSize,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
);
}
Widget _buildMiniSettingsCard(BuildContext context, {
required double iconSize,
required double textSize,
}) {
return Card(
elevation: 1,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
child: InkWell(
borderRadius: BorderRadius.circular(6),
onTap: () => Navigator.pushNamed(context, '/settings'),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.grey.shade700, Colors.grey.shade800],
),
),
child: FittedBox(
fit: BoxFit.scaleDown,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.settings, size: iconSize, color: Colors.white),
const SizedBox(height: 2),
Text(
"Settings",
style: TextStyle(
color: Colors.white,
fontSize: textSize,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
);
}
}