importDictionary method
- {required File file,
- required ValueNotifier<
String> progressNotifier, - required dynamic onImportSuccess(
Start the process of importing a dictionary. This is called from the dictionary menu, and starts the process of importing for the lastSelectedDictionaryFormat.
Implementation
Future<void> importDictionary({
required File file,
required ValueNotifier<String> progressNotifier,
required Function() onImportSuccess,
}) async {
/// New results may be wrong after dictionary is added so this has to be
/// done.
clearDictionaryResultsCache();
Directory workingDirectory = _dictionaryImportWorkingDirectory;
DictionaryFormat dictionaryFormat = lastSelectedDictionaryFormat;
/// Importing makes heavy use of isolates as it is very performance
/// intensive to work with files. In order to ensure the UI isolate isn't
/// blocked, a [ReceivePort] is necessary to receive UI updates.
ReceivePort receivePort = ReceivePort();
receivePort.listen((message) {
progressNotifier.value = '$message';
});
/// Used to show an [AlertDialog] if critical information needs to be
/// given to a user regarding the dictionary they are importing.
ReceivePort alertReceivePort = ReceivePort();
alertReceivePort.listen((message) {
Fluttertoast.showToast(
msg: message.toString(),
toastLength: Toast.LENGTH_LONG,
);
});
/// If any [Exception] occurs, the process is aborted with a message as
/// shown below. A dialog is shown to show the progress of the dictionary
/// file import, with messages pertaining to the above [ValueNotifier].
try {
/// The working directory should always be emptied before and after
/// dictionary import to ensure that no files bloat the system and that
/// files from previous imports do not carry over.
if (workingDirectory.existsSync()) {
progressNotifier.value = t.import_clean;
workingDirectory.deleteSync(recursive: true);
workingDirectory.createSync();
}
String charset = '';
/// Find a way to check if this is a text file or a binary file instead
/// of doing this, it's not good to do format-specific tweaks in a
/// general function like this.
if (dictionaryFormat.isTextFormat) {
var randomAccessFile = file.openSync();
var bytes = randomAccessFile.readSync(100);
DecodingResult result = await CharsetDetector.autoDecode(bytes);
charset = result.charset;
}
PrepareDirectoryParams prepareDirectoryParams = PrepareDirectoryParams(
file: file,
charset: charset,
directoryPath: _databaseDirectory.path,
workingDirectory: workingDirectory,
dictionaryFormat: dictionaryFormat,
sendPort: receivePort.sendPort,
);
progressNotifier.value = t.import_extract;
await dictionaryFormat.prepareDirectory(prepareDirectoryParams);
String name = await dictionaryFormat.prepareName(prepareDirectoryParams);
progressNotifier.value = t.import_name(name: name);
Dictionary? bottomMostDictionary = _database.dictionarys
.where(sort: Sort.desc)
.anyOrder()
.findFirstSync();
Dictionary? sameNameDictionary =
_database.dictionarys.where().nameEqualTo(name).findFirstSync();
if (sameNameDictionary != null) {
throw Exception(t.import_duplicate(name: name));
}
int order = (bottomMostDictionary?.order ?? 0) + 1;
Dictionary dictionary = Dictionary(
order: order,
name: name,
formatKey: dictionaryFormat.uniqueKey,
);
PrepareDictionaryParams prepareDictionaryParams = PrepareDictionaryParams(
dictionary: dictionary,
workingDirectory: workingDirectory,
directoryPath: _databaseDirectory.path,
dictionaryFormat: dictionaryFormat,
useSlowImport: useSlowImport,
sendPort: receivePort.sendPort,
alertSendPort: alertReceivePort.sendPort,
);
await compute(depositDictionaryDataHelper, prepareDictionaryParams);
/// The working directory should always be emptied before and after
/// dictionary import to ensure that no files bloat the system and that
/// files from previous imports do not carry over.
if (workingDirectory.existsSync()) {
progressNotifier.value = t.import_clean;
workingDirectory.deleteSync(recursive: true);
workingDirectory.createSync();
}
progressNotifier.value = t.import_complete;
onImportSuccess();
await Future.delayed(const Duration(seconds: 1), () {});
} catch (e) {
progressNotifier.value = '$e';
await Future.delayed(const Duration(seconds: 3), () {});
progressNotifier.value = t.import_failed;
await Future.delayed(const Duration(seconds: 1), () {});
} finally {
receivePort.close();
}
}