feat(meditate): the library says what a recording speaks, and shows the languages chosen (ADR 0038, D17)

An item's page names its spoken language. Where the library has several,
its cards do too and Explore offers them, several at once, none meaning
every one, kept in the person's sealed settings. A library with one
language asks nothing.

Whats-New: The library says each recording's spoken language, and Explore lets you choose among several.
Whats-New-De: Die Bibliothek nennt die gesprochene Sprache jeder Aufnahme, und bei mehreren wählst du sie in „Entdecken“ aus.

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-05 15:54:12 +01:00
commit 3e69e6b2f7
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 287 additions and 4 deletions

View file

@ -1,6 +1,8 @@
import 'package:clock/clock.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_app/testing.dart';
import 'package:halkyon_meditate_client/halkyon_meditate_client.dart'
show LibraryCatalogue;
import 'package:halkyon_meditate_flutter/src/core/privacy/meditate_keys.dart';
import 'package:halkyon_meditate_flutter/src/core/sealed/json_payload.dart';
import 'package:halkyon_meditate_flutter/src/core/sound/guide_player.dart';
@ -293,4 +295,31 @@ void main() {
},
);
});
group('spoken languages', () {
LibraryCatalogue speaking(List<String> languages) {
final sample = sampleCatalogue();
return sample.copyWith(
courses: const [],
items: [
for (final language in languages)
sample.items.first.copyWith(language: language),
],
);
}
test('are told apart by primary language', () {
expect(languageKey('de-CH'), 'de');
expect(speaking(['en', 'de-CH', 'de']).languagesUsed, ['de', 'en']);
});
test('are no choice with only one', () {
expect(speaking(['de', 'de-AT']).languagesShown(['de']), isEmpty);
});
test('forget what is no longer offered', () {
expect(speaking(['en', 'de']).languagesShown(['en', 'fr']), ['en']);
expect(speaking(['en', 'de']).languagesShown(['fr']), isEmpty);
});
});
}

View file

@ -64,4 +64,17 @@ void main() {
expect(once.isFavourite('body-scan'), isTrue);
expect(once.toggleFavourite('body-scan').favourites, isEmpty);
});
test("the library's spoken languages are kept; a list of something else "
'reads as none', () {
const settings = MeditateSettings(libraryLanguages: ['de', 'en']);
expect(
decodeSettings(encodeSettings(settings))?.libraryLanguages,
settings.libraryLanguages,
);
expect(
json(encodeSettings(const MeditateSettings())),
isNot(contains('libraryLanguages')),
);
});
}