diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 4c64b100..61aa7d61 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -1290,5 +1290,14 @@ "purchase": "Purchase", "multiplierLabel": "Multiplier", "specialOnly": "Special Only", - "matches": "Matches" + "matches": "Matches", + "thoughtDefaultTopic": "Reflection", + "thoughtAiName": "SN-chan", + "thoughtUserName": "You", + "thoughtStreamingHint": "Sn-chan is thinking...", + "thoughtInputHint": "Ask sn-chan anything...", + "thoughtNewConversation": "Start New Conversation", + "thoughtParseError": "Failed to parse AI response", + "aiThought": "AI Thought", + "aiThoughtTitle": "Let sn-chan think" } diff --git a/assets/i18n/zh-CN.json b/assets/i18n/zh-CN.json index 4b35e5b7..980013ed 100644 --- a/assets/i18n/zh-CN.json +++ b/assets/i18n/zh-CN.json @@ -1081,5 +1081,14 @@ "postPublish": "发布帖子", "restoreDraftTitle": "恢复草稿", "restoreDraftMessage": "发现了一个草稿。你想要恢复它吗?", - "draft": "草稿" + "draft": "草稿", + "thoughtDefaultTopic": "寻思", + "thoughtAiName": "SN 酱", + "thoughtUserName": "您", + "thoughtStreamingHint": "Sn-chan 正在思考...", + "thoughtInputHint": "问 sn-chan 任何问题...", + "thoughtNewConversation": "开始新对话", + "thoughtParseError": "解析 AI 响应失败", + "aiThought": "寻思", + "aiThoughtTitle": "让 SN 酱寻思寻思" } diff --git a/lib/screens/tabs.dart b/lib/screens/tabs.dart index 02104d4d..21185143 100644 --- a/lib/screens/tabs.dart +++ b/lib/screens/tabs.dart @@ -173,7 +173,7 @@ class TabsScreen extends HookConsumerWidget { horizontal: 24, ), leading: const Icon(Symbols.bubble_chart), - title: Text('让 SN 酱寻思寻思'), + title: Text('aiThoughtTitle'.tr()), onTap: () async { Navigator.of(context).pop(); context.pushNamed('thought'); diff --git a/lib/screens/thought/think.dart b/lib/screens/thought/think.dart index 839ce0f7..d70c40e4 100644 --- a/lib/screens/thought/think.dart +++ b/lib/screens/thought/think.dart @@ -1,6 +1,7 @@ import "dart:async"; import "dart:convert"; import "package:dio/dio.dart"; +import "package:easy_localization/easy_localization.dart"; import "package:flutter/material.dart"; import "package:flutter_hooks/flutter_hooks.dart"; import "package:gap/gap.dart"; @@ -43,7 +44,7 @@ class ThoughtScreen extends HookConsumerWidget { : const AsyncValue>.data([]); final localThoughts = useState>([]); - final currentTopic = useState('寻思'); + final currentTopic = useState('aiThought'.tr()); final messageController = useTextEditingController(); final scrollController = useScrollController(); @@ -61,7 +62,7 @@ class ThoughtScreen extends HookConsumerWidget { if (data.isNotEmpty && data.first.sequence?.topic != null) { currentTopic.value = data.first.sequence!.topic; } else { - currentTopic.value = '寻思'; + currentTopic.value = 'aiThought'.tr(); } }); return null; @@ -186,7 +187,7 @@ class ThoughtScreen extends HookConsumerWidget { currentTopic.value = topic; } } catch (e) { - showErrorAlert('Failed to parse AI response'); + showErrorAlert('thoughtParseError'.tr()); } }, onError: (error) { @@ -195,7 +196,7 @@ class ThoughtScreen extends HookConsumerWidget { // Handle streaming response errors differently if (error is DioException && error.response?.data is ResponseBody) { // For streaming responses, show a generic error message - showErrorAlert('Failed to get AI response. Please try again.'); + showErrorAlert('toughtParseError'.tr()); } else { showErrorAlert(error); } @@ -243,8 +244,8 @@ class ThoughtScreen extends HookConsumerWidget { children: [ Text( thought.role == ThinkingThoughtRole.assistant - ? 'SN 酱' - : '您', + ? 'toughtAiName'.tr() + : 'thoughtUserName'.tr(), style: Theme.of(context).textTheme.titleSmall, ), Tooltip( @@ -309,7 +310,10 @@ class ThoughtScreen extends HookConsumerWidget { children: [ Icon(Symbols.smart_toy, size: 20), const Gap(8), - Text('SN 酱', style: Theme.of(context).textTheme.titleSmall), + Text( + 'thoughtAiName'.tr(), + style: Theme.of(context).textTheme.titleSmall, + ), const Spacer(), SizedBox( width: 16, @@ -327,27 +331,9 @@ class ThoughtScreen extends HookConsumerWidget { ), ); - Widget newConversationButton() => Container( - margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), - child: FilledButton.icon( - onPressed: () { - // Clear current conversation and start new one - selectedSequenceId.value = null; - localThoughts.value = []; - currentTopic.value = '寻思'; - messageController.clear(); - }, - icon: const Icon(Symbols.add), - label: const Text('开始新对话'), - style: FilledButton.styleFrom( - minimumSize: const Size(double.infinity, 48), - ), - ), - ); - return AppScaffold( appBar: AppBar( - title: Text(currentTopic.value ?? '寻思'), + title: Text(currentTopic.value ?? 'aiThought'.tr()), actions: [ IconButton( icon: const Icon(Symbols.history), @@ -364,29 +350,25 @@ class ThoughtScreen extends HookConsumerWidget { ); }, ), + if (localThoughts.value.isNotEmpty && + !isStreaming.value && + localThoughts.value.last.role == ThinkingThoughtRole.assistant) + IconButton( + icon: const Icon(Symbols.add), + tooltip: 'thoughtNewConversation'.tr(), + onPressed: () { + // Clear current conversation and start new one + selectedSequenceId.value = null; + localThoughts.value = []; + currentTopic.value = 'aiThought'.tr(); + messageController.clear(); + }, + ), const Gap(8), ], ), body: Column( children: [ - // New conversation button - only show when there are messages and last is AI - AnimatedOpacity( - opacity: - (localThoughts.value.isNotEmpty && - localThoughts.value.last.role == - ThinkingThoughtRole.assistant && - !isStreaming.value) - ? 1.0 - : 0.0, - duration: const Duration(milliseconds: 300), - child: - (localThoughts.value.isNotEmpty && - localThoughts.value.last.role == - ThinkingThoughtRole.assistant && - !isStreaming.value) - ? newConversationButton() - : const SizedBox.shrink(), - ), Expanded( child: thoughts.when( data: @@ -447,8 +429,8 @@ class ThoughtScreen extends HookConsumerWidget { decoration: InputDecoration( hintText: isStreaming.value - ? 'Sn-chan is thinking...' - : 'Ask sn-chan anything...', + ? 'thoughtStreamingHint'.tr() + : 'thoughtInputHint'.tr(), border: InputBorder.none, isDense: true, contentPadding: const EdgeInsets.symmetric(