feat(learn): the assistant's field spans the screen, its buttons boxed and still as who answers changes
Following the developer's review of 3 Nov 2026 (ADR 0021, D67): - Unfolded in the Library, the field spans the screen between its margins, as on Home and a studyset: it fell short on the right, by the padding around the two folded buttons, which now stands only around those. - Who answers stands right before the buttons at the right, which no longer shift as its name changes (Claude Haiku, Claude Opus): it fills the space left, aligned to its end, rather than a share of it. - Every button of the field and of a conversation's follow-up is boxed, a tile a shade above the field with rounded corners, as Claude's apps have them; who answers too. - On a studyset with a licence, the unfolded field takes its usual place over the licence's line rather than squeezing in above it; folded, its row still keeps clear of the line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
55fc245859
commit
96b1a0fc64
2 changed files with 209 additions and 64 deletions
|
|
@ -465,6 +465,53 @@ void main() {
|
|||
debugDefaultTargetPlatformOverride = null;
|
||||
});
|
||||
|
||||
for (final (where, location) in [
|
||||
('Home', RoutePaths.home),
|
||||
('the Library', RoutePaths.library),
|
||||
('a studyset', RoutePaths.studyset('japanese')),
|
||||
]) {
|
||||
testWidgets('unfolded on $where, the field spans the width between the '
|
||||
"screen's margins, as wide on the right as on the left (the "
|
||||
"developer's review of 3 Nov 2026)", (tester) async {
|
||||
await showApp(tester, location: location);
|
||||
await unfold(tester);
|
||||
final field = tester.getRect(find.byType(AssistantField));
|
||||
expect(field.left, closeTo(16, 0.01));
|
||||
expect(field.right, closeTo(400 - 16, 0.01));
|
||||
});
|
||||
}
|
||||
|
||||
testWidgets('on a studyset with a licence, the folded button keeps clear '
|
||||
'of its line; unfolded, the field takes its usual place over it rather '
|
||||
"than squeezing in above it (the developer's review of 3 Nov 2026)", (
|
||||
tester,
|
||||
) async {
|
||||
studysets.receiveRemoteChange(
|
||||
'japanese',
|
||||
encodeStudysetPayload(
|
||||
StudysetContent(
|
||||
title: 'Japanese',
|
||||
description: RichContent.empty(),
|
||||
license: 'CC-BY-SA-4.0',
|
||||
licenseHolder: 'Tae Kim',
|
||||
licenseYear: 2026,
|
||||
),
|
||||
),
|
||||
);
|
||||
await showApp(tester, location: RoutePaths.studyset('japanese'));
|
||||
final licence = find.textContaining('Tae Kim', findRichText: true);
|
||||
final line = tester.getRect(licence);
|
||||
expect(
|
||||
tester.getRect(find.byTooltip('Search the web')).bottom,
|
||||
lessThan(line.top),
|
||||
reason: 'folded, clear of the line',
|
||||
);
|
||||
|
||||
await unfold(tester);
|
||||
final field = tester.getRect(find.byType(AssistantField));
|
||||
expect(field.bottom, greaterThan(tester.getRect(licence).top));
|
||||
});
|
||||
|
||||
testWidgets("a studyset's name is never offered to go into a web search", (
|
||||
tester,
|
||||
) async {
|
||||
|
|
|
|||
|
|
@ -316,6 +316,60 @@ void main() {
|
|||
);
|
||||
});
|
||||
|
||||
testWidgets('the buttons right of who answers stay where they are '
|
||||
'whatever its name, and every button of the field is boxed, as '
|
||||
"Claude's (the developer's review of 3 Nov 2026)", (tester) async {
|
||||
assistants.offer = AssistantsOffer(
|
||||
assistants: [
|
||||
_claude(),
|
||||
OfferedAssistant(
|
||||
id: 'opus',
|
||||
name: 'Claude Opus, thinking longer',
|
||||
protocol: 'anthropic',
|
||||
host: 'api.anthropic.com',
|
||||
model: 'claude-opus',
|
||||
agreedAt: _agreed,
|
||||
),
|
||||
],
|
||||
);
|
||||
await showApp(tester);
|
||||
Rect at(String tooltip) => tester.getRect(
|
||||
find.descendant(
|
||||
of: find.byType(AssistantField),
|
||||
matching: find.byTooltip(tooltip),
|
||||
),
|
||||
);
|
||||
final history = at('Conversations');
|
||||
final speak = at('Speak your question');
|
||||
final field = tester.getRect(find.byType(AssistantField));
|
||||
expect(field.right - speak.right, lessThan(16), reason: 'at the right');
|
||||
|
||||
await openPicker(tester);
|
||||
await tester.tap(find.text('Claude Opus, thinking longer').last);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Ask Claude Opus, thinking longer…'), findsOneWidget);
|
||||
expect(at('Conversations'), history);
|
||||
expect(at('Speak your question'), speak);
|
||||
|
||||
for (final icon in [
|
||||
LucideIcons.plus,
|
||||
LucideIcons.history,
|
||||
LucideIcons.mic,
|
||||
]) {
|
||||
final button = tester.widget<IconButton>(
|
||||
find.descendant(
|
||||
of: find.byType(AssistantField),
|
||||
matching: find.widgetWithIcon(IconButton, icon),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
button.style?.backgroundColor?.resolve({}),
|
||||
isNotNull,
|
||||
reason: '$icon boxed',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets("an answer's Copy stands beneath it, its icon in line with "
|
||||
"the answer's text", (tester) async {
|
||||
await showApp(tester);
|
||||
|
|
@ -750,7 +804,8 @@ void main() {
|
|||
await unfold(tester);
|
||||
await choose(tester, ['Studyset: Diary']);
|
||||
|
||||
await ask(tester, 'What is this about?');
|
||||
// Short: the test's wide font would hang the text's handle over Ask.
|
||||
await ask(tester, 'About what?');
|
||||
|
||||
expect(find.text(warning), findsOneWidget);
|
||||
expect(find.textContaining('to api.anthropic.com'), findsOneWidget);
|
||||
|
|
@ -758,7 +813,7 @@ void main() {
|
|||
await tester.tap(find.text('Cancel'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(assistants.asked, isEmpty);
|
||||
expect(find.text('What is this about?'), findsOneWidget);
|
||||
expect(find.text('About what?'), findsOneWidget);
|
||||
|
||||
assistants.answers.add(_says('Your diary.'));
|
||||
await tester.tap(
|
||||
|
|
|
|||
Loading…
Reference in a new issue