fix saving draft with shared user, display user shared to/from in expanded leg card
All checks were successful
Release / meta (push) Successful in 6s
Release / linux-build (push) Successful in 58s
Release / web-build (push) Successful in 2m0s
Release / android-build (push) Successful in 9m58s
Release / release-master (push) Successful in 37s
Release / release-dev (push) Successful in 44s

This commit is contained in:
2026-01-03 23:26:33 +00:00
parent 1689869ce5
commit af37e25692
5 changed files with 83 additions and 47 deletions

View File

@@ -294,6 +294,7 @@ jobs:
tags: | tags: |
type=sha,prefix= type=sha,prefix=
type=raw,value=${{ needs.meta.outputs.base_version }}${{ needs.meta.outputs.dev_suffix }} type=raw,value=${{ needs.meta.outputs.base_version }}${{ needs.meta.outputs.dev_suffix }}
type=raw,value=dev
- name: Login to the docker registry - name: Login to the docker registry
uses: docker/login-action@v3 uses: docker/login-action@v3

View File

@@ -234,34 +234,62 @@ class _LegCardState extends State<LegCard> {
padding: const EdgeInsets.fromLTRB(16, 0, 16, 12), padding: const EdgeInsets.fromLTRB(16, 0, 16, 12),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (leg.notes.isNotEmpty) ...[ if (leg.notes.isNotEmpty) ...[
Text('Notes', style: textTheme.titleSmall), Text('Notes', style: textTheme.titleSmall),
const SizedBox(height: 4), const SizedBox(height: 4),
Text(leg.notes), Text(leg.notes),
const SizedBox(height: 12), const SizedBox(height: 12),
], ],
if (leg.locos.isNotEmpty) ...[ if (leg.locos.isNotEmpty) ...[
Text('Locos', style: textTheme.titleSmall), Text('Locos', style: textTheme.titleSmall),
const SizedBox(height: 6), const SizedBox(height: 6),
Wrap( Wrap(
spacing: 8, spacing: 8,
runSpacing: 8, runSpacing: 8,
children: _buildLocoChips(context, leg), children: _buildLocoChips(context, leg),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
], ],
if (_hasTrainDetails(leg)) ...[ if (_hasTrainDetails(leg)) ...[
Text('Train', style: textTheme.titleSmall), Text('Train', style: textTheme.titleSmall),
const SizedBox(height: 6), const SizedBox(height: 6),
..._buildTrainDetails(leg, textTheme), ..._buildTrainDetails(leg, textTheme),
const SizedBox(height: 12), const SizedBox(height: 12),
], ],
if (routeSegments.isNotEmpty) ...[ if (sharedFrom != null)
Text('Route', style: textTheme.titleSmall), Padding(
const SizedBox(height: 6), padding: const EdgeInsets.only(bottom: 8.0),
_buildRouteList(routeSegments), child: Text(
], 'Shared from ${sharedFrom.sharedFromDisplay.isNotEmpty ? sharedFrom.sharedFromDisplay : 'another user'}.',
style: textTheme.bodyMedium,
),
),
if (sharedTo.isNotEmpty) ...[
Text(
'Shared to:',
style: textTheme.bodyMedium,
),
const SizedBox(height: 4),
Wrap(
spacing: 8,
runSpacing: 4,
children: sharedTo
.map((s) => Chip(
label: Text(s.sharedToDisplay.isNotEmpty
? s.sharedToDisplay
: s.sharedToUserId),
visualDensity: VisualDensity.compact,
))
.toList(),
),
const SizedBox(height: 12),
],
if (routeSegments.isNotEmpty) ...[
Text('Route', style: textTheme.titleSmall),
const SizedBox(height: 6),
_buildRouteList(routeSegments),
],
], ],
), ),
), ),

View File

