From 91f53916849227f5f0bb7a06ff8a7bc684f675a6 Mon Sep 17 00:00:00 2001 From: Pete Gregory Date: Mon, 12 Jan 2026 15:00:09 +0000 Subject: [PATCH] fix edit widget issues --- .../leg_share_edit_notification_card.dart | 114 +++++++++++++++++- .../widgets/leg_share_notification_card.dart | 48 ++++++-- pubspec.yaml | 2 +- 3 files changed, 151 insertions(+), 13 deletions(-) diff --git a/lib/components/widgets/leg_share_edit_notification_card.dart b/lib/components/widgets/leg_share_edit_notification_card.dart index 80bc2b3..3535e34 100644 --- a/lib/components/widgets/leg_share_edit_notification_card.dart +++ b/lib/components/widgets/leg_share_edit_notification_card.dart @@ -19,6 +19,8 @@ class _LegShareEditNotificationCardState extends State? _shareFuture; bool _loading = false; static const int _summaryLimit = 3; @@ -33,11 +35,11 @@ class _LegShareEditNotificationCardState extends State().fetchLegShare(_shareId!.toString()); + } + + Future _loadShareIfNeeded() async { + if (_share != null) return; + if (_shareId == null) return; + try { + final future = _shareFuture ?? + context.read().fetchLegShare(_shareId!.toString()); + final share = await future; + if (!mounted) return; + _share = share; + } catch (e) { + // ignore: avoid_empty_catches + } + } + Leg? _findCurrentLeg(int? legId) { if (legId == null) return null; final data = context.read(); @@ -174,6 +202,79 @@ class _LegShareEditNotificationCardState extends State( + future: future, + builder: (context, snapshot) { + final share = snapshot.data; + if (share != null) { + _share = share; + } + final leg = share?.entry ?? _currentLeg; + if (leg == null) { + return const SizedBox.shrink(); + } + return _legSummaryRow(context, leg); + }, + ); + } + + Widget _legSummaryRow(BuildContext context, Leg leg) { + final start = leg.route.isNotEmpty ? leg.route.first : leg.start; + final end = leg.route.isNotEmpty ? leg.route.last : leg.end; + return Text('${_formatDateTime(leg.beginTime)} • $start → $end'); + } + + String _asString(dynamic value) { + if (value == null) return ''; + return value.toString(); + } + + Loco? _resolveLocoById(int locoId, {Leg? shareLeg}) { + for (final loco in shareLeg?.locos ?? const []) { + if (loco.id == locoId) return loco; + } + for (final loco in _currentLeg?.locos ?? const []) { + if (loco.id == locoId) return loco; + } + for (final loco in context.read().traction) { + if (loco.id == locoId) return loco; + } + return null; + } + + String _locoDisplayName(Map loco, {Leg? shareLeg}) { + final locoId = _parseInt(loco['loco_id']); + var locoClass = _asString(loco['class'] ?? loco['loco_class']); + var number = _asString(loco['number'] ?? loco['loco_number']); + if ((locoClass.isEmpty || number.isEmpty) && locoId != null) { + final resolved = _resolveLocoById(locoId, shareLeg: shareLeg); + if (resolved != null) { + if (locoClass.isEmpty) locoClass = resolved.locoClass; + if (number.isEmpty) number = resolved.number; + } + } + final parts = []; + if (locoClass.isNotEmpty) parts.add(locoClass); + if (number.isNotEmpty) parts.add(number); + if (parts.isNotEmpty) return parts.join(' '); + return 'Loco ${locoId ?? '?'}'; + } + @override Widget build(BuildContext context) { @@ -184,10 +285,14 @@ class _LegShareEditNotificationCardState extends State _changePreview(context, e)), if (remaining > 0) Padding( @@ -325,6 +430,7 @@ class _LegShareEditNotificationCardState extends State _openDrawer(Map changes) async { setState(() => _loading = true); await _loadLegIdIfNeeded(); + await _loadShareIfNeeded(); _currentLeg ??= _findCurrentLeg(_legId); if (!mounted) return; setState(() => _loading = false); @@ -398,7 +504,9 @@ class _LegShareEditNotificationCardState extends State createState() => _LegShareNotificationCardState(); +} + +class _LegShareNotificationCardState extends State { + bool _accepting = false; + bool _rejecting = false; + @override Widget build(BuildContext context) { final data = context.read(); - final legShareId = _extractLegShareId(notification.body); + final legShareId = _extractLegShareId(widget.notification.body); if (legShareId == null) { return const Text('Invalid leg share notification.'); } @@ -78,16 +86,28 @@ class LegShareNotificationCard extends StatelessWidget { runSpacing: 8, children: [ ElevatedButton( - onPressed: () => _accept(context, share), - child: const Text('Accept'), + onPressed: _accepting ? null : () => _accept(context, share), + child: _accepting + ? const SizedBox( + height: 18, + width: 18, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Accept'), ), OutlinedButton( onPressed: () => _inspect(context, share), child: const Text('Inspect'), ), TextButton( - onPressed: () => _reject(context, share), - child: const Text('Reject'), + onPressed: _rejecting ? null : () => _reject(context, share), + child: _rejecting + ? const SizedBox( + height: 18, + width: 18, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Reject'), ), ], ), @@ -98,12 +118,13 @@ class LegShareNotificationCard extends StatelessWidget { } Future _accept(BuildContext context, LegShareData share) async { + setState(() => _accepting = true); final data = context.read(); final messenger = ScaffoldMessenger.maybeOf(context); try { await data.acceptLegShare(share); if (!context.mounted) return; - await data.dismissNotifications([notification.id]); + await data.dismissNotifications([widget.notification.id]); // Refresh legs in the background. unawaited(data.refreshLegs()); messenger?.showSnackBar( @@ -113,16 +134,21 @@ class LegShareNotificationCard extends StatelessWidget { messenger?.showSnackBar( SnackBar(content: Text('Failed to add shared entry: $e')), ); + } finally { + if (mounted) { + setState(() => _accepting = false); + } } } Future _reject(BuildContext context, LegShareData share) async { + setState(() => _rejecting = true); final data = context.read(); final messenger = ScaffoldMessenger.maybeOf(context); try { await data.rejectLegShare(share.id); if (!context.mounted) return; - await data.dismissNotifications([notification.id]); + await data.dismissNotifications([widget.notification.id]); messenger?.showSnackBar( const SnackBar(content: Text('Share rejected')), ); @@ -130,6 +156,10 @@ class LegShareNotificationCard extends StatelessWidget { messenger?.showSnackBar( SnackBar(content: Text('Failed to reject share: $e')), ); + } finally { + if (mounted) { + setState(() => _rejecting = false); + } } } @@ -140,7 +170,7 @@ class LegShareNotificationCard extends StatelessWidget { Navigator.of(context).pop(); } await Future.delayed(Duration.zero); - final target = share.copyWith(notificationId: notification.id); + final target = share.copyWith(notificationId: widget.notification.id); final ts = DateTime.now().millisecondsSinceEpoch; final path = '/add?share=${Uri.encodeComponent(share.id)}&ts=$ts'; router.go(path, extra: target); diff --git a/pubspec.yaml b/pubspec.yaml index 94f8e19..e42fd38 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.7.2+10 +version: 0.7.3+11 environment: sdk: ^3.8.1