698 lines
25 KiB
Dart
698 lines
25 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:aiplot/tools/gallery/gallery_content_model.dart';
|
||
import 'package:cached_network_image/cached_network_image.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/services.dart';
|
||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||
|
||
import '../../bean/gallery_label_bean.dart';
|
||
import '../../bean/gallery_work_label_bean.dart';
|
||
import '../../bean/gallery_work_list_bean.dart';
|
||
import '../../bean/recommender_bean.dart';
|
||
import '../../common/Global.dart';
|
||
import '../../common/dialog_bean.dart';
|
||
import '../../common/dialog_manager.dart';
|
||
import '../../common/dialog_util.dart';
|
||
import '../../common/func.dart';
|
||
import '../../dialog/login_dialog.dart';
|
||
import '../../dialog/phone_login_dialog.dart';
|
||
import '../../generated/l10n.dart';
|
||
import '../../network/NetworkConfig.dart';
|
||
import '../drawdetails/expert_user_details_page.dart';
|
||
import '../drawdetails/influential_details_page.dart';
|
||
|
||
class GalleryContentPage extends StatefulWidget {
|
||
GalleryContentPage({Key? key}) : super(key: key);
|
||
|
||
@override
|
||
State<GalleryContentPage> createState() => _GalleryContentPageState();
|
||
}
|
||
|
||
class _GalleryContentPageState extends State<GalleryContentPage> with SingleTickerProviderStateMixin {
|
||
StreamSubscription? subscription;
|
||
final GalleryContentModel _viewModel = GalleryContentModel();
|
||
GlobalKey<LoginDialogState> loginDialogKey = GlobalKey(); //登录弹框key
|
||
final ScrollController _scrollController = ScrollController();
|
||
TabController? tabController;
|
||
List<GalleryLabelBean> labelList = [];
|
||
List<Tab> myTabs = [];
|
||
String influentialCode = "";
|
||
List<RecommenderBean> recommenderList = [];
|
||
List<GalleryWorkLabelBean> workLabelList = [];
|
||
int currentLabelIndex = 0; //当前选中标签
|
||
int currentChild = 1; //当前选中的子标签
|
||
List<GalleryWorkListBean> galleryList = [];
|
||
int index = 1; //当前页数
|
||
FocusNode focusNode = FocusNode();
|
||
|
||
//创建StreamController
|
||
StreamController? streamController;
|
||
|
||
// 获取StreamSink用于发射事件
|
||
StreamSink? get streamSink => streamController?.sink;
|
||
|
||
// 获取Stream用于监听
|
||
Stream? get streamData => streamController?.stream;
|
||
|
||
void influentialChange(String str) {
|
||
influentialCode = str.toUpperCase();
|
||
}
|
||
|
||
void getWorksListByLabel(bool isLoad) {
|
||
EasyLoading.show(status: 'loading...');
|
||
_viewModel.getWorksListByLabel(workLabelList[currentLabelIndex].LabelId, currentChild, index, isLoad);
|
||
}
|
||
|
||
@override
|
||
void initState() {
|
||
// TODO: implement initState
|
||
super.initState();
|
||
|
||
streamController = StreamController<bool>();
|
||
|
||
//网络请求回调
|
||
subscription = _viewModel.streamController.stream.listen((newData) {
|
||
String code = newData['code'];
|
||
if (code.isNotEmpty) {
|
||
EasyLoading.dismiss();
|
||
|
||
switch (code) {
|
||
case "getRecommenderList":
|
||
recommenderList = newData['data'];
|
||
break;
|
||
|
||
case "getGalleryWorkLabel":
|
||
workLabelList = newData['data'];
|
||
|
||
getWorksListByLabel(false);
|
||
|
||
break;
|
||
case "getWorksListByLabel":
|
||
if (newData['isLoad']) {
|
||
galleryList.addAll(newData['data']);
|
||
} else {
|
||
galleryList = newData['data'];
|
||
}
|
||
|
||
break;
|
||
case "getUserHomePageByPw": //搜索达人
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (context) => ExpertUserDetailsPage(
|
||
workUserId: "${newData['data']}",
|
||
worksID: '0',
|
||
),
|
||
));
|
||
break;
|
||
default:
|
||
String message = newData['data'];
|
||
EasyLoading.showToast(message);
|
||
break;
|
||
}
|
||
setState(() {});
|
||
}
|
||
});
|
||
|
||
//上拉加载
|
||
_scrollController.addListener(() {
|
||
//判断是否滑动到了页面的最底部
|
||
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
|
||
//如果不是最后一页数据,则生成新的数据添加到list里面
|
||
index++;
|
||
getWorksListByLabel(true);
|
||
}
|
||
|
||
///置顶按钮
|
||
if (_scrollController.position.pixels > 600) {
|
||
streamSink?.add(true);
|
||
} else {
|
||
streamSink?.add(false);
|
||
}
|
||
});
|
||
|
||
_viewModel.getRecommenderList();
|
||
_viewModel.getGalleryWorkLabel();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
// TODO: implement dispose
|
||
subscription?.cancel();
|
||
streamController?.close();
|
||
tabController?.dispose();
|
||
focusNode.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final size = MediaQuery.of(context).size;
|
||
return Scaffold(
|
||
backgroundColor: Colors.white,
|
||
appBar: AppBar(
|
||
backgroundColor: Colors.white,
|
||
elevation: 0,
|
||
title: Row(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Container(
|
||
margin: const EdgeInsets.only(right: 10),
|
||
child: const Image(
|
||
width: 23,
|
||
height: 23,
|
||
image: AssetImage('assets/images/ic_title.png'),
|
||
),
|
||
),
|
||
Text(
|
||
"AI${S.of(context).Gallery}",
|
||
style: const TextStyle(color: Colors.black, fontSize: 20),
|
||
),
|
||
],
|
||
),
|
||
centerTitle: true,
|
||
),
|
||
body: RefreshIndicator(
|
||
onRefresh: _onRefresh,
|
||
child: Stack(
|
||
children: [
|
||
SingleChildScrollView(
|
||
controller: _scrollController,
|
||
child: Container(
|
||
margin: const EdgeInsets.only(left: 15),
|
||
child: Column(
|
||
children: [
|
||
///搜索达人
|
||
Container(
|
||
margin: const EdgeInsets.only(right: 15),
|
||
child: Container(
|
||
width: double.infinity,
|
||
height: 40,
|
||
decoration: BoxDecoration(
|
||
border: Border.all(width: 1, color: const Color(0xFF8841FF)),
|
||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||
),
|
||
child: Stack(
|
||
alignment: Alignment.center,
|
||
children: [
|
||
const Positioned(
|
||
left: 17,
|
||
child: Image(
|
||
image: AssetImage('assets/images/ic_search.png'),
|
||
width: 19,
|
||
height: 19,
|
||
)),
|
||
Positioned(
|
||
left: 47,
|
||
right: 70,
|
||
child: Container(
|
||
height: 30,
|
||
width: double.infinity,
|
||
alignment: Alignment.centerLeft,
|
||
child: TextField(
|
||
keyboardType: TextInputType.text,
|
||
focusNode: focusNode,
|
||
decoration: InputDecoration(
|
||
hintText: S.of(context).Search_influential,
|
||
hintStyle: const TextStyle(fontSize: 14, color: Color(0xFF999999)),
|
||
border: InputBorder.none,
|
||
isCollapsed: true,
|
||
),
|
||
onChanged: influentialChange,
|
||
),
|
||
),
|
||
),
|
||
Positioned(
|
||
right: 7,
|
||
child: GestureDetector(
|
||
onTap: () {
|
||
if (NetworkConfig.userId == "") {
|
||
showLoginDialog();
|
||
} else {
|
||
if (influentialCode != "") {
|
||
focusNode.unfocus();
|
||
_viewModel.getUserHomePageByPw(influentialCode);
|
||
}
|
||
}
|
||
},
|
||
child: Container(
|
||
width: 60,
|
||
height: 28,
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(color: const Color(0xFF8841FF), borderRadius: BorderRadius.circular(14)),
|
||
child: Text(
|
||
S.of(context).search,
|
||
style: const TextStyle(color: Colors.white, fontSize: 14),
|
||
),
|
||
),
|
||
)),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
|
||
///推荐达人
|
||
recommenderList.isNotEmpty
|
||
? Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: const EdgeInsets.only(top: 20),
|
||
child: Text(
|
||
S.of(context).Recommended_influencers,
|
||
style: const TextStyle(fontSize: 16, color: Colors.black, fontWeight: FontWeight.w600),
|
||
),
|
||
)
|
||
: Container(),
|
||
recommenderList.isNotEmpty
|
||
? Container(
|
||
height: 70,
|
||
alignment: Alignment.centerLeft,
|
||
margin: const EdgeInsets.only(top: 20, right: 15),
|
||
child: ListView.builder(
|
||
shrinkWrap: true,
|
||
itemCount: recommenderList.length,
|
||
itemBuilder: (context, index) {
|
||
return influential(recommenderList[index]);
|
||
},
|
||
scrollDirection: Axis.horizontal),
|
||
)
|
||
: Container(),
|
||
|
||
///作品展示
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
margin: const EdgeInsets.only(top: 20),
|
||
child: Text(
|
||
S.of(context).Exhibition_works,
|
||
style: const TextStyle(fontSize: 16, color: Colors.black, fontWeight: FontWeight.w600),
|
||
),
|
||
),
|
||
|
||
///标签
|
||
Container(
|
||
height: 25,
|
||
alignment: Alignment.center,
|
||
margin: const EdgeInsets.only(top: 12),
|
||
child: ListView.builder(
|
||
itemCount: workLabelList.length,
|
||
itemBuilder: (context, index) {
|
||
return _labelItem(workLabelList[index], index);
|
||
},
|
||
scrollDirection: Axis.horizontal,
|
||
),
|
||
),
|
||
|
||
///子标签
|
||
Container(
|
||
margin: const EdgeInsets.only(top: 11),
|
||
child: Row(
|
||
children: [
|
||
GestureDetector(
|
||
onTap: () {
|
||
currentChild = 1;
|
||
getWorksListByLabel(false);
|
||
},
|
||
child: Container(
|
||
margin: const EdgeInsets.only(right: 10),
|
||
child: Text(
|
||
S.of(context).Newest,
|
||
style: TextStyle(color: currentChild == 1 ? Colors.black : Color(0xFF999999)),
|
||
),
|
||
),
|
||
),
|
||
GestureDetector(
|
||
onTap: () {
|
||
currentChild = 2;
|
||
getWorksListByLabel(false);
|
||
},
|
||
child: Container(
|
||
margin: EdgeInsets.only(right: 10),
|
||
child: Text(
|
||
S.of(context).Popular,
|
||
style: TextStyle(color: currentChild == 2 ? Colors.black : Color(0xFF999999)),
|
||
),
|
||
),
|
||
),
|
||
GestureDetector(
|
||
onTap: () {
|
||
currentChild = 3;
|
||
getWorksListByLabel(false);
|
||
},
|
||
child: Container(
|
||
margin: EdgeInsets.only(right: 10),
|
||
child: Text(
|
||
S.of(context).all,
|
||
style: TextStyle(color: currentChild == 3 ? Colors.black : Color(0xFF999999)),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
Container(
|
||
margin: EdgeInsets.only(top: 16, right: 15),
|
||
child: MasonryGridView.count(
|
||
crossAxisCount: 2,
|
||
itemCount: galleryList.length,
|
||
itemBuilder: (BuildContext context, int index) {
|
||
return _galleryItem(galleryList[index], index);
|
||
},
|
||
shrinkWrap: true,
|
||
// 纵向元素间距
|
||
mainAxisSpacing: 0,
|
||
// 横向元素间距
|
||
crossAxisSpacing: 10,
|
||
physics: const NeverScrollableScrollPhysics(),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
|
||
///置顶
|
||
StreamBuilder(
|
||
stream: streamData,
|
||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||
if (snapshot.data != null && snapshot.data) {
|
||
return Positioned(
|
||
right: 10,
|
||
bottom: 50,
|
||
child: GestureDetector(
|
||
onTap: () {
|
||
_scrollController.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.decelerate);
|
||
},
|
||
child: const Image(
|
||
width: 60,
|
||
image: AssetImage('assets/images/ic_topping.png'),
|
||
),
|
||
),
|
||
);
|
||
} else {
|
||
return Container();
|
||
}
|
||
}),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
// 下拉刷新
|
||
Future<void> _onRefresh() async {
|
||
// 持续两秒
|
||
await Future.delayed(const Duration(milliseconds: 1500), () {
|
||
currentLabelIndex = 0;
|
||
currentChild = 1;
|
||
index = 1;
|
||
galleryList = [];
|
||
_viewModel.getRecommenderList();
|
||
_viewModel.getGalleryWorkLabel();
|
||
});
|
||
}
|
||
|
||
//达人条目
|
||
influential(RecommenderBean data) {
|
||
return GestureDetector(
|
||
onTap: () {
|
||
if (NetworkConfig.userId == "") {
|
||
showLoginDialog();
|
||
} else {
|
||
focusNode.unfocus();
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (context) => ExpertUserDetailsPage(
|
||
workUserId: "${data.UserId}",
|
||
worksID: '${data.UserFollow}',
|
||
),
|
||
));
|
||
}
|
||
},
|
||
child: Container(
|
||
width: 50,
|
||
margin: EdgeInsets.only(right: 10),
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
ClipOval(
|
||
child: CachedNetworkImage(
|
||
width: 50,
|
||
height: 50,
|
||
imageUrl: data.UserIconUrl!,
|
||
errorWidget: (context, url, error) => Icon(Icons.error),
|
||
),
|
||
),
|
||
SizedBox(
|
||
width: 50,
|
||
child: Text(
|
||
"${data.NickName}",
|
||
style: TextStyle(fontSize: 12, color: Color(0xFF999999)),
|
||
overflow: TextOverflow.ellipsis,
|
||
),
|
||
)
|
||
],
|
||
),
|
||
));
|
||
}
|
||
|
||
//作品标签
|
||
_labelItem(GalleryWorkLabelBean data, index) {
|
||
return GestureDetector(
|
||
onTap: () {
|
||
if (NetworkConfig.userId == "") {
|
||
showLoginDialog();
|
||
} else {
|
||
focusNode.unfocus();
|
||
currentLabelIndex = index;
|
||
currentChild = 1;
|
||
getWorksListByLabel(false);
|
||
setState(() {});
|
||
}
|
||
},
|
||
child: Container(
|
||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||
alignment: Alignment.center,
|
||
decoration: BoxDecoration(
|
||
color: Color(currentLabelIndex == index ? 0xFF8841FF : 0xFFF6F7FF),
|
||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||
),
|
||
margin: const EdgeInsets.only(right: 12),
|
||
child: Text(
|
||
"${data.LabelName}",
|
||
style: TextStyle(color: currentLabelIndex == index ? Colors.white : Color(0xFF999999), fontSize: 13),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
//画廊
|
||
_galleryItem(GalleryWorkListBean bean, int index) {
|
||
return Column(
|
||
children: [
|
||
///Ai图
|
||
ClipRRect(
|
||
borderRadius: BorderRadius.circular(7),
|
||
child: GestureDetector(
|
||
onTap: () {
|
||
focusNode.unfocus();
|
||
if (NetworkConfig.userId == "") {
|
||
showLoginDialog();
|
||
} else {
|
||
// Navigator.push(
|
||
// context,
|
||
// MaterialPageRoute(
|
||
// builder: (context) => DrawDetailsPage(
|
||
// false,
|
||
// drawId: bean.DrawId.toString(),
|
||
// isMyWork: false,
|
||
// status: 3,
|
||
// ),
|
||
// ));
|
||
Navigator.push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (context) => InfluentialDetailsPage(bean.DrawId.toString()),
|
||
));
|
||
}
|
||
},
|
||
child: Stack(
|
||
children: [
|
||
CachedNetworkImage(
|
||
imageUrl: bean.ImageUrl!,
|
||
errorWidget: (context, url, error) => Icon(Icons.error),
|
||
),
|
||
bean.IsTalent == 1
|
||
? const Positioned(
|
||
left: 6,
|
||
top: 6,
|
||
child: Image(
|
||
width: 42,
|
||
image: AssetImage('assets/images/ic_portfolio.webp'),
|
||
))
|
||
: Container(),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
Row(
|
||
children: [
|
||
bean.IsTalent == 1
|
||
? Container(
|
||
width: 48,
|
||
height: 15,
|
||
alignment: Alignment.center,
|
||
margin: EdgeInsets.only(top: 2),
|
||
decoration: BoxDecoration(
|
||
border: Border.all(color: Color(0xFFFF6316), width: 1),
|
||
borderRadius: BorderRadius.all(Radius.circular(3)),
|
||
),
|
||
child: Text(
|
||
S.of(context).Expert_selection,
|
||
style: TextStyle(fontSize: 10, color: Color(0xFFFF661B)),
|
||
),
|
||
)
|
||
: Container(),
|
||
Container(
|
||
width: bean.IsTalent == 1 ? 100 : 140,
|
||
alignment: Alignment.centerLeft,
|
||
margin: EdgeInsets.only(left: 5),
|
||
child: Text(
|
||
"${bean.Title}",
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
style: TextStyle(color: Colors.black),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
|
||
Container(
|
||
height: 25,
|
||
margin: EdgeInsets.only(bottom: 10),
|
||
child: Stack(
|
||
alignment: Alignment.center,
|
||
children: [
|
||
///头像
|
||
Positioned(
|
||
left: 0,
|
||
child: ClipOval(
|
||
child: CachedNetworkImage(
|
||
fit: BoxFit.fitHeight,
|
||
width: 18,
|
||
height: 18,
|
||
imageUrl: bean.UserIocn!,
|
||
errorWidget: (context, url, error) => Image(
|
||
fit: BoxFit.fitWidth,
|
||
width: 18,
|
||
height: 18,
|
||
image: AssetImage('assets/images/head.png'),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
Positioned(
|
||
left: 23,
|
||
child: Container(
|
||
width: 80,
|
||
child: Text(
|
||
bean.UserNickName!,
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
style: TextStyle(color: Colors.black, fontSize: 12),
|
||
),
|
||
),
|
||
),
|
||
|
||
///点赞收藏
|
||
Positioned(
|
||
right: 0,
|
||
child: GestureDetector(
|
||
behavior: HitTestBehavior.opaque,
|
||
onTap: () {
|
||
focusNode.unfocus();
|
||
if (NetworkConfig.userId == "") {
|
||
showLoginDialog();
|
||
} else {
|
||
if (NetworkConfig.userId != "${bean.UserId}") {
|
||
bean.IsCollect = !bean.IsCollect!;
|
||
if (bean.IsCollect!) {
|
||
bean.LikeNum = (bean.LikeNum! + 1);
|
||
} else {
|
||
if (bean.LikeNum! > 0) {
|
||
bean.LikeNum = (bean.LikeNum! - 1);
|
||
}
|
||
}
|
||
setState(() {});
|
||
}
|
||
_viewModel.userDrawCollect(bean.IsCollect!, bean.DrawId.toString());
|
||
}
|
||
},
|
||
child: Container(
|
||
padding: EdgeInsets.all(15),
|
||
child: Row(
|
||
children: [
|
||
Image(
|
||
width: 13,
|
||
height: 12,
|
||
image: bean.IsCollect!
|
||
? const AssetImage('assets/images/ic_collect_s.png')
|
||
: const AssetImage('assets/images/ic_collect.png'),
|
||
),
|
||
Container(
|
||
margin: EdgeInsets.only(left: 5),
|
||
child: Text(
|
||
bean.LikeNum.toString(),
|
||
style: TextStyle(color: bean.IsCollect! ? Color(0xFFBB72E0) : Colors.black, fontSize: 12),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
)),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
//弹出登录
|
||
showLoginDialog() {
|
||
DialogManager()
|
||
..add(DialogBean(
|
||
dialogPriority: DialogPriority.highClear,
|
||
createDialogWidget: () => DialogUtil.createTipWidget(
|
||
context,
|
||
LoginDialog(
|
||
loginDialogKey,
|
||
onTap: (index) {
|
||
switch (index) {
|
||
case 0:
|
||
if (loginDialogKey.currentState != null) {
|
||
loginDialogKey.currentState!.Pop();
|
||
}
|
||
FunctionUtil.bottomSheetDialog(context, PhoneLoginDialog());
|
||
break;
|
||
case 1: //谷歌登录
|
||
Map<String, String> map = {"googleLogin": "googleLogin"};
|
||
invokeNativeMethod("googleLogin", map);
|
||
break;
|
||
}
|
||
},
|
||
),
|
||
"LoginDialog",
|
||
canceled: true)))
|
||
..show(context);
|
||
}
|
||
|
||
// 获取原生的值
|
||
invokeNativeMethod(String method, Map<String, dynamic> map) async {
|
||
dynamic args;
|
||
try {
|
||
args = await Global.method.invokeMethod(method, map);
|
||
} on PlatformException catch (e) {}
|
||
}
|
||
}
|