set trip to null, not 0
Some checks failed
Release / meta (push) Successful in 8s
Release / linux-build (push) Successful in 1m13s
Release / android-build (push) Successful in 11m2s
Release / release-master (push) Successful in 3s
Release / release-dev (push) Successful in 14s
Release / windows-build (push) Has been cancelled
Some checks failed
Release / meta (push) Successful in 8s
Release / linux-build (push) Successful in 1m13s
Release / android-build (push) Successful in 11m2s
Release / release-master (push) Successful in 3s
Release / release-dev (push) Successful in 14s
Release / windows-build (push) Has been cancelled
This commit is contained in:
@@ -67,15 +67,10 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
items: [
|
||||
const DropdownMenuItem(
|
||||
value: null,
|
||||
child: Text('No trip'),
|
||||
),
|
||||
const DropdownMenuItem(value: null, child: Text('No trip')),
|
||||
...sorted.map(
|
||||
(t) => DropdownMenuItem(
|
||||
value: t.tripId,
|
||||
child: Text(t.tripName),
|
||||
),
|
||||
(t) =>
|
||||
DropdownMenuItem(value: t.tripId, child: Text(t.tripName)),
|
||||
),
|
||||
],
|
||||
onChanged: (val) => setState(() => _selectedTripId = val),
|
||||
@@ -99,9 +94,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
title: const Text('New Trip'),
|
||||
content: TextField(
|
||||
controller: controller,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Trip name',
|
||||
),
|
||||
decoration: const InputDecoration(labelText: 'Trip name'),
|
||||
autofocus: true,
|
||||
),
|
||||
actions: [
|
||||
@@ -128,7 +121,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
final trips = data.tripList;
|
||||
final match = trips.firstWhere(
|
||||
(t) => t.tripName == result,
|
||||
orElse: () => trips.isNotEmpty ? trips.first : TripSummary(tripId: 0, tripName: result, tripMileage: 0),
|
||||
orElse: () => trips.isNotEmpty
|
||||
? trips.first
|
||||
: TripSummary(tripId: 0, tripName: result, tripMileage: 0),
|
||||
);
|
||||
setState(() => _selectedTripId = match.tripId);
|
||||
} catch (e) {
|
||||
@@ -168,12 +163,17 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
selectionMode: true,
|
||||
selectedKeys: selectedKeys,
|
||||
onSelect: (loco) {
|
||||
final markerIndex =
|
||||
_tractionItems.indexWhere((element) => element.isMarker);
|
||||
final markerIndex = _tractionItems.indexWhere(
|
||||
(element) => element.isMarker,
|
||||
);
|
||||
final key = '${loco.locoClass}-${loco.number}';
|
||||
setState(() {
|
||||
final existingIndex = _tractionItems.indexWhere(
|
||||
(e) => !e.isMarker && e.loco != null && '${e.loco!.locoClass}-${e.loco!.number}' == key);
|
||||
(e) =>
|
||||
!e.isMarker &&
|
||||
e.loco != null &&
|
||||
'${e.loco!.locoClass}-${e.loco!.number}' == key,
|
||||
);
|
||||
if (existingIndex != -1) {
|
||||
_tractionItems.removeAt(existingIndex);
|
||||
} else {
|
||||
@@ -216,8 +216,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
);
|
||||
|
||||
List<Map<String, dynamic>> _buildTractionPayload() {
|
||||
final markerIndex =
|
||||
_tractionItems.indexWhere((element) => element.isMarker);
|
||||
final markerIndex = _tractionItems.indexWhere(
|
||||
(element) => element.isMarker,
|
||||
);
|
||||
final payload = <Map<String, dynamic>>[];
|
||||
for (var i = 0; i < _tractionItems.length; i++) {
|
||||
final item = _tractionItems[i];
|
||||
@@ -262,7 +263,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
|
||||
if (_useManualMileage) {
|
||||
final body = {
|
||||
"leg_trip": _selectedTripId ?? 0,
|
||||
"leg_trip": _selectedTripId ?? null,
|
||||
"leg_start": startVal,
|
||||
"leg_end": endVal,
|
||||
"leg_begin_time": _legDateTime.toIso8601String(),
|
||||
@@ -276,12 +277,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
await api.post('/add/manual', body);
|
||||
} else {
|
||||
final body = {
|
||||
"leg_trip": _selectedTripId ?? 0,
|
||||
"leg_start": startVal,
|
||||
"leg_end": endVal,
|
||||
"leg_trip": _selectedTripId ?? null,
|
||||
"leg_begin_time": _legDateTime.toIso8601String(),
|
||||
"leg_route": routeStations,
|
||||
"leg_mileage": mileageVal,
|
||||
"leg_notes": _notesController.text.trim(),
|
||||
"leg_headcode": _headcodeController.text.trim(),
|
||||
"leg_network": _networkController.text.trim(),
|
||||
@@ -294,15 +292,15 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
}
|
||||
try {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Entry submitted')),
|
||||
);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('Entry submitted')));
|
||||
_formKey.currentState!.reset();
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Failed to submit: $e')),
|
||||
);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text('Failed to submit: $e')));
|
||||
} finally {
|
||||
if (mounted) setState(() => _submitting = false);
|
||||
}
|
||||
@@ -319,9 +317,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
builder: (context, constraints) {
|
||||
final twoCol = !isMobile && constraints.maxWidth > 1000;
|
||||
|
||||
final detailPanel = _section(
|
||||
'Details',
|
||||
[
|
||||
final detailPanel = _section('Details', [
|
||||
_buildTripSelector(context),
|
||||
Row(
|
||||
children: [
|
||||
@@ -394,12 +390,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
]);
|
||||
|
||||
final tractionPanel = _section(
|
||||
'Traction',
|
||||
[
|
||||
final tractionPanel = _section('Traction', [
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: ElevatedButton.icon(
|
||||
@@ -409,16 +402,12 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
),
|
||||
),
|
||||
_buildTractionList(),
|
||||
],
|
||||
);
|
||||
]);
|
||||
|
||||
final mileagePanel = _section(
|
||||
'Mileage',
|
||||
[
|
||||
final mileagePanel = _section('Mileage', [
|
||||
SwitchListTile(
|
||||
title: const Text('Use manual mileage'),
|
||||
subtitle: const Text(
|
||||
'Turn off to calculate mileage automatically'),
|
||||
subtitle: const Text('Turn on to enter mileage manually'),
|
||||
value: _useManualMileage,
|
||||
onChanged: (val) {
|
||||
setState(() {
|
||||
@@ -429,8 +418,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
if (_useManualMileage)
|
||||
TextFormField(
|
||||
controller: _mileageController,
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true,
|
||||
),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Mileage (mi)',
|
||||
border: OutlineInputBorder(),
|
||||
@@ -440,8 +430,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: const Text('Calculated mileage'),
|
||||
subtitle:
|
||||
Text('${_routeResult!.distance.toStringAsFixed(2)} mi'),
|
||||
subtitle: Text(
|
||||
'${_routeResult!.distance.toStringAsFixed(2)} mi',
|
||||
),
|
||||
),
|
||||
if (!_useManualMileage)
|
||||
Align(
|
||||
@@ -452,8 +443,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
label: const Text('Open mileage calculator'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
]);
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
@@ -528,14 +518,18 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
leading: Icon(Icons.train),
|
||||
title: Text('Rolling stock marker'),
|
||||
subtitle: Text(
|
||||
'Place locomotives above/below. Positions set relative to this.'),
|
||||
'Place locomotives above/below. Positions set relative to this.',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
final loco = item.loco!;
|
||||
final markerIndex =
|
||||
_tractionItems.indexWhere((element) => element.isMarker);
|
||||
final pos = index > markerIndex ? -(index - markerIndex) : (markerIndex - 1) - index;
|
||||
final markerIndex = _tractionItems.indexWhere(
|
||||
(element) => element.isMarker,
|
||||
);
|
||||
final pos = index > markerIndex
|
||||
? -(index - markerIndex)
|
||||
: (markerIndex - 1) - index;
|
||||
return Card(
|
||||
key: ValueKey('${loco.locoClass}-${loco.number}-$index'),
|
||||
child: ListTile(
|
||||
@@ -553,8 +547,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
value: item.powering,
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
_tractionItems[index] =
|
||||
item.copyWith(powering: v);
|
||||
_tractionItems[index] = item.copyWith(powering: v);
|
||||
});
|
||||
},
|
||||
),
|
||||
@@ -583,10 +576,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
...children.map(
|
||||
@@ -616,9 +608,7 @@ class _CalculatorPickerPage extends StatelessWidget {
|
||||
),
|
||||
title: const Text('Mileage calculator'),
|
||||
),
|
||||
body: RouteCalculator(
|
||||
onApplyRoute: onResult,
|
||||
),
|
||||
body: RouteCalculator(onApplyRoute: onResult),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -628,9 +618,14 @@ class _TractionItem {
|
||||
final bool powering;
|
||||
final bool isMarker;
|
||||
|
||||
_TractionItem({required this.loco, this.powering = true, this.isMarker = false});
|
||||
_TractionItem({
|
||||
required this.loco,
|
||||
this.powering = true,
|
||||
this.isMarker = false,
|
||||
});
|
||||
|
||||
factory _TractionItem.marker() => _TractionItem(loco: null, powering: false, isMarker: true);
|
||||
factory _TractionItem.marker() =>
|
||||
_TractionItem(loco: null, powering: false, isMarker: true);
|
||||
|
||||
_TractionItem copyWith({LocoSummary? loco, bool? powering, bool? isMarker}) {
|
||||
return _TractionItem(
|
||||
|
||||
@@ -171,8 +171,9 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
}
|
||||
|
||||
void _onItemTapped(int index, int currentIndex) {
|
||||
if (index < 0 || index >= contentPages.length || index == currentIndex)
|
||||
if (index < 0 || index >= contentPages.length || index == currentIndex) {
|
||||
return;
|
||||
}
|
||||
context.push(contentPages[index]);
|
||||
_getIndexFromLocation(contentPages[index]);
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ class LocoSummary extends Loco {
|
||||
required String locoType,
|
||||
required String locoNumber,
|
||||
required String locoName,
|
||||
required String locoClass,
|
||||
required super.locoClass,
|
||||
required String locoOperator,
|
||||
String? locoNotes,
|
||||
String? locoEvn,
|
||||
@@ -159,7 +159,6 @@ class LocoSummary extends Loco {
|
||||
type: locoType,
|
||||
number: locoNumber,
|
||||
name: locoName,
|
||||
locoClass: locoClass,
|
||||
operator: locoOperator,
|
||||
notes: locoNotes,
|
||||
evn: locoEvn,
|
||||
@@ -174,9 +173,8 @@ class LocoSummary extends Loco {
|
||||
locoOperator: json['operator'] ?? json['loco_operator'] ?? '',
|
||||
locoNotes: json['notes'],
|
||||
locoEvn: json['evn'] ?? json['loco_evn'],
|
||||
mileage: ((json['loco_mileage'] ?? json['mileage']) as num?)
|
||||
?.toDouble() ??
|
||||
0,
|
||||
mileage:
|
||||
((json['loco_mileage'] ?? json['mileage']) as num?)?.toDouble() ?? 0,
|
||||
journeys: (json['loco_journeys'] ?? json['journeys'] ?? 0) is num
|
||||
? (json['loco_journeys'] ?? json['journeys'] ?? 0).toInt()
|
||||
: 0,
|
||||
@@ -359,14 +357,13 @@ class TripLeg {
|
||||
beginTime:
|
||||
json['leg_begin_time'] != null && json['leg_begin_time'] is String
|
||||
? DateTime.tryParse(json['leg_begin_time'])
|
||||
: (json['leg_begin_time'] is DateTime
|
||||
? json['leg_begin_time']
|
||||
: null),
|
||||
: (json['leg_begin_time'] is DateTime ? json['leg_begin_time'] : null),
|
||||
network: json['leg_network'],
|
||||
route: json['leg_route'],
|
||||
mileage: (json['leg_mileage'] as num?)?.toDouble(),
|
||||
notes: json['leg_notes'],
|
||||
locos: (json['locos'] as List?)
|
||||
locos:
|
||||
(json['locos'] as List?)
|
||||
?.map((e) => Loco.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
@@ -392,9 +389,9 @@ class TripDetail {
|
||||
id: json['trip_id'] ?? 0,
|
||||
name: json['trip_name'] ?? '',
|
||||
mileage: (json['trip_mileage'] as num?)?.toDouble() ?? 0,
|
||||
legCount: json['leg_count'] ??
|
||||
((json['trip_legs'] as List?)?.length ?? 0),
|
||||
legs: (json['trip_legs'] as List?)
|
||||
legCount: json['leg_count'] ?? ((json['trip_legs'] as List?)?.length ?? 0),
|
||||
legs:
|
||||
(json['trip_legs'] as List?)
|
||||
?.map((e) => TripLeg.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
|
||||
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 0.1.0+1
|
||||
version: 0.1.1+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.8.1
|
||||
|
||||
Reference in New Issue
Block a user