searchForSentences method
- {required BuildContext context,
- required AppModel appModel,
- required String searchTerm}
Search the Massif API for example sentences and return a list of results.
Implementation
Future<List<ImmersionKitResult>> searchForSentences({
required BuildContext context,
required AppModel appModel,
required String searchTerm,
}) async {
if (searchTerm.trim().isEmpty) {
return [];
}
if (_immersionKitCache[searchTerm] != null) {
return _immersionKitCache[searchTerm]!;
}
List<ImmersionKitResult> results = [];
late http.Response response;
try {
/// Query the ImmersionKit API for results.
response = await _client.get(Uri.parse(
'https://api.immersionkit.com/look_up_dictionary?keyword=${Uri.encodeComponent(searchTerm)}&sort=shortness&min_length=${max(searchTerm.length, 10)}'));
Map<String, dynamic> json = jsonDecode(utf8.decode(response.bodyBytes));
/// For each response, create a [ImmersionKitResult] that can be used to display
/// the widget as well as hold the sentence and source data.
List<Map<String, dynamic>> dataResponse =
List<Map<String, dynamic>>.from(json['data']);
Map<String, dynamic> firstHit = dataResponse.first;
List<Map<String, dynamic>> examples =
List<Map<String, dynamic>>.from(firstHit['examples']);
if (examples.isEmpty) {
response = await _client.get(Uri.parse(
'https://api.immersionkit.com/look_up_dictionary?keyword=${Uri.encodeComponent(searchTerm)}'));
json = jsonDecode(utf8.decode(response.bodyBytes));
dataResponse = List<Map<String, dynamic>>.from(json['data']);
firstHit = dataResponse.first;
examples = List<Map<String, dynamic>>.from(firstHit['examples']);
}
for (Map<String, dynamic> example in examples) {
String source = example['deck_name'];
String text = example['sentence'];
List<String> wordList = List<String>.from(example['word_list']);
List<int> wordIndices = List<int>.from(example['word_index']);
String imageUrl = example['image_url'];
String audioUrl = example['sound_url'];
ImmersionKitResult result = ImmersionKitResult(
text: text,
source: source,
imageUrl: imageUrl,
audioUrl: audioUrl,
wordList: wordList,
wordIndices: wordIndices,
);
/// Sentence examples that are merely the word itself are pretty
/// redundant.
if (result.text != searchTerm) {
results.add(result);
}
}
/// Make sure series aren't too consecutive.
results.shuffle();
/// Results with images come first.
results.sort((a, b) {
int hasImage = (a.imageUrl.isNotEmpty ? -1 : 1)
.compareTo(b.imageUrl.isNotEmpty ? -1 : 1);
if (hasImage != 0) {
return hasImage;
}
int hasAudio = (a.audioUrl.isNotEmpty ? -1 : 1)
.compareTo(b.audioUrl.isNotEmpty ? -1 : 1);
if (hasAudio != 0) {
return hasAudio;
}
return a.text.length.compareTo(b.text.length);
});
/// Save this into cache.
_immersionKitCache[searchTerm] = results;
return results;
} catch (e) {
/// Used to log if this third-party service is down or changes domains.
appModel.showFailedToCommunicateMessage();
throw Exception(
'Failed to communicate with ImmersionKit: ${response.reasonPhrase}',
);
}
}