nc-photos/app/lib/suggester.dart

57 lines
1.6 KiB
Dart
Raw Normal View History

2023-05-01 19:05:33 +02:00
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:np_codegen/np_codegen.dart';
import 'package:np_collection/np_collection.dart';
2023-08-25 18:37:17 +02:00
import 'package:np_string/np_string.dart';
2023-05-01 19:05:33 +02:00
import 'package:woozy_search/woozy_search.dart';
part 'suggester.g.dart';
@npLog
class Suggester<T> {
Suggester({
required this.items,
required this.itemToKeywords,
int maxResult = 5,
}) : _searcher = Woozy(limit: maxResult) {
for (final a in items) {
for (final k in itemToKeywords(a)) {
_searcher.addEntry(k.toCaseInsensitiveString(), value: a);
}
}
}
List<T> search(CiString phrase) {
final results = _searcher.search(phrase.toCaseInsensitiveString());
if (kDebugMode) {
final str = results.map((e) => "${e.score}: ${e.text}").join("\n");
_log.info("[search] Search '$phrase':\n$str");
}
final matches = results
.where((e) => e.score > 0)
.map((e) {
if (itemToKeywords(e.value as T).any((k) => k.startsWith(phrase))) {
// prefer names that start exactly with the search phrase
2024-06-30 21:00:11 +02:00
return (score: e.score + 1, item: e.value as T);
2023-05-01 19:05:33 +02:00
} else {
2024-06-30 21:00:11 +02:00
return (score: e.score, item: e.value as T);
2023-05-01 19:05:33 +02:00
}
})
2024-06-30 21:00:11 +02:00
.sorted((a, b) => a.score.compareTo(b.score))
2023-05-01 19:05:33 +02:00
.reversed
.distinctIf(
2024-06-30 21:00:11 +02:00
(a, b) => identical(a.item, b.item),
(a) => a.item.hashCode,
2023-05-01 19:05:33 +02:00
)
2024-06-30 21:00:11 +02:00
.map((e) => e.item)
2023-05-01 19:05:33 +02:00
.toList();
return matches;
}
final List<T> items;
final List<CiString> Function(T item) itemToKeywords;
final Woozy _searcher;
}