Skip to content

Commit f00bb9d

Browse files
committed
Fix creating packs from the selection menu, fixes #1178
1 parent 2af3d85 commit f00bb9d

6 files changed

Lines changed: 129 additions & 36 deletions

File tree

app/lib/api/file_system.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,25 @@ class ButterflyFileSystem {
388388
PackFileSystem buildDefaultPackSystem({bool forceRecreate = false}) =>
389389
buildPackSystem(settingsCubit.state.getDefaultRemote(), forceRecreate);
390390

391+
Future<String> createPack(
392+
NoteData pack, {
393+
String? name,
394+
ExternalStorage? storage,
395+
}) async {
396+
final fallback = pack.name?.trim().isNotEmpty == true ? pack.name! : 'pack';
397+
var fileName = name?.trim().isNotEmpty == true ? name! : fallback;
398+
if (!fileName.endsWith('.bfly')) fileName = '$fileName.bfly';
399+
final fileSystem = buildPackSystem(storage);
400+
await fileSystem.initialize();
401+
await fileSystem.createFile(fileName, pack);
402+
final files = await fileSystem.getFiles();
403+
return files
404+
.where((file) => file.pathWithoutLeadingSlash == fileName)
405+
.firstOrNull
406+
?.path ??
407+
fileName;
408+
}
409+
391410
Future<PackItem<T>?> findPack<T extends PackAsset>(
392411
NamedItem<T>? Function(NoteData) test, [
393412
ExternalStorage? storage,

app/lib/dialogs/packs/asset.dart

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,67 @@ import 'package:phosphor_flutter/phosphor_flutter.dart';
1414
import '../../bloc/document_bloc.dart';
1515
import 'pack.dart';
1616

17-
class AssetDialog extends StatelessWidget {
17+
class AssetDialog extends StatefulWidget {
1818
final PackAssetLocation? value;
1919
final String initialName;
2020

2121
const AssetDialog({super.key, this.value, this.initialName = ''});
2222

23+
@override
24+
State<AssetDialog> createState() => _AssetDialogState();
25+
}
26+
27+
class _AssetDialogState extends State<AssetDialog> {
28+
late final ButterflyFileSystem _fileSystem;
29+
late final PackFileSystem _packSystem;
30+
late Future<List<FileSystemFile<NoteData>>> _packsFuture;
31+
late String _name;
32+
String? _pack;
33+
34+
@override
35+
void initState() {
36+
super.initState();
37+
_fileSystem = context.read<ButterflyFileSystem>();
38+
_packSystem = _fileSystem.buildDefaultPackSystem();
39+
_packsFuture = _getPacks();
40+
_pack = widget.value?.namespace;
41+
_name = widget.value?.key ?? widget.initialName;
42+
}
43+
44+
Future<List<FileSystemFile<NoteData>>> _getPacks() =>
45+
_packSystem.initialize().then((_) => _packSystem.getFiles());
46+
47+
Future<void> _createPack() async {
48+
final pack = await showDialog<NoteData>(
49+
context: context,
50+
builder: (context) => const PackDialog(),
51+
);
52+
if (pack == null) return;
53+
final createdPath = await _fileSystem.createPack(
54+
pack,
55+
storage: _packSystem.storage,
56+
);
57+
final packs = await _packSystem.getFiles();
58+
if (!mounted) return;
59+
setState(() {
60+
_pack = createdPath;
61+
_packsFuture = Future.value(packs);
62+
});
63+
}
64+
2365
@override
2466
Widget build(BuildContext context) {
25-
String? pack = value?.namespace;
26-
String name = value?.key ?? initialName;
27-
final bloc = context.read<DocumentBloc>();
28-
final packSystem = context
29-
.read<ButterflyFileSystem>()
30-
.buildDefaultPackSystem();
3167
return FutureBuilder<List<FileSystemFile<NoteData>>>(
32-
future: packSystem.initialize().then((_) => packSystem.getFiles()),
68+
future: _packsFuture,
3369
builder: (context, snapshot) => BlocBuilder<DocumentBloc, DocumentState>(
3470
buildWhen: (previous, current) => previous.data != current.data,
3571
builder: (context, state) {
3672
if (state is! DocumentLoaded) return const SizedBox();
3773
final packs = snapshot.data ?? <FileSystemFile<NoteData>>[];
38-
pack ??= packs.firstOrNull?.path;
74+
_pack ??= packs.firstOrNull?.path;
3975
return AlertDialog(
4076
title: Text(
41-
value == null
77+
widget.value == null
4278
? AppLocalizations.of(context).addAsset
4379
: AppLocalizations.of(context).editAsset,
4480
),
@@ -62,24 +98,15 @@ class AssetDialog extends StatelessWidget {
6298
),
6399
);
64100
}).toList(),
65-
onSelected: (value) {
66-
pack = value;
67-
},
68-
initialSelection: pack,
101+
onSelected: (value) => _pack = value,
102+
initialSelection: _pack,
69103
expandedInsets: const EdgeInsets.all(0),
70104
),
71105
),
72106
const SizedBox(width: 8),
73107
IconButton(
74108
icon: const PhosphorIcon(PhosphorIconsLight.plusCircle),
75-
onPressed: () async {
76-
final pack = await showDialog<NoteData>(
77-
context: context,
78-
builder: (context) => const PackDialog(),
79-
);
80-
if (pack == null) return;
81-
bloc.add(PackAdded(pack));
82-
},
109+
onPressed: _createPack,
83110
tooltip: AppLocalizations.of(context).createPack,
84111
),
85112
],
@@ -90,10 +117,8 @@ class AssetDialog extends StatelessWidget {
90117
labelText: LeapLocalizations.of(context).name,
91118
filled: true,
92119
),
93-
initialValue: name,
94-
onChanged: (value) {
95-
name = value;
96-
},
120+
initialValue: _name,
121+
onChanged: (value) => _name = value,
97122
),
98123
],
99124
),
@@ -108,8 +133,8 @@ class AssetDialog extends StatelessWidget {
108133
),
109134
ElevatedButton(
110135
onPressed: () {
111-
if (pack == null) return;
112-
Navigator.of(context).pop(PackAssetLocation(pack!, name));
136+
if (_pack == null) return;
137+
Navigator.of(context).pop(PackAssetLocation(_pack!, _name));
113138
},
114139
child: Text(MaterialLocalizations.of(context).okButtonLabel),
115140
),

app/lib/dialogs/packs/dialog.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,12 @@ class _PacksDialogState extends State<PacksDialog>
242242
);
243243
}
244244

