opt.: add a btn to minimize ai dialog (#1004)

* opt.: add a btn to minimize ai dialog
Fixes #1003

* opt.

* opt.
This commit is contained in:
lollipopkit🏳️‍⚧️
2026-01-14 15:15:33 +08:00
committed by GitHub
parent 7693e30cbf
commit 8589b3b4d7

View File

@@ -84,6 +84,7 @@ class _AskAiSheetState extends ConsumerState<_AskAiSheet> {
String? _streamingContent; String? _streamingContent;
String? _error; String? _error;
bool _isStreaming = false; bool _isStreaming = false;
bool _isMinimized = false;
@override @override
void initState() { void initState() {
@@ -387,12 +388,23 @@ class _AskAiSheetState extends ConsumerState<_AskAiSheet> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final bottomPadding = MediaQuery.viewInsetsOf(context).bottom; final bottomPadding = MediaQuery.viewInsetsOf(context).bottom;
final heightFactor = _isMinimized ? 0.18 : 0.85;
return FractionallySizedBox( return TweenAnimationBuilder<double>(
heightFactor: 0.85, tween: Tween<double>(end: heightFactor),
duration: const Duration(milliseconds: 200),
curve: Curves.easeOutCubic,
builder: (context, animatedHeightFactor, child) {
return ClipRect(
child: FractionallySizedBox(
heightFactor: animatedHeightFactor,
child: child,
),
);
},
child: SafeArea( child: SafeArea(
child: Column( child: Column(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0), padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
child: Row( child: Row(
@@ -402,83 +414,96 @@ class _AskAiSheetState extends ConsumerState<_AskAiSheet> {
if (_isStreaming) if (_isStreaming)
const SizedBox(height: 16, width: 16, child: CircularProgressIndicator(strokeWidth: 2)), const SizedBox(height: 16, width: 16, child: CircularProgressIndicator(strokeWidth: 2)),
const Spacer(), const Spacer(),
IconButton(
icon: Icon(_isMinimized ? Icons.unfold_more : Icons.unfold_less),
tooltip: libL10n.fold,
onPressed: () {
FocusManager.instance.primaryFocus?.unfocus();
setState(() {
_isMinimized = !_isMinimized;
});
},
),
IconButton(icon: const Icon(Icons.close), onPressed: () => Navigator.of(context).pop()), IconButton(icon: const Icon(Icons.close), onPressed: () => Navigator.of(context).pop()),
], ],
), ),
), ),
Expanded( if (!_isMinimized) ...[
child: Scrollbar( Expanded(
controller: _scrollController, child: Scrollbar(
child: ListView(
controller: _scrollController, controller: _scrollController,
padding: const EdgeInsets.fromLTRB(16, 12, 16, 12), child: ListView(
children: [ controller: _scrollController,
Text(context.l10n.askAiSelectedContent, style: theme.textTheme.titleMedium), padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
const SizedBox(height: 6), children: [
CardX( Text(context.l10n.askAiSelectedContent, style: theme.textTheme.titleMedium),
child: Padding( const SizedBox(height: 6),
padding: const EdgeInsets.all(12),
child: SelectableText(
widget.selection,
style: const TextStyle(fontFamily: 'monospace'),
),
),
),
const SizedBox(height: 16),
Text(context.l10n.askAiConversation, style: theme.textTheme.titleMedium),
const SizedBox(height: 6),
..._buildConversationWidgets(context, theme),
if (_error != null) ...[
const SizedBox(height: 16),
CardX( CardX(
child: Padding( child: Padding(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Text(_error!, style: TextStyle(color: theme.colorScheme.error)), child: SelectableText(
widget.selection,
style: const TextStyle(fontFamily: 'monospace'),
),
), ),
), ),
const SizedBox(height: 16),
Text(context.l10n.askAiConversation, style: theme.textTheme.titleMedium),
const SizedBox(height: 6),
..._buildConversationWidgets(context, theme),
if (_error != null) ...[
const SizedBox(height: 16),
CardX(
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(_error!, style: TextStyle(color: theme.colorScheme.error)),
),
),
],
if (_isStreaming) ...[const SizedBox(height: 16), const LinearProgressIndicator()],
const SizedBox(height: 16),
], ],
if (_isStreaming) ...[const SizedBox(height: 16), const LinearProgressIndicator()], ),
const SizedBox(height: 16),
],
), ),
), ),
), Padding(
Padding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), child: Text(
child: Text( context.l10n.askAiDisclaimer,
context.l10n.askAiDisclaimer, style: theme.textTheme.bodySmall?.copyWith(
style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.error,
color: theme.colorScheme.error, fontWeight: FontWeight.bold,
fontWeight: FontWeight.bold, ),
), textAlign: TextAlign.center,
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.fromLTRB(16, 8, 16, 16 + bottomPadding),
child: Row(
children: [
Expanded(
child: Input(
controller: _inputController,
minLines: 1,
maxLines: 4,
hint: context.l10n.askAiFollowUpHint,
action: TextInputAction.send,
onSubmitted: (_) => _sendMessage(),
),
),
const SizedBox(width: 12),
Btn.icon(
onTap: _isStreaming || _inputController.text.trim().isEmpty ? null : _sendMessage,
icon: const Icon(Icons.send, size: 18),
), ),
),
Padding(
padding: EdgeInsets.fromLTRB(16, 8, 16, 16 + bottomPadding),
child: Row(
children: [
Expanded(
child: Input(
controller: _inputController,
minLines: 1,
maxLines: 4,
hint: context.l10n.askAiFollowUpHint,
action: TextInputAction.send,
onSubmitted: (_) => _sendMessage(),
),
),
const SizedBox(width: 12),
Btn.icon(
onTap: _isStreaming || _inputController.text.trim().isEmpty ? null : _sendMessage,
icon: const Icon(Icons.send, size: 18),
),
],
).cardx,
),
] else
const SizedBox(height: 8),
], ],
).cardx, ),
), ),
],
),
),
); );
} }
} }