feat(learn): + opens a sheet as Claude's, Camera, Photos and Files, and what goes along in rounded rows

Following the developer's review of 3 Nov 2026 (ADR 0021, D67):

- + below the assistant's field, and below a conversation's follow-up,
  opens "Add to your question" as Claude's "Add to session": three big
  tiles side by side, Camera (where the device takes photos) and Photos
  for an assistant reading images, and Files; below them, in the field, a
  row leading to what goes along, showing how far the assistant looks and
  how many parts are chosen.
- Camera and Photos through image_picker (flutter.dev's own): the camera's
  own app and the system's photo picker, no permission asked on Android, a
  file dialog on the desktop, which has no Camera; photos made at most
  2048 pixels a side, read on the device like any file attached.
- What goes along is chosen in rounded rows, as Claude's Permission, in
  place of radio buttons and chips: how far it looks with a tick, private
  studysets with a switch, the parts each with a tick, a card's image with
  its thumbnail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-03 21:56:18 +01:00
commit 7be31dcbfc
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 639 additions and 94 deletions

View file

@ -0,0 +1,29 @@
import 'package:halkyon_app/halkyon_app.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/photo_picker.dart';
/// A [PhotoPicker] that takes [taken] and picks [picked], noting each ask.
class FakePhotoPicker() implements PhotoPicker {
@override
bool hasCamera = true;
/// What the camera takes next; null as if the person took none.
PickedFile? taken;
/// What the photos picked next are.
List<PickedFile> picked = const [];
/// How often the camera and the photos were asked, in order.
final asked = <String>[];
@override
Future<PickedFile?> take() async {
asked.add('camera');
return taken;
}
@override
Future<List<PickedFile>> pick() async {
asked.add('photos');
return picked;
}
}

View file

@ -24,6 +24,7 @@ import 'package:halkyon_learn_flutter/src/feature/archive/model/import_archive.d
import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_files.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/assistant_lookups.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/conversation_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/photo_picker.dart';
import 'package:halkyon_learn_flutter/src/feature/assistant/data/web_search.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_deletions.dart';
import 'package:halkyon_learn_flutter/src/feature/card/data/card_gateway.dart';
@ -95,6 +96,7 @@ import 'fake_note_gateway.dart';
import 'fake_path_answer_gateway.dart';
import 'fake_pdf_engine.dart';
import 'fake_pdf_source_gateway.dart';
import 'fake_photo_picker.dart';
import 'fake_pomodoro_platform.dart';
import 'fake_publish_gateway.dart';
import 'fake_review_gateway.dart';
@ -172,6 +174,7 @@ Dependencies testDependencies({
OpenPerson? openPerson,
WebSearch? webSearch,
SpeechInput? speech,
PhotoPicker? photos,
JellyfinGateway? jellyfinGateway,
JellyfinStore? jellyfinStore,
JellyfinSuggestion? jellyfinSuggestion,
@ -264,6 +267,7 @@ Dependencies testDependencies({
deviceSearch: (query) async => false,
),
speech: speech ?? FakeSpeechInput(),
photos: photos ?? FakePhotoPicker(),
jellyfin: JellyfinRepository(
(device) => jellyfinGateway ?? FakeJellyfinGateway(),
jellyfinStore ?? MemoryJellyfinStore(),