mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Add custom tag suggestion handler (#424)
This commit is contained in:
@@ -363,6 +363,11 @@ This part is used to load comics of a category.
|
|||||||
|
|
||||||
// enable tags suggestions
|
// enable tags suggestions
|
||||||
enableTagsSuggestions: false,
|
enableTagsSuggestions: false,
|
||||||
|
// [Optional] handle tag suggestion click
|
||||||
|
onTagSuggestionSelected: (namespace, tag) => {
|
||||||
|
// return the text to insert into search box
|
||||||
|
return `${namespace}:${tag}`
|
||||||
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -184,6 +184,9 @@ class ComicSource {
|
|||||||
|
|
||||||
final HandleClickTagEvent? handleClickTagEvent;
|
final HandleClickTagEvent? handleClickTagEvent;
|
||||||
|
|
||||||
|
/// Callback when a tag suggestion is selected in search.
|
||||||
|
final TagSuggestionSelectFunc? onTagSuggestionSelected;
|
||||||
|
|
||||||
final LinkHandler? linkHandler;
|
final LinkHandler? linkHandler;
|
||||||
|
|
||||||
final bool enableTagsSuggestions;
|
final bool enableTagsSuggestions;
|
||||||
@@ -259,6 +262,7 @@ class ComicSource {
|
|||||||
this.idMatcher,
|
this.idMatcher,
|
||||||
this.translations,
|
this.translations,
|
||||||
this.handleClickTagEvent,
|
this.handleClickTagEvent,
|
||||||
|
this.onTagSuggestionSelected,
|
||||||
this.linkHandler,
|
this.linkHandler,
|
||||||
this.enableTagsSuggestions,
|
this.enableTagsSuggestions,
|
||||||
this.enableTagsTranslate,
|
this.enableTagsTranslate,
|
||||||
|
@@ -148,6 +148,7 @@ class ComicSourceParser {
|
|||||||
_parseIdMatch(),
|
_parseIdMatch(),
|
||||||
_parseTranslation(),
|
_parseTranslation(),
|
||||||
_parseClickTagEvent(),
|
_parseClickTagEvent(),
|
||||||
|
_parseTagSuggestionSelectFunc(),
|
||||||
_parseLinkHandler(),
|
_parseLinkHandler(),
|
||||||
_getValue("search.enableTagsSuggestions") ?? false,
|
_getValue("search.enableTagsSuggestions") ?? false,
|
||||||
_getValue("comic.enableTagsTranslate") ?? false,
|
_getValue("comic.enableTagsTranslate") ?? false,
|
||||||
@@ -1057,6 +1058,19 @@ class ComicSourceParser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TagSuggestionSelectFunc? _parseTagSuggestionSelectFunc() {
|
||||||
|
if (!_checkExists("search.onTagSuggestionSelected")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (namespace, tag) {
|
||||||
|
var res = JsEngine().runCode("""
|
||||||
|
ComicSource.sources.$_key.search.onTagSuggestionSelected(
|
||||||
|
${jsonEncode(namespace)}, ${jsonEncode(tag)})
|
||||||
|
""");
|
||||||
|
return res is String ? res : "$namespace:$tag";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
LinkHandler? _parseLinkHandler() {
|
LinkHandler? _parseLinkHandler() {
|
||||||
if (!_checkExists("comic.link")) {
|
if (!_checkExists("comic.link")) {
|
||||||
return null;
|
return null;
|
||||||
|
@@ -44,5 +44,10 @@ typedef VoteCommentFunc = Future<Res<int?>> Function(
|
|||||||
typedef HandleClickTagEvent = PageJumpTarget? Function(
|
typedef HandleClickTagEvent = PageJumpTarget? Function(
|
||||||
String namespace, String tag);
|
String namespace, String tag);
|
||||||
|
|
||||||
|
/// Handle tag suggestion selection event. Should return the text to insert
|
||||||
|
/// into the search field.
|
||||||
|
typedef TagSuggestionSelectFunc = String Function(
|
||||||
|
String namespace, String tag);
|
||||||
|
|
||||||
/// [rating] is the rating value, 0-10. 1 represents 0.5 star.
|
/// [rating] is the rating value, 0-10. 1 represents 0.5 star.
|
||||||
typedef StarRatingFunc = Future<Res<bool>> Function(String comicId, int rating);
|
typedef StarRatingFunc = Future<Res<bool>> Function(String comicId, int rating);
|
@@ -376,11 +376,16 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
controller.text =
|
controller.text =
|
||||||
controller.text.replaceLast(words[words.length - 1], "");
|
controller.text.replaceLast(words[words.length - 1], "");
|
||||||
}
|
}
|
||||||
if (type != null) {
|
final source = ComicSource.find(searchTarget);
|
||||||
controller.text += "${type.name}:$text ";
|
String insert;
|
||||||
|
if (source?.onTagSuggestionSelected != null) {
|
||||||
|
insert = source!.onTagSuggestionSelected!(type?.name ?? '', text);
|
||||||
} else {
|
} else {
|
||||||
controller.text += "$text ";
|
var t = text;
|
||||||
|
if (t.contains(' ')) t = "'$t'";
|
||||||
|
insert = type != null ? "${type.name}:$t" : t;
|
||||||
}
|
}
|
||||||
|
controller.text += "$insert ";
|
||||||
suggestions.clear();
|
suggestions.clear();
|
||||||
update();
|
update();
|
||||||
focusNode.requestFocus();
|
focusNode.requestFocus();
|
||||||
|
@@ -124,7 +124,7 @@ class _SearchResultPageState extends State<SearchResultPage> {
|
|||||||
options = widget.options ?? const [];
|
options = widget.options ?? const [];
|
||||||
validateOptions();
|
validateOptions();
|
||||||
appdata.addSearchHistory(text);
|
appdata.addSearchHistory(text);
|
||||||
suggestionsController = _SuggestionsController(controller);
|
suggestionsController = _SuggestionsController(controller, sourceKey);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +213,8 @@ class _SuggestionsController {
|
|||||||
|
|
||||||
final SearchBarController controller;
|
final SearchBarController controller;
|
||||||
|
|
||||||
|
final String sourceKey;
|
||||||
|
|
||||||
OverlayEntry? entry;
|
OverlayEntry? entry;
|
||||||
|
|
||||||
void updateWidget() {
|
void updateWidget() {
|
||||||
@@ -270,7 +272,7 @@ class _SuggestionsController {
|
|||||||
find(TagsTranslation.cosplayerTags, TranslationType.cosplayer);
|
find(TagsTranslation.cosplayerTags, TranslationType.cosplayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_SuggestionsController(this.controller);
|
_SuggestionsController(this.controller, this.sourceKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Suggestions extends StatefulWidget {
|
class _Suggestions extends StatefulWidget {
|
||||||
@@ -400,14 +402,16 @@ class _SuggestionsState extends State<_Suggestions> {
|
|||||||
controller.text =
|
controller.text =
|
||||||
controller.text.replaceLast(words[words.length - 1], "");
|
controller.text.replaceLast(words[words.length - 1], "");
|
||||||
}
|
}
|
||||||
if (text.contains(' ')) {
|
final source = ComicSource.find(widget.controller.sourceKey);
|
||||||
text = "'$text'";
|
String insert;
|
||||||
}
|
if (source?.onTagSuggestionSelected != null) {
|
||||||
if (type != null) {
|
insert = source!.onTagSuggestionSelected!(type?.name ?? '', text);
|
||||||
controller.text += "${type.name}:$text ";
|
|
||||||
} else {
|
} else {
|
||||||
controller.text += "$text ";
|
var t = text;
|
||||||
|
if (t.contains(' ')) t = "'$t'";
|
||||||
|
insert = type != null ? "${type.name}:$t" : t;
|
||||||
}
|
}
|
||||||
|
controller.text += "$insert ";
|
||||||
widget.controller.suggestions.clear();
|
widget.controller.suggestions.clear();
|
||||||
widget.controller.remove();
|
widget.controller.remove();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user