feat: UI pages
This commit is contained in:
1 parent
fbcd33ea2b
commit
197c3e9b88
41 files changed
+1270
-274
No files matched your search
@@ -0,0 +1,63 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../../utils/tools/app_sp.dart';
|
||||
|
||||
/// 本地搜索历史(SharedPreferences),key 与 [AppSp] 规则一致(`.search.history`)。
|
||||
class SearchUtil {
|
||||
SearchUtil._();
|
||||
|
||||
static const String _storageKey = 'sky.search.history';
|
||||
static const int _maxHistory = 20;
|
||||
|
||||
static Future<List<String>> _readList(SharedPreferences prefs) async {
|
||||
final raw = prefs.getString(_storageKey);
|
||||
if (raw == null || raw.isEmpty) return [];
|
||||
try {
|
||||
final decoded = jsonDecode(raw);
|
||||
if (decoded is! List) return [];
|
||||
return decoded.map((e) => e.toString()).where((s) => s.isNotEmpty).toList();
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _writeList(SharedPreferences prefs, List<String> list) async {
|
||||
await prefs.setString(_storageKey, jsonEncode(list));
|
||||
}
|
||||
|
||||
/// 查询搜索历史列表(新记录在前)。
|
||||
static Future<List<String>> getSearchList() async {
|
||||
final prefs = await AppSp.getInstance();
|
||||
return _readList(prefs);
|
||||
}
|
||||
|
||||
/// 添加一条搜索;去重、去空白,并移到最前。
|
||||
static Future<void> addSearch(String keyword) async {
|
||||
final q = keyword.trim();
|
||||
if (q.isEmpty) return;
|
||||
|
||||
final prefs = await AppSp.getInstance();
|
||||
final list = await _readList(prefs);
|
||||
list.removeWhere((e) => e == q);
|
||||
list.insert(0, q);
|
||||
if (list.length > _maxHistory) {
|
||||
list.removeRange(_maxHistory, list.length);
|
||||
}
|
||||
await _writeList(prefs, list);
|
||||
}
|
||||
|
||||
/// 删除单条搜索记录。
|
||||
static Future<void> deleteSearch(String keyword) async {
|
||||
final prefs = await AppSp.getInstance();
|
||||
final list = await _readList(prefs);
|
||||
list.removeWhere((e) => e == keyword);
|
||||
await _writeList(prefs, list);
|
||||
}
|
||||
|
||||
/// 清空全部搜索历史。
|
||||
static Future<void> clearAllSearch() async {
|
||||
final prefs = await AppSp.getInstance();
|
||||
await prefs.remove(_storageKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:skywood/global/const/common_color.dart';
|
||||
import 'package:skywood/main/lib_file.dart';
|
||||
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
|
||||
|
||||
class SearchView extends StatelessWidget {
|
||||
const SearchView({super.key,
|
||||
required this.searchHistory,
|
||||
this.onTapHistory,
|
||||
this.onTapClear,
|
||||
});
|
||||
|
||||
final List<String> searchHistory;
|
||||
final ValueChanged<String>? onTapHistory;
|
||||
final Function()? onTapClear;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15.w),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: SkyText(text: 'Search History',
|
||||
fontSize: 14,
|
||||
color: CommonColor.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
lineHeight: 1,
|
||||
)),
|
||||
IconButton(onPressed: () {
|
||||
onTapClear?.call();
|
||||
}, icon: HelpImg.asset(ConstImg.delete, width: 16.w, height: 16.w)),
|
||||
],
|
||||
),
|
||||
Wrap(
|
||||
spacing: 16.w,
|
||||
runSpacing: 14.h,
|
||||
children: searchHistory
|
||||
.map(
|
||||
(item) => _HistoryChip(
|
||||
text: item,
|
||||
onTap: () => onTapHistory?.call(item),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _HistoryChip extends StatelessWidget {
|
||||
const _HistoryChip({
|
||||
required this.text,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final String text;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x0D000000),
|
||||
borderRadius: BorderRadius.circular(20.r),
|
||||
),
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
color: const Color(0x80000000),
|
||||
fontSize: 12.sp,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user