feat: Drag-and-Drop-Reihenfolge, Station-Abschluss-Flow und UI-Verbesserungen
Lieferstationen-Dialog (Backend/Vaadin): - Aufgaben per Drag & Drop neu anordnen, inkl. Drag-Handle, komprimierter Kachelansicht während des Drags und horizontaler Einfügelinie als Drop-Target - Drop-Indikator wird unterdrückt, wenn der Drop keine Positionsänderung bewirken würde, und nach dem Abschluss clientseitig zuverlässig aufgeräumt - Drag-Handle, Aufgabentyp-Label und Close-Button auf einheitlicher Position ausgerichtet; Abstände in der Kachel komprimiert Station-Abschluss-Flow (Flutter-App + Backend): - Neuer Button "Station abschließen" unter den Aufgaben; deaktiviert, solange Pflichtaufgaben offen sind, ansonsten aktiv (auch wenn nur optionale Aufgaben existieren) - Hinweisdialog nach Erledigung der letzten Pflichtaufgabe sowie Warnung bei offenen optionalen Aufgaben vor dem Senden - Neue station_completed-Nachricht (jobId, jobNumber, stationOrder, completedAt, hasIncompleteOptionalTasks) wird an den Server gesendet - Backend: Auftrag wird nicht mehr automatisch beim Erledigen der letzten Pflichtaufgabe abgeschlossen, sondern erst beim Empfang der station_completed-Nachricht (neuer Handler in MessageController und MessagingConfig) Aufgabenliste in der App: - Farbcodierung optionaler Aufgaben entfernt; stattdessen vertikal zentrierter "Optional"-Chip am rechten Kartenrand Weitere UI-Überarbeitungen über Login, Jobs, Chats, Settings, Aufgaben-Capture- Screens, Offline-Banner und zugehörige Widgets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
175
app/lib/app_theme.dart
Normal file
175
app/lib/app_theme.dart
Normal file
@@ -0,0 +1,175 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppColors {
|
||||
static const Color primary = Color(0xFF2563EB);
|
||||
static const Color primaryStrong = Color(0xFF1D4ED8);
|
||||
static const Color primarySoft = Color(0xFFE8F0FF);
|
||||
static const Color secondary = Color(0xFF0F4C5C);
|
||||
static const Color secondarySoft = Color(0xFFDDEEF2);
|
||||
static const Color success = Color(0xFF059669);
|
||||
static const Color successSoft = Color(0xFFE7F6F1);
|
||||
static const Color warning = Color(0xFFD97706);
|
||||
static const Color warningSoft = Color(0xFFFFF4E5);
|
||||
static const Color danger = Color(0xFFDC2626);
|
||||
static const Color dangerSoft = Color(0xFFFDECEC);
|
||||
static const Color surface = Color(0xFFFFFFFF);
|
||||
static const Color surfaceMuted = Color(0xFFF7FAFF);
|
||||
static const Color scaffold = Color(0xFFF5F7FB);
|
||||
static const Color scaffoldAccent = Color(0xFFEEF4FF);
|
||||
static const Color border = Color(0xFFD6DDE7);
|
||||
static const Color borderStrong = Color(0xFFC6D0DD);
|
||||
static const Color text = Color(0xFF1E293B);
|
||||
static const Color textStrong = Color(0xFF0F172A);
|
||||
static const Color textMuted = Color(0xFF64748B);
|
||||
}
|
||||
|
||||
class AppGradients {
|
||||
static const LinearGradient shellBackground = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
AppColors.scaffoldAccent,
|
||||
AppColors.surfaceMuted,
|
||||
AppColors.scaffold,
|
||||
],
|
||||
stops: [0, 0.45, 1],
|
||||
);
|
||||
}
|
||||
|
||||
ThemeData buildAppTheme() {
|
||||
final colorScheme = ColorScheme.fromSeed(
|
||||
seedColor: AppColors.primary,
|
||||
brightness: Brightness.light,
|
||||
).copyWith(
|
||||
primary: AppColors.primary,
|
||||
onPrimary: Colors.white,
|
||||
primaryContainer: AppColors.primarySoft,
|
||||
onPrimaryContainer: AppColors.primaryStrong,
|
||||
secondary: AppColors.secondary,
|
||||
onSecondary: Colors.white,
|
||||
secondaryContainer: AppColors.secondarySoft,
|
||||
onSecondaryContainer: AppColors.secondary,
|
||||
tertiary: AppColors.success,
|
||||
onTertiary: Colors.white,
|
||||
tertiaryContainer: AppColors.successSoft,
|
||||
onTertiaryContainer: AppColors.success,
|
||||
surface: AppColors.surface,
|
||||
onSurface: AppColors.textStrong,
|
||||
onSurfaceVariant: AppColors.textMuted,
|
||||
outline: AppColors.border,
|
||||
surfaceTint: Colors.transparent,
|
||||
error: AppColors.danger,
|
||||
onError: Colors.white,
|
||||
);
|
||||
final baseTheme = ThemeData(useMaterial3: true, colorScheme: colorScheme);
|
||||
const radius = Radius.circular(14);
|
||||
final border = OutlineInputBorder(
|
||||
borderRadius: const BorderRadius.all(radius),
|
||||
borderSide: const BorderSide(color: AppColors.border),
|
||||
);
|
||||
|
||||
return baseTheme.copyWith(
|
||||
scaffoldBackgroundColor: AppColors.scaffold,
|
||||
canvasColor: AppColors.scaffold,
|
||||
textTheme: baseTheme.textTheme
|
||||
.apply(bodyColor: AppColors.text, displayColor: AppColors.textStrong)
|
||||
.copyWith(
|
||||
headlineMedium: baseTheme.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textStrong,
|
||||
),
|
||||
titleLarge: baseTheme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textStrong,
|
||||
),
|
||||
bodyLarge: baseTheme.textTheme.bodyLarge?.copyWith(
|
||||
color: AppColors.text,
|
||||
),
|
||||
bodyMedium: baseTheme.textTheme.bodyMedium?.copyWith(
|
||||
color: AppColors.text,
|
||||
),
|
||||
),
|
||||
appBarTheme: const AppBarTheme(
|
||||
backgroundColor: AppColors.primarySoft,
|
||||
foregroundColor: AppColors.primaryStrong,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
),
|
||||
cardTheme: const CardThemeData(
|
||||
color: AppColors.surface,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
margin: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(18)),
|
||||
side: BorderSide(color: AppColors.border),
|
||||
),
|
||||
),
|
||||
dividerTheme: const DividerThemeData(
|
||||
color: AppColors.border,
|
||||
space: 1,
|
||||
thickness: 1,
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
filled: true,
|
||||
fillColor: AppColors.surface,
|
||||
labelStyle: const TextStyle(color: AppColors.textMuted),
|
||||
hintStyle: const TextStyle(color: AppColors.textMuted),
|
||||
prefixIconColor: AppColors.textMuted,
|
||||
suffixIconColor: AppColors.textMuted,
|
||||
border: border,
|
||||
enabledBorder: border,
|
||||
focusedBorder: border.copyWith(
|
||||
borderSide: const BorderSide(color: AppColors.primary, width: 1.5),
|
||||
),
|
||||
errorBorder: border.copyWith(
|
||||
borderSide: const BorderSide(color: AppColors.danger),
|
||||
),
|
||||
focusedErrorBorder: border.copyWith(
|
||||
borderSide: const BorderSide(color: AppColors.danger, width: 1.5),
|
||||
),
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.primary,
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: AppColors.border,
|
||||
disabledForegroundColor: AppColors.textMuted,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
textStyle: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
outlinedButtonTheme: OutlinedButtonThemeData(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: AppColors.primaryStrong,
|
||||
side: const BorderSide(color: AppColors.border),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14),
|
||||
),
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppColors.primaryStrong,
|
||||
textStyle: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
snackBarTheme: SnackBarThemeData(
|
||||
behavior: SnackBarBehavior.floating,
|
||||
backgroundColor: AppColors.textStrong,
|
||||
contentTextStyle: baseTheme.textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
|
||||
),
|
||||
badgeTheme: const BadgeThemeData(
|
||||
backgroundColor: AppColors.primary,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(
|
||||
color: AppColors.primary,
|
||||
),
|
||||
listTileTheme: const ListTileThemeData(iconColor: AppColors.textMuted),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user