|
|
@ -1,4 +1,3 @@
|
|
|
|
import 'dart:math';
|
|
|
|
|
|
|
|
import 'dart:ui';
|
|
|
|
import 'dart:ui';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
@ -6,9 +5,11 @@ import 'package:recook/constants/api.dart';
|
|
|
|
import 'package:recook/constants/header.dart';
|
|
|
|
import 'package:recook/constants/header.dart';
|
|
|
|
import 'package:recook/manager/http_manager.dart';
|
|
|
|
import 'package:recook/manager/http_manager.dart';
|
|
|
|
import 'package:recook/pages/live/models/topic_base_info_model.dart';
|
|
|
|
import 'package:recook/pages/live/models/topic_base_info_model.dart';
|
|
|
|
|
|
|
|
import 'package:recook/pages/live/models/topic_content_list_model.dart';
|
|
|
|
import 'package:recook/pages/live/widget/live_attention_button.dart';
|
|
|
|
import 'package:recook/pages/live/widget/live_attention_button.dart';
|
|
|
|
import 'package:recook/widgets/custom_image_button.dart';
|
|
|
|
import 'package:recook/widgets/custom_image_button.dart';
|
|
|
|
import 'package:recook/widgets/recook_back_button.dart';
|
|
|
|
import 'package:recook/widgets/recook_back_button.dart';
|
|
|
|
|
|
|
|
import 'package:recook/widgets/refresh_widget.dart';
|
|
|
|
import 'package:waterfall_flow/waterfall_flow.dart';
|
|
|
|
import 'package:waterfall_flow/waterfall_flow.dart';
|
|
|
|
|
|
|
|
|
|
|
|
class TopicPage extends StatefulWidget {
|
|
|
|
class TopicPage extends StatefulWidget {
|
|
|
@ -21,6 +22,9 @@ class TopicPage extends StatefulWidget {
|
|
|
|
|
|
|
|
|
|
|
|
class _TopicPageState extends State<TopicPage> {
|
|
|
|
class _TopicPageState extends State<TopicPage> {
|
|
|
|
TopicBaseInfoModel _topicBaseInfoModel = TopicBaseInfoModel.zero();
|
|
|
|
TopicBaseInfoModel _topicBaseInfoModel = TopicBaseInfoModel.zero();
|
|
|
|
|
|
|
|
GSRefreshController _controller = GSRefreshController();
|
|
|
|
|
|
|
|
int _page = 1;
|
|
|
|
|
|
|
|
List<TopicContentListModel> models = [];
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
super.initState();
|
|
|
@ -34,118 +38,131 @@ class _TopicPageState extends State<TopicPage> {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
|
|
void dispose() {
|
|
|
|
|
|
|
|
_controller?.dispose();
|
|
|
|
|
|
|
|
super.dispose();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
|
|
|
return Scaffold(
|
|
|
|
backgroundColor: AppColor.frenchColor,
|
|
|
|
backgroundColor: AppColor.frenchColor,
|
|
|
|
body: Stack(
|
|
|
|
body: Stack(
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
CustomScrollView(
|
|
|
|
NestedScrollView(
|
|
|
|
physics:
|
|
|
|
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
|
|
|
BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
|
|
|
return [
|
|
|
|
slivers: [
|
|
|
|
SliverAppBar(
|
|
|
|
SliverAppBar(
|
|
|
|
leading: RecookBackButton(white: true),
|
|
|
|
leading: RecookBackButton(white: true),
|
|
|
|
brightness: Brightness.light,
|
|
|
|
brightness: Brightness.light,
|
|
|
|
stretch: true,
|
|
|
|
stretch: true,
|
|
|
|
floating: true,
|
|
|
|
floating: true,
|
|
|
|
expandedHeight:
|
|
|
|
expandedHeight:
|
|
|
|
rSize(140) + MediaQuery.of(context).viewPadding.top,
|
|
|
|
rSize(140) + MediaQuery.of(context).viewPadding.top,
|
|
|
|
flexibleSpace: FlexibleSpaceBar(
|
|
|
|
flexibleSpace: FlexibleSpaceBar(
|
|
|
|
background: Stack(
|
|
|
|
background: Stack(
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Positioned(
|
|
|
|
Positioned(
|
|
|
|
left: 0,
|
|
|
|
left: 0,
|
|
|
|
right: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 0,
|
|
|
|
bottom: 0,
|
|
|
|
top: 0,
|
|
|
|
top: 0,
|
|
|
|
child: FadeInImage.assetNetwork(
|
|
|
|
child: FadeInImage.assetNetwork(
|
|
|
|
placeholder: R.ASSETS_PLACEHOLDER_NEW_1X1_A_PNG,
|
|
|
|
placeholder: R.ASSETS_PLACEHOLDER_NEW_1X1_A_PNG,
|
|
|
|
image: Api.getImgUrl(_topicBaseInfoModel.topicImg),
|
|
|
|
image: Api.getImgUrl(_topicBaseInfoModel.topicImg),
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
BackdropFilter(
|
|
|
|
BackdropFilter(
|
|
|
|
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
|
|
|
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
|
|
|
child: Container(
|
|
|
|
child: Container(
|
|
|
|
color: Colors.black.withOpacity(0.11),
|
|
|
|
color: Colors.black.withOpacity(0.11),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Positioned(
|
|
|
|
Positioned(
|
|
|
|
bottom: rSize(22),
|
|
|
|
bottom: rSize(22),
|
|
|
|
left: rSize(15),
|
|
|
|
left: rSize(15),
|
|
|
|
right: rSize(15),
|
|
|
|
right: rSize(15),
|
|
|
|
child: Row(
|
|
|
|
child: Row(
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
FadeInImage.assetNetwork(
|
|
|
|
FadeInImage.assetNetwork(
|
|
|
|
placeholder: R.ASSETS_PLACEHOLDER_NEW_1X1_A_PNG,
|
|
|
|
placeholder: R.ASSETS_PLACEHOLDER_NEW_1X1_A_PNG,
|
|
|
|
image:
|
|
|
|
image:
|
|
|
|
Api.getImgUrl(_topicBaseInfoModel.topicImg),
|
|
|
|
Api.getImgUrl(_topicBaseInfoModel.topicImg),
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
height: rSize(64),
|
|
|
|
height: rSize(64),
|
|
|
|
width: rSize(64),
|
|
|
|
width: rSize(64),
|
|
|
|
alignment: Alignment.bottomRight,
|
|
|
|
alignment: Alignment.bottomRight,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
SizedBox(width: rSize(15)),
|
|
|
|
SizedBox(width: rSize(15)),
|
|
|
|
Expanded(
|
|
|
|
Expanded(
|
|
|
|
child: Column(
|
|
|
|
child: Column(
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Row(
|
|
|
|
Row(
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Expanded(
|
|
|
|
Expanded(
|
|
|
|
child: Text(
|
|
|
|
child: Text(
|
|
|
|
'#${_topicBaseInfoModel.title}',
|
|
|
|
'#${_topicBaseInfoModel.title}',
|
|
|
|
style: TextStyle(
|
|
|
|
style: TextStyle(
|
|
|
|
color: Colors.white,
|
|
|
|
color: Colors.white,
|
|
|
|
fontSize: rSP(16),
|
|
|
|
fontSize: rSP(16),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
LiveAttentionButton(
|
|
|
|
LiveAttentionButton(
|
|
|
|
initAttention:
|
|
|
|
initAttention:
|
|
|
|
_topicBaseInfoModel.isFollow == 1,
|
|
|
|
_topicBaseInfoModel.isFollow == 1,
|
|
|
|
filled: true,
|
|
|
|
filled: true,
|
|
|
|
width: rSize(56),
|
|
|
|
width: rSize(56),
|
|
|
|
height: rSize(26),
|
|
|
|
height: rSize(26),
|
|
|
|
onAttention: (oldAttentionState) {
|
|
|
|
onAttention: (oldAttentionState) {
|
|
|
|
HttpManager.post(
|
|
|
|
HttpManager.post(
|
|
|
|
oldAttentionState
|
|
|
|
oldAttentionState
|
|
|
|
? LiveAPI.cancelTopic
|
|
|
|
? LiveAPI.cancelTopic
|
|
|
|
: LiveAPI.addTopic,
|
|
|
|
: LiveAPI.addTopic,
|
|
|
|
{'topicId': widget.topicId},
|
|
|
|
{'topicId': widget.topicId},
|
|
|
|
);
|
|
|
|
);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
SliverPadding(
|
|
|
|
},
|
|
|
|
|
|
|
|
body: RefreshWidget(
|
|
|
|
|
|
|
|
controller: _controller,
|
|
|
|
|
|
|
|
onRefresh: () {
|
|
|
|
|
|
|
|
_page = 1;
|
|
|
|
|
|
|
|
_getTopicContentModels().then((getModels) {
|
|
|
|
|
|
|
|
models = getModels;
|
|
|
|
|
|
|
|
if (mounted) setState(() {});
|
|
|
|
|
|
|
|
_controller.refreshCompleted();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
body: WaterfallFlow.builder(
|
|
|
|
padding: EdgeInsets.all(rSize(15)),
|
|
|
|
padding: EdgeInsets.all(rSize(15)),
|
|
|
|
sliver: SliverWaterfallFlow(
|
|
|
|
gridDelegate:
|
|
|
|
delegate: SliverChildBuilderDelegate(
|
|
|
|
SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
|
|
|
|
(context, index) {
|
|
|
|
crossAxisCount: 2,
|
|
|
|
return _buildCard();
|
|
|
|
crossAxisSpacing: rSize(15),
|
|
|
|
},
|
|
|
|
mainAxisSpacing: rSize(15),
|
|
|
|
// childCount:
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
gridDelegate:
|
|
|
|
|
|
|
|
SliverWaterfallFlowDelegateWithFixedCrossAxisCount(
|
|
|
|
|
|
|
|
crossAxisCount: 2,
|
|
|
|
|
|
|
|
crossAxisSpacing: rSize(15),
|
|
|
|
|
|
|
|
mainAxisSpacing: rSize(15),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
|
|
|
|
return _buildCard(models[index]);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
itemCount: models.length,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Positioned(
|
|
|
|
Positioned(
|
|
|
|
bottom: MediaQuery.of(context).viewPadding.bottom,
|
|
|
|
bottom: MediaQuery.of(context).viewPadding.bottom,
|
|
|
@ -177,30 +194,29 @@ class _TopicPageState extends State<TopicPage> {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_buildCard() {
|
|
|
|
_buildCard(TopicContentListModel model) {
|
|
|
|
final height = 100 + 150 * Random().nextDouble();
|
|
|
|
|
|
|
|
return ClipRRect(
|
|
|
|
return ClipRRect(
|
|
|
|
borderRadius: BorderRadius.circular(10),
|
|
|
|
borderRadius: BorderRadius.circular(rSize(10)),
|
|
|
|
child: CustomImageButton(
|
|
|
|
child: MaterialButton(
|
|
|
|
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
|
|
|
|
color: Colors.white,
|
|
|
|
onPressed: () {},
|
|
|
|
onPressed: () {},
|
|
|
|
|
|
|
|
splashColor: Colors.black26,
|
|
|
|
child: Column(
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Container(
|
|
|
|
FadeInImage.assetNetwork(
|
|
|
|
height: height,
|
|
|
|
placeholder: R.ASSETS_PLACEHOLDER_NEW_1X1_A_PNG,
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
image: model.coverUrl,
|
|
|
|
color: Colors.white,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
child: Placeholder(),
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Container(
|
|
|
|
Container(
|
|
|
|
color: Colors.white,
|
|
|
|
|
|
|
|
padding: EdgeInsets.all(rSize(10)),
|
|
|
|
padding: EdgeInsets.all(rSize(10)),
|
|
|
|
child: Column(
|
|
|
|
child: Column(
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
Text(
|
|
|
|
'爱生活,爱厨房,爱上厨房精美的器具里生活的…',
|
|
|
|
model.content,
|
|
|
|
maxLines: 2,
|
|
|
|
maxLines: 2,
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
style: TextStyle(
|
|
|
|
style: TextStyle(
|
|
|
@ -212,12 +228,21 @@ class _TopicPageState extends State<TopicPage> {
|
|
|
|
SizedBox(height: rSize(6)),
|
|
|
|
SizedBox(height: rSize(6)),
|
|
|
|
Row(
|
|
|
|
Row(
|
|
|
|
children: [
|
|
|
|
children: [
|
|
|
|
CircleAvatar(
|
|
|
|
ClipRRect(
|
|
|
|
radius: rSize(9),
|
|
|
|
borderRadius: BorderRadius.circular(9),
|
|
|
|
|
|
|
|
child: FadeInImage.assetNetwork(
|
|
|
|
|
|
|
|
placeholder: R.ASSETS_PLACEHOLDER_NEW_1X1_A_PNG,
|
|
|
|
|
|
|
|
image: Api.getImgUrl(model.headImgUrl),
|
|
|
|
|
|
|
|
height: rSize(18),
|
|
|
|
|
|
|
|
width: rSize(18),
|
|
|
|
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
|
|
|
|
rWBox(4),
|
|
|
|
Expanded(
|
|
|
|
Expanded(
|
|
|
|
child: Text(
|
|
|
|
child: Text(
|
|
|
|
'',
|
|
|
|
model.nickname,
|
|
|
|
|
|
|
|
maxLines: 1,
|
|
|
|
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
style: TextStyle(
|
|
|
|
style: TextStyle(
|
|
|
|
color: Color(0xFF666666),
|
|
|
|
color: Color(0xFF666666),
|
|
|
|
fontSize: rSP(12),
|
|
|
|
fontSize: rSP(12),
|
|
|
@ -230,7 +255,7 @@ class _TopicPageState extends State<TopicPage> {
|
|
|
|
width: rSize(14),
|
|
|
|
width: rSize(14),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Text(
|
|
|
|
Text(
|
|
|
|
'13',
|
|
|
|
model.praise.toString(),
|
|
|
|
style: TextStyle(
|
|
|
|
style: TextStyle(
|
|
|
|
color: Color(0xFf666666),
|
|
|
|
color: Color(0xFf666666),
|
|
|
|
fontSize: rSP(12),
|
|
|
|
fontSize: rSP(12),
|
|
|
@ -246,4 +271,18 @@ class _TopicPageState extends State<TopicPage> {
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Future<List<TopicContentListModel>> _getTopicContentModels() async {
|
|
|
|
|
|
|
|
ResultData resultData = await HttpManager.post(LiveAPI.topicContentList, {
|
|
|
|
|
|
|
|
'topicId': widget.topicId,
|
|
|
|
|
|
|
|
'page': _page,
|
|
|
|
|
|
|
|
'limit': 12,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
if (resultData?.data['data']['list'] == null)
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
return (resultData.data['data']['list'] as List)
|
|
|
|
|
|
|
|
.map((e) => TopicContentListModel.fromJson(e))
|
|
|
|
|
|
|
|
.toList();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|