diff --git a/lib/ui/screens/crash_screen.dart b/lib/ui/screens/crash_screen.dart index 02c49f3..0780c25 100644 --- a/lib/ui/screens/crash_screen.dart +++ b/lib/ui/screens/crash_screen.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -17,20 +18,35 @@ class CrashScreen extends StatelessWidget { final StackTrace? stackTrace; final String gitHash; - Future _buildReport() async { - String version = 'unknown'; + String get _buildMode { + if (kDebugMode) return 'debug'; + if (kProfileMode) return 'profile'; + return 'release'; + } + + Future _fetchVersion() async { try { final info = await PackageInfo.fromPlatform(); - version = '${info.version}+${info.buildNumber}'; - } catch (_) {} + return '${info.version}+${info.buildNumber}'; + } catch (_) { + return 'unknown'; + } + } + + Future _buildReport() async { + final version = await _fetchVersion(); final platform = '${Platform.operatingSystem} ${Platform.operatingSystemVersion}'; final gitLine = gitHash.isNotEmpty ? 'Git Commit: [$gitHash](https://codeberg.org/guettli/sharedinbox/commit/$gitHash)\n' : ''; + final timestamp = DateTime.now().toUtc().toIso8601String(); return 'App Version: $version\n' + 'Build Mode: $_buildMode\n' '$gitLine' - 'Platform: $platform\n\n' + 'Platform: $platform\n' + 'Dart: ${Platform.version}\n' + 'Timestamp: $timestamp\n\n' 'Error:\n```\n$exception\n```\n\n' 'Stack Trace:\n```\n$stackTrace\n```'; } @@ -56,6 +72,18 @@ class CrashScreen extends StatelessWidget { style: Theme.of(ctx).textTheme.titleMedium, textAlign: TextAlign.center, ), + const SizedBox(height: 4), + FutureBuilder( + future: _fetchVersion(), + builder: (context, snapshot) => Text( + 'v${snapshot.data ?? '…'} • $_buildMode • ' + '${Platform.operatingSystem} ${Platform.operatingSystemVersion}', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + ), if (gitHash.isNotEmpty) ...[ const SizedBox(height: 8), GestureDetector( diff --git a/test/widget/crash_screen_test.dart b/test/widget/crash_screen_test.dart index 80e5106..3925dbb 100644 --- a/test/widget/crash_screen_test.dart +++ b/test/widget/crash_screen_test.dart @@ -116,7 +116,10 @@ void main() { expect(clipboardText, isNotNull); expect(clipboardText, contains('App Version: 1.0.0+42')); + expect(clipboardText, contains('Build Mode:')); expect(clipboardText, contains('Platform:')); + expect(clipboardText, contains('Dart:')); + expect(clipboardText, contains('Timestamp:')); expect(clipboardText, contains('TestException: clipboard test')); // GIT_HASH is empty in test builds — no Git Commit line expected expect(clipboardText, isNot(contains('Git Commit:'))); @@ -167,6 +170,35 @@ void main() { }, ); + testWidgets( + 'CrashScreen shows version, build mode, and platform in the UI', + (tester) async { + tester.view.physicalSize = const Size(800, 1200); + tester.view.devicePixelRatio = 1.0; + addTearDown(() => tester.view.resetPhysicalSize()); + + const exception = 'TestException: info row test'; + final stackTrace = StackTrace.current; + + await tester.pumpWidget( + MaterialApp( + home: CrashScreen(exception: exception, stackTrace: stackTrace), + ), + ); + await tester.pumpAndSettle(); + + // Info row shows app version (from mock), build mode, and platform OS. + expect(find.textContaining('1.0.0+42'), findsWidgets); + // In test builds kDebugMode is true. + expect(find.textContaining('debug'), findsOneWidget); + // Platform OS is always present (linux in CI, android/ios on device). + expect( + find.textContaining(RegExp(r'linux|android|ios|windows|macos')), + findsWidgets, + ); + }, + ); + testWidgets( 'CrashScreen used as root widget — buttons work without ScaffoldMessenger crash', (tester) async {