Skip to content

Commit

Permalink
feat: sort by longest exact match
Browse files Browse the repository at this point in the history
  • Loading branch information
m-edlund committed Mar 3, 2024
1 parent c9ee043 commit 363c632
Showing 1 changed file with 54 additions and 12 deletions.
66 changes: 54 additions & 12 deletions yuuna/lib/src/creator/enhancements/immersion_kit_enhancement.dart
Expand Up @@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Expand All @@ -26,6 +27,7 @@ class ImmersionKitResult {
required this.wordList,
required this.wordIndices,
required this.calculateRange,
required this.longestExactMatch,
});

/// The sentence in plain unformatted form.
Expand All @@ -48,6 +50,9 @@ class ImmersionKitResult {

TextRange? _calculatedRange;

/// How many consecutive characters match the search term exactly
int longestExactMatch;

/// Function to calculate the range of search term
TextRange Function() calculateRange;

Expand Down Expand Up @@ -236,6 +241,31 @@ class ImmersionKitEnhancement extends Enhancement {
}
}

int _longestExactRangeForResult({
required List<int> wordIndices,
required List<String> wordList,
required String term,
required String text,
}) {
/// Start at the first character of the given cloze
int textPosition = wordList.sublist(0, wordIndices.first).join().length;
int termPosition = 0;

int longest = 0;

var termChar = term.characters.elementAtOrNull(termPosition);
var textChar = text.characters.elementAtOrNull(textPosition);
while (textChar != null && termChar != null && termChar == textChar) {
longest++;
termPosition++;
textPosition++;
termChar = term.characters.elementAtOrNull(termPosition);
textChar = text.characters.elementAtOrNull(textPosition);
}

return longest;
}

/// Search the Massif API for example sentences and return a list of results.
Future<List<ImmersionKitResult>> searchForSentences({
required AppModel appModel,
Expand Down Expand Up @@ -290,18 +320,23 @@ class ImmersionKitEnhancement extends Enhancement {
String audioUrl = example['sound_url'];

ImmersionKitResult result = ImmersionKitResult(
text: text,
source: source,
imageUrl: imageUrl,
audioUrl: audioUrl,
wordList: wordList,
wordIndices: wordIndices,
calculateRange: () => _getRangeFromIndexedList(
wordIndices: wordIndices,
text: text,
source: source,
imageUrl: imageUrl,
audioUrl: audioUrl,
wordList: wordList,
term: searchTerm,
),
);
wordIndices: wordIndices,
calculateRange: () => _getRangeFromIndexedList(
wordIndices: wordIndices,
wordList: wordList,
term: searchTerm,
),
longestExactMatch: _longestExactRangeForResult(
wordIndices: wordIndices,
wordList: wordList,
text: text,
term: searchTerm,
));

/// Sentence examples that are merely the word itself are pretty
/// redundant.
Expand All @@ -313,7 +348,7 @@ class ImmersionKitEnhancement extends Enhancement {
/// Make sure series aren't too consecutive.
results.shuffle();

/// Results with images come first.
/// Sort by: has image -> has audio -> longest exact match -> shortest sentence
results.sort((a, b) {
int hasImage = (a.imageUrl.isNotEmpty ? -1 : 1)
.compareTo(b.imageUrl.isNotEmpty ? -1 : 1);
Expand All @@ -329,6 +364,13 @@ class ImmersionKitEnhancement extends Enhancement {
return hasAudio;
}

/// Sort by longest subterm
int longestMatch = b.longestExactMatch.compareTo(a.longestExactMatch);

if (longestMatch != 0) {
return longestMatch;
}

return a.text.length.compareTo(b.text.length);
});

Expand Down

0 comments on commit 363c632

Please sign in to comment.