feat(library): Import and Refresh behind one menu button
The library's top bar had a button each for Import and Refresh. Pulling
the list down refreshes too, and is the quicker way on a phone, so both
now sit in a menu ("Library options"), leaving the bar to Search.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
660e5548e0
commit
25e73c8c80
9 changed files with 70 additions and 18 deletions
|
|
@ -48,6 +48,7 @@
|
|||
"studysetCountNotes": "{count, plural, =1{1 Notiz} other{{count} Notizen}}",
|
||||
"studysetCountFiles": "{count, plural, =1{1 Datei} other{{count} Dateien}}",
|
||||
"libraryRefresh": "Aktualisieren",
|
||||
"libraryOptions": "Optionen der Bibliothek",
|
||||
"libraryImport": "Importieren",
|
||||
"libraryImportAnkiHint": "Wird ein eigenes Lernset, aus einer .apkg- oder .colpkg-Datei",
|
||||
"libraryImportArchive": "Halkyon-Archiv",
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
"studysetCountFiles": "{count, plural, =1{1 file} other{{count} files}}",
|
||||
"@studysetCountFiles": {"placeholders": {"count": {"type": "int"}}},
|
||||
"libraryRefresh": "Refresh",
|
||||
"libraryOptions": "Library options",
|
||||
"libraryImport": "Import",
|
||||
"libraryImportAnkiHint": "Becomes a studyset of its own, from an .apkg or .colpkg file",
|
||||
"libraryImportArchive": "Halkyon archive",
|
||||
|
|
|
|||
|
|
@ -346,6 +346,12 @@ abstract class AppLocalizations {
|
|||
/// **'Refresh'**
|
||||
String get libraryRefresh;
|
||||
|
||||
/// No description provided for @libraryOptions.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Library options'**
|
||||
String get libraryOptions;
|
||||
|
||||
/// No description provided for @libraryImport.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
|
|
|||
|
|
@ -191,6 +191,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
@override
|
||||
String get libraryRefresh => 'Aktualisieren';
|
||||
|
||||
@override
|
||||
String get libraryOptions => 'Optionen der Bibliothek';
|
||||
|
||||
@override
|
||||
String get libraryImport => 'Importieren';
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
@override
|
||||
String get libraryRefresh => 'Refresh';
|
||||
|
||||
@override
|
||||
String get libraryOptions => 'Library options';
|
||||
|
||||
@override
|
||||
String get libraryImport => 'Import';
|
||||
|
||||
|
|
|
|||
|
|
@ -158,6 +158,12 @@ class _LibraryState() extends State<_Library> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Syncs, and asks again which studysets are published.
|
||||
void _refresh(BuildContext context) {
|
||||
context.read<SyncStatusBloc>().add(const SyncStatusEventSyncRequested());
|
||||
unawaited(context.read<PublishedCubit>().refresh());
|
||||
}
|
||||
|
||||
Future<void> _create(BuildContext context) async {
|
||||
final bloc = context.read<StudysetListBloc>();
|
||||
final content = await showStudysetSheet(context);
|
||||
|
|
@ -207,20 +213,38 @@ class _LibraryState() extends State<_Library> {
|
|||
),
|
||||
onPressed: _toggleSearch,
|
||||
),
|
||||
IconButton(
|
||||
tooltip: l10n.libraryImport,
|
||||
icon: const Icon(LucideIcons.fileInput),
|
||||
onPressed: () => unawaited(_import(context)),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: l10n.libraryRefresh,
|
||||
icon: const Icon(LucideIcons.refreshCw),
|
||||
onPressed: () {
|
||||
context.read<SyncStatusBloc>().add(
|
||||
const SyncStatusEventSyncRequested(),
|
||||
);
|
||||
unawaited(context.read<PublishedCubit>().refresh());
|
||||
// Import and Refresh behind one button: pulling the list
|
||||
// down refreshes too, and is the quicker way on a phone.
|
||||
PopupMenuButton<_LibraryOption>(
|
||||
icon: const Icon(LucideIcons.ellipsisVertical),
|
||||
tooltip: l10n.libraryOptions,
|
||||
onSelected: (option) => switch (option) {
|
||||
_LibraryOption.import => unawaited(_import(context)),
|
||||
_LibraryOption.refresh => _refresh(context),
|
||||
},
|
||||
itemBuilder: (context) => [
|
||||
for (final (option, icon, text) in [
|
||||
(
|
||||
_LibraryOption.import,
|
||||
LucideIcons.fileInput,
|
||||
l10n.libraryImport,
|
||||
),
|
||||
(
|
||||
_LibraryOption.refresh,
|
||||
LucideIcons.refreshCw,
|
||||
l10n.libraryRefresh,
|
||||
),
|
||||
])
|
||||
PopupMenuItem(
|
||||
value: option,
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: Icon(icon),
|
||||
title: Text(text),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (wide)
|
||||
Padding(
|
||||
|
|
@ -615,6 +639,12 @@ class const _SearchRow({
|
|||
}
|
||||
}
|
||||
|
||||
/// The library's options, behind its menu button.
|
||||
enum _LibraryOption() {
|
||||
import,
|
||||
refresh,
|
||||
}
|
||||
|
||||
/// What the library imports as new studysets.
|
||||
enum _LibraryImport() {
|
||||
anki,
|
||||
|
|
|
|||
|
|
@ -144,7 +144,9 @@ void main() {
|
|||
await tester.pump(const Duration(seconds: 1));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byTooltip('Import'));
|
||||
await tester.tap(find.byTooltip('Library options'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Import'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Anki deck'));
|
||||
await tester.pump();
|
||||
|
|
@ -187,7 +189,9 @@ void main() {
|
|||
await tester.pump(const Duration(seconds: 1));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byTooltip('Import'));
|
||||
await tester.tap(find.byTooltip('Library options'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Import'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Anki deck'));
|
||||
await tester.pump();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ void main() {
|
|||
}
|
||||
|
||||
Future<void> choose(WidgetTester tester) async {
|
||||
await tester.tap(find.byTooltip('Import'));
|
||||
await tester.tap(find.byTooltip('Library options'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Import'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Halkyon archive'));
|
||||
await tester.pump();
|
||||
|
|
|
|||
|
|
@ -132,13 +132,15 @@ void main() {
|
|||
expect(find.text('Japanese'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Refresh syncs, from the app bar and by pulling the list '
|
||||
testWidgets('Refresh syncs, from the menu and by pulling the list '
|
||||
'down', (tester) async {
|
||||
stored('japanese', 'Japanese');
|
||||
await showLibrary(tester);
|
||||
final before = syncs;
|
||||
|
||||
await tester.tap(find.byTooltip('Refresh'));
|
||||
await tester.tap(find.byTooltip('Library options'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Refresh'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(syncs, before + 1);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue