Initial commit: Flutter Weight Tracker Web
This commit is contained in:
126
lib/pages/home/home_view.dart
Normal file
126
lib/pages/home/home_view.dart
Normal file
@@ -0,0 +1,126 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../controllers/home_controller.dart';
|
||||
import '../../models/home_model.dart';
|
||||
import '../../widgets/glass_app_bar.dart';
|
||||
import '../../widgets/person_weight_card.dart';
|
||||
|
||||
class HomePage extends GetView<HomeController> {
|
||||
static const String namedRoute = '/home-page';
|
||||
const HomePage({super.key});
|
||||
|
||||
/// Gruppiert eine flache Liste nach `name` und gibt eine Map zurück,
|
||||
/// die je Person alle zugehörigen Einträge enthält.
|
||||
Map<String, List<WeightModel>> _groupByName(List<WeightModel> weights) {
|
||||
final map = <String, List<WeightModel>>{};
|
||||
for (final w in weights) {
|
||||
map.putIfAbsent(w.name, () => []).add(w);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final homeCtrl = controller;
|
||||
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: GlassAppBar(
|
||||
title: 'Weight Tracker',
|
||||
subtitle: 'Verfolge dein Gewicht',
|
||||
),
|
||||
body: Container(
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [
|
||||
Color(0xFF0D0F14),
|
||||
Color(0xFF141824),
|
||||
Color(0xFF1A2035),
|
||||
Color(0xFF0F1520),
|
||||
],
|
||||
stops: [0.0, 0.35, 0.65, 1.0],
|
||||
),
|
||||
),
|
||||
child: Obx(() {
|
||||
if (homeCtrl.isloading.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (homeCtrl.weights.isEmpty) {
|
||||
return const Center(
|
||||
child: Text(
|
||||
'Noch keine Gewichtsangaben.\nKlicke auf das "+" Symbol, um deinen ersten Eintrag hinzuzufügen.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(fontSize: 18, color: Colors.white70),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final grouped = _groupByName(homeCtrl.weights);
|
||||
final names = grouped.keys.toList()..sort();
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
// Responsive: ab 700 px Breite → 2-spaltiges Grid
|
||||
final isWide = constraints.maxWidth >= 700;
|
||||
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: MediaQuery.of(context).padding.top + 96,
|
||||
left: isWide ? 24 : 16,
|
||||
right: isWide ? 24 : 16,
|
||||
bottom: 24,
|
||||
),
|
||||
sliver: isWide
|
||||
? SliverGrid(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 600,
|
||||
mainAxisSpacing: 16,
|
||||
crossAxisSpacing: 16,
|
||||
childAspectRatio: 0.95,
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, i) => PersonWeightCard(
|
||||
personName: names[i],
|
||||
entries: grouped[names[i]]!,
|
||||
onAddWeight: () =>
|
||||
homeCtrl.openAddDialog(names[i]),
|
||||
onEditEntry: (entry) =>
|
||||
homeCtrl.openEditDialog(entry),
|
||||
),
|
||||
childCount: names.length,
|
||||
),
|
||||
)
|
||||
: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, i) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: PersonWeightCard(
|
||||
personName: names[i],
|
||||
entries: grouped[names[i]]!,
|
||||
onAddWeight: () =>
|
||||
homeCtrl.openAddDialog(names[i]),
|
||||
onEditEntry: (entry) =>
|
||||
homeCtrl.openEditDialog(entry),
|
||||
),
|
||||
),
|
||||
childCount: names.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user