Merge branch 'design'
This commit is contained in:
@ -2,12 +2,18 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
class HttpError extends StatelessWidget {
|
class HttpError extends StatelessWidget {
|
||||||
const HttpError(
|
const HttpError({
|
||||||
{required this.errMsg, required this.fn, this.btnText, super.key});
|
required this.errMsg,
|
||||||
|
required this.fn,
|
||||||
|
this.btnText,
|
||||||
|
this.isShowBtn = true,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final String? errMsg;
|
final String? errMsg;
|
||||||
final Function()? fn;
|
final Function()? fn;
|
||||||
final String? btnText;
|
final String? btnText;
|
||||||
|
final bool isShowBtn;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -29,6 +35,7 @@ class HttpError extends StatelessWidget {
|
|||||||
style: Theme.of(context).textTheme.titleSmall,
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
if (isShowBtn)
|
||||||
FilledButton.tonal(
|
FilledButton.tonal(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
fn!();
|
fn!();
|
||||||
@ -40,7 +47,8 @@ class HttpError extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
btnText ?? '点击重试',
|
btnText ?? '点击重试',
|
||||||
style: TextStyle(color: Theme.of(context).colorScheme.primary),
|
style:
|
||||||
|
TextStyle(color: Theme.of(context).colorScheme.primary),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -88,7 +88,11 @@ class SearchHttp {
|
|||||||
if (tids != null && tids != -1) 'tids': tids,
|
if (tids != null && tids != -1) 'tids': tids,
|
||||||
};
|
};
|
||||||
var res = await Request().get(Api.searchByType, data: reqData);
|
var res = await Request().get(Api.searchByType, data: reqData);
|
||||||
if (res.data['code'] == 0 && res.data['data']['numPages'] > 0) {
|
if (res.data['code'] == 0) {
|
||||||
|
if (res.data['data']['numPages'] == 0) {
|
||||||
|
// 我想返回数据,使得可以通过data.list 取值,结果为[]
|
||||||
|
return {'status': true, 'data': Data()};
|
||||||
|
}
|
||||||
Object data;
|
Object data;
|
||||||
try {
|
try {
|
||||||
switch (searchType) {
|
switch (searchType) {
|
||||||
@ -125,9 +129,7 @@ class SearchHttp {
|
|||||||
return {
|
return {
|
||||||
'status': false,
|
'status': false,
|
||||||
'data': [],
|
'data': [],
|
||||||
'msg': res.data['data'] != null && res.data['data']['numPages'] == 0
|
'msg': res.data['message'],
|
||||||
? '没有相关数据'
|
|
||||||
: res.data['message'],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,3 +208,9 @@ class SearchHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Data {
|
||||||
|
List<dynamic> list;
|
||||||
|
|
||||||
|
Data({this.list = const []});
|
||||||
|
}
|
||||||
|
|||||||
@ -5,7 +5,9 @@ class SearchVideoModel {
|
|||||||
SearchVideoModel({this.list});
|
SearchVideoModel({this.list});
|
||||||
List<SearchVideoItemModel>? list;
|
List<SearchVideoItemModel>? list;
|
||||||
SearchVideoModel.fromJson(Map<String, dynamic> json) {
|
SearchVideoModel.fromJson(Map<String, dynamic> json) {
|
||||||
list = json['result']
|
list = json['result'] == null
|
||||||
|
? []
|
||||||
|
: json['result']
|
||||||
.where((e) => e['available'] == true)
|
.where((e) => e['available'] == true)
|
||||||
.map<SearchVideoItemModel>((e) => SearchVideoItemModel.fromJson(e))
|
.map<SearchVideoItemModel>((e) => SearchVideoItemModel.fromJson(e))
|
||||||
.toList();
|
.toList();
|
||||||
|
|||||||
@ -357,25 +357,29 @@ class CustomChip extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ColorScheme colorTheme = Theme.of(context).colorScheme;
|
final ColorScheme colorTheme = Theme.of(context).colorScheme;
|
||||||
final Color secondaryContainer = colorTheme.secondaryContainer;
|
final Color secondaryContainer = colorTheme.secondaryContainer;
|
||||||
|
final Color onPrimary = colorTheme.onPrimary;
|
||||||
|
final Color primary = colorTheme.primary;
|
||||||
final TextStyle chipTextStyle = selected
|
final TextStyle chipTextStyle = selected
|
||||||
? const TextStyle(fontWeight: FontWeight.bold, fontSize: 13)
|
? TextStyle(fontSize: 13, color: onPrimary)
|
||||||
: const TextStyle(fontSize: 13);
|
: TextStyle(fontSize: 13, color: colorTheme.onSecondaryContainer);
|
||||||
final ColorScheme colorScheme = Theme.of(context).colorScheme;
|
|
||||||
const VisualDensity visualDensity =
|
const VisualDensity visualDensity =
|
||||||
VisualDensity(horizontal: -4.0, vertical: -2.0);
|
VisualDensity(horizontal: -4.0, vertical: -2.0);
|
||||||
return InputChip(
|
return InputChip(
|
||||||
side: BorderSide(
|
side: BorderSide.none,
|
||||||
color: selected
|
|
||||||
? colorScheme.onSecondaryContainer.withOpacity(0.2)
|
|
||||||
: Colors.transparent,
|
|
||||||
),
|
|
||||||
backgroundColor: secondaryContainer,
|
backgroundColor: secondaryContainer,
|
||||||
selectedColor: secondaryContainer,
|
color: MaterialStateProperty.resolveWith((states) {
|
||||||
color: MaterialStateProperty.resolveWith<Color>(
|
if (states.contains(MaterialState.selected) ||
|
||||||
(Set<MaterialState> states) => secondaryContainer.withAlpha(200)),
|
states.contains(MaterialState.hovered)) {
|
||||||
padding: const EdgeInsets.fromLTRB(7, 1, 7, 1),
|
return primary;
|
||||||
|
}
|
||||||
|
return colorTheme.secondaryContainer;
|
||||||
|
}),
|
||||||
|
padding: const EdgeInsets.fromLTRB(6, 1, 6, 1),
|
||||||
label: Text(label, style: chipTextStyle),
|
label: Text(label, style: chipTextStyle),
|
||||||
onPressed: () => onTap(),
|
onPressed: () => onTap(),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
),
|
||||||
selected: selected,
|
selected: selected,
|
||||||
showCheckmark: false,
|
showCheckmark: false,
|
||||||
visualDensity: visualDensity,
|
visualDensity: visualDensity,
|
||||||
|
|||||||
@ -30,9 +30,9 @@ class SearchPanelController extends GetxController {
|
|||||||
);
|
);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
if (type == 'onRefresh') {
|
if (type == 'onRefresh') {
|
||||||
resultList.value = result['data'].list;
|
resultList.value = result['data'].list ?? [];
|
||||||
} else {
|
} else {
|
||||||
resultList.addAll(result['data'].list);
|
resultList.addAll(result['data'].list ?? []);
|
||||||
}
|
}
|
||||||
page.value++;
|
page.value++;
|
||||||
onPushDetail(keyword, resultList);
|
onPushDetail(keyword, resultList);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/common/widgets/video_card_h.dart';
|
import 'package:pilipala/common/widgets/video_card_h.dart';
|
||||||
import 'package:pilipala/models/common/search_type.dart';
|
import 'package:pilipala/models/common/search_type.dart';
|
||||||
import 'package:pilipala/pages/search/widgets/search_text.dart';
|
import 'package:pilipala/pages/search/widgets/search_text.dart';
|
||||||
@ -25,7 +26,8 @@ class SearchVideoPanel extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 36),
|
padding: const EdgeInsets.only(top: 36),
|
||||||
child: ListView.builder(
|
child: list!.isNotEmpty
|
||||||
|
? ListView.builder(
|
||||||
controller: ctr!.scrollController,
|
controller: ctr!.scrollController,
|
||||||
addAutomaticKeepAlives: false,
|
addAutomaticKeepAlives: false,
|
||||||
addRepaintBoundaries: false,
|
addRepaintBoundaries: false,
|
||||||
@ -43,6 +45,15 @@ class SearchVideoPanel extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
HttpError(
|
||||||
|
errMsg: '没有数据',
|
||||||
|
isShowBtn: false,
|
||||||
|
fn: () => {},
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// 分类筛选
|
// 分类筛选
|
||||||
|
|||||||
@ -109,6 +109,7 @@ class VideoDetailController extends GetxController
|
|||||||
].obs;
|
].obs;
|
||||||
RxDouble sheetHeight = 0.0.obs;
|
RxDouble sheetHeight = 0.0.obs;
|
||||||
RxString archiveSourceType = 'dash'.obs;
|
RxString archiveSourceType = 'dash'.obs;
|
||||||
|
ScrollController? replyScrillController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -551,4 +552,15 @@ class VideoDetailController extends GetxController
|
|||||||
cover.value = videoItem['pic'] = pic;
|
cover.value = videoItem['pic'] = pic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onControllerCreated(ScrollController controller) {
|
||||||
|
replyScrillController = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTapTabbar(int index) {
|
||||||
|
if (index == 1 && tabCtr.index == 1) {
|
||||||
|
replyScrillController?.animateTo(0,
|
||||||
|
duration: const Duration(milliseconds: 300), curve: Curves.ease);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,12 +19,14 @@ class VideoReplyPanel extends StatefulWidget {
|
|||||||
final int? oid;
|
final int? oid;
|
||||||
final int rpid;
|
final int rpid;
|
||||||
final String? replyLevel;
|
final String? replyLevel;
|
||||||
|
final Function(ScrollController)? onControllerCreated;
|
||||||
|
|
||||||
const VideoReplyPanel({
|
const VideoReplyPanel({
|
||||||
this.bvid,
|
this.bvid,
|
||||||
this.oid,
|
this.oid,
|
||||||
this.rpid = 0,
|
this.rpid = 0,
|
||||||
this.replyLevel,
|
this.replyLevel,
|
||||||
|
this.onControllerCreated,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -68,6 +70,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
|
|
||||||
_futureBuilderFuture = _videoReplyController.queryReplyList();
|
_futureBuilderFuture = _videoReplyController.queryReplyList();
|
||||||
scrollController = ScrollController();
|
scrollController = ScrollController();
|
||||||
|
widget.onControllerCreated?.call(scrollController);
|
||||||
fabAnimationCtr.forward();
|
fabAnimationCtr.forward();
|
||||||
scrollListener();
|
scrollListener();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -387,6 +387,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
dividerColor: Colors.transparent,
|
dividerColor: Colors.transparent,
|
||||||
tabs:
|
tabs:
|
||||||
vdCtr.tabs.map((String name) => Tab(text: name)).toList(),
|
vdCtr.tabs.map((String name) => Tab(text: name)).toList(),
|
||||||
|
onTap: (index) => vdCtr.onTapTabbar(index),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -683,6 +684,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
() => VideoReplyPanel(
|
() => VideoReplyPanel(
|
||||||
bvid: vdCtr.bvid,
|
bvid: vdCtr.bvid,
|
||||||
oid: vdCtr.oid.value,
|
oid: vdCtr.oid.value,
|
||||||
|
onControllerCreated: vdCtr.onControllerCreated,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user