245-
String _normalizePackFileName(String? name, NoteData pack) {
246-
final fallback = pack.name?.trim().isNotEmpty == true ? pack.name! : 'pack';
247-
final fileName = name?.trim().isNotEmpty == true ? name! : fallback;
248-
return fileName.endsWith('.bfly') ? fileName : '$fileName.bfly';
249-
}
250-
251245
Future<void> _addPack(NoteData pack, {String? name}) async {
252-
await _packSystem.createFile(_normalizePackFileName(name, pack), pack);
246+
await _fileSystem.createPack(
247+
pack,
248+
name: name,
249+
storage: _packSystem.storage,
250+
);
253251
_refresh();
254252
}
255253

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import 'package:butterfly/cubits/settings.dart';
2+
import 'package:butterfly/models/defaults.dart';
3+
import 'package:butterfly_api/butterfly_api.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:mocktail/mocktail.dart';
6+
7+
import '../helpers/mocks.dart';
8+
9+
void main() {
10+
test('creating a pack stores it in the global pack filesystem', () async {
11+
final fileSystem = MockButterflyFileSystem();
12+
final settingsCubit = fileSystem.settingsCubit as MockSettingsCubit;
13+
when(
14+
() => settingsCubit.state,
15+
).thenReturn(const ButterflySettings(autosave: false));
16+
final packSystem = fileSystem.buildDefaultPackSystem();
17+
final pack = DocumentDefaults.createPack().setMetadata(
18+
DocumentDefaults.createMetadata(
19+
type: NoteFileType.pack,
20+
name: 'New Pack',
21+
),
22+
);
23+
24+
final createdPath = await fileSystem.createPack(pack);
25+
final packs = await packSystem.getFiles();
26+
27+
expect(createdPath, packs.single.path);
28+
expect(packs.single.pathWithoutLeadingSlash, 'New Pack.bfly');
29+
});
30+
}

app/test/helpers/mocks.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ class MockButterflyFileSystem implements ButterflyFileSystem {
3636
PackFileSystem buildDefaultPackSystem({bool forceRecreate = false}) =>
3737
_packFileSystem;
3838

39+
@override
40+
Future<String> createPack(
41+
NoteData pack, {
42+
String? name,
43+
ExternalStorage? storage,
44+
}) async {
45+
final fallback = pack.name?.trim().isNotEmpty == true ? pack.name! : 'pack';
46+
var fileName = name?.trim().isNotEmpty == true ? name! : fallback;
47+
if (!fileName.endsWith('.bfly')) fileName = '$fileName.bfly';
48+
final fileSystem = buildPackSystem(storage);
49+
await fileSystem.initialize();
50+
await fileSystem.createFile(fileName, pack);
51+
final files = await fileSystem.getFiles();
52+
return files
53+
.where((file) => file.pathWithoutLeadingSlash == fileName)
54+
.firstOrNull
55+
?.path ??
56+
fileName;
57+
}
58+
3959
@override
4060
TemplateFileSystem buildDefaultTemplateSystem({bool forceRecreate = false}) =>
4161
_templateFileSystem;

metadata/en-US/changelogs/190.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@
1010
* Fix file previews resetting the language to the system locale
1111
* Fix filename preview appearing when renaming existing documents
1212
* Fix navigation menus broken on mobile layout ([#1177](https://github.com/LinwoodDev/Butterfly/issues/1177))
13+
* Fix creating packs from the selection menu ([#1178](https://github.com/LinwoodDev/Butterfly/issues/1178))
1314

14-
Read more here: https://linwood.dev/butterfly/2.6.0-beta.3
15+
Read more here: https://linwood.dev/butterfly/2.6.0-beta.3

0 commit comments

Comments
 (0)