conclusion_page.dart 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import '../../../../services/analysis_providers.dart';
  4. import '../../../shared/presentation/widgets/async_value_view.dart';
  5. import '../../../shared/presentation/widgets/lab_section_scaffold.dart';
  6. class ConclusionPage extends ConsumerWidget {
  7. const ConclusionPage({super.key});
  8. @override
  9. Widget build(BuildContext context, WidgetRef ref) {
  10. final theme = Theme.of(context);
  11. final snapshot = ref.watch(selectedSessionSnapshotProvider);
  12. return LabSectionScaffold(
  13. eyebrow: 'Conclusion',
  14. title: 'Review the evidence-backed result.',
  15. description:
  16. 'This page presents ranked findings, supporting evidence, contradicting evidence, uncertainty, and next-step suggestions from the AI analyst.',
  17. children: [
  18. AsyncValueView(
  19. value: snapshot,
  20. loadingMessage: 'Loading conclusion...',
  21. data: (session) {
  22. if (session == null) {
  23. return const Card(
  24. child: Padding(
  25. padding: EdgeInsets.all(20),
  26. child: Text('No session selected yet.'),
  27. ),
  28. );
  29. }
  30. final conclusion = session.conclusion;
  31. return Column(
  32. children: [
  33. Card(
  34. child: Padding(
  35. padding: const EdgeInsets.all(20),
  36. child: Column(
  37. crossAxisAlignment: CrossAxisAlignment.start,
  38. children: [
  39. Text('Summary', style: theme.textTheme.titleLarge),
  40. const SizedBox(height: 8),
  41. Text(
  42. conclusion.summary,
  43. style: theme.textTheme.bodyLarge,
  44. ),
  45. ],
  46. ),
  47. ),
  48. ),
  49. const SizedBox(height: 16),
  50. Card(
  51. child: Padding(
  52. padding: const EdgeInsets.all(20),
  53. child: Column(
  54. crossAxisAlignment: CrossAxisAlignment.start,
  55. children: [
  56. Text(
  57. 'Leading Hypotheses',
  58. style: theme.textTheme.titleLarge,
  59. ),
  60. const SizedBox(height: 12),
  61. ...session.hypotheses.map(
  62. (hypothesis) => ListTile(
  63. contentPadding: EdgeInsets.zero,
  64. title: Text(hypothesis.label),
  65. subtitle: Text(hypothesis.rationale),
  66. trailing: Text(
  67. hypothesis.confidence.toStringAsFixed(2),
  68. ),
  69. ),
  70. ),
  71. ],
  72. ),
  73. ),
  74. ),
  75. const SizedBox(height: 16),
  76. Card(
  77. child: Padding(
  78. padding: const EdgeInsets.all(20),
  79. child: Column(
  80. crossAxisAlignment: CrossAxisAlignment.start,
  81. children: [
  82. Text('Findings', style: theme.textTheme.titleLarge),
  83. const SizedBox(height: 12),
  84. ...conclusion.findings.map(
  85. (finding) => Padding(
  86. padding: const EdgeInsets.only(bottom: 16),
  87. child: Column(
  88. crossAxisAlignment: CrossAxisAlignment.start,
  89. children: [
  90. Text(
  91. '${finding.label} | ${finding.confidence.toStringAsFixed(2)}',
  92. style: theme.textTheme.titleMedium,
  93. ),
  94. const SizedBox(height: 6),
  95. ...finding.supportingEvidence.map(
  96. (item) => Text('- $item'),
  97. ),
  98. const SizedBox(height: 4),
  99. ...finding.contradictingEvidence.map(
  100. (item) => Text('Conflict: $item'),
  101. ),
  102. ],
  103. ),
  104. ),
  105. ),
  106. Text('Uncertainty', style: theme.textTheme.titleLarge),
  107. const SizedBox(height: 8),
  108. ...conclusion.uncertainty.map(
  109. (item) => Text('- $item'),
  110. ),
  111. const SizedBox(height: 16),
  112. Text(
  113. 'Suggested Next Actions',
  114. style: theme.textTheme.titleLarge,
  115. ),
  116. const SizedBox(height: 8),
  117. ...conclusion.suggestedNextActions.map(
  118. (item) => Text('- $item'),
  119. ),
  120. ],
  121. ),
  122. ),
  123. ),
  124. ],
  125. );
  126. },
  127. ),
  128. ],
  129. );
  130. }
  131. }