@@ -14,7 +14,7 @@ import '../../core/platform/file_selector_type_groups.dart';
1414import '../../core/theme/app_theme.dart' ;
1515import 'character_editor_dialog.dart' ;
1616
17- enum _ImportSource { photos, files }
17+ enum _ImportSource { photos, files, worldbook, create }
1818
1919class ImportPreviewDialog extends StatefulWidget {
2020 const ImportPreviewDialog ({
@@ -102,6 +102,10 @@ class _ImportPreviewDialogState extends State<ImportPreviewDialog> {
102102 }
103103
104104 Future <void > _pickAndParseFromSource (_ImportSource source) async {
105+ if (source == _ImportSource .create) {
106+ await _createCharacter ();
107+ return ;
108+ }
105109 if (_busy || _pickingFile) {
106110 return ;
107111 }
@@ -151,6 +155,37 @@ class _ImportPreviewDialogState extends State<ImportPreviewDialog> {
151155 _pickingFile = false ;
152156 _busy = true ;
153157 });
158+ if (source == _ImportSource .worldbook) {
159+ try {
160+ final LorebookImportPreview lorebookPreview =
161+ await lorebookPreviewLoader (sourceFile);
162+ if (! mounted) {
163+ return ;
164+ }
165+ setState (() {
166+ _preview = null ;
167+ _lorebookPreview = lorebookPreview;
168+ _selectedLorebookTargetCharacterId ?? =
169+ appState.availableCharacters.isEmpty
170+ ? null
171+ : appState.availableCharacters.first.id;
172+ _busy = false ;
173+ _error = null ;
174+ });
175+ return ;
176+ } catch (error) {
177+ if (! mounted) {
178+ return ;
179+ }
180+ setState (() {
181+ _busy = false ;
182+ _preview = null ;
183+ _lorebookPreview = null ;
184+ _error = _friendlyErrorMessage (error);
185+ });
186+ return ;
187+ }
188+ }
154189 try {
155190 final CharacterImportPreview preview = await previewLoader (sourceFile);
156191 if (! mounted) {
@@ -212,10 +247,13 @@ class _ImportPreviewDialogState extends State<ImportPreviewDialog> {
212247 }
213248
214249 Future <_ImportSource ?> _chooseImportSource () async {
215- if (! _supportsPhotoImport) {
216- return _ImportSource .files;
217- }
218250 final AppLocalizations ? l10n = AppLocalizations .of (context);
251+ final bool isZh = Localizations .localeOf (context)
252+ .toLanguageTag ()
253+ .toLowerCase ()
254+ .startsWith (
255+ 'zh' ,
256+ );
219257 return showModalBottomSheet <_ImportSource >(
220258 context: context,
221259 backgroundColor: AppTheme .cardElevated,
@@ -249,16 +287,19 @@ class _ImportPreviewDialogState extends State<ImportPreviewDialog> {
249287 ),
250288 ),
251289 const SizedBox (height: 16 ),
252- _buildImportSourceTile (
253- context: sheetContext,
254- key: const ValueKey <String >('import-source-photos' ),
255- icon: Icons .photo_library_rounded,
256- title: l10n? .importFromPhotosTitle ?? 'Import From Photos' ,
257- subtitle: l10n? .importFromPhotosSubtitle ??
258- 'Pick a Tavern PNG card that is already in your photo library.' ,
259- source: _ImportSource .photos,
260- ),
261- const SizedBox (height: 10 ),
290+ if (_supportsPhotoImport) ...< Widget > [
291+ _buildImportSourceTile (
292+ context: sheetContext,
293+ key: const ValueKey <String >('import-source-photos' ),
294+ icon: Icons .photo_library_rounded,
295+ title:
296+ l10n? .importFromPhotosTitle ?? 'Import From Photos' ,
297+ subtitle: l10n? .importFromPhotosSubtitle ??
298+ 'Pick a Tavern PNG card that is already in your photo library.' ,
299+ source: _ImportSource .photos,
300+ ),
301+ const SizedBox (height: 10 ),
302+ ],
262303 _buildImportSourceTile (
263304 context: sheetContext,
264305 key: const ValueKey <String >('import-source-files' ),
@@ -268,6 +309,28 @@ class _ImportPreviewDialogState extends State<ImportPreviewDialog> {
268309 'Pick a Tavern PNG card, JSON card, or standalone worldbook from Files.' ,
269310 source: _ImportSource .files,
270311 ),
312+ const SizedBox (height: 10 ),
313+ _buildImportSourceTile (
314+ context: sheetContext,
315+ key: const ValueKey <String >('import-source-worldbook' ),
316+ icon: Icons .menu_book_rounded,
317+ title: isZh ? '导入世界书' : 'Import Worldbook' ,
318+ subtitle: isZh
319+ ? '选择独立世界书 JSON,并把它挂到已有剧情卡下面。'
320+ : 'Pick a standalone worldbook JSON and attach it to an existing story card.' ,
321+ source: _ImportSource .worldbook,
322+ ),
323+ const SizedBox (height: 10 ),
324+ _buildImportSourceTile (
325+ context: sheetContext,
326+ key: const ValueKey <String >('import-source-create' ),
327+ icon: Icons .draw_rounded,
328+ title: l10n? .createCharacterButton ?? 'Create Character' ,
329+ subtitle: isZh
330+ ? '不导入文件,直接自己写一张新的剧情卡。'
331+ : 'Start from a blank story card instead of importing a file.' ,
332+ source: _ImportSource .create,
333+ ),
271334 ],
272335 ),
273336 ),
@@ -346,6 +409,14 @@ class _ImportPreviewDialogState extends State<ImportPreviewDialog> {
346409 acceptedTypeGroups: characterCardImportTypeGroups,
347410 ));
348411 return picked == null ? null : File (picked.path);
412+ case _ImportSource .worldbook:
413+ final XFile ? picked = await (widget.pickFile? .call () ??
414+ openFile (
415+ acceptedTypeGroups: lorebookImportTypeGroups,
416+ ));
417+ return picked == null ? null : File (picked.path);
418+ case _ImportSource .create:
419+ return null ;
349420 }
350421 }
351422
0 commit comments