feat(learn): Settings' dictionaries on this device, one row a language
The developer's review of 4 Nov 2026. "Japanese on this device" becomes "Dictionaries on this device", with one row a language: its name at the start, what the device holds or that the download failed beneath it, and its action at the end (Download with its size, the progress, Remove), built as a list of rows so Korean's and Chinese's line up beneath later. Japanese's is the only one now. The help speaks of a language's dictionaries in general, then of what Japanese's hold (MeCab's, JMdict). Whats-New: Settings lists the dictionaries on this device by language, each with its own Download or Remove. Whats-New-De: Die Einstellungen listen die Wörterbücher auf diesem Gerät nach Sprache, jede mit eigenem Herunterladen oder Entfernen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
12bc31b982
commit
a7638e5e54
6 changed files with 106 additions and 60 deletions
|
|
@ -1964,8 +1964,8 @@
|
|||
"deviceDictionaryPreparing": "Wird eingerichtet…",
|
||||
"deviceDictionaryReady": "Wörter werden jetzt auf diesem Gerät nachgeschlagen.",
|
||||
"deviceDictionaryFailed": "Die Wörterbücher konnten nicht heruntergeladen werden. Versuch es in den Einstellungen noch einmal.",
|
||||
"settingsDeviceDictionaryTitle": "Japanisch auf diesem Gerät",
|
||||
"settingsDeviceDictionaryAbout": "Mit den japanischen Wörterbüchern auf diesem Gerät werden die Zeilen von Videos und Liedern hier in Wörter zerlegt, wie Jisho.org es tut, und ihr Text verlässt es nicht. Ohne sie fragt die App die Instanz, die antwortet und nichts speichert.",
|
||||
"settingsDeviceDictionaryTitle": "Wörterbücher auf diesem Gerät",
|
||||
"settingsDeviceDictionaryAbout": "Die Wörterbücher einer Sprache, auf dieses Gerät geladen, schlagen Wörter hier nach, und der Text verlässt es nicht. Ohne sie fragt die App die Instanz, die antwortet und nichts speichert. Die japanischen sind das von MeCab, das die Zeilen von Videos und Liedern in Wörter zerlegt, wie Jisho.org es tut, und JMdict, mit den Lesungen und Bedeutungen jedes Worts.",
|
||||
"settingsDeviceDictionaryHeld": "Auf diesem Gerät: {size}",
|
||||
"@settingsDeviceDictionaryHeld": {"placeholders": {"size": {"type": "String"}}},
|
||||
"settingsDeviceDictionaryDownload": "Herunterladen ({size})",
|
||||
|
|
|
|||
|
|
@ -2361,8 +2361,8 @@
|
|||
"deviceDictionaryPreparing": "Setting them up…",
|
||||
"deviceDictionaryReady": "Words are now looked up on this device.",
|
||||
"deviceDictionaryFailed": "Couldn't download the dictionaries. Try again in Settings.",
|
||||
"settingsDeviceDictionaryTitle": "Japanese on this device",
|
||||
"settingsDeviceDictionaryAbout": "With Japanese's dictionaries on this device, the lines of videos and songs are cut into words here, as Jisho.org does, and their text never leaves it. Without them, the app asks the instance, which answers and keeps nothing.",
|
||||
"settingsDeviceDictionaryTitle": "Dictionaries on this device",
|
||||
"settingsDeviceDictionaryAbout": "A language's dictionaries, downloaded to this device, look words up here, and the text never leaves it. Without them, the app asks the instance, which answers and keeps nothing. Japanese's are MeCab's, which cuts the lines of videos and songs into words as Jisho.org does, and JMdict, with each word's readings and meanings.",
|
||||
"settingsDeviceDictionaryHeld": "On this device: {size}",
|
||||
"@settingsDeviceDictionaryHeld": {"placeholders": {"size": {"type": "String"}}},
|
||||
"settingsDeviceDictionaryDownload": "Download ({size})",
|
||||
|
|
|
|||
|
|
@ -11609,13 +11609,13 @@ abstract class AppLocalizations {
|
|||
/// No description provided for @settingsDeviceDictionaryTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Japanese on this device'**
|
||||
/// **'Dictionaries on this device'**
|
||||
String get settingsDeviceDictionaryTitle;
|
||||
|
||||
/// No description provided for @settingsDeviceDictionaryAbout.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'With Japanese\'s dictionaries on this device, the lines of videos and songs are cut into words here, as Jisho.org does, and their text never leaves it. Without them, the app asks the instance, which answers and keeps nothing.'**
|
||||
/// **'A language\'s dictionaries, downloaded to this device, look words up here, and the text never leaves it. Without them, the app asks the instance, which answers and keeps nothing. Japanese\'s are MeCab\'s, which cuts the lines of videos and songs into words as Jisho.org does, and JMdict, with each word\'s readings and meanings.'**
|
||||
String get settingsDeviceDictionaryAbout;
|
||||
|
||||
/// No description provided for @settingsDeviceDictionaryHeld.
|
||||
|
|
|
|||
|
|
@ -7474,11 +7474,11 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
'Die Wörterbücher konnten nicht heruntergeladen werden. Versuch es in den Einstellungen noch einmal.';
|
||||
|
||||
@override
|
||||
String get settingsDeviceDictionaryTitle => 'Japanisch auf diesem Gerät';
|
||||
String get settingsDeviceDictionaryTitle => 'Wörterbücher auf diesem Gerät';
|
||||
|
||||
@override
|
||||
String get settingsDeviceDictionaryAbout =>
|
||||
'Mit den japanischen Wörterbüchern auf diesem Gerät werden die Zeilen von Videos und Liedern hier in Wörter zerlegt, wie Jisho.org es tut, und ihr Text verlässt es nicht. Ohne sie fragt die App die Instanz, die antwortet und nichts speichert.';
|
||||
'Die Wörterbücher einer Sprache, auf dieses Gerät geladen, schlagen Wörter hier nach, und der Text verlässt es nicht. Ohne sie fragt die App die Instanz, die antwortet und nichts speichert. Die japanischen sind das von MeCab, das die Zeilen von Videos und Liedern in Wörter zerlegt, wie Jisho.org es tut, und JMdict, mit den Lesungen und Bedeutungen jedes Worts.';
|
||||
|
||||
@override
|
||||
String settingsDeviceDictionaryHeld(String size) {
|
||||
|
|
|
|||
|
|
@ -7408,11 +7408,11 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
'Couldn\'t download the dictionaries. Try again in Settings.';
|
||||
|
||||
@override
|
||||
String get settingsDeviceDictionaryTitle => 'Japanese on this device';
|
||||
String get settingsDeviceDictionaryTitle => 'Dictionaries on this device';
|
||||
|
||||
@override
|
||||
String get settingsDeviceDictionaryAbout =>
|
||||
'With Japanese\'s dictionaries on this device, the lines of videos and songs are cut into words here, as Jisho.org does, and their text never leaves it. Without them, the app asks the instance, which answers and keeps nothing.';
|
||||
'A language\'s dictionaries, downloaded to this device, look words up here, and the text never leaves it. Without them, the app asks the instance, which answers and keeps nothing. Japanese\'s are MeCab\'s, which cuts the lines of videos and songs into words as Jisho.org does, and JMdict, with each word\'s readings and meanings.';
|
||||
|
||||
@override
|
||||
String settingsDeviceDictionaryHeld(String size) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:halkyon_learn_flutter/l10n/app_localizations.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/dependencies/dependencies.dart';
|
||||
|
|
@ -158,9 +160,11 @@ class const DeviceDictionaryProgressView({
|
|||
}
|
||||
}
|
||||
|
||||
/// Settings' card for Japanese's dictionaries on this device: what they are
|
||||
/// for, and downloading or removing them. Shown where the instance offers
|
||||
/// them or the device holds them.
|
||||
/// Settings' card for the dictionaries on this device: what they are for,
|
||||
/// and one row a language, its name at the start and downloading, the
|
||||
/// download's progress or removing at the end, so the languages to come
|
||||
/// line up beneath (the developer's review of 4 Nov 2026). Japanese's alone
|
||||
/// for now. Shown where the instance offers them or the device holds them.
|
||||
class const DeviceDictionarySettingsCard({super.key}) extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) =>
|
||||
|
|
@ -174,11 +178,12 @@ class const _SettingsCard() extends StatelessWidget {
|
|||
final theme = Theme.of(context);
|
||||
final view = context.watch<DeviceDictionaryCubit>().state;
|
||||
final dictionaries = view.dictionaries;
|
||||
final installed = dictionaries.installed;
|
||||
final size = view.offeredSize;
|
||||
if (installed == null && size == null && dictionaries.progress == null) {
|
||||
if (dictionaries.installed == null &&
|
||||
view.offeredSize == null &&
|
||||
dictionaries.progress == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final rows = [_LanguageRow(language: l10n.languageJapanese, view: view)];
|
||||
return Padding(
|
||||
// As Settings spaces its cards; none while it is hidden.
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
|
|
@ -193,50 +198,81 @@ class const _SettingsCard() extends StatelessWidget {
|
|||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (dictionaries.progress case final progress?)
|
||||
DeviceDictionaryProgressView(progress: progress)
|
||||
else if (installed != null)
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
l10n.settingsDeviceDictionaryHeld(
|
||||
formatFileSize(l10n, installed.bytes),
|
||||
),
|
||||
),
|
||||
),
|
||||
OutlinedButton(
|
||||
onPressed: () =>
|
||||
context.read<DeviceDictionaryCubit>().remove(),
|
||||
child: Text(l10n.settingsDeviceDictionaryRemove),
|
||||
),
|
||||
],
|
||||
)
|
||||
else ...[
|
||||
if (dictionaries.failed) ...[
|
||||
Text(
|
||||
l10n.settingsDeviceDictionaryFailed,
|
||||
style: TextStyle(color: theme.colorScheme.error),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: FilledButton.tonal(
|
||||
onPressed: () =>
|
||||
context.read<DeviceDictionaryCubit>().download(),
|
||||
child: Text(
|
||||
l10n.settingsDeviceDictionaryDownload(
|
||||
formatFileSize(l10n, size!),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
for (final row in rows) ...[const SizedBox(height: 8), row],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A language's dictionaries on Settings' card: its name, with what the
|
||||
/// device holds or that the download failed beneath, and at the end its
|
||||
/// action: Download with its size, the download's progress, or Remove.
|
||||
class const _LanguageRow({
|
||||
required final String language,
|
||||
required final DeviceDictionaryState view,
|
||||
}) extends StatelessWidget {
|
||||
/// How wide the download's progress is at the row's end.
|
||||
static const _progressWidth = 180.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
final theme = Theme.of(context);
|
||||
final dictionaries = view.dictionaries;
|
||||
final installed = dictionaries.installed;
|
||||
final progress = dictionaries.progress;
|
||||
final note = switch ((progress, installed)) {
|
||||
(null, final installed?) => (
|
||||
l10n.settingsDeviceDictionaryHeld(
|
||||
formatFileSize(l10n, installed.bytes),
|
||||
),
|
||||
theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
(null, null) when dictionaries.failed => (
|
||||
l10n.settingsDeviceDictionaryFailed,
|
||||
theme.colorScheme.error,
|
||||
),
|
||||
_ => null,
|
||||
};
|
||||
final Widget action = switch ((progress, installed, view.offeredSize)) {
|
||||
(final progress?, _, _) => SizedBox(
|
||||
width: _progressWidth,
|
||||
child: DeviceDictionaryProgressView(progress: progress),
|
||||
),
|
||||
(null, _?, _) => OutlinedButton(
|
||||
onPressed: () =>
|
||||
unawaited(context.read<DeviceDictionaryCubit>().remove()),
|
||||
child: Text(l10n.settingsDeviceDictionaryRemove),
|
||||
),
|
||||
(null, null, final size?) => FilledButton.tonal(
|
||||
onPressed: () =>
|
||||
unawaited(context.read<DeviceDictionaryCubit>().download()),
|
||||
child: Text(
|
||||
l10n.settingsDeviceDictionaryDownload(formatFileSize(l10n, size)),
|
||||
),
|
||||
),
|
||||
(null, null, null) => const SizedBox.shrink(),
|
||||
};
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(language, style: theme.textTheme.bodyLarge),
|
||||
if (note case (final text, final color))
|
||||
Text(
|
||||
text,
|
||||
style: theme.textTheme.bodySmall?.copyWith(color: color),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
action,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue