mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: unify trending api & feat: search recommend (#694)
* opt: unify trending api * opt: disable icon * feat: search recommend * mod: recommend api
This commit is contained in:
committed by
GitHub
parent
3638d65008
commit
f0e3b776bb
101
lib/common/widgets/disabled_icon.dart
Normal file
101
lib/common/widgets/disabled_icon.dart
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
|
||||||
|
class DisabledIcon<T extends Widget> extends SingleChildRenderObjectWidget {
|
||||||
|
final Color? color;
|
||||||
|
final double lineLengthScale;
|
||||||
|
final StrokeCap strokeCap;
|
||||||
|
|
||||||
|
const DisabledIcon({
|
||||||
|
super.key,
|
||||||
|
required T child,
|
||||||
|
this.color,
|
||||||
|
double? lineLengthScale,
|
||||||
|
StrokeCap? strokeCap,
|
||||||
|
}) : lineLengthScale = lineLengthScale ?? 0.9,
|
||||||
|
strokeCap = strokeCap ?? StrokeCap.butt,
|
||||||
|
super(child: child);
|
||||||
|
|
||||||
|
@override
|
||||||
|
RenderObject createRenderObject(BuildContext context) {
|
||||||
|
return RenderMaskedIcon(
|
||||||
|
color ??
|
||||||
|
(child is Icon
|
||||||
|
? (child as Icon).color ?? IconTheme.of(context).color!
|
||||||
|
: IconTheme.of(context).color!),
|
||||||
|
lineLengthScale,
|
||||||
|
strokeCap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
T enable() => child as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RenderMaskedIcon extends RenderProxyBox {
|
||||||
|
final Color color;
|
||||||
|
final double lineLengthScale;
|
||||||
|
final StrokeCap strokeCap;
|
||||||
|
|
||||||
|
RenderMaskedIcon(this.color, this.lineLengthScale, this.strokeCap);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(PaintingContext context, Offset offset) {
|
||||||
|
final strokeWidth = size.width / 12;
|
||||||
|
|
||||||
|
final canvas = context.canvas;
|
||||||
|
var rect = offset & size;
|
||||||
|
|
||||||
|
final sqrt2Width = strokeWidth * sqrt2; // rotate pi / 4
|
||||||
|
|
||||||
|
// final path = Path.combine(
|
||||||
|
// PathOperation.difference,
|
||||||
|
// Path()..addRect(rect),
|
||||||
|
// Path()..moveTo(rect.left, rect.top)
|
||||||
|
// ..relativeLineTo(sqrt2Width, 0)
|
||||||
|
// ..lineTo(rect.right, rect.bottom - sqrt2Width)
|
||||||
|
// ..lineTo(rect.right, rect.bottom)
|
||||||
|
// ..close(),
|
||||||
|
// );
|
||||||
|
|
||||||
|
final path = Path.combine(
|
||||||
|
PathOperation.union,
|
||||||
|
Path() // bottom
|
||||||
|
..moveTo(rect.left, rect.bottom)
|
||||||
|
..lineTo(rect.left, rect.top + sqrt2Width)
|
||||||
|
..lineTo(rect.right - sqrt2Width, rect.bottom)
|
||||||
|
..close(),
|
||||||
|
Path() // top
|
||||||
|
..moveTo(rect.right, rect.top)
|
||||||
|
..lineTo(rect.right, rect.bottom - sqrt2Width)
|
||||||
|
..lineTo(rect.left + sqrt2Width, rect.top));
|
||||||
|
|
||||||
|
canvas.save();
|
||||||
|
|
||||||
|
canvas.clipPath(path, doAntiAlias: false);
|
||||||
|
super.paint(context, offset);
|
||||||
|
|
||||||
|
context.canvas.restore();
|
||||||
|
|
||||||
|
final linePaint = Paint()
|
||||||
|
..color = color
|
||||||
|
..strokeWidth = strokeWidth
|
||||||
|
..strokeCap = strokeCap;
|
||||||
|
|
||||||
|
final strokeOffset = strokeWidth * sqrt1_2 / 2;
|
||||||
|
rect = rect
|
||||||
|
.translate(-strokeOffset, strokeOffset)
|
||||||
|
.deflate(size.width * lineLengthScale);
|
||||||
|
canvas.drawLine(
|
||||||
|
rect.topLeft,
|
||||||
|
rect.bottomRight,
|
||||||
|
linePaint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DisabledIconExt on Icon {
|
||||||
|
DisabledIcon<Icon> disable([double? lineLengthScale]) =>
|
||||||
|
DisabledIcon(lineLengthScale: lineLengthScale, child: this);
|
||||||
|
}
|
||||||
@@ -766,4 +766,7 @@ class Api {
|
|||||||
static const String searchTrending = '/x/v2/search/trending/ranking';
|
static const String searchTrending = '/x/v2/search/trending/ranking';
|
||||||
|
|
||||||
static const String setTopDyn = '/x/dynamic/feed/space/set_top';
|
static const String setTopDyn = '/x/dynamic/feed/space/set_top';
|
||||||
|
|
||||||
|
static const String searchRecommend =
|
||||||
|
'${HttpString.appBaseUrl}/x/v2/search/recommend';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ abstract class LoadingState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Loading extends LoadingState<Never> {
|
class Loading extends LoadingState<Never> {
|
||||||
Loading._internal();
|
const Loading._internal();
|
||||||
|
|
||||||
static final Loading _instance = Loading._internal();
|
static const Loading _instance = Loading._internal();
|
||||||
|
|
||||||
factory Loading() => _instance;
|
factory Loading() => _instance;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,33 +6,12 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import '../models/bangumi/info.dart';
|
import '../models/bangumi/info.dart';
|
||||||
import '../models/common/search_type.dart';
|
import '../models/common/search_type.dart';
|
||||||
import '../models/search/hot.dart';
|
|
||||||
import '../models/search/result.dart';
|
import '../models/search/result.dart';
|
||||||
import '../models/search/suggest.dart';
|
import '../models/search/suggest.dart';
|
||||||
import '../utils/storage.dart';
|
import '../utils/storage.dart';
|
||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
|
||||||
class SearchHttp {
|
class SearchHttp {
|
||||||
static Future hotSearchList() async {
|
|
||||||
var res = await Request().get(Api.hotSearchList);
|
|
||||||
if (res.data is String) {
|
|
||||||
Map<String, dynamic> resultMap = json.decode(res.data);
|
|
||||||
if (resultMap['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': HotSearchModel.fromJson(resultMap),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (res.data is Map<String, dynamic> && res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': HotSearchModel.fromJson(res.data),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {'status': false, 'msg': '请求错误'};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取搜索建议
|
// 获取搜索建议
|
||||||
static Future searchSuggest({required term}) async {
|
static Future searchSuggest({required term}) async {
|
||||||
var res = await Request().get(Api.searchSuggest,
|
var res = await Request().get(Api.searchSuggest,
|
||||||
@@ -211,7 +190,7 @@ class SearchHttp {
|
|||||||
|
|
||||||
static Future<LoadingState<TrendingData>> searchTrending(
|
static Future<LoadingState<TrendingData>> searchTrending(
|
||||||
{int limit = 30}) async {
|
{int limit = 30}) async {
|
||||||
final dynamic res = await Request().get(
|
final res = await Request().get(
|
||||||
Api.searchTrending,
|
Api.searchTrending,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'limit': limit,
|
'limit': limit,
|
||||||
@@ -223,4 +202,17 @@ class SearchHttp {
|
|||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<SearchKeywordData>> searchRecommend() async {
|
||||||
|
final res = await Request().get(Api.searchRecommend, queryParameters: {
|
||||||
|
'build': '8350200',
|
||||||
|
'c_locale': 'zh_CN',
|
||||||
|
'mobi_app': 'android',
|
||||||
|
'platform': 'android',
|
||||||
|
's_locale': 'zh_CN',
|
||||||
|
});
|
||||||
|
return res.data['code'] == 0
|
||||||
|
? LoadingState.success(SearchKeywordData.fromJson(res.data['data']))
|
||||||
|
: LoadingState.error(res.data['message']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import 'package:hive/hive.dart';
|
|
||||||
|
|
||||||
part 'hot.g.dart';
|
|
||||||
|
|
||||||
@HiveType(typeId: 6)
|
|
||||||
class HotSearchModel {
|
|
||||||
HotSearchModel({
|
|
||||||
this.list,
|
|
||||||
});
|
|
||||||
|
|
||||||
@HiveField(0)
|
|
||||||
List<HotSearchItem>? list;
|
|
||||||
|
|
||||||
HotSearchModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
list = (json['list'] as List?)
|
|
||||||
?.map<HotSearchItem>((e) => HotSearchItem.fromJson(e))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@HiveType(typeId: 7)
|
|
||||||
class HotSearchItem {
|
|
||||||
HotSearchItem({
|
|
||||||
this.keyword,
|
|
||||||
this.showName,
|
|
||||||
this.wordType,
|
|
||||||
this.icon,
|
|
||||||
});
|
|
||||||
|
|
||||||
@HiveField(0)
|
|
||||||
String? keyword;
|
|
||||||
@HiveField(1)
|
|
||||||
String? showName;
|
|
||||||
// 4/5热 11话题 8普通 7直播
|
|
||||||
@HiveField(2)
|
|
||||||
int? wordType;
|
|
||||||
@HiveField(3)
|
|
||||||
String? icon;
|
|
||||||
|
|
||||||
HotSearchItem.fromJson(Map<String, dynamic> json) {
|
|
||||||
keyword = json['keyword'];
|
|
||||||
showName = json['show_name'];
|
|
||||||
wordType = json['word_type'];
|
|
||||||
icon = json['icon'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'hot.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// TypeAdapterGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
class HotSearchModelAdapter extends TypeAdapter<HotSearchModel> {
|
|
||||||
@override
|
|
||||||
final int typeId = 6;
|
|
||||||
|
|
||||||
@override
|
|
||||||
HotSearchModel read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return HotSearchModel(
|
|
||||||
list: (fields[0] as List?)?.cast<HotSearchItem>(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, HotSearchModel obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(1)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is HotSearchModelAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class HotSearchItemAdapter extends TypeAdapter<HotSearchItem> {
|
|
||||||
@override
|
|
||||||
final int typeId = 7;
|
|
||||||
|
|
||||||
@override
|
|
||||||
HotSearchItem read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return HotSearchItem(
|
|
||||||
keyword: fields[0] as String?,
|
|
||||||
showName: fields[1] as String?,
|
|
||||||
wordType: fields[2] as int?,
|
|
||||||
icon: fields[3] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, HotSearchItem obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(4)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.keyword)
|
|
||||||
..writeByte(1)
|
|
||||||
..write(obj.showName)
|
|
||||||
..writeByte(2)
|
|
||||||
..write(obj.wordType)
|
|
||||||
..writeByte(3)
|
|
||||||
..write(obj.icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is HotSearchItemAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import 'trending_data.dart';
|
|
||||||
|
|
||||||
class SearchTrending {
|
|
||||||
int? code;
|
|
||||||
String? message;
|
|
||||||
int? ttl;
|
|
||||||
TrendingData? data;
|
|
||||||
|
|
||||||
SearchTrending({this.code, this.message, this.ttl, this.data});
|
|
||||||
|
|
||||||
factory SearchTrending.fromJson(Map<String, dynamic> json) {
|
|
||||||
return SearchTrending(
|
|
||||||
code: json['code'] as int?,
|
|
||||||
message: json['message'] as String?,
|
|
||||||
ttl: json['ttl'] as int?,
|
|
||||||
data: json['data'] == null
|
|
||||||
? null
|
|
||||||
: TrendingData.fromJson(json['data'] as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'code': code,
|
|
||||||
'message': message,
|
|
||||||
'ttl': ttl,
|
|
||||||
'data': data?.toJson(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
import 'stat_datas.dart';
|
|
||||||
|
|
||||||
class TopList {
|
|
||||||
int? hotId;
|
|
||||||
String? keyword;
|
|
||||||
String? showName;
|
|
||||||
int? score;
|
|
||||||
int? wordType;
|
|
||||||
int? gotoType;
|
|
||||||
String? gotoValue;
|
|
||||||
String? icon;
|
|
||||||
List<dynamic>? liveId;
|
|
||||||
int? callReason;
|
|
||||||
String? heatLayer;
|
|
||||||
int? pos;
|
|
||||||
int? id;
|
|
||||||
String? status;
|
|
||||||
String? nameType;
|
|
||||||
int? resourceId;
|
|
||||||
int? setGray;
|
|
||||||
List<dynamic>? cardValues;
|
|
||||||
int? heatScore;
|
|
||||||
StatDatas? statDatas;
|
|
||||||
|
|
||||||
TopList({
|
|
||||||
this.hotId,
|
|
||||||
this.keyword,
|
|
||||||
this.showName,
|
|
||||||
this.score,
|
|
||||||
this.wordType,
|
|
||||||
this.gotoType,
|
|
||||||
this.gotoValue,
|
|
||||||
this.icon,
|
|
||||||
this.liveId,
|
|
||||||
this.callReason,
|
|
||||||
this.heatLayer,
|
|
||||||
this.pos,
|
|
||||||
this.id,
|
|
||||||
this.status,
|
|
||||||
this.nameType,
|
|
||||||
this.resourceId,
|
|
||||||
this.setGray,
|
|
||||||
this.cardValues,
|
|
||||||
this.heatScore,
|
|
||||||
this.statDatas,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory TopList.fromJson(Map<String, dynamic> json) => TopList(
|
|
||||||
hotId: json['hot_id'] as int?,
|
|
||||||
keyword: json['keyword'] as String?,
|
|
||||||
showName: json['show_name'] as String?,
|
|
||||||
score: json['score'] as int?,
|
|
||||||
wordType: json['word_type'] as int?,
|
|
||||||
gotoType: json['goto_type'] as int?,
|
|
||||||
gotoValue: json['goto_value'] as String?,
|
|
||||||
icon: json['icon'] as String?,
|
|
||||||
liveId: json['live_id'] as List<dynamic>?,
|
|
||||||
callReason: json['call_reason'] as int?,
|
|
||||||
heatLayer: json['heat_layer'] as String?,
|
|
||||||
pos: json['pos'] as int?,
|
|
||||||
id: json['id'] as int?,
|
|
||||||
status: json['status'] as String?,
|
|
||||||
nameType: json['name_type'] as String?,
|
|
||||||
resourceId: json['resource_id'] as int?,
|
|
||||||
setGray: json['set_gray'] as int?,
|
|
||||||
cardValues: json['card_values'] as List<dynamic>?,
|
|
||||||
heatScore: json['heat_score'] as int?,
|
|
||||||
statDatas: json['stat_datas'] == null
|
|
||||||
? null
|
|
||||||
: StatDatas.fromJson(json['stat_datas'] as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'hot_id': hotId,
|
|
||||||
'keyword': keyword,
|
|
||||||
'show_name': showName,
|
|
||||||
'score': score,
|
|
||||||
'word_type': wordType,
|
|
||||||
'goto_type': gotoType,
|
|
||||||
'goto_value': gotoValue,
|
|
||||||
'icon': icon,
|
|
||||||
'live_id': liveId,
|
|
||||||
'call_reason': callReason,
|
|
||||||
'heat_layer': heatLayer,
|
|
||||||
'pos': pos,
|
|
||||||
'id': id,
|
|
||||||
'status': status,
|
|
||||||
'name_type': nameType,
|
|
||||||
'resource_id': resourceId,
|
|
||||||
'set_gray': setGray,
|
|
||||||
'card_values': cardValues,
|
|
||||||
'heat_score': heatScore,
|
|
||||||
'stat_datas': statDatas?.toJson(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,19 @@
|
|||||||
import 'package:PiliPlus/models/search/search_trending/trending_list.dart';
|
import 'package:PiliPlus/models/search/search_trending/trending_list.dart';
|
||||||
|
|
||||||
class TrendingData {
|
class SearchKeywordData {
|
||||||
|
List<SearchKeywordList>? list;
|
||||||
|
|
||||||
|
SearchKeywordData.fromJson(Map<String, dynamic> json) {
|
||||||
|
list =
|
||||||
|
(json['list'] as List?)?.map((e) => TrendingList.fromJson(e)).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrendingData implements SearchKeywordData {
|
||||||
String? trackid;
|
String? trackid;
|
||||||
List<TrendingList>? list;
|
@override
|
||||||
List<TrendingList>? topList;
|
List<SearchKeywordList>? list;
|
||||||
|
List<SearchKeywordList>? topList;
|
||||||
String? hotwordEggInfo;
|
String? hotwordEggInfo;
|
||||||
|
|
||||||
TrendingData({this.trackid, this.list, this.topList, this.hotwordEggInfo});
|
TrendingData({this.trackid, this.list, this.topList, this.hotwordEggInfo});
|
||||||
@@ -18,11 +28,4 @@ class TrendingData {
|
|||||||
.toList(),
|
.toList(),
|
||||||
hotwordEggInfo: json['hotword_egg_info'] as String?,
|
hotwordEggInfo: json['hotword_egg_info'] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'trackid': trackid,
|
|
||||||
'list': list?.map((e) => e.toJson()).toList(),
|
|
||||||
'top_list': topList?.map((e) => e.toJson()).toList(),
|
|
||||||
'hotword_egg_info': hotwordEggInfo,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,28 @@
|
|||||||
class TrendingList {
|
class SearchKeywordList {
|
||||||
int? position;
|
|
||||||
String? keyword;
|
String? keyword;
|
||||||
String? showName;
|
|
||||||
int? wordType;
|
|
||||||
String? icon;
|
String? icon;
|
||||||
|
bool? showLiveIcon;
|
||||||
|
|
||||||
|
SearchKeywordList.fromJson(Map<String, dynamic> json) {
|
||||||
|
keyword = json['keyword'] as String?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrendingList extends SearchKeywordList {
|
||||||
|
String? showName;
|
||||||
|
// 4/5热 11话题 8普通 7直播
|
||||||
|
int? wordType;
|
||||||
int? hotId;
|
int? hotId;
|
||||||
String? isCommercial;
|
String? isCommercial;
|
||||||
int? resourceId;
|
int? resourceId;
|
||||||
bool? showLiveIcon;
|
|
||||||
|
|
||||||
TrendingList({
|
TrendingList.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
|
||||||
this.position,
|
showName = json['show_name'] as String?;
|
||||||
this.keyword,
|
wordType = json['word_type'] as int?;
|
||||||
this.showName,
|
icon = json['icon'] as String?;
|
||||||
this.wordType,
|
hotId = json['hot_id'] as int?;
|
||||||
this.icon,
|
isCommercial = json['is_commercial'] as String?;
|
||||||
this.hotId,
|
resourceId = json['resource_id'] as int?;
|
||||||
this.isCommercial,
|
showLiveIcon = json['show_live_icon'] as bool?;
|
||||||
this.resourceId,
|
}
|
||||||
this.showLiveIcon,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory TrendingList.fromJson(Map<String, dynamic> json) => TrendingList(
|
|
||||||
position: json['position'] as int?,
|
|
||||||
keyword: json['keyword'] as String?,
|
|
||||||
showName: json['show_name'] as String?,
|
|
||||||
wordType: json['word_type'] as int?,
|
|
||||||
icon: json['icon'] as String?,
|
|
||||||
hotId: json['hot_id'] as int?,
|
|
||||||
isCommercial: json['is_commercial'] as String?,
|
|
||||||
resourceId: json['resource_id'] as int?,
|
|
||||||
showLiveIcon: json['show_live_icon'] as bool?,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'position': position,
|
|
||||||
'keyword': keyword,
|
|
||||||
'show_name': showName,
|
|
||||||
'word_type': wordType,
|
|
||||||
'icon': icon,
|
|
||||||
'hot_id': hotId,
|
|
||||||
'is_commercial': isCommercial,
|
|
||||||
'resource_id': resourceId,
|
|
||||||
'show_live_icon': showLiveIcon,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:PiliPlus/common/widgets/dialog.dart';
|
import 'package:PiliPlus/common/widgets/dialog.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/search/search_trending/trending_data.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:PiliPlus/http/search.dart';
|
import 'package:PiliPlus/http/search.dart';
|
||||||
@@ -8,9 +9,6 @@ import 'package:PiliPlus/utils/storage.dart';
|
|||||||
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
|
import 'package:get/get_rx/src/rx_workers/utils/debouncer.dart';
|
||||||
|
|
||||||
class SSearchController extends GetxController {
|
class SSearchController extends GetxController {
|
||||||
late final historyOff =
|
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#000000"><path d="m785-289-58-58q16-29 24.5-63t8.5-70q0-117-81.5-198.5T480-760q-35 0-68.5 8.5T348-726l-59-59q43-26 91.5-40.5T480-840q75 0 140.5 28.5t114 77q48.5 48.5 77 114T840-480q0 53-14.5 101T785-289ZM520-554l-80-80v-46h80v126ZM792-56 672-176q-42 26-90 41t-102 15q-138 0-240.5-91.5T122-440h82q14 104 92.5 172T480-200q37 0 70.5-8.5T614-234L288-560H120v-168l-64-64 56-56 736 736-56 56Z"/></svg>';
|
|
||||||
|
|
||||||
final searchFocusNode = FocusNode();
|
final searchFocusNode = FocusNode();
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
|
|
||||||
@@ -21,8 +19,13 @@ class SSearchController extends GetxController {
|
|||||||
String hintText = '搜索';
|
String hintText = '搜索';
|
||||||
|
|
||||||
late bool enableHotKey;
|
late bool enableHotKey;
|
||||||
|
late bool enableSearchRcmd;
|
||||||
|
|
||||||
Rx<LoadingState> loadingState = LoadingState.loading().obs;
|
Rx<LoadingState<TrendingData>> loadingState =
|
||||||
|
LoadingState<TrendingData>.loading().obs;
|
||||||
|
|
||||||
|
Rx<LoadingState<SearchKeywordData>> recommendData =
|
||||||
|
LoadingState<SearchKeywordData>.loading().obs;
|
||||||
|
|
||||||
int initIndex = 0;
|
int initIndex = 0;
|
||||||
|
|
||||||
@@ -32,6 +35,8 @@ class SSearchController extends GetxController {
|
|||||||
late final searchSuggestion = GStorage.searchSuggestion;
|
late final searchSuggestion = GStorage.searchSuggestion;
|
||||||
late final RxBool recordSearchHistory = GStorage.recordSearchHistory.obs;
|
late final RxBool recordSearchHistory = GStorage.recordSearchHistory.obs;
|
||||||
|
|
||||||
|
late final digitOnlyRegExp = RegExp(r'^\d+$');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -53,13 +58,20 @@ class SSearchController extends GetxController {
|
|||||||
enableHotKey =
|
enableHotKey =
|
||||||
GStorage.setting.get(SettingBoxKey.enableHotKey, defaultValue: true);
|
GStorage.setting.get(SettingBoxKey.enableHotKey, defaultValue: true);
|
||||||
|
|
||||||
|
enableSearchRcmd = GStorage.setting
|
||||||
|
.get(SettingBoxKey.enableSearchRcmd, defaultValue: true);
|
||||||
|
|
||||||
if (enableHotKey) {
|
if (enableHotKey) {
|
||||||
queryHotSearchList();
|
queryHotSearchList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enableSearchRcmd) {
|
||||||
|
queryRecommendList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void validateUid() {
|
void validateUid() {
|
||||||
showUidBtn.value = RegExp(r'^\d+$').hasMatch(controller.text);
|
showUidBtn.value = digitOnlyRegExp.hasMatch(controller.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onChange(String value) {
|
void onChange(String value) {
|
||||||
@@ -112,12 +124,11 @@ class SSearchController extends GetxController {
|
|||||||
|
|
||||||
// 获取热搜关键词
|
// 获取热搜关键词
|
||||||
Future queryHotSearchList() async {
|
Future queryHotSearchList() async {
|
||||||
dynamic result = await SearchHttp.hotSearchList();
|
loadingState.value = await SearchHttp.searchTrending(limit: 10);
|
||||||
if (result['status']) {
|
}
|
||||||
loadingState.value = LoadingState.success(result['data'].list);
|
|
||||||
} else {
|
Future queryRecommendList() async {
|
||||||
loadingState.value = LoadingState.error(result['msg']);
|
recommendData.value = await SearchHttp.searchRecommend();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onClickKeyword(String keyword) {
|
void onClickKeyword(String keyword) {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import 'package:PiliPlus/common/widgets/disabled_icon.dart';
|
||||||
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models/search/search_trending/trending_data.dart';
|
||||||
import 'package:PiliPlus/models/search/suggest.dart';
|
import 'package:PiliPlus/models/search/suggest.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
import 'widgets/hot_keyword.dart';
|
import 'widgets/hot_keyword.dart';
|
||||||
@@ -42,11 +43,8 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
tooltip: 'UID搜索用户',
|
tooltip: 'UID搜索用户',
|
||||||
icon: const Icon(Icons.person_outline, size: 22),
|
icon: const Icon(Icons.person_outline, size: 22),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (RegExp(r'^\d+$')
|
Get.toNamed(
|
||||||
.hasMatch(_searchController.controller.text)) {
|
'/member?mid=${_searchController.controller.text}');
|
||||||
Get.toNamed(
|
|
||||||
'/member?mid=${_searchController.controller.text}');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
@@ -83,11 +81,9 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
// 搜索建议
|
// 搜索建议
|
||||||
if (_searchController.searchSuggestion) _searchSuggest(),
|
if (_searchController.searchSuggestion) _searchSuggest(),
|
||||||
if (context.orientation == Orientation.portrait) ...[
|
if (context.orientation == Orientation.portrait) ...[
|
||||||
if (_searchController.enableHotKey)
|
if (_searchController.enableHotKey) hotSearch(),
|
||||||
// 热搜
|
_history(),
|
||||||
hotSearch(),
|
if (_searchController.enableSearchRcmd) hotSearch(false)
|
||||||
// 搜索历史
|
|
||||||
_history()
|
|
||||||
] else
|
] else
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -95,6 +91,8 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
if (_searchController.enableHotKey)
|
if (_searchController.enableHotKey)
|
||||||
Expanded(child: hotSearch()),
|
Expanded(child: hotSearch()),
|
||||||
Expanded(child: _history()),
|
Expanded(child: _history()),
|
||||||
|
if (_searchController.enableSearchRcmd)
|
||||||
|
Expanded(child: hotSearch(false)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -135,7 +133,15 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget hotSearch() {
|
Widget hotSearch([bool isHot = true]) {
|
||||||
|
final text = Text(
|
||||||
|
isHot ? '大家都在搜' : '搜索发现',
|
||||||
|
strutStyle: const StrutStyle(leading: 0, height: 1),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(height: 1, fontWeight: FontWeight.bold),
|
||||||
|
);
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(10, 25, 4, 25),
|
padding: const EdgeInsets.fromLTRB(10, 25, 4, 25),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -144,61 +150,54 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(6, 0, 6, 6),
|
padding: const EdgeInsets.fromLTRB(6, 0, 6, 6),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
isHot
|
||||||
'大家都在搜',
|
? Row(
|
||||||
strutStyle: StrutStyle(leading: 0, height: 1),
|
mainAxisSize: MainAxisSize.min,
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.titleMedium!
|
|
||||||
.copyWith(height: 1, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
GestureDetector(
|
|
||||||
behavior: HitTestBehavior.opaque,
|
|
||||||
onTap: () {
|
|
||||||
Get.toNamed(
|
|
||||||
'/searchTrending',
|
|
||||||
parameters: {'tag': _tag},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
|
|
||||||
child: Text.rich(
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
text,
|
||||||
text: '完整榜单',
|
Padding(
|
||||||
),
|
padding: const EdgeInsets.only(left: 14),
|
||||||
WidgetSpan(
|
child: SizedBox(
|
||||||
alignment: PlaceholderAlignment.middle,
|
height: 34,
|
||||||
child: Icon(
|
child: TextButton.icon(
|
||||||
size: 16,
|
onPressed: () {
|
||||||
Icons.keyboard_arrow_right,
|
Get.toNamed(
|
||||||
color: Theme.of(context).colorScheme.outline,
|
'/searchTrending',
|
||||||
|
parameters: {'tag': _tag},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
label: Text(
|
||||||
|
'完整榜单',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
icon: Icon(
|
||||||
|
size: 16,
|
||||||
|
Icons.keyboard_arrow_right,
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
|
iconAlignment: IconAlignment.end,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
),
|
)
|
||||||
),
|
: text,
|
||||||
),
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 34,
|
height: 34,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: WidgetStateProperty.all(
|
padding: const WidgetStatePropertyAll(
|
||||||
const EdgeInsets.only(
|
EdgeInsets.symmetric(horizontal: 10, vertical: 6)),
|
||||||
left: 10, top: 6, bottom: 6, right: 10),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
onPressed: _searchController.queryHotSearchList,
|
onPressed: isHot
|
||||||
|
? _searchController.queryHotSearchList
|
||||||
|
: _searchController.queryRecommendList,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.refresh_outlined,
|
Icons.refresh_outlined,
|
||||||
size: 18,
|
size: 18,
|
||||||
@@ -215,7 +214,11 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() => _buildHotKey(_searchController.loadingState.value)),
|
Obx(() => _buildHotKey(
|
||||||
|
isHot
|
||||||
|
? _searchController.loadingState.value
|
||||||
|
: _searchController.recommendData.value,
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -223,8 +226,7 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
|
|
||||||
Widget _history() {
|
Widget _history() {
|
||||||
return Obx(
|
return Obx(
|
||||||
() => Container(
|
() => Padding(
|
||||||
width: double.infinity,
|
|
||||||
padding: EdgeInsets.fromLTRB(
|
padding: EdgeInsets.fromLTRB(
|
||||||
10,
|
10,
|
||||||
context.orientation == Orientation.landscape
|
context.orientation == Orientation.landscape
|
||||||
@@ -233,7 +235,7 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
? 0
|
? 0
|
||||||
: 6,
|
: 6,
|
||||||
6,
|
6,
|
||||||
MediaQuery.of(context).padding.bottom + 50,
|
25,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -262,25 +264,8 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
? '记录搜索'
|
? '记录搜索'
|
||||||
: '无痕搜索',
|
: '无痕搜索',
|
||||||
icon: _searchController.recordSearchHistory.value
|
icon: _searchController.recordSearchHistory.value
|
||||||
? Icon(
|
? historyIcon
|
||||||
Icons.history,
|
: historyIcon.disable(),
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onSurfaceVariant
|
|
||||||
.withOpacity(0.8),
|
|
||||||
)
|
|
||||||
: SvgPicture.string(
|
|
||||||
width: 22,
|
|
||||||
height: 22,
|
|
||||||
colorFilter: ColorFilter.mode(
|
|
||||||
Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.outline
|
|
||||||
.withOpacity(0.8),
|
|
||||||
BlendMode.srcIn,
|
|
||||||
),
|
|
||||||
_searchController.historyOff,
|
|
||||||
),
|
|
||||||
style: IconButton.styleFrom(
|
style: IconButton.styleFrom(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
@@ -349,13 +334,16 @@ class _SearchPageState extends State<SearchPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHotKey(LoadingState loadingState) {
|
Icon get historyIcon => Icon(Icons.history,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.8));
|
||||||
|
|
||||||
|
Widget _buildHotKey(LoadingState<SearchKeywordData> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => loadingState.response.list?.isNotEmpty == true
|
||||||
? LayoutBuilder(
|
? LayoutBuilder(
|
||||||
builder: (context, constraints) => HotKeyword(
|
builder: (context, constraints) => HotKeyword(
|
||||||
width: constraints.maxWidth,
|
width: constraints.maxWidth,
|
||||||
hotSearchList: loadingState.response,
|
hotSearchList: loadingState.response.list!,
|
||||||
onClick: _searchController.onClickKeyword,
|
onClick: _searchController.onClickKeyword,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
|
import 'package:PiliPlus/models/search/search_trending/trending_list.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class HotKeyword extends StatelessWidget {
|
class HotKeyword extends StatelessWidget {
|
||||||
final double? width;
|
final double width;
|
||||||
final List? hotSearchList;
|
final List<SearchKeywordList> hotSearchList;
|
||||||
final Function? onClick;
|
final Function? onClick;
|
||||||
|
final bool showMore;
|
||||||
const HotKeyword({
|
const HotKeyword({
|
||||||
this.width,
|
|
||||||
this.hotSearchList,
|
|
||||||
this.onClick,
|
|
||||||
super.key,
|
super.key,
|
||||||
});
|
required double width,
|
||||||
|
required this.hotSearchList,
|
||||||
|
this.onClick,
|
||||||
|
this.showMore = true,
|
||||||
|
}) : this.width = width / 2 - 4;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -19,22 +22,19 @@ class HotKeyword extends StatelessWidget {
|
|||||||
runSpacing: 0.4,
|
runSpacing: 0.4,
|
||||||
spacing: 5.0,
|
spacing: 5.0,
|
||||||
children: [
|
children: [
|
||||||
for (var i in hotSearchList!)
|
for (var i in hotSearchList)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: width! / 2 - 4,
|
width: width,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(3),
|
borderRadius: const BorderRadius.all(Radius.circular(3)),
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => onClick?.call(i.keyword),
|
onTap: () => onClick?.call(i.keyword),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: const EdgeInsets.only(left: 2, right: 10),
|
||||||
left: 2,
|
|
||||||
right: 10,
|
|
||||||
),
|
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: i.keyword!,
|
message: i.keyword,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
@@ -48,16 +48,14 @@ class HotKeyword extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (i.icon != null && i.icon != '') ...[
|
if (!i.icon.isNullOrEmpty)
|
||||||
const SizedBox(width: 4),
|
Padding(
|
||||||
SizedBox(
|
padding: const EdgeInsets.only(left: 4),
|
||||||
height: 15,
|
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: (i.icon as String).http2https,
|
imageUrl: i.icon!.http2https,
|
||||||
height: 15.0,
|
height: 15,
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
]
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:PiliPlus/models/search/search_trending/trending_list.dart';
|
|||||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||||
|
|
||||||
class SearchTrendingController
|
class SearchTrendingController
|
||||||
extends CommonListController<TrendingData, TrendingList> {
|
extends CommonListController<TrendingData, SearchKeywordList> {
|
||||||
int topCount = 0;
|
int topCount = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -15,10 +15,11 @@ class SearchTrendingController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<TrendingList>? getDataList(TrendingData response) {
|
List<SearchKeywordList>? getDataList(TrendingData response) {
|
||||||
List<TrendingList> topList = (response.topList ?? <TrendingList>[]);
|
List<SearchKeywordList> topList = response.topList ?? <TrendingList>[];
|
||||||
topCount = topList.length;
|
topCount = topList.length;
|
||||||
return topList + (response.list ?? <TrendingList>[]);
|
return response.list == null ? topList : topList
|
||||||
|
..addAll(response.list ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class _SearchTrendingPageState extends State<SearchTrendingPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(LoadingState<List<TrendingList>?> loadingState) {
|
Widget _buildBody(LoadingState<List<SearchKeywordList>?> loadingState) {
|
||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => SliverToBoxAdapter(child: LinearProgressIndicator()),
|
Loading() => SliverToBoxAdapter(child: LinearProgressIndicator()),
|
||||||
Success() => loadingState.response?.isNotEmpty == true
|
Success() => loadingState.response?.isNotEmpty == true
|
||||||
|
|||||||
@@ -2212,6 +2212,14 @@ List<SettingsModel> get extraSettings => [
|
|||||||
setKey: SettingBoxKey.enableHotKey,
|
setKey: SettingBoxKey.enableHotKey,
|
||||||
defaultVal: true,
|
defaultVal: true,
|
||||||
),
|
),
|
||||||
|
SettingsModel(
|
||||||
|
settingsType: SettingsType.sw1tch,
|
||||||
|
title: '搜索发现',
|
||||||
|
subtitle: '是否展示「搜索发现」',
|
||||||
|
leading: const Icon(Icons.search_outlined),
|
||||||
|
setKey: SettingBoxKey.enableSearchRcmd,
|
||||||
|
defaultVal: true,
|
||||||
|
),
|
||||||
SettingsModel(
|
SettingsModel(
|
||||||
settingsType: SettingsType.sw1tch,
|
settingsType: SettingsType.sw1tch,
|
||||||
title: '搜索默认词',
|
title: '搜索默认词',
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ class AccountManager extends Interceptor {
|
|||||||
Api.searchDefault,
|
Api.searchDefault,
|
||||||
Api.searchSuggest,
|
Api.searchSuggest,
|
||||||
Api.liveList,
|
Api.liveList,
|
||||||
|
Api.searchTrending,
|
||||||
|
Api.searchRecommend,
|
||||||
},
|
},
|
||||||
AccountType.video: {Api.videoUrl, Api.bangumiVideoUrl}
|
AccountType.video: {Api.videoUrl, Api.bangumiVideoUrl}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import 'package:get/get_navigation/src/routes/transitions_type.dart';
|
|||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:PiliPlus/models/model_owner.dart';
|
import 'package:PiliPlus/models/model_owner.dart';
|
||||||
import 'package:PiliPlus/models/search/hot.dart';
|
|
||||||
import 'package:PiliPlus/models/user/info.dart';
|
import 'package:PiliPlus/models/user/info.dart';
|
||||||
import 'global_data.dart';
|
import 'global_data.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
@@ -588,8 +587,6 @@ class GStorage {
|
|||||||
Hive.registerAdapter(OwnerAdapter());
|
Hive.registerAdapter(OwnerAdapter());
|
||||||
Hive.registerAdapter(UserInfoDataAdapter());
|
Hive.registerAdapter(UserInfoDataAdapter());
|
||||||
Hive.registerAdapter(LevelInfoAdapter());
|
Hive.registerAdapter(LevelInfoAdapter());
|
||||||
Hive.registerAdapter(HotSearchModelAdapter());
|
|
||||||
Hive.registerAdapter(HotSearchItemAdapter());
|
|
||||||
Hive.registerAdapter(BiliCookieJarAdapter());
|
Hive.registerAdapter(BiliCookieJarAdapter());
|
||||||
Hive.registerAdapter(LoginAccountAdapter());
|
Hive.registerAdapter(LoginAccountAdapter());
|
||||||
Hive.registerAdapter(AccountTypeAdapter());
|
Hive.registerAdapter(AccountTypeAdapter());
|
||||||
@@ -685,6 +682,7 @@ class SettingBoxKey {
|
|||||||
replySortType = 'replySortType',
|
replySortType = 'replySortType',
|
||||||
defaultDynamicType = 'defaultDynamicType',
|
defaultDynamicType = 'defaultDynamicType',
|
||||||
enableHotKey = 'enableHotKey',
|
enableHotKey = 'enableHotKey',
|
||||||
|
enableSearchRcmd = 'enableSearchRcmd',
|
||||||
enableQuickFav = 'enableQuickFav',
|
enableQuickFav = 'enableQuickFav',
|
||||||
enableWordRe = 'enableWordRe',
|
enableWordRe = 'enableWordRe',
|
||||||
enableSearchWord = 'enableSearchWord',
|
enableSearchWord = 'enableSearchWord',
|
||||||
|
|||||||
Reference in New Issue
Block a user