diff --git a/lib/ui/screens/crash_screen.dart b/lib/ui/screens/crash_screen.dart index 3e25078..02c49f3 100644 --- a/lib/ui/screens/crash_screen.dart +++ b/lib/ui/screens/crash_screen.dart @@ -10,12 +10,12 @@ class CrashScreen extends StatelessWidget { super.key, required this.exception, required this.stackTrace, + this.gitHash = const String.fromEnvironment('GIT_HASH'), }); final Object exception; final StackTrace? stackTrace; - - static const _gitHash = String.fromEnvironment('GIT_HASH'); + final String gitHash; Future _buildReport() async { String version = 'unknown'; @@ -25,8 +25,8 @@ class CrashScreen extends StatelessWidget { } catch (_) {} final platform = '${Platform.operatingSystem} ${Platform.operatingSystemVersion}'; - final gitLine = _gitHash.isNotEmpty - ? 'Git Commit: [$_gitHash](https://codeberg.org/guettli/sharedinbox/commit/$_gitHash)\n' + final gitLine = gitHash.isNotEmpty + ? 'Git Commit: [$gitHash](https://codeberg.org/guettli/sharedinbox/commit/$gitHash)\n' : ''; return 'App Version: $version\n' '$gitLine' @@ -56,12 +56,27 @@ class CrashScreen extends StatelessWidget { style: Theme.of(ctx).textTheme.titleMedium, textAlign: TextAlign.center, ), - if (_gitHash.isNotEmpty) ...[ + if (gitHash.isNotEmpty) ...[ const SizedBox(height: 8), - const Text( - 'Git Commit: $_gitHash', - style: TextStyle(fontSize: 12, color: Colors.grey), - textAlign: TextAlign.center, + GestureDetector( + onTap: () async { + final url = Uri.parse( + 'https://codeberg.org/guettli/sharedinbox/commit/$gitHash', + ); + await launchUrl( + url, + mode: LaunchMode.externalApplication, + ); + }, + child: Text( + 'Git Commit: $gitHash', + style: const TextStyle( + fontSize: 12, + color: Colors.blue, + decoration: TextDecoration.underline, + ), + textAlign: TextAlign.center, + ), ), ], const SizedBox(height: 24), @@ -106,32 +121,6 @@ class CrashScreen extends StatelessWidget { ), ), ], - if (_gitHash.isNotEmpty) ...[ - const SizedBox(height: 16), - const Text( - 'Git Commit:', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 4), - GestureDetector( - onTap: () async { - final url = Uri.parse( - 'https://codeberg.org/guettli/sharedinbox/commit/$_gitHash', - ); - await launchUrl( - url, - mode: LaunchMode.externalApplication, - ); - }, - child: const Text( - _gitHash, - style: TextStyle( - color: Colors.blue, - decoration: TextDecoration.underline, - ), - ), - ), - ], const SizedBox(height: 24), FilledButton.icon( onPressed: () async { diff --git a/test/widget/crash_screen_test.dart b/test/widget/crash_screen_test.dart index 2f90866..80e5106 100644 --- a/test/widget/crash_screen_test.dart +++ b/test/widget/crash_screen_test.dart @@ -123,6 +123,50 @@ void main() { }, ); + testWidgets( + 'CrashScreen shows git hash as clickable link above stacktrace', + (tester) async { + tester.view.physicalSize = const Size(800, 1200); + tester.view.devicePixelRatio = 1.0; + addTearDown(() => tester.view.resetPhysicalSize()); + + final mock = MockUrlLauncher(); + UrlLauncherPlatform.instance = mock; + + const exception = 'TestException: git hash test'; + final stackTrace = StackTrace.current; + const testHash = 'abc1234'; + + await tester.pumpWidget( + CrashScreen( + exception: exception, + stackTrace: stackTrace, + gitHash: testHash, + ), + ); + + // Git hash link should be present + final gitLinkFinder = find.textContaining('Git Commit: abc1234'); + expect(gitLinkFinder, findsOneWidget); + + // Link must appear above the stack trace + final stackTraceFinder = find.text('Stack Trace:'); + expect( + tester.getTopLeft(gitLinkFinder).dy, + lessThan(tester.getTopLeft(stackTraceFinder).dy), + ); + + // Tapping the link should open the Codeberg commit URL + await tester.tap(gitLinkFinder); + await tester.pumpAndSettle(); + + expect( + mock.launchedUrl, + equals('https://codeberg.org/guettli/sharedinbox/commit/abc1234'), + ); + }, + ); + testWidgets( 'CrashScreen used as root widget — buttons work without ScaffoldMessenger crash', (tester) async {