feat(learn): search ranks titles first; privacy changes show progress

- The Library's search lists titles starting with what is typed first,
  then titles holding it as a word, then secondary titles, rather than
  by the shelves' recency.
- The offer to make every studyset private is gone: each studyset's
  lock already says and changes it, and new ones are private.
- Making a studyset private or not from its sheet flips the switch as
  soon as the person agrees and says that everything in it is being
  written anew, rather than standing still for a minute.
- Jellyfin's password can be shown while typed.

Whats-New: Searching the library lists title matches first; changing a studyset's privacy shows its progress; Jellyfin's password can be shown.
Whats-New-De: Die Suche in der Bibliothek zeigt Treffer im Titel zuerst; das Ändern der Privatsphäre eines Lernsets zeigt den Fortschritt; das Jellyfin-Passwort lässt sich anzeigen.

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-10 22:39:10 +01:00
commit 1cc27ef0d6
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 276 additions and 235 deletions

View file

@ -75,6 +75,10 @@ class FakeStudysetGateway() implements StudysetGateway {
/// Every change of privacy, in order, as (id, private).
final privacyChanges = <(String, bool)>[];
/// While set, making a tree private or readable waits for it, as a
/// rewrite of thousands of rows does.
Completer<void>? holdPrivacy;
@override
bool canMakePrivate = false;
@ -100,6 +104,9 @@ class FakeStudysetGateway() implements StudysetGateway {
@override
Future<int> setPrivate(String id, {required bool private}) async {
if (holdPrivacy case final hold?) {
await hold.future;
}
final tree = {id};
var grew = true;
while (grew) {

View file

@ -70,7 +70,6 @@ import 'package:halkyon_learn_flutter/src/feature/settings/data/settings_gateway
import 'package:halkyon_learn_flutter/src/feature/settings/data/settings_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/study/data/review_gateway.dart';
import 'package:halkyon_learn_flutter/src/feature/study/data/review_repository.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/private_offer_store.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_deletions.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_gateway.dart';
import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_progress_repository.dart';
@ -109,7 +108,6 @@ import 'fake_youtube_videos.dart';
import 'memory_asset_file_cache.dart';
import 'memory_device_settings_store.dart';
import 'memory_pomodoro_run_store.dart';
import 'memory_private_offer_store.dart';
import 'memory_published_store.dart';
import 'memory_studyset_tab_store.dart';
@ -163,7 +161,6 @@ Dependencies testDependencies({
PublishGateway? publishGateway,
PublishedStore? publishedStore,
StudysetTabStore? studysetTabStore,
PrivateOfferStore? privateOffer,
ExploreGateway? exploreGateway,
FeedbackWriteGateway? feedbackWriteGateway,
FeedbackServerGateway? feedbackServerGateway,
@ -382,7 +379,6 @@ Dependencies testDependencies({
conversationDeletions: conversationDeletions,
pomodoroRuns: pomodoroRuns ?? MemoryPomodoroRunStore(),
studysetTabs: studysetTabs,
privateOffer: privateOffer ?? MemoryPrivateOfferStore(),
publishing: PublishRepository(
publishGateway ?? FakePublishGateway(),
publishedStore ?? MemoryPublishedStore(),