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