Update search

This commit is contained in:
2024-10-24 08:56:01 +00:00
committed by GitHub
parent 4334346632
commit 7782c9adec
10 changed files with 230 additions and 46 deletions

View File

@@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import '../globals.dart';
import './number_field.dart';
class AlertNumberFormDialog extends StatefulWidget {
const AlertNumberFormDialog(this.confKey,
{this.title,
this.initial,
this.decoration,
this.max,
this.min,
this.errorMsg,
super.key});
final Widget? title;
final int? initial;
final InputDecoration? decoration;
final int? max;
final int? min;
final String? errorMsg;
final String confKey;
@override
State<StatefulWidget> createState() => _AlertNumberFormDialog();
}
class _AlertNumberFormDialog extends State<AlertNumberFormDialog> {
final _formKey = GlobalKey<FormState>();
int? now;
@override
void initState() {
now = prefs.getInt(widget.confKey) ?? widget.initial;
super.initState();
}
@override
Widget build(BuildContext context) {
final i18n = AppLocalizations.of(context)!;
return AlertDialog(
title: widget.title ?? Text(i18n.changeSettings),
content: Form(
key: _formKey,
child: NumberFormField(
initialValue: now,
decoration: widget.decoration,
onChanged: (s) {
setState(() {
now = s;
});
},
max: widget.max,
min: widget.min,
errorMsg: widget.errorMsg,
)),
actions: [
TextButton(
onPressed: now != null
? () {
prefs.setInt(widget.confKey, now!);
listener
.tryEmit("settings_updated", (widget.confKey, now!));
context.pop();
}
: null,
child: Text(i18n.ok)),
TextButton(
onPressed: () {
context.pop();
},
child: Text(i18n.cancel)),
],
);
}
}

View File

@@ -12,6 +12,7 @@ import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.dart'
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import 'package:meilisearch/meilisearch.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:window_manager/window_manager.dart';
import 'api/client.dart';
@@ -312,26 +313,34 @@ Widget buildMoreVertSettingsButon(BuildContext context) {
Widget buildSearchButton(BuildContext context, {bool openGallery = true}) {
return auth.meilisearch != null
? SearchAnchor(builder: (context, controller) {
return IconButton(
onPressed: () {
controller.openView();
},
icon: const Icon(Icons.search));
}, suggestionsBuilder: (context, controller) async {
final c = auth.meiliSearchClient!;
final re = await c.index("gmeta").search(controller.text);
return re.asSearchResult().hits.map((e) {
final m = GMetaSearchInfo.fromJson(e);
return ListTile(
title: Text(m.preferredTitle),
onTap: () {
controller.closeView(m.preferredTitle);
if (openGallery) context.push("/gallery/${m.gid}");
},
);
}).toList();
})
? SearchAnchor(
builder: (context, controller) {
return IconButton(
onPressed: () {
controller.openView();
},
icon: const Icon(Icons.search));
},
suggestionsBuilder: (context, controller) async {
if (controller.text.isEmpty) return [];
final c = auth.meiliSearchClient!;
final max = prefs.getInt("maxSearchSuggestions") ?? 100;
final re = await c
.index("gmeta")
.search(controller.text, SearchQuery(limit: max));
return re.asSearchResult().hits.map((e) {
final m = GMetaSearchInfo.fromJson(e);
return ListTile(
title: Text(m.preferredTitle),
onTap: () {
controller.closeView(controller.text);
if (openGallery) context.push("/gallery/${m.gid}");
},
);
}).toList();
},
isFullScreen: true,
)
: Container();
}

View File

@@ -333,5 +333,9 @@
"translationFile": "Tnanslation file",
"translationFileHelp": "The path to json file contains tag's translation. Will download from website if this is empty.",
"thumbnailFormat": "Thumbnail format",
"thumbnailFormatHelp": "Webp is not supported in ffmpeg API method."
"thumbnailFormatHelp": "Webp is not supported in ffmpeg API method.",
"search": "Search",
"maxSearchSuggestions": "Maximum results of search suggestions",
"ok": "Ok",
"changeSettings": "Change settings"
}

View File

@@ -333,5 +333,9 @@
"translationFile": "翻译文件",
"translationFileHelp": "包含标签翻译的JSON文件路径。未指定时将从网站上下载。",
"thumbnailFormat": "缩略图格式",
"thumbnailFormatHelp": "ffmpeg API方式不支持webp格式。"
"thumbnailFormatHelp": "ffmpeg API方式不支持webp格式。",
"search": "搜索",
"maxSearchSuggestions": "最大搜索建议结果数量",
"ok": "确定",
"changeSettings": "修改设置"
}

View File

