feat: 新增追问模式和iOS本地化,重构后端输出模型

This commit is contained in:
qzl
2026-04-29 14:26:15 +08:00
parent f497afbff2
commit 16cb47e75a
39 changed files with 1346 additions and 600 deletions
@@ -207,8 +207,6 @@ class _DivinationResultScreenState extends State<DivinationResultScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_ResultHeader(data: widget.data),
const SizedBox(height: AppSpacing.md),
_SignCard(
key: _finalSignCardKey,
signType: widget.data.signType,
@@ -221,17 +219,17 @@ class _DivinationResultScreenState extends State<DivinationResultScreen> {
content: widget.data.conclusion,
),
const SizedBox(height: AppSpacing.md),
_FocusPointsCard(points: widget.data.focusPoints),
_AnalysisCard(
title: l10n.resultSuggestion,
content: widget.data.suggestion,
),
const SizedBox(height: AppSpacing.md),
_AnalysisCard(
title: l10n.resultAnalysis,
content: widget.data.analysis,
),
const SizedBox(height: AppSpacing.md),
_AnalysisCard(
title: l10n.resultSuggestion,
content: widget.data.suggestion,
),
_FocusPointsCard(points: widget.data.focusPoints),
const SizedBox(height: AppSpacing.md),
Container(
width: double.infinity,
@@ -270,13 +268,16 @@ class _DivinationResultScreenState extends State<DivinationResultScreen> {
),
const SizedBox(height: AppSpacing.md),
_InfoCard(data: widget.data),
const SizedBox(height: AppSpacing.xl),
Text(
l10n.resultHexagramDetail,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: AppSpacing.md),
_HexagramDetailCard(data: widget.data),
if (widget.data.isSuccess) ...[
const SizedBox(height: AppSpacing.xl),
Text(
l10n.resultHexagramDetail,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: AppSpacing.md),
_HexagramDetailCard(data: widget.data),
] else
_HexagramDetailPlaceholder(status: widget.data.status),
],
),
),
@@ -412,27 +413,6 @@ class _DivinationResultScreenState extends State<DivinationResultScreen> {
}
}
class _ResultHeader extends StatelessWidget {
const _ResultHeader({required this.data});
final DivinationResultData data;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Row(
children: [
Text(
l10n.resultAIAnalysis,
style: Theme.of(
context,
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w700),
),
],
);
}
}
class _SignCard extends StatelessWidget {
const _SignCard({super.key, required this.signType});
@@ -543,8 +523,7 @@ class _FocusPointsCard extends StatelessWidget {
Widget build(BuildContext context) {
final colors = Theme.of(context).colorScheme;
final l10n = AppLocalizations.of(context)!;
final languageCode = Localizations.localeOf(context).languageCode;
final title = languageCode == 'en' ? 'Focus Points' : '断卦要点';
final title = l10n.resultFocusPoints;
if (points.isEmpty) {
return const SizedBox.shrink();
}
@@ -572,11 +551,7 @@ class _FocusPointsCard extends StatelessWidget {
const Spacer(),
TextButton(
onPressed: () {
final content = points
.asMap()
.entries
.map((e) => '${e.key + 1}. ${e.value}')
.join('\n');
final content = points.join('\n');
Clipboard.setData(ClipboardData(text: content));
Toast.show(
context,
@@ -589,28 +564,12 @@ class _FocusPointsCard extends StatelessWidget {
],
),
const SizedBox(height: AppSpacing.sm),
...List<Widget>.generate(points.length, (index) {
...points.map((point) {
return Padding(
padding: const EdgeInsets.only(bottom: AppSpacing.xs),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${index + 1}. ',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: colors.primary,
fontWeight: FontWeight.w700,
),
),
Expanded(
child: Text(
points[index],
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(height: 1.55),
),
),
],
child: Text(
point,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(height: 1.55),
),
);
}),
@@ -781,6 +740,46 @@ class _InfoCard extends StatelessWidget {
}
}
class _HexagramDetailPlaceholder extends StatelessWidget {
const _HexagramDetailPlaceholder({required this.status});
final DivinationRunStatus status;
@override
Widget build(BuildContext context) {
final colors = Theme.of(context).colorScheme;
final l10n = AppLocalizations.of(context)!;
final message = switch (status) {
DivinationRunStatus.failed => l10n.resultHexagramDetailFailed,
DivinationRunStatus.refused => l10n.resultHexagramDetailRefused,
DivinationRunStatus.success => '',
};
return Padding(
padding: const EdgeInsets.only(top: AppSpacing.xl),
child: Card(
margin: EdgeInsets.zero,
color: colors.surfaceContainerHighest,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.md),
),
child: Padding(
padding: const EdgeInsets.all(AppSpacing.xl),
child: Center(
child: Text(
message,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: colors.onSurfaceVariant,
),
),
),
),
),
);
}
}
class _HexagramDetailCard extends StatelessWidget {
const _HexagramDetailCard({required this.data});