feat: 添加日历批量操作与客户端时区感知功能,优化前端 UI 交互体验
This commit is contained in:
@@ -41,7 +41,9 @@ const _transcribingStrokeWidth = 2.0;
|
||||
const _attachmentPreviewSize = 88.0;
|
||||
const _attachmentPreviewRadius = 10.0;
|
||||
const _attachmentPreviewGap = 8.0;
|
||||
const _bottomStackReservedHeight = 140.0;
|
||||
const _bottomStackReservedHeight = 116.0;
|
||||
const _toolResultWidthFactor = 0.9;
|
||||
const _pullRefreshMinVisibleMs = 450;
|
||||
|
||||
const homeConversationStageKey = ValueKey('home_conversation_stage');
|
||||
const homeBottomInputStackKey = ValueKey('home_bottom_input_stack');
|
||||
@@ -92,7 +94,7 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
late final Future<void> Function(String transcript) _autoSendTranscript;
|
||||
late final AnimationController _listeningAnimationController;
|
||||
bool _isRecording = false;
|
||||
bool _isHoldToSpeakMode = false;
|
||||
bool _isHoldToSpeakMode = true;
|
||||
bool _isTranscribing = false;
|
||||
bool _isCancelGestureActive = false;
|
||||
bool _isSendingMessage = false;
|
||||
@@ -356,12 +358,29 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
if (_isPullRefreshing) {
|
||||
return;
|
||||
}
|
||||
final chatBloc = context.read<ChatBloc>();
|
||||
if (chatBloc.state.isLoadingHistory) {
|
||||
return;
|
||||
}
|
||||
final hasEarlierHistory = chatBloc.state.hasEarlierHistory;
|
||||
if (mounted) {
|
||||
setState(() => _isPullRefreshing = true);
|
||||
}
|
||||
final startedAt = DateTime.now();
|
||||
try {
|
||||
await context.read<ChatBloc>().loadMoreHistory();
|
||||
if (hasEarlierHistory) {
|
||||
await chatBloc.loadMoreHistory();
|
||||
} else {
|
||||
Toast.show(context, '没有更早的历史记录了', type: ToastType.info);
|
||||
}
|
||||
} finally {
|
||||
final elapsed = DateTime.now().difference(startedAt);
|
||||
final minDuration = const Duration(
|
||||
milliseconds: _pullRefreshMinVisibleMs,
|
||||
);
|
||||
if (elapsed < minDuration) {
|
||||
await Future.delayed(minDuration - elapsed);
|
||||
}
|
||||
if (mounted) {
|
||||
setState(() => _isPullRefreshing = false);
|
||||
}
|
||||
@@ -585,7 +604,32 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
}
|
||||
|
||||
Widget _buildToolResultItem(ToolResultItem item) {
|
||||
return UiSchemaRenderer.renderSchema(item.uiSchema);
|
||||
final rootNode = item.uiSchema['root'];
|
||||
final appearance = rootNode is Map<String, dynamic>
|
||||
? rootNode['appearance'] as String?
|
||||
: null;
|
||||
final needsOuterCard = appearance == null || appearance == 'plain';
|
||||
final schemaContent = UiSchemaRenderer.renderSchema(item.uiSchema);
|
||||
final wrappedContent = needsOuterCard
|
||||
? Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(AppSpacing.md),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.white,
|
||||
borderRadius: BorderRadius.circular(AppRadius.lg),
|
||||
border: Border.all(color: AppColors.homeConversationBorder),
|
||||
),
|
||||
child: schemaContent,
|
||||
)
|
||||
: schemaContent;
|
||||
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: _toolResultWidthFactor,
|
||||
child: wrappedContent,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBottomInputStack(BuildContext context, ChatState state) {
|
||||
@@ -733,8 +777,7 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
}
|
||||
|
||||
void _onHoldToSpeakStart() {
|
||||
HapticFeedback.heavyImpact();
|
||||
HapticFeedback.vibrate();
|
||||
HapticFeedback.selectionClick();
|
||||
setState(() {
|
||||
_isCancelGestureActive = false;
|
||||
});
|
||||
@@ -747,7 +790,7 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
_cancelRecording(showToast: false);
|
||||
return;
|
||||
}
|
||||
HapticFeedback.mediumImpact();
|
||||
HapticFeedback.selectionClick();
|
||||
_stopRecording(autoSendAfterTranscribe: true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user