@@ -27,6 +27,7 @@ import 'pages/login.dart';
import 'pages/settings.dart';
import 'pages/settings/cache.dart';
import 'pages/settings/display.dart';
import 'pages/settings/search.dart';
import 'pages/settings/server.dart';
import 'pages/settings/server_url.dart';
import 'pages/settings/user.dart';
@@ -337,6 +338,10 @@ final _router = GoRouter(
return NewUpdateTagTranslationTaskPage();
});
}),
GoRoute(
path: SearchSettingsPage.routeName,
builder: (context, state) => SearchSettingsPage(key: state.pageKey),
),
],
observers: [
_NavigatorObserver(),

View File

@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import '../globals.dart';
@@ -65,16 +64,35 @@ class HomeDrawer extends StatelessWidget {
}
}
class HomePage extends HookWidget with IsTopWidget {
class HomePage extends StatefulWidget {
const HomePage({super.key});
static const String routeName = '/';
@override
State<StatefulWidget> createState() => _HomePage();
}
class _HomePage extends State<HomePage> with ThemeModeWidget, IsTopWidget2 {
void _onStateChanged(dynamic _) {
setState(() {});
}
@override
void initState() {
listener.on("meilisearch_enabled", _onStateChanged);
super.initState();
}
@override
void dispose() {
listener.removeEventListener("meilisearch_enabled", _onStateChanged);
super.dispose();
}
@override
Widget build(BuildContext context) {
tryInitApi(context);
var mode = useState(MainApp.of(context).themeMode);
mode.value = MainApp.of(context).themeMode;
if (isTop(context)) {
setCurrentTitle("", Theme.of(context).primaryColor.value,
usePrefix: true);
@@ -84,17 +102,7 @@ class HomePage extends HookWidget with IsTopWidget {
title: Text(AppLocalizations.of(context)!.titleBar),
actions: [
buildSearchButton(context),
IconButton(
onPressed: () {
final n = themeModeNext(mode.value);
MainApp.of(context).changeThemeMode(n);
mode.value = n;
},
icon: Icon(mode.value == ThemeMode.system
? Icons.brightness_auto
: mode.value == ThemeMode.dark
? Icons.dark_mode
: Icons.light_mode)),
buildThemeModeIcon(context),
buildMoreVertSettingsButon(context),
],
),

View File

@@ -94,6 +94,12 @@ class _SettingsPage extends State<SettingsPage>
},
)
: Container(),
ListTile(
leading: const Icon(Icons.search),
title: Text(i18n.search),
onTap: () {
context.push("/settings/search");
}),
],
));
},

View File

@@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import '../../components/alert_number_form_dialog.dart';
import '../../globals.dart';
final _log = Logger("SearchSettingsPage");
class SearchSettingsPage extends StatefulWidget {
const SearchSettingsPage({super.key});
static const String routeName = '/settings/search';
@override
State<StatefulWidget> createState() => _SearchSettingsPage();
}
class _SearchSettingsPage extends State<SearchSettingsPage>
with ThemeModeWidget, IsTopWidget2 {
void _onStateChanged(dynamic _) {
setState(() {});
}
@override
void initState() {
listener.on("settings_updated", _onStateChanged);
super.initState();
}
@override
void dispose() {
listener.removeEventListener("settings_updated", _onStateChanged);
super.dispose();
}
Widget _buildMain(BuildContext context) {
final i18n = AppLocalizations.of(context)!;
return SingleChildScrollView(
child: Column(mainAxisSize: MainAxisSize.min, children: [
ListTile(
title: Text(i18n.maxSearchSuggestions),
onTap: () => showDialog(
context: context,
builder: (context) => AlertNumberFormDialog("maxSearchSuggestions",
initial: 100,
min: 1,
max: 1000,
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: i18n.maxSearchSuggestions,
))),
subtitle:
Text((prefs.getInt("maxSearchSuggestions") ?? 100).toString()),
)
]));
}
@override
Widget build(BuildContext context) {
final i18n = AppLocalizations.of(context)!;
if (isTop(context)) {
setCurrentTitle("${i18n.settings} - ${i18n.search}",
Theme.of(context).primaryColor.value);
}
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () {
context.canPop() ? context.pop() : context.go("/settings");
},
icon: const Icon(Icons.arrow_back),
),
title: Text(i18n.search),
actions: [
buildThemeModeIcon(context),
buildMoreVertSettingsButon(context),
],
),
body: _buildMain(context),
);
}
}

View File

@@ -308,14 +308,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
flutter_hooks:
dependency: "direct main"
description:
name: flutter_hooks
sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70
url: "https://pub.dev"
source: hosted
version: "0.20.5"
flutter_lints:
dependency: "direct dev"
description:

View File

@@ -17,7 +17,6 @@ dependencies:
flutter:
sdk: flutter
flutter_datetime_picker_plus: ^2.2.0
flutter_hooks: ^0.20.0
flutter_localizations:
sdk: flutter
flutter_web_plugins: