diff --git a/lib/screens/receive/widgets/qr_address_widget.dart b/lib/screens/receive/widgets/qr_address_widget.dart index 677ba900..2d189c08 100644 --- a/lib/screens/receive/widgets/qr_address_widget.dart +++ b/lib/screens/receive/widgets/qr_address_widget.dart @@ -39,20 +39,20 @@ class QRAddressWidget extends StatelessWidget { TextSpan( children: [ TextSpan( - text: subtitle.substring(0, 6), + text: _slice(subtitle, 0, 6), style: const TextStyle(fontWeight: .bold), ), const TextSpan(text: ' '), TextSpan( - text: subtitle.substring(6, 21), + text: _slice(subtitle, 6, 21), ), const TextSpan(text: '\n'), TextSpan( - text: subtitle.substring(21, 36), + text: _slice(subtitle, 21, 36), ), const TextSpan(text: ' '), TextSpan( - text: subtitle.substring(36), + text: _slice(subtitle, 36), style: const TextStyle(fontWeight: .bold), ), ], @@ -72,4 +72,14 @@ class QRAddressWidget extends StatelessWidget { ); Future _copyToClipboard() => Clipboard.setData(ClipboardData(text: subtitle)); + + // Length-safe slice: a full 0x-address is grouped into fixed chunks, but a + // short or empty address must not crash with a RangeError (issue #657 P6 — + // this widget renders on both Receive and Settings). Clamps the bounds to + // the string length instead of slicing past the end. + static String _slice(String value, int start, [int? end]) { + if (start >= value.length) return ''; + final clampedEnd = end == null || end > value.length ? value.length : end; + return value.substring(start, clampedEnd); + } } diff --git a/test/screens/receive/widgets/qr_address_widget_test.dart b/test/screens/receive/widgets/qr_address_widget_test.dart index abac737f..72ef8186 100644 --- a/test/screens/receive/widgets/qr_address_widget_test.dart +++ b/test/screens/receive/widgets/qr_address_widget_test.dart @@ -47,5 +47,24 @@ void main() { await tester.tap(find.byType(InkWell)); await tester.pump(); }); + + testWidgets( + 'renders a short/unexpected address without a RangeError ' + '(issue #657 P6 regression)', (tester) async { + // A too-short subtitle used to crash on the fixed-index substring(6, 21) + // etc. — it must now render gracefully on Receive and Settings. + await tester.pumpWidget(_host( + const QRAddressWidget(uri: '', subtitle: '0x1234'), + )); + + expect(tester.takeException(), isNull); + expect(find.textContaining('0x1234'), findsAtLeastNWidgets(1)); + + // The extreme case: an empty address must also not throw. + await tester.pumpWidget(_host( + const QRAddressWidget(uri: '', subtitle: ''), + )); + expect(tester.takeException(), isNull); + }); }); }