Skip to content

Commit

Permalink
Merge pull request #610 from project-violet/renew-msg-search
Browse files Browse the repository at this point in the history
Refactor 016: Refactor message search
  • Loading branch information
violet-dev authored Jan 12, 2025
2 parents 220624f + eff1e94 commit c34159e
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 181 deletions.
33 changes: 33 additions & 0 deletions violet/lib/component/hitomi/message_search.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,36 @@ class MessageSearch {
autocompleteTarget.sort((x, y) => y.$3.compareTo(x.$3));
}
}

class MessageSearchResult {
final double matchScore;
final int id;
final int page;
final double correctness;
final List<double> rect;

MessageSearchResult({
required this.matchScore,
required this.id,
required this.page,
required this.correctness,
required this.rect,
});

static List<MessageSearchResult> fromJson(String json) {
final result = jsonDecode(json) as List<dynamic>;
return result
.map(
(e) => MessageSearchResult(
matchScore: e['MatchScore'] as double,
id: e['Id'] as int,
page: e['Page'] as int,
correctness: e['Correctness'] as double,
rect: (e['Rect'] as List<dynamic>)
.map((e) => double.parse(e.toString()))
.toList(),
),
)
.toList();
}
}
23 changes: 5 additions & 18 deletions violet/lib/pages/bookmark/crop_bookmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:pull_down_button/pull_down_button.dart';
import 'package:violet/component/hentai.dart';
import 'package:violet/component/image_provider.dart';
import 'package:violet/database/user/bookmark.dart';
import 'package:violet/database/user/record.dart';
import 'package:violet/log/log.dart';
Expand Down Expand Up @@ -150,22 +148,11 @@ class _CropBookmarkPageState extends State<CropBookmarkPage> {
return FutureBuilder(
future:
Future.delayed(const Duration(milliseconds: 100)).then((value) async {
VioletImageProvider provider;

if (ProviderManager.isExists(articleId)) {
provider = await ProviderManager.get(articleId);
} else {
final query =
(await HentaiManager.idSearch(articleId.toString())).results;
provider = await HentaiManager.getImageProvider(query[0]);
await provider.init();
ProviderManager.insert(query[0].id(), provider);
}

return (
imagesUrlForEvict![index] = await provider.getImageUrl(page),
await provider.getHeader(page)
);
final provider = await getImageProviderFromId(articleId);
final image = await provider.getImageUrl(page);
final header = await provider.getHeader(page);
imagesUrlForEvict![index] = image;
return (image, header);
}),
builder:
(context, AsyncSnapshot<(String, Map<String, String>)> snapshot) {
Expand Down
32 changes: 23 additions & 9 deletions violet/lib/pages/common/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,7 @@ Future showArticleInfoRaw({
queryResult = await HentaiManager.idQueryWeb('$id');
}

late final VioletImageProvider provider;
if (ProviderManager.isExists(id)) {
provider = await ProviderManager.get(id);
} else {
provider = await HentaiManager.getImageProvider(queryResult);
await provider.init();
ProviderManager.insert(id, provider);
}

final provider = await getImageProvider(queryResult);
final thumbnail = await provider.getThumbnailUrl();
final headers = await provider.getHeader(0);

Expand Down Expand Up @@ -100,3 +92,25 @@ Future showArticleInfoRaw({
},
);
}

Future<VioletImageProvider> getImageProviderFromId(int id) async {
if (ProviderManager.isExists(id)) {
return await ProviderManager.get(id);
}

final query = (await HentaiManager.idSearch(id.toString())).results;
return getImageProvider(query[0]);
}

Future<VioletImageProvider> getImageProvider(QueryResult queryResult) async {
final id = queryResult.id();
if (ProviderManager.isExists(id)) {
return await ProviderManager.get(id);
}

final provider = await HentaiManager.getImageProvider(queryResult);
await provider.init();
ProviderManager.insert(id, provider);

return provider;
}
136 changes: 31 additions & 105 deletions violet/lib/pages/lab/lab/search_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
// Copyright (C) 2020-2024. violet-team. Licensed under the Apache-2.0 License.

import 'dart:async';
import 'dart:convert';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:violet/component/hentai.dart';
import 'package:violet/component/hitomi/message_search.dart';
import 'package:violet/component/hitomi/tag_translate.dart';
import 'package:violet/component/image_provider.dart';
import 'package:violet/network/wrapper.dart' as http;
import 'package:violet/other/dialogs.dart';
import 'package:violet/pages/common/utils.dart';
import 'package:violet/pages/lab/lab/search_message_rank.dart';
Expand All @@ -19,7 +16,6 @@ import 'package:violet/pages/segment/platform_navigator.dart';
import 'package:violet/script/script_manager.dart';
import 'package:violet/server/violet.dart';
import 'package:violet/util/evict_image_urls.dart';
import 'package:violet/widgets/article_item/image_provider_manager.dart';
import 'package:violet/widgets/v_cached_network_image.dart';

class LabSearchMessage extends StatefulWidget {
Expand All @@ -30,30 +26,16 @@ class LabSearchMessage extends StatefulWidget {
}

class _LabSearchMessageState extends State<LabSearchMessage> {
List<(double, int, int, double, List<double>)> messages =
<(double, int, int, double, List<double>)>[];
List<MessageSearchResult> messages = <MessageSearchResult>[];
TextEditingController text = TextEditingController(text: '은근슬쩍');
String latestSearch = '은근슬쩍';
List<(String, String, int)>? autocompleteTarget;

@override
void initState() {
super.initState();

Future.delayed(const Duration(milliseconds: 100)).then((value) async {
var tmessages = (await VioletServer.searchMessage('contains', text.text))
as List<dynamic>;
messages = tmessages
.map((e) => (
double.parse(e['MatchScore'] as String),
e['Id'] as int,
e['Page'] as int,
e['Correctness'] as double,
(e['Rect'] as List<dynamic>)
.map((e) => double.parse(e.toString()))
.toList()
))
.toList();
messages = (await VioletServer.searchMessage('contains', text.text))!;

if (_height == null) {
_height = List<double>.filled(messages.length, 0);
Expand All @@ -64,20 +46,7 @@ class _LabSearchMessageState extends State<LabSearchMessage> {

await ScriptManager.refresh();

setState(() {});
});

Future.delayed(const Duration(milliseconds: 100)).then((value) async {
const url =
'https://raw.githubusercontent.com/project-violet/violet-message-search/master/SORT-COMBINE.json';

var m = jsonDecode((await http.get(url)).body) as Map<String, dynamic>;

autocompleteTarget = m.entries
.map((e) => (e.key, TagTranslate.disassembly(e.key), e.value as int))
.toList();

autocompleteTarget!.sort((x, y) => y.$3.compareTo(x.$3));
await MessageSearch.init();

setState(() {});
});
Expand Down Expand Up @@ -119,28 +88,16 @@ class _LabSearchMessageState extends State<LabSearchMessage> {
cacheExtent: height * 3.0,
itemCount: messages.length,
itemBuilder: (BuildContext ctxt, int index) {
// if (messages.length == 0) return Container();
var e = messages[index];

final e = messages[index];
return FutureBuilder(
future: Future.delayed(const Duration(milliseconds: 100))
.then((value) async {
VioletImageProvider provider;
if (ProviderManager.isExists(e.$2)) {
provider = await ProviderManager.get(e.$2);
} else {
final query =
(await HentaiManager.idSearch(e.$2.toString()))
.results;
provider = await HentaiManager.getImageProvider(query[0]);
await provider.init();
ProviderManager.insert(query[0].id(), provider);
}
final provider = await getImageProviderFromId(e.id);
final image = await provider.getImageUrl(e.page);
final header = await provider.getHeader(e.page);
_urls![index] = image;

return (
_urls![index] = await provider.getImageUrl(e.$3),
await provider.getHeader(e.$3)
);
return (image, header);
}),
builder: (context,
AsyncSnapshot<(String, Map<String, String>)> snapshot) {
Expand All @@ -160,16 +117,16 @@ class _LabSearchMessageState extends State<LabSearchMessage> {
),
),
ListTile(
title: Text('${e.$2} (${e.$3 + 1} Page)'),
subtitle: Text('Score: ${e.$1}'),
title: Text('${e.id} (${e.page + 1} Page)'),
subtitle: Text('Score: ${e.matchScore}'),
),
],
);
}
return InkWell(
onTap: () async {
FocusScope.of(context).unfocus();
showArticleInfoById(context, e.$2);
showArticleInfoById(context, e.id);
},
splashColor: Colors.white,
child: Column(
Expand Down Expand Up @@ -235,10 +192,10 @@ class _LabSearchMessageState extends State<LabSearchMessage> {
(context, AsyncSnapshot<Size> snapshot2) {
if (!snapshot2.hasData) return Container();

var brtx = e.$5[0];
var brty = e.$5[1];
var brbx = e.$5[2];
var brby = e.$5[3];
var brtx = e.rect[0];
var brty = e.rect[1];
var brbx = e.rect[2];
var brby = e.rect[3];

var w = snapshot2.data!.width;

Expand All @@ -265,8 +222,8 @@ class _LabSearchMessageState extends State<LabSearchMessage> {
],
),
ListTile(
title: Text('${e.$2} (${e.$3 + 1} Page)'),
subtitle: Text('Score: ${e.$1}'),
title: Text('${e.id} (${e.page + 1} Page)'),
subtitle: Text('Score: ${e.matchScore}'),
),
],
),
Expand All @@ -287,50 +244,28 @@ class _LabSearchMessageState extends State<LabSearchMessage> {
value: selected,
onChanged: (String? value) async {
if (value == selected) return;
messages = <(double, int, int, double, List<double>)>[];

messages.clear();
setState(() {
selected = value!;
});
var tmessages = (await VioletServer.searchMessage(
selected.toLowerCase(), text.text)) as List<dynamic>;
messages = tmessages
.map((e) => (
double.parse(e['MatchScore'] as String),
e['Id'] as int,
e['Page'] as int,
e['Correctness'] as double,
(e['Rect'] as List<dynamic>)
.map((e) => double.parse(e.toString()))
.toList(),
))
.toList();

evictImageUrls(_urls);

_height = List<double>.filled(messages.length, 0);
_keys = List<GlobalKey>.generate(
messages.length, (index) => GlobalKey());
_urls = List<String>.filled(messages.length, '');

setState(() {});
_doSearch();
},
),
),
Container(width: 4),
Expanded(
child: TypeAheadField(
suggestionsCallback: (pattern) async {
if (autocompleteTarget == null) {
if (MessageSearch.autocompleteTarget.isEmpty) {
return <(String, String, int)>[];
}

var ppattern = TagTranslate.disassembly(pattern);

return autocompleteTarget!
return MessageSearch.autocompleteTarget
.where((element) => element.$2.startsWith(ppattern))
.toList()
..addAll(autocompleteTarget!
..addAll(MessageSearch.autocompleteTarget
.where((element) =>
!element.$2.startsWith(ppattern) &&
element.$2.contains(ppattern))
Expand Down Expand Up @@ -406,23 +341,14 @@ class _LabSearchMessageState extends State<LabSearchMessage> {
Future<void> _onModifiedText() async {
if (latestSearch == text.text) return;
latestSearch = text.text;
messages = <(double, int, int, double, List<double>)>[];

messages.clear();
setState(() {});
var tmessages =
(await VioletServer.searchMessage(selected.toLowerCase(), text.text))
as List<dynamic>;
messages = tmessages
.map((e) => (
double.parse(e['MatchScore'] as String),
e['Id'] as int,
e['Page'] as int,
double.parse(e['Correctness'].toString()),
(e['Rect'] as List<dynamic>)
.map((e) => double.parse(e.toString()))
.toList()
))
.toList();
_doSearch();
}

_doSearch() async {
messages =
(await VioletServer.searchMessage(selected.toLowerCase(), text.text))!;

evictImageUrls(_urls);

Expand Down
12 changes: 6 additions & 6 deletions violet/lib/pages/viewer/vertical_viewer_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -411,19 +411,19 @@ class _VerticalViewerPageState extends State<VerticalViewerPage>
_isExistsMessageSearchLayer(int index) {
return c.search.value &&
c.imgHeight[index] != 0 &&
c.messages.where((element) => element.$3 == index).isNotEmpty;
c.messages.where((element) => element.page == index).isNotEmpty;
}

_messageSearchLayer(int index) {
final ratio = c.imgHeight[index] / c.realImgHeight[index];
final messages =
c.messages.where((element) => element.$3 == index).toList();
c.messages.where((element) => element.page == index).toList();

final boxes = messages.map((e) {
var brtx = e.$5[0];
var brty = e.$5[1];
var brbx = e.$5[2];
var brby = e.$5[3];
var brtx = e.rect[0];
var brty = e.rect[1];
var brbx = e.rect[2];
var brby = e.rect[3];

return Positioned(
top: brty * ratio - 4,
Expand Down
Loading

0 comments on commit c34159e

Please sign in to comment.