This commit is contained in:
MarcWieland
2026-07-26 23:58:12 +02:00
commit 411ede36ef
596 changed files with 39941 additions and 0 deletions
+307
View File
@@ -0,0 +1,307 @@
import 'package:flutter/material.dart';
import '../models/schedule_item.dart';
import '../theme/app_theme.dart';
class OrdersWeekView extends StatefulWidget {
final List<DaySummary> summaries;
const OrdersWeekView({
super.key,
required this.summaries,
});
@override
State<OrdersWeekView> createState() => _OrdersWeekViewState();
}
class _OrdersWeekViewState extends State<OrdersWeekView> {
late int _selectedDayIndex;
bool _isAccordionExpanded = true;
@override
void initState() {
super.initState();
// Default select Friday (Fr) or Thursday (Do) as highlighted in mockup
_selectedDayIndex = widget.summaries.indexWhere((s) => s.dayName == 'Fr');
if (_selectedDayIndex < 0) _selectedDayIndex = 3;
}
@override
Widget build(BuildContext context) {
final selectedDay = widget.summaries[_selectedDayIndex];
return SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Column(
children: [
// Weekly Summary Matrix Card
Container(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppTheme.cardBorder),
boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 2),
),
],
),
child: Row(
children: [
// Labels Column (Aufträge, Stunden)
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24),
Text(
'Aufträge',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: AppTheme.textSecondary,
),
),
SizedBox(height: 28),
Text(
'Stunden',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: AppTheme.textSecondary,
),
),
],
),
const SizedBox(width: 8),
// Days Columns (Mo - So)
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: List.generate(widget.summaries.length, (index) {
final summary = widget.summaries[index];
final isSelected = index == _selectedDayIndex;
return GestureDetector(
onTap: () {
setState(() {
_selectedDayIndex = index;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 6),
decoration: BoxDecoration(
color: isSelected ? AppTheme.primaryBlue : Colors.transparent,
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Text(
summary.dayName,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: isSelected ? Colors.white : AppTheme.textPrimary,
),
),
const SizedBox(height: 12),
// Aufträge Count Circle / Pill
Container(
width: 26,
height: 26,
alignment: Alignment.center,
decoration: BoxDecoration(
color: isSelected
? const Color(0xFF1D4ED8)
: AppTheme.backgroundLight,
shape: BoxShape.circle,
),
child: Text(
'${summary.ordersCount}',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: isSelected ? Colors.white : AppTheme.textPrimary,
),
),
),
const SizedBox(height: 16),
// Stunden Text Box
Container(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
decoration: BoxDecoration(
color: isSelected
? const Color(0xFF1D4ED8)
: AppTheme.backgroundLight,
borderRadius: BorderRadius.circular(6),
),
child: Text(
summary.hoursTotal.toStringAsFixed(1),
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: isSelected ? Colors.white : AppTheme.textPrimary,
),
),
),
],
),
),
);
}),
),
),
],
),
),
const SizedBox(height: 20),
// Collapsible Day Details Card Accordion
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppTheme.cardBorder),
),
child: Column(
children: [
// Header Bar for Selected Day
InkWell(
onTap: () {
setState(() {
_isAccordionExpanded = !_isAccordionExpanded;
});
},
borderRadius: BorderRadius.circular(16),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${selectedDay.fullDayName}, ${selectedDay.dateString}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppTheme.textPrimary,
),
),
Icon(
_isAccordionExpanded
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: AppTheme.textSecondary,
),
],
),
),
),
if (_isAccordionExpanded) ...[
const Divider(height: 1, color: AppTheme.cardBorder),
if (selectedDay.items.isEmpty)
const Padding(
padding: EdgeInsets.all(20),
child: Text(
'Keine Aufträge für diesen Tag eingetragen.',
style: TextStyle(color: AppTheme.textSecondary),
),
)
else
ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(12),
itemCount: selectedDay.items.length,
separatorBuilder: (context, index) => const SizedBox(height: 10),
itemBuilder: (context, index) {
final item = selectedDay.items[index];
return _buildWeekJobCard(item);
},
),
],
],
),
),
],
),
);
}
Widget _buildWeekJobCard(ScheduleItem item) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppTheme.backgroundLight,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppTheme.cardBorder),
),
child: Row(
children: [
// Icon Container
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppTheme.cardBorder),
),
child: Icon(
item.isCompleted ? Icons.hvac_outlined : Icons.location_on,
color: item.isCompleted ? AppTheme.textSecondary : AppTheme.primaryBlue,
size: 22,
),
),
const SizedBox(width: 12),
// Content
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.customerName ?? item.title,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: AppTheme.textPrimary,
),
),
if (item.address != null) ...[
const SizedBox(height: 2),
Text(
item.address!,
style: const TextStyle(
fontSize: 12,
color: AppTheme.textSecondary,
),
),
],
if (item.taskDescription != null) ...[
const SizedBox(height: 2),
Text(
item.taskDescription!,
style: const TextStyle(
fontSize: 11,
color: AppTheme.textMuted,
),
),
],
],
),
),
// Status Badge / Icon
Icon(
item.isCompleted ? Icons.check_circle_outline : Icons.person_outline,
color: item.isCompleted ? Colors.green[700] : AppTheme.textSecondary,
size: 20,
),
],
),
);
}
}