add loco legs panel
Some checks failed
Release / meta (push) Failing after 9s
Release / android-build (push) Has been skipped
Release / linux-build (push) Has been skipped
Release / release-dev (push) Has been skipped
Release / release-master (push) Has been skipped

This commit is contained in:
2025-12-17 14:42:31 +00:00
parent fa9773bcd1
commit e9a9e66e39
7 changed files with 389 additions and 160 deletions

View File

@@ -0,0 +1,119 @@
import 'package:flutter/material.dart';
import 'package:mileograph_flutter/components/legs/leg_card.dart';
import 'package:mileograph_flutter/objects/objects.dart';
import 'package:mileograph_flutter/services/data_service.dart';
import 'package:provider/provider.dart';
class LocoLegsPage extends StatefulWidget {
const LocoLegsPage({
super.key,
required this.locoId,
required this.locoLabel,
});
final int locoId;
final String locoLabel;
@override
State<LocoLegsPage> createState() => _LocoLegsPageState();
}
class _LocoLegsPageState extends State<LocoLegsPage> {
bool _includeNonPowering = false;
late Future<List<Leg>> _future;
@override
void initState() {
super.initState();
_future = _fetch();
}
Future<List<Leg>> _fetch() {
return context.read<DataService>().fetchLegsForLoco(
widget.locoId,
includeNonPowering: _includeNonPowering,
);
}
Future<void> _refresh() async {
final items = await _fetch();
if (!mounted) return;
setState(() {
_future = Future.value(items);
});
}
@override
Widget build(BuildContext context) {
final titleLabel =
widget.locoLabel.trim().isEmpty ? 'Loco ${widget.locoId}' : widget.locoLabel;
return Scaffold(
appBar: AppBar(
title: Text('Legs · $titleLabel'),
actions: [
IconButton(
tooltip: 'Refresh',
onPressed: _refresh,
icon: const Icon(Icons.refresh),
),
],
),
body: SafeArea(
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
child: Card(
child: SwitchListTile(
title: const Text('Include non-powering (dead-in-tow)'),
subtitle: const Text('Off by default'),
value: _includeNonPowering,
onChanged: (val) {
setState(() {
_includeNonPowering = val;
_future = _fetch();
});
},
),
),
),
Expanded(
child: FutureBuilder<List<Leg>>(
future: _future,
builder: (context, snapshot) {
final items = snapshot.data ?? const <Leg>[];
final isLoading =
snapshot.connectionState == ConnectionState.waiting;
if (isLoading && items.isEmpty) {
return const Center(child: CircularProgressIndicator());
}
if (!isLoading && items.isEmpty) {
return const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text('No legs found for this loco.'),
),
);
}
return RefreshIndicator(
onRefresh: _refresh,
child: ListView.builder(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
physics: const AlwaysScrollableScrollPhysics(),
itemCount: items.length,
itemBuilder: (context, index) => LegCard(leg: items[index]),
),
);
},
),
),
],
),
),
);
}
}