242 lines
8.2 KiB
Dart
242 lines
8.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
import '../models/kauf_filament_model.dart';
|
|
import '../theme/app_theme.dart';
|
|
import '../helper/display_formats.dart';
|
|
|
|
class FilamentCard extends StatelessWidget {
|
|
const FilamentCard({
|
|
super.key,
|
|
required this.filament,
|
|
required this.onTap,
|
|
required this.onAction,
|
|
this.verbrauchGramm = 0,
|
|
this.hatProfil = false,
|
|
});
|
|
|
|
final KaufFilamentModel filament;
|
|
final VoidCallback onTap;
|
|
final ValueChanged<String> onAction;
|
|
final double verbrauchGramm;
|
|
final bool hatProfil;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final price = NumberFormat.currency(
|
|
locale: 'de_AT',
|
|
symbol: '€',
|
|
).format(filament.preis);
|
|
final weight = filament.gewichtGramm != null
|
|
? '${DisplayFormats.number(filament.gewichtGramm!)} g'
|
|
: RegExp(r'[a-zA-Z]').hasMatch(filament.gewicht)
|
|
? filament.gewicht
|
|
: '${filament.gewicht} g';
|
|
final start = filament.gewichtGramm;
|
|
final rest = start == null ? null : start - verbrauchGramm;
|
|
return Card(
|
|
margin: EdgeInsets.zero,
|
|
color: Colors.white,
|
|
surfaceTintColor: Colors.transparent,
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
|
|
clipBehavior: Clip.antiAlias,
|
|
child: InkWell(
|
|
onTap: onTap,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(20),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
padding: const EdgeInsets.all(12),
|
|
decoration: BoxDecoration(
|
|
color: AppTheme.inputSurface,
|
|
borderRadius: BorderRadius.circular(14),
|
|
),
|
|
child: const Icon(
|
|
Icons.inventory_2_outlined,
|
|
color: AppTheme.teal,
|
|
size: 26,
|
|
),
|
|
),
|
|
const SizedBox(width: 14),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
filament.marke.isEmpty
|
|
? filament.material
|
|
: filament.marke,
|
|
style: const TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
filament.farbe,
|
|
style: const TextStyle(
|
|
color: AppTheme.muted,
|
|
fontSize: 14,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
PopupMenuButton<String>(
|
|
tooltip: 'Filament verwalten',
|
|
onSelected: onAction,
|
|
itemBuilder: (context) => const [
|
|
PopupMenuItem(
|
|
value: 'edit',
|
|
child: ListTile(
|
|
leading: Icon(Icons.edit_outlined),
|
|
title: Text('Bearbeiten'),
|
|
contentPadding: EdgeInsets.zero,
|
|
),
|
|
),
|
|
PopupMenuItem(
|
|
value: 'duplicate',
|
|
child: ListTile(
|
|
leading: Icon(Icons.copy_outlined),
|
|
title: Text('Duplizieren'),
|
|
contentPadding: EdgeInsets.zero,
|
|
),
|
|
),
|
|
PopupMenuItem(
|
|
value: 'delete',
|
|
child: ListTile(
|
|
leading: Icon(Icons.delete_outline),
|
|
title: Text('Löschen'),
|
|
contentPadding: EdgeInsets.zero,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
rest == null
|
|
? 'Restgewicht unbekannt'
|
|
: '${DisplayFormats.number(rest)} g verbleibend',
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w700,
|
|
color: rest != null && rest < 0
|
|
? Theme.of(context).colorScheme.error
|
|
: AppTheme.teal,
|
|
),
|
|
),
|
|
if (start != null && start > 0) ...[
|
|
const SizedBox(height: 8),
|
|
LinearProgressIndicator(
|
|
value: (rest! / start).clamp(0.0, 1.0),
|
|
minHeight: 6,
|
|
borderRadius: BorderRadius.circular(8),
|
|
backgroundColor: AppTheme.inputSurface,
|
|
),
|
|
],
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
'${DisplayFormats.number(verbrauchGramm)} g verbraucht',
|
|
style: const TextStyle(color: AppTheme.muted, fontSize: 12),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Wrap(
|
|
spacing: 8,
|
|
runSpacing: 8,
|
|
children: [
|
|
_DetailPill(
|
|
label: filament.material,
|
|
icon: Icons.layers_outlined,
|
|
),
|
|
_DetailPill(label: weight, icon: Icons.scale_outlined),
|
|
if (hatProfil)
|
|
const _DetailPill(
|
|
label: 'Profil erstellt',
|
|
icon: Icons.check_circle_outline,
|
|
),
|
|
],
|
|
),
|
|
const Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 14),
|
|
child: Divider(height: 1, color: Color(0xFFE7EDF0)),
|
|
),
|
|
Wrap(
|
|
alignment: WrapAlignment.spaceBetween,
|
|
crossAxisAlignment: WrapCrossAlignment.center,
|
|
spacing: 16,
|
|
runSpacing: 12,
|
|
children: [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
filament.haendler,
|
|
style: const TextStyle(color: AppTheme.muted),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
DateFormat('dd.MM.yyyy').format(filament.kaufdatum),
|
|
style: const TextStyle(
|
|
color: AppTheme.muted,
|
|
fontSize: 12,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
Text(
|
|
price,
|
|
style: const TextStyle(
|
|
color: AppTheme.teal,
|
|
fontSize: 21,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _DetailPill extends StatelessWidget {
|
|
const _DetailPill({required this.label, required this.icon});
|
|
|
|
final String label;
|
|
final IconData icon;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFFF0F5F7),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(icon, size: 14, color: AppTheme.muted),
|
|
const SizedBox(width: 6),
|
|
Flexible(
|
|
child: Text(
|
|
label,
|
|
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w600),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|