@@ -707,7 +707,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
final enabled = value ?? false; final enabled = value ?? false;
setState(() { setState(() {
_matchDestinationToEntry = enabled; _matchDestinationToEntry = enabled;
if (enabled) _hasDestinationTime = true; if (enabled && _hasEndTime) _hasDestinationTime = true;
}); });
_scheduleMatchUpdate(); _scheduleMatchUpdate();
_saveDraft(); _saveDraft();
@@ -1127,7 +1127,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
if (_destinationController.text != endVal) { if (_destinationController.text != endVal) {
_destinationController.text = endVal; _destinationController.text = endVal;
} }
if (_hasDestinationTime) { if (_hasDestinationTime && _hasEndTime) {
final endTime = _legEndDateTime ?? _legDateTime; final endTime = _legEndDateTime ?? _legDateTime;
_selectedDestinationDate = DateTime( _selectedDestinationDate = DateTime(
endTime.year, endTime.year,
@@ -1283,9 +1283,9 @@ class _NewEntryPageState extends State<NewEntryPage> {
const SizedBox(height: 8), const SizedBox(height: 8),
_buildSharedBanner(), _buildSharedBanner(),
], ],
_buildTripSelector(context), _buildTripSelector(context),
const SizedBox(height: 12), const SizedBox(height: 8),
if (_activeLegShare == null) _buildShareSection(context), if (_activeLegShare == null) _buildShareSection(context),
_dateTimeGroup( _dateTimeGroup(
context, context,
title: 'Departure time', title: 'Departure time',
@@ -1366,6 +1366,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
), ),
const Divider(height: 24),
_trainLocationBlock( _trainLocationBlock(
label: 'Origin', label: 'Origin',
controller: _originController, controller: _originController,
@@ -1384,6 +1385,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
singleColumn: true, singleColumn: true,
), ),
), ),
const Divider(height: 24),
_trainLocationBlock( _trainLocationBlock(
label: 'Destination', label: 'Destination',
controller: _destinationController, controller: _destinationController,
@@ -1403,6 +1405,7 @@ class _NewEntryPageState extends State<NewEntryPage> {
singleColumn: true, singleColumn: true,
), ),
), ),
const Divider(height: 24),
TextFormField( TextFormField(
controller: _networkController, controller: _networkController,
textCapitalization: TextCapitalization.characters, textCapitalization: TextCapitalization.characters,

View File

@@ -7,6 +7,7 @@ import 'package:mileograph_flutter/components/traction/traction_card.dart';
import 'package:mileograph_flutter/objects/objects.dart'; import 'package:mileograph_flutter/objects/objects.dart';
import 'package:mileograph_flutter/services/data_service.dart'; import 'package:mileograph_flutter/services/data_service.dart';
import 'package:mileograph_flutter/services/distance_unit_service.dart'; import 'package:mileograph_flutter/services/distance_unit_service.dart';
import 'package:mileograph_flutter/services/authservice.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';

View File

@@ -569,6 +569,7 @@ class _TractionPageState extends State<TractionPage> {
} }
Widget _buildHeaderActions(BuildContext context, bool isMobile) { Widget _buildHeaderActions(BuildContext context, bool isMobile) {
final isElevated = context.read<AuthService>().isElevated;
final refreshButton = IconButton( final refreshButton = IconButton(
tooltip: 'Refresh', tooltip: 'Refresh',
onPressed: _refreshTraction, onPressed: _refreshTraction,
@@ -587,32 +588,34 @@ class _TractionPageState extends State<TractionPage> {
), ),
); );
final newTractionButton = FilledButton.icon( final newTractionButton = !isElevated
onPressed: () async { ? null
final createdClass = await context.push<String>( : FilledButton.icon(
'/traction/new', onPressed: () async {
); final createdClass = await context.push<String>(
if (!mounted) return; '/traction/new',
if (createdClass != null && createdClass.isNotEmpty) { );
_classController.text = createdClass; if (!mounted) return;
_selectedClass = createdClass; if (createdClass != null && createdClass.isNotEmpty) {
_refreshTraction(); _classController.text = createdClass;
} else if (createdClass == '') { _selectedClass = createdClass;
_refreshTraction(); _refreshTraction();
} } else if (createdClass == '') {
}, _refreshTraction();
icon: const Icon(Icons.add), }
label: const Text('New Traction'), },
); icon: const Icon(Icons.add),
label: const Text('New Traction'),
);
final desktopActions = [ final desktopActions = [
refreshButton, refreshButton,
if (classStatsButton != null) classStatsButton, if (classStatsButton != null) classStatsButton,
newTractionButton, if (newTractionButton != null) newTractionButton,
]; ];
final mobileActions = [ final mobileActions = [
newTractionButton, if (newTractionButton != null) newTractionButton,
if (classStatsButton != null) classStatsButton, if (classStatsButton != null) classStatsButton,
refreshButton, refreshButton,
]; ];