Skip to content

Commit

Permalink
new: sftp search (#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
lollipopkit committed Apr 26, 2024
1 parent ece74d7 commit 2535c8c
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 4 deletions.
38 changes: 34 additions & 4 deletions lib/view/page/storage/sftp.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'package:toolbox/data/res/provider.dart';
import 'package:toolbox/data/res/store.dart';
import 'package:toolbox/view/widget/omit_start_text.dart';
import 'package:toolbox/view/widget/cardx.dart';
import 'package:toolbox/view/widget/search.dart';
import 'package:toolbox/view/widget/val_builder.dart';

import '../../../core/extension/numx.dart';
Expand Down Expand Up @@ -129,8 +130,10 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
final children = widget.isSelect
? [
IconButton(
onPressed: () => context.pop(_status.path?.path),
icon: const Icon(Icons.done))
onPressed: () => context.pop(_status.path?.path),
icon: const Icon(Icons.done),
),
_buildSearchBtn(),
]
: [
IconButton(
Expand All @@ -143,6 +146,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
_buildAddBtn(),
_buildGotoBtn(),
_buildUploadBtn(),
_buildSearchBtn(),
];
if (isDesktop) children.add(_buildRefreshBtn());
return SafeArea(
Expand All @@ -162,6 +166,28 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
);
}

Widget _buildSearchBtn() {
return IconButton(
onPressed: () async {
Stream<SftpName> find(String query) async* {
final fs = _status.files;
if (fs == null) return;
for (final f in fs) {
if (f.filename.contains(query)) yield f;
}
}

final search = SearchPage(
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3),
future: (q) => find(q).toList(),
builder: (ctx, e) => _buildItem(e, beforeTap: () => ctx.pop()),
);
await showSearch(context: context, delegate: search);
},
icon: const Icon(Icons.search),
);
}

Widget _buildUploadBtn() {
return IconButton(
onPressed: () async {
Expand Down Expand Up @@ -314,7 +340,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
);
}

Widget _buildItem(SftpName file) {
Widget _buildItem(SftpName file, {VoidCallback? beforeTap}) {
final isDir = file.attr.isDirectory;
final trailing = Text(
'${_getTime(file.attr.modifyTime)}\n${file.attr.mode?.str ?? ''}',
Expand All @@ -333,14 +359,18 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
style: UIs.textGrey,
),
onTap: () {
beforeTap?.call();
if (isDir) {
_status.path?.update(file.filename);
_listDir();
} else {
_onItemPress(file, true);
}
},
onLongPress: () => _onItemPress(file, !isDir),
onLongPress: () {
beforeTap?.call();
_onItemPress(file, !isDir);
},
),
);
}
Expand Down
87 changes: 87 additions & 0 deletions lib/view/widget/search.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/widget/future_widget.dart';

final class SearchPage<T> extends SearchDelegate<T> {
final Future<List<T>> Function(String) future;
final Widget Function(BuildContext, T) builder;
final EdgeInsetsGeometry? padding;
final Duration throttleInterval;

List<T> _cache = [];
DateTime? _lastSearch;

SearchPage({
required this.future,
required this.builder,
this.padding,
this.throttleInterval = const Duration(milliseconds: 200),
});

@override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}

@override
Widget? buildLeading(BuildContext context) {
return IconButton(
onPressed: context.pop,
icon: const Icon(Icons.arrow_back),
);
}

@override
Widget buildResults(BuildContext context) {
return _buildList(context);
}

@override
Widget buildSuggestions(BuildContext context) {
return _buildList(context);
}

Widget _buildList(BuildContext context) {
return FutureWidget(
future: _search(query),
loading: const Center(child: UIs.centerSizedLoading),
error: (error, trace) {
return Center(
child: Text('$error\n$trace'),
);
},
success: (list) {
if (list == null || list.isEmpty) {
return Center(child: Text(l10n.noResult));
}

return ListView.builder(
padding: padding,
itemCount: list.length,
itemBuilder: (_, index) => builder(context, list[index]),
);
},
);
}

Future<List<T>> _search(String query) async {
final lastSearch = _lastSearch;
if (lastSearch != null) {
final now = DateTime.now();
if (now.difference(lastSearch) < throttleInterval) {
return _cache;
}
}
_cache = await future(query);
return _cache;
}
}

0 comments on commit 2535c8c

Please sign in to comment.