Merge branch 'codex/web-bottom-console-controls'
This commit is contained in:
commit
472173425f
@ -44,6 +44,7 @@ class _WebAssistantPageState extends State<WebAssistantPage> {
|
||||
AssistantPermissionLevel _permissionLevel =
|
||||
AssistantPermissionLevel.defaultAccess;
|
||||
bool _useMultiAgent = false;
|
||||
bool _workspaceChromeCollapsed = false;
|
||||
bool _sidePaneCollapsed = false;
|
||||
double _sidePaneWidth = 344;
|
||||
double _composerHeight = 196;
|
||||
@ -64,7 +65,6 @@ class _WebAssistantPageState extends State<WebAssistantPage> {
|
||||
return AnimatedBuilder(
|
||||
animation: controller,
|
||||
builder: (context, _) {
|
||||
final uiFeatures = controller.featuresFor(UiFeaturePlatform.web);
|
||||
final currentMessages = controller.chatMessages;
|
||||
final connectionState = controller.currentAssistantConnectionState;
|
||||
|
||||
@ -99,8 +99,12 @@ class _WebAssistantPageState extends State<WebAssistantPage> {
|
||||
children: [
|
||||
_AssistantWorkspaceChrome(
|
||||
controller: controller,
|
||||
currentTarget: controller.assistantExecutionTarget,
|
||||
availableTargets: uiFeatures.availableExecutionTargets,
|
||||
collapsed: _workspaceChromeCollapsed,
|
||||
onToggleCollapsed: () {
|
||||
setState(() {
|
||||
_workspaceChromeCollapsed = !_workspaceChromeCollapsed;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
@ -193,6 +197,7 @@ class _WebAssistantPageState extends State<WebAssistantPage> {
|
||||
onRemoveAttachment: (index) {
|
||||
setState(() => _attachments.removeAt(index));
|
||||
},
|
||||
onOpenSessionSettings: _openSessionSettings,
|
||||
onSubmit: _submitPrompt,
|
||||
),
|
||||
),
|
||||
@ -208,6 +213,30 @@ class _WebAssistantPageState extends State<WebAssistantPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openSessionSettings() async {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
showDragHandle: true,
|
||||
builder: (context) {
|
||||
return _AssistantSessionSettingsSheet(
|
||||
controller: widget.controller,
|
||||
thinkingLevel: _thinkingLevel,
|
||||
permissionLevel: _permissionLevel,
|
||||
onThinkingChanged: (value) {
|
||||
setState(() => _thinkingLevel = value);
|
||||
},
|
||||
onPermissionChanged: (value) {
|
||||
setState(() => _permissionLevel = value);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openConversationActions(String sessionKey) async {
|
||||
final controller = widget.controller;
|
||||
if (!mounted) {
|
||||
@ -410,77 +439,89 @@ class _WebAssistantPageState extends State<WebAssistantPage> {
|
||||
class _AssistantWorkspaceChrome extends StatelessWidget {
|
||||
const _AssistantWorkspaceChrome({
|
||||
required this.controller,
|
||||
required this.currentTarget,
|
||||
required this.availableTargets,
|
||||
required this.collapsed,
|
||||
required this.onToggleCollapsed,
|
||||
});
|
||||
|
||||
final AppController controller;
|
||||
final AssistantExecutionTarget currentTarget;
|
||||
final List<AssistantExecutionTarget> availableTargets;
|
||||
final bool collapsed;
|
||||
final VoidCallback onToggleCollapsed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SurfaceCard(
|
||||
tone: SurfaceCardTone.chrome,
|
||||
borderRadius: 10,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
_ChromePill(
|
||||
icon: Icons.home_rounded,
|
||||
label: appText('主页', 'Home'),
|
||||
),
|
||||
_ChromePill(
|
||||
label: WorkspaceDestination.assistant.label,
|
||||
emphasized: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
FilledButton.icon(
|
||||
onPressed: () => controller.createConversation(
|
||||
target: controller.assistantExecutionTarget,
|
||||
),
|
||||
icon: const Icon(Icons.edit_square),
|
||||
label: Text(appText('新对话', 'New conversation')),
|
||||
child: AnimatedSize(
|
||||
duration: const Duration(milliseconds: 180),
|
||||
curve: Curves.easeOutCubic,
|
||||
child: collapsed
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _ChromePill(
|
||||
label: WorkspaceDestination.assistant.label,
|
||||
emphasized: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
key: const Key('assistant-workspace-chrome-toggle'),
|
||||
tooltip: appText('展开顶部导航', 'Expand top navigation'),
|
||||
onPressed: onToggleCollapsed,
|
||||
icon: const Icon(Icons.keyboard_arrow_down_rounded),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
_ChromePill(
|
||||
icon: Icons.home_rounded,
|
||||
label: appText('主页', 'Home'),
|
||||
),
|
||||
_ChromePill(
|
||||
label: WorkspaceDestination.assistant.label,
|
||||
emphasized: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
FilledButton.icon(
|
||||
onPressed: () => controller.createConversation(
|
||||
target: controller.assistantExecutionTarget,
|
||||
),
|
||||
icon: const Icon(Icons.edit_square),
|
||||
label: Text(appText('新对话', 'New conversation')),
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () =>
|
||||
controller.openSettings(tab: SettingsTab.gateway),
|
||||
icon: const Icon(Icons.tune_rounded),
|
||||
label: Text(
|
||||
appText('连接设置', 'Connection settings'),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
key: const Key('assistant-workspace-chrome-toggle'),
|
||||
tooltip: appText('折叠顶部导航', 'Collapse top navigation'),
|
||||
onPressed: onToggleCollapsed,
|
||||
icon: const Icon(Icons.keyboard_arrow_up_rounded),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () =>
|
||||
controller.openSettings(tab: SettingsTab.gateway),
|
||||
icon: const Icon(Icons.tune_rounded),
|
||||
label: Text(appText('连接设置', 'Connection settings')),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: context.palette.surfacePrimary,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
border: Border.all(color: context.palette.strokeSoft),
|
||||
),
|
||||
child: _CompactDropdown<AssistantExecutionTarget>(
|
||||
key: const Key('assistant-top-target-button'),
|
||||
value: currentTarget,
|
||||
items: availableTargets,
|
||||
labelBuilder: _targetLabel,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.setAssistantExecutionTarget(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -1309,6 +1350,7 @@ class _ConversationWorkspace extends StatelessWidget {
|
||||
required this.onToggleMultiAgent,
|
||||
required this.onAddAttachment,
|
||||
required this.onRemoveAttachment,
|
||||
required this.onOpenSessionSettings,
|
||||
required this.onSubmit,
|
||||
});
|
||||
|
||||
@ -1328,6 +1370,7 @@ class _ConversationWorkspace extends StatelessWidget {
|
||||
final ValueChanged<bool> onToggleMultiAgent;
|
||||
final Future<void> Function() onAddAttachment;
|
||||
final ValueChanged<int> onRemoveAttachment;
|
||||
final Future<void> Function() onOpenSessionSettings;
|
||||
final Future<void> Function() onSubmit;
|
||||
|
||||
@override
|
||||
@ -1336,7 +1379,6 @@ class _ConversationWorkspace extends StatelessWidget {
|
||||
builder: (context, constraints) {
|
||||
final palette = context.palette;
|
||||
final currentTarget = controller.assistantExecutionTarget;
|
||||
final modelChoices = controller.assistantModelChoices;
|
||||
final connected = connectionState.ready;
|
||||
final maxComposerHeight = math.max(
|
||||
_webAssistantComposerMinHeight,
|
||||
@ -1385,97 +1427,6 @@ class _ConversationWorkspace extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
_HeaderDropdownShell(
|
||||
child: _CompactDropdown<AssistantExecutionTarget>(
|
||||
key: const Key('assistant-target-button'),
|
||||
value: currentTarget,
|
||||
items: controller
|
||||
.featuresFor(UiFeaturePlatform.web)
|
||||
.availableExecutionTargets,
|
||||
labelBuilder: _targetLabel,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.setAssistantExecutionTarget(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
if (currentTarget == AssistantExecutionTarget.singleAgent)
|
||||
_HeaderDropdownShell(
|
||||
child: _CompactDropdown<SingleAgentProvider>(
|
||||
key: const Key(
|
||||
'assistant-single-agent-provider-button',
|
||||
),
|
||||
value: controller.currentSingleAgentProvider,
|
||||
items: controller.singleAgentProviderOptions,
|
||||
labelBuilder: (item) => item.label,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.setSingleAgentProvider(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
if (modelChoices.isNotEmpty)
|
||||
_HeaderDropdownShell(
|
||||
child: _CompactDropdown<String>(
|
||||
key: const Key('assistant-model-button'),
|
||||
value: controller.resolvedAssistantModel,
|
||||
items: modelChoices,
|
||||
labelBuilder: (item) => item,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.selectAssistantModel(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
_HeaderDropdownShell(
|
||||
child: _CompactDropdown<AssistantMessageViewMode>(
|
||||
key: const Key('assistant-message-view-mode-button'),
|
||||
value: controller.currentAssistantMessageViewMode,
|
||||
items: AssistantMessageViewMode.values,
|
||||
labelBuilder: (item) => item.label,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.setAssistantMessageViewMode(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
_HeaderDropdownShell(
|
||||
child: _CompactDropdown<String>(
|
||||
key: const Key('assistant-thinking-button'),
|
||||
value: thinkingLevel,
|
||||
items: const <String>['low', 'medium', 'high'],
|
||||
labelBuilder: _thinkingLabel,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onThinkingChanged(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
_HeaderDropdownShell(
|
||||
child: _CompactDropdown<AssistantPermissionLevel>(
|
||||
key: const Key('assistant-permission-button'),
|
||||
value: permissionLevel,
|
||||
items: AssistantPermissionLevel.values,
|
||||
labelBuilder: (item) => item.label,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onPermissionChanged(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -1636,6 +1587,14 @@ class _ConversationWorkspace extends StatelessWidget {
|
||||
runSpacing: 10,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
OutlinedButton.icon(
|
||||
key: const Key('assistant-session-settings-button'),
|
||||
onPressed: onOpenSessionSettings,
|
||||
icon: const Icon(Icons.tune_rounded),
|
||||
label: Text(
|
||||
appText('会话设置', 'Session settings'),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@ -1699,6 +1658,201 @@ class _ConversationWorkspace extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _AssistantSessionSettingsSheet extends StatefulWidget {
|
||||
const _AssistantSessionSettingsSheet({
|
||||
required this.controller,
|
||||
required this.thinkingLevel,
|
||||
required this.permissionLevel,
|
||||
required this.onThinkingChanged,
|
||||
required this.onPermissionChanged,
|
||||
});
|
||||
|
||||
final AppController controller;
|
||||
final String thinkingLevel;
|
||||
final AssistantPermissionLevel permissionLevel;
|
||||
final ValueChanged<String> onThinkingChanged;
|
||||
final ValueChanged<AssistantPermissionLevel> onPermissionChanged;
|
||||
|
||||
@override
|
||||
State<_AssistantSessionSettingsSheet> createState() =>
|
||||
_AssistantSessionSettingsSheetState();
|
||||
}
|
||||
|
||||
class _AssistantSessionSettingsSheetState
|
||||
extends State<_AssistantSessionSettingsSheet> {
|
||||
late String _thinkingLevel = widget.thinkingLevel;
|
||||
late AssistantPermissionLevel _permissionLevel = widget.permissionLevel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final palette = context.palette;
|
||||
return AnimatedBuilder(
|
||||
animation: widget.controller,
|
||||
builder: (context, _) {
|
||||
final controller = widget.controller;
|
||||
final currentTarget = controller.assistantExecutionTarget;
|
||||
final modelChoices = controller.assistantModelChoices;
|
||||
return SafeArea(
|
||||
top: false,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
16,
|
||||
0,
|
||||
16,
|
||||
MediaQuery.of(context).viewInsets.bottom + 16,
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
appText('会话设置', 'Session settings'),
|
||||
key: const Key('assistant-session-settings-sheet-title'),
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
appText(
|
||||
'线程模式、渲染方式和执行参数统一放到底部对话框管理。',
|
||||
'Manage thread mode, rendering, and execution parameters from this bottom sheet.',
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: palette.textSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_SessionSettingField(
|
||||
label: appText('执行目标', 'Execution target'),
|
||||
child: _HeaderDropdownShell(
|
||||
child: _CompactDropdown<AssistantExecutionTarget>(
|
||||
key: const Key('assistant-target-button'),
|
||||
value: currentTarget,
|
||||
items: controller
|
||||
.featuresFor(UiFeaturePlatform.web)
|
||||
.availableExecutionTargets,
|
||||
labelBuilder: _targetLabel,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.setAssistantExecutionTarget(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
if (currentTarget == AssistantExecutionTarget.singleAgent)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: _SessionSettingField(
|
||||
label: appText('Provider', 'Provider'),
|
||||
child: _HeaderDropdownShell(
|
||||
child: _CompactDropdown<SingleAgentProvider>(
|
||||
key: const Key(
|
||||
'assistant-single-agent-provider-button',
|
||||
),
|
||||
value: controller.currentSingleAgentProvider,
|
||||
items: controller.singleAgentProviderOptions,
|
||||
labelBuilder: (item) => item.label,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.setSingleAgentProvider(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (modelChoices.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: _SessionSettingField(
|
||||
label: appText('模型', 'Model'),
|
||||
child: _HeaderDropdownShell(
|
||||
child: _CompactDropdown<String>(
|
||||
key: const Key('assistant-model-button'),
|
||||
value: controller.resolvedAssistantModel,
|
||||
items: modelChoices,
|
||||
labelBuilder: (item) => item,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.selectAssistantModel(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: _SessionSettingField(
|
||||
label: appText('消息视图', 'Message view'),
|
||||
child: _HeaderDropdownShell(
|
||||
child: _CompactDropdown<AssistantMessageViewMode>(
|
||||
key: const Key('assistant-message-view-mode-button'),
|
||||
value: controller.currentAssistantMessageViewMode,
|
||||
items: AssistantMessageViewMode.values,
|
||||
labelBuilder: (item) => item.label,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
controller.setAssistantMessageViewMode(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: _SessionSettingField(
|
||||
label: appText('思考强度', 'Thinking level'),
|
||||
child: _HeaderDropdownShell(
|
||||
child: _CompactDropdown<String>(
|
||||
key: const Key('assistant-thinking-button'),
|
||||
value: _thinkingLevel,
|
||||
items: const <String>['low', 'medium', 'high'],
|
||||
labelBuilder: _thinkingLabel,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
setState(() => _thinkingLevel = value);
|
||||
widget.onThinkingChanged(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: _SessionSettingField(
|
||||
label: appText('权限', 'Permissions'),
|
||||
child: _HeaderDropdownShell(
|
||||
child: _CompactDropdown<AssistantPermissionLevel>(
|
||||
key: const Key('assistant-permission-button'),
|
||||
value: _permissionLevel,
|
||||
items: AssistantPermissionLevel.values,
|
||||
labelBuilder: (item) => item.label,
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
setState(() => _permissionLevel = value);
|
||||
widget.onPermissionChanged(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ConversationEmptyState extends StatelessWidget {
|
||||
const _ConversationEmptyState({required this.controller});
|
||||
|
||||
@ -1927,6 +2081,30 @@ class _HeaderDropdownShell extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _SessionSettingField extends StatelessWidget {
|
||||
const _SessionSettingField({required this.label, required this.child});
|
||||
|
||||
final String label;
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w700),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
child,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MetaChip extends StatelessWidget {
|
||||
const _MetaChip({required this.icon, required this.label});
|
||||
|
||||
|
||||
@ -27,12 +27,53 @@ void main() {
|
||||
expect(find.byKey(const Key('web-shell-theme-toggle')), findsNothing);
|
||||
expect(find.text('Tasks'), findsNothing);
|
||||
expect(find.byKey(const Key('assistant-task-rail')), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('assistant-workspace-chrome-toggle')),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(
|
||||
find.byKey(const Key('assistant-session-settings-button')),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(const Key('assistant-top-target-button')), findsNothing);
|
||||
expect(find.byKey(const Key('assistant-target-button')), findsNothing);
|
||||
expect(
|
||||
find.byKey(const Key('assistant-attachment-menu-button')),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(const Key('assistant-focus-panel-title')), findsNothing);
|
||||
|
||||
await tester.tap(find.byKey(const Key('assistant-workspace-chrome-toggle')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('连接设置'), findsNothing);
|
||||
|
||||
await tester.tap(find.byKey(const Key('assistant-workspace-chrome-toggle')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('连接设置'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(const Key('assistant-session-settings-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.byKey(const Key('assistant-session-settings-sheet-title')),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(const Key('assistant-target-button')), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('assistant-message-view-mode-button')),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(const Key('assistant-thinking-button')), findsOneWidget);
|
||||
expect(
|
||||
find.byKey(const Key('assistant-permission-button')),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
await tester.tapAt(const Offset(24, 24));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key('assistant-side-pane-tab-quick')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user