fmk
3 years ago
20 changed files with 1619 additions and 430 deletions
@ -0,0 +1,376 @@ |
|||||||
|
import 'package:dio/dio.dart'; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
||||||
|
import 'package:huixiang/community/community_view/community_comment.dart'; |
||||||
|
import 'package:huixiang/community/community_view/community_dynamic.dart'; |
||||||
|
import 'package:huixiang/generated/l10n.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/base_data.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/member_comment_list.dart'; |
||||||
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
||||||
|
import 'package:huixiang/utils/font_weight.dart'; |
||||||
|
import 'package:huixiang/view_widget/comment_menu.dart'; |
||||||
|
import 'package:huixiang/view_widget/login_tips_dialog.dart'; |
||||||
|
import 'package:huixiang/view_widget/tips_dialog.dart'; |
||||||
|
import 'package:huixiang/web/web_view/input_comment.dart'; |
||||||
|
import 'package:shared_preferences/shared_preferences.dart'; |
||||||
|
|
||||||
|
class CommunityDetails extends StatefulWidget { |
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _CommunityDetails(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _CommunityDetails extends State<CommunityDetails> { |
||||||
|
double height = 0; |
||||||
|
double commentHeight = 60.h; |
||||||
|
|
||||||
|
List<MemberCommentList> memberList = []; |
||||||
|
ApiService apiService; |
||||||
|
var commentFocus = FocusNode(); |
||||||
|
|
||||||
|
String hintText = S.current.liuxianinjingcaidepinglunba; |
||||||
|
bool isKeyBoardShow = false; |
||||||
|
|
||||||
|
@override |
||||||
|
void didChangeMetrics() { |
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) { |
||||||
|
if (MediaQuery.of(context).viewInsets.bottom == 0) { |
||||||
|
if (isKeyBoardShow) { |
||||||
|
FocusScope.of(context).requestFocus(FocusNode()); |
||||||
|
setState(() { |
||||||
|
hintText = S.current.liuxianinjingcaidepinglunba; |
||||||
|
isKeyBoardShow = false; |
||||||
|
}); |
||||||
|
} |
||||||
|
} else { |
||||||
|
setState(() { |
||||||
|
isKeyBoardShow = true; |
||||||
|
}); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
|
||||||
|
SharedPreferences.getInstance().then((value) { |
||||||
|
apiService = ApiService( |
||||||
|
Dio(), |
||||||
|
context: context, |
||||||
|
token: value.getString("token"), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Column( |
||||||
|
children: [ |
||||||
|
Expanded( |
||||||
|
child: NestedScrollView( |
||||||
|
headerSliverBuilder: (context, position) { |
||||||
|
return [ |
||||||
|
SliverOverlapAbsorber( |
||||||
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), |
||||||
|
sliver: SliverAppBar( |
||||||
|
expandedHeight: (height == 0) ? 614 : height, |
||||||
|
pinned: true, |
||||||
|
backgroundColor: Colors.white, |
||||||
|
title: Text( |
||||||
|
"动态详情", |
||||||
|
style: TextStyle( |
||||||
|
color: Colors.black, |
||||||
|
fontSize: 18.sp, |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
), |
||||||
|
), |
||||||
|
elevation: 0, |
||||||
|
leading: GestureDetector( |
||||||
|
onTap: () { |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
alignment: Alignment.centerRight, |
||||||
|
margin: EdgeInsets.only(left: 10), |
||||||
|
padding: EdgeInsets.all(6), |
||||||
|
child: Icon( |
||||||
|
Icons.arrow_back_ios, |
||||||
|
color: Colors.black, |
||||||
|
size: 24, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
flexibleSpace: FlexibleSpaceBar( |
||||||
|
//Colors.white, |
||||||
|
background: Container( |
||||||
|
padding: EdgeInsets.only( |
||||||
|
top: MediaQuery.of(context).padding.top + |
||||||
|
kToolbarHeight, |
||||||
|
), |
||||||
|
color: Colors.white, |
||||||
|
child: CommunityDynamic( |
||||||
|
itemCount: 3, |
||||||
|
isDetails: true, |
||||||
|
heightFun: (height) { |
||||||
|
this.height = height + |
||||||
|
MediaQuery.of(context).padding.top + |
||||||
|
kToolbarHeight + |
||||||
|
68; |
||||||
|
setState(() {}); |
||||||
|
}, |
||||||
|
), |
||||||
|
), |
||||||
|
collapseMode: CollapseMode.pin, |
||||||
|
), |
||||||
|
bottom: PreferredSize( |
||||||
|
preferredSize: Size( |
||||||
|
MediaQuery.of(context).size.width, |
||||||
|
46, |
||||||
|
), |
||||||
|
child: Container( |
||||||
|
padding: EdgeInsets.all(16), |
||||||
|
margin: EdgeInsets.only(top: 16.h), |
||||||
|
color: Colors.white, |
||||||
|
child: Row( |
||||||
|
children: [ |
||||||
|
Text( |
||||||
|
S.of(context).pinglun_("1"), |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14, |
||||||
|
fontWeight: FontWeight.bold, |
||||||
|
color: Color(0xff1A1A1A), |
||||||
|
), |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
width: 16.w, |
||||||
|
), |
||||||
|
Text( |
||||||
|
S.of(context).xihuan_("0"), |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14, |
||||||
|
fontWeight: FontWeight.bold, |
||||||
|
color: Color(0xff1A1A1A), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
]; |
||||||
|
}, |
||||||
|
body: Container( |
||||||
|
height: MediaQuery.of(context).size.height - |
||||||
|
MediaQuery.of(context).padding.top + |
||||||
|
kToolbarHeight - |
||||||
|
68, |
||||||
|
margin: EdgeInsets.only(top: 68 + 50 + kToolbarHeight), |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
if (memberList != null && memberList.length > 0) |
||||||
|
ListView.builder( |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
itemCount: memberList != null ? memberList.length : 0, |
||||||
|
scrollDirection: Axis.vertical, |
||||||
|
itemBuilder: (context, position) { |
||||||
|
return Material( |
||||||
|
color: Colors.white, |
||||||
|
child: InkWell( |
||||||
|
onTap: () { |
||||||
|
showPressMenu(memberList[position].createUser, |
||||||
|
memberList[position]); |
||||||
|
}, |
||||||
|
child: CommunityComment( |
||||||
|
memberList[position], |
||||||
|
_queryCommentLike, |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
}, |
||||||
|
), |
||||||
|
if (memberList != null && memberList.length > 0) |
||||||
|
Container( |
||||||
|
height: commentHeight, |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: Color(0xFFF2F2F2), |
||||||
|
boxShadow: [ |
||||||
|
BoxShadow( |
||||||
|
color: Colors.black.withAlpha(12), |
||||||
|
offset: Offset(0, 2), |
||||||
|
blurRadius: 14, |
||||||
|
spreadRadius: 0, |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
alignment: Alignment.topCenter, |
||||||
|
padding: EdgeInsets.only(top: 22.h), |
||||||
|
child: Text( |
||||||
|
S.of(context).yixiansquanbupinglun, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 12, |
||||||
|
color: Color(0xff353535), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
if (memberList == null || memberList.length == 0) |
||||||
|
Container( |
||||||
|
width: double.infinity, |
||||||
|
alignment: Alignment.topCenter, |
||||||
|
padding: EdgeInsets.all(22.h), |
||||||
|
child: Text( |
||||||
|
S.of(context).zanwupinglun, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 12, |
||||||
|
fontWeight: FontWeight.bold, |
||||||
|
color: Color(0xFFA0A0A0), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
flex: 1, |
||||||
|
), |
||||||
|
|
||||||
|
/// 富文本评论的输入框 |
||||||
|
InputComment( |
||||||
|
inputKey, |
||||||
|
hintText, |
||||||
|
isKeyBoardShow, |
||||||
|
commentFocus, |
||||||
|
commentTextController, |
||||||
|
_toComment, |
||||||
|
_queryMemberComment, |
||||||
|
_queryInformationLikes, |
||||||
|
), |
||||||
|
], |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
//给文章/活动点赞 |
||||||
|
_queryInformationLikes() async { |
||||||
|
BaseData baseData = await apiService.informationLikes(""); |
||||||
|
if (baseData != null && baseData.isSuccess) { |
||||||
|
// commentKey.currentState.setState(() {}); |
||||||
|
} else { |
||||||
|
SmartDialog.showToast(baseData.msg, alignment: Alignment.center); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//发布评论 |
||||||
|
_queryMemberComment(String content) async { |
||||||
|
// BaseData baseData = await apiService.memberComment({ |
||||||
|
// "content": content, |
||||||
|
// "parentId": parenId, |
||||||
|
// "relationalId": |
||||||
|
// widget.arguments["activityId"] ?? widget.arguments["articleId"], |
||||||
|
// "relationalType": 1 |
||||||
|
// }).catchError((error) {}); |
||||||
|
// if (baseData != null && baseData.isSuccess) { |
||||||
|
// commentKey.currentState.initState(); |
||||||
|
// commentTextController.text = ""; |
||||||
|
// _toComment(); |
||||||
|
// } |
||||||
|
} |
||||||
|
|
||||||
|
///滑动到评论列表 |
||||||
|
_toComment() { |
||||||
|
// if (commentKey.currentContext == null) return; |
||||||
|
// RenderBox firstRenderBox = commentKey.currentContext.findRenderObject(); |
||||||
|
// Offset first = firstRenderBox.localToGlobal(Offset.zero); |
||||||
|
// scrollController.animateTo(first.dy + scrollController.offset - |
||||||
|
// (kToolbarHeight + MediaQuery.of(context).padding.top), |
||||||
|
// duration: Duration(milliseconds: 300), |
||||||
|
// curve: Curves.easeIn); |
||||||
|
} |
||||||
|
|
||||||
|
final GlobalKey inputKey = GlobalKey(); |
||||||
|
final TextEditingController commentTextController = TextEditingController(); |
||||||
|
|
||||||
|
contentHeight() { |
||||||
|
double contentHeight = MediaQuery.of(context).size.height - |
||||||
|
kToolbarHeight - |
||||||
|
MediaQuery.of(context).padding.top - |
||||||
|
160.h; |
||||||
|
if ((contentHeight - 60.h) > (128.h * memberList.length)) { |
||||||
|
commentHeight = contentHeight - (128.h * memberList.length); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
showPressMenu(String userId, memberComment) { |
||||||
|
if (isKeyBoardShow) { |
||||||
|
FocusScope.of(context).requestFocus(FocusNode()); |
||||||
|
return; |
||||||
|
} |
||||||
|
SharedPreferences.getInstance().then((value) { |
||||||
|
SmartDialog.show( |
||||||
|
widget: CommentMenu( |
||||||
|
(type) { |
||||||
|
SmartDialog.dismiss(); |
||||||
|
if (type == "huifu") { |
||||||
|
_reply(memberComment); |
||||||
|
} else if (type == "shanchu") { |
||||||
|
_delCommentTips(); |
||||||
|
} |
||||||
|
}, |
||||||
|
isSelf: userId == value.getString("userId"), |
||||||
|
), |
||||||
|
alignmentTemp: Alignment.bottomCenter, |
||||||
|
isUseAnimationTemp: true, |
||||||
|
animationDurationTemp: Duration(milliseconds: 300), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
///删除评论的提示 |
||||||
|
_delCommentTips() { |
||||||
|
SmartDialog.show(widget: Tips(() { |
||||||
|
delComment(); |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
///删除评论 |
||||||
|
delComment() async { |
||||||
|
BaseData baseData = await apiService.delComment(""); |
||||||
|
if (baseData != null && baseData.isSuccess) { |
||||||
|
// commentKey.currentState.initState(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
///评论 回复 |
||||||
|
_reply(memberComment) { |
||||||
|
FocusScope.of(context).requestFocus(commentFocus); |
||||||
|
// parenId = memberComment.id; |
||||||
|
hintText = S.of(context).huifu_("${memberComment.username}"); |
||||||
|
} |
||||||
|
|
||||||
|
//评论点赞 |
||||||
|
_queryCommentLike(String id) async { |
||||||
|
SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); |
||||||
|
String token = sharedPreferences.getString("token"); |
||||||
|
if (token == null || token == "") { |
||||||
|
LoginTipsDialog().show(context); |
||||||
|
return; |
||||||
|
} |
||||||
|
BaseData baseData = await apiService.commentLike(id).catchError((error) {}); |
||||||
|
if (baseData != null && baseData.isSuccess) { |
||||||
|
memberList.forEach((element) { |
||||||
|
if (element.id == id) { |
||||||
|
if (element.liked) { |
||||||
|
element.likes -= 1; |
||||||
|
element.liked = false; |
||||||
|
} else { |
||||||
|
element.likes += 1; |
||||||
|
element.liked = true; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,201 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:huixiang/generated/l10n.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/base_data.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/member_comment_list.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
import 'package:huixiang/view_widget/custom_image.dart'; |
||||||
|
import 'package:huixiang/view_widget/login_tips_dialog.dart'; |
||||||
|
import 'package:like_button/like_button.dart'; |
||||||
|
import 'package:shared_preferences/shared_preferences.dart'; |
||||||
|
|
||||||
|
|
||||||
|
class CommunityComment extends StatefulWidget { |
||||||
|
|
||||||
|
MemberCommentList memberList; |
||||||
|
Function(String id) queryCommentLike; |
||||||
|
CommunityComment(this.memberList, this.queryCommentLike); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _CommunityComment(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
class _CommunityComment extends State<CommunityComment> { |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Container( |
||||||
|
padding: EdgeInsets.symmetric(vertical: 8.w), |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
Container( |
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w), |
||||||
|
child: Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||||
|
children: [ |
||||||
|
MImage( |
||||||
|
widget.memberList.userAvatarUrl ?? "", |
||||||
|
fit: BoxFit.cover, |
||||||
|
isCircle: true, |
||||||
|
width: 40, |
||||||
|
height: 40, |
||||||
|
fadeSrc: "assets/image/default_user.png", |
||||||
|
errorSrc: "assets/image/default_user.png", |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
width: 12.w, |
||||||
|
), |
||||||
|
Expanded( |
||||||
|
child: Container( |
||||||
|
// height: 60.h, |
||||||
|
child: Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Text.rich( |
||||||
|
TextSpan( |
||||||
|
children: [ |
||||||
|
TextSpan( |
||||||
|
text: widget.memberList.username, |
||||||
|
style: TextStyle( |
||||||
|
fontWeight: FontWeight.bold, |
||||||
|
fontSize: 12, |
||||||
|
color: Colors.black, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
textDirection: TextDirection.ltr, |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
height: 3.h, |
||||||
|
), |
||||||
|
Text( |
||||||
|
widget.memberList.createTime, |
||||||
|
overflow: TextOverflow.ellipsis, |
||||||
|
maxLines: 2, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14, |
||||||
|
color: Color(0xff808080), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
flex: 1, |
||||||
|
), |
||||||
|
Tooltip( |
||||||
|
message: S.of(context).dianzanxihuan_(S.of(context).pinglun), |
||||||
|
child: Container( |
||||||
|
alignment: Alignment.topRight, |
||||||
|
child: LikeButton( |
||||||
|
padding: EdgeInsets.all(10), |
||||||
|
circleSize: 16, |
||||||
|
circleColor: CircleColor( |
||||||
|
start: Color(0xff00ddff), |
||||||
|
end: Color(0xff0099cc), |
||||||
|
), |
||||||
|
bubblesColor: BubblesColor( |
||||||
|
dotPrimaryColor: Color(0xff33b5e5), |
||||||
|
dotSecondaryColor: Color(0xff0099cc), |
||||||
|
), |
||||||
|
bubblesSize: 15, |
||||||
|
likeBuilder: (bool isLiked) { |
||||||
|
return isLiked |
||||||
|
? Image.asset( |
||||||
|
"assets/image/icon_like.png", |
||||||
|
width: 16, |
||||||
|
height: 16, |
||||||
|
) |
||||||
|
: Image.asset( |
||||||
|
"assets/image/icon_like_h.png", |
||||||
|
width: 16, |
||||||
|
height: 16, |
||||||
|
); |
||||||
|
}, |
||||||
|
isLiked: widget.memberList.liked ?? false, |
||||||
|
onTap: (isLiked) async { |
||||||
|
widget.queryCommentLike(widget.memberList.id); |
||||||
|
return (widget.memberList == null || widget.memberList.liked == null) |
||||||
|
? false |
||||||
|
: widget.memberList.liked; |
||||||
|
}, |
||||||
|
likeCount: widget.memberList.likes, |
||||||
|
countBuilder: (int count, bool isLiked, String text) { |
||||||
|
return Text( |
||||||
|
text, |
||||||
|
style: TextStyle( |
||||||
|
color: Color(0xFF1A1A1A), |
||||||
|
fontSize: 14, |
||||||
|
), |
||||||
|
); |
||||||
|
}, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
Container( |
||||||
|
padding: EdgeInsets.only( |
||||||
|
left: 68.w, |
||||||
|
right: 16.w, |
||||||
|
top: 16.h, |
||||||
|
bottom: 16.h, |
||||||
|
), |
||||||
|
child: Align( |
||||||
|
alignment: Alignment.centerLeft, |
||||||
|
child: Text( |
||||||
|
widget.memberList.content, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 12, |
||||||
|
color: Color(0xff1A1A1A), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
height: 12.h, |
||||||
|
), |
||||||
|
if (widget.memberList.parentContent != null) |
||||||
|
Container( |
||||||
|
margin: EdgeInsets.only(left: 68.w, right: 16.w), |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: Color(0xffF2F2F2), |
||||||
|
borderRadius: BorderRadius.circular(2.0), |
||||||
|
), |
||||||
|
child: Padding( |
||||||
|
padding: EdgeInsets.only(left: 4.w, top: 4.h, bottom: 4.h), |
||||||
|
child: Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Text( |
||||||
|
"${widget.memberList.parentUserName}:" ?? "", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14, |
||||||
|
color: Color(0xff808080), |
||||||
|
), |
||||||
|
), |
||||||
|
Expanded( |
||||||
|
flex: 1, |
||||||
|
child: Text( |
||||||
|
widget.memberList.parentContent ?? "", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14, |
||||||
|
color: Color(0xff808080), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,213 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter_svg/flutter_svg.dart'; |
||||||
|
import 'package:huixiang/utils/font_weight.dart'; |
||||||
|
import 'package:huixiang/view_widget/icon_text.dart'; |
||||||
|
import 'package:huixiang/view_widget/round_button.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
|
||||||
|
class CommunityDynamic extends StatefulWidget { |
||||||
|
|
||||||
|
final int itemCount; |
||||||
|
final Function(double height) heightFun; |
||||||
|
final bool isDetails ; |
||||||
|
|
||||||
|
CommunityDynamic({ |
||||||
|
Key key, |
||||||
|
this.itemCount = 9, |
||||||
|
this.heightFun, |
||||||
|
this.isDetails = false, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _CommunityDynamic(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _CommunityDynamic extends State<CommunityDynamic> { |
||||||
|
|
||||||
|
GlobalKey globalKey = GlobalKey(); |
||||||
|
double height = 0; |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Column( |
||||||
|
children: [ |
||||||
|
Container( |
||||||
|
alignment: Alignment.topCenter, |
||||||
|
padding: EdgeInsets.all(16), |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: Colors.white, |
||||||
|
boxShadow: [ |
||||||
|
BoxShadow( |
||||||
|
color: Color(0x08000000), |
||||||
|
offset: Offset(0, 1), |
||||||
|
blurRadius: 8, |
||||||
|
spreadRadius: 0, |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
child: Column( |
||||||
|
key: globalKey, |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
mainAxisSize: MainAxisSize.min, |
||||||
|
children: [ |
||||||
|
Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||||
|
children: [ |
||||||
|
Container( |
||||||
|
height: 44, |
||||||
|
child: Row( |
||||||
|
children: [ |
||||||
|
ClipRRect( |
||||||
|
child: Image.asset( |
||||||
|
"assets/image/default_user.png", |
||||||
|
width: 44, |
||||||
|
height: 44, |
||||||
|
), |
||||||
|
borderRadius: BorderRadius.circular(22), |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
width: 8, |
||||||
|
), |
||||||
|
Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Text( |
||||||
|
"百花谷", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
fontWeight: MyFontWeight.medium, |
||||||
|
color: Color(0xFF1A1A1A), |
||||||
|
), |
||||||
|
), |
||||||
|
Text( |
||||||
|
"2021.04.12", |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 12.sp, |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
color: Color(0xFF808080), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
RoundButton( |
||||||
|
padding: EdgeInsets.symmetric( |
||||||
|
horizontal: 8, |
||||||
|
vertical: 3, |
||||||
|
), |
||||||
|
backgroup: Color(0xFF32A060), |
||||||
|
textColor: Colors.white, |
||||||
|
text: "关注", |
||||||
|
radius: 20, |
||||||
|
icons: SvgPicture.asset( |
||||||
|
"assets/svg/shequ_fabu.svg", |
||||||
|
fit: BoxFit.contain, |
||||||
|
color: Colors.white, |
||||||
|
width: 14, |
||||||
|
height: 14, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
height: 12.h, |
||||||
|
), |
||||||
|
Text( |
||||||
|
"文本,是指书面语言的表现形式,从文学角度说,通常是具有完整、系统含义(Message)的一个句子或多个句子的组说,通常是具有完整、系统含义(Message)的一个句子或多个句子的组或多个句子的组说。", |
||||||
|
maxLines: 5, |
||||||
|
overflow: TextOverflow.ellipsis, |
||||||
|
style: TextStyle( |
||||||
|
color: Color(0xFF1A1A1A), |
||||||
|
fontWeight: MyFontWeight.regular, |
||||||
|
fontSize: 14.sp, |
||||||
|
), |
||||||
|
), |
||||||
|
SizedBox( |
||||||
|
height: 16.h, |
||||||
|
), |
||||||
|
if (widget.itemCount == 1) |
||||||
|
Container( |
||||||
|
width: MediaQuery.of(context).size.width / 2, |
||||||
|
height: MediaQuery.of(context).size.width, |
||||||
|
color: Colors.blue.withAlpha(123), |
||||||
|
) |
||||||
|
else |
||||||
|
GridView.builder( |
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( |
||||||
|
crossAxisCount: |
||||||
|
(widget.itemCount == 2 || widget.itemCount == 4) ? 2 : 3, |
||||||
|
crossAxisSpacing: 12.w, |
||||||
|
mainAxisSpacing: 12.w, |
||||||
|
childAspectRatio: 1, |
||||||
|
), |
||||||
|
padding: EdgeInsets.zero, |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
itemBuilder: (context, position) { |
||||||
|
return Container( |
||||||
|
color: Colors.blue.withAlpha(123), |
||||||
|
); |
||||||
|
}, |
||||||
|
itemCount: widget.itemCount, |
||||||
|
), |
||||||
|
if (!widget.isDetails) |
||||||
|
SizedBox( |
||||||
|
height: 12.h, |
||||||
|
), |
||||||
|
if (!widget.isDetails) |
||||||
|
Row( |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||||
|
children: [ |
||||||
|
IconText( |
||||||
|
"58", |
||||||
|
space: 4.w, |
||||||
|
leftImage: "assets/svg/liulanliang.svg", |
||||||
|
iconSize: 16, |
||||||
|
), |
||||||
|
IconText( |
||||||
|
"58", |
||||||
|
space: 4.w, |
||||||
|
leftImage: "assets/svg/pinglun.svg", |
||||||
|
iconSize: 16, |
||||||
|
), |
||||||
|
IconText( |
||||||
|
"58", |
||||||
|
space: 4.w, |
||||||
|
leftImage: "assets/svg/xihuan.svg", |
||||||
|
iconSize: 16, |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
Container( |
||||||
|
height: 16, |
||||||
|
color: Color(0xFFF7F7F7), |
||||||
|
) |
||||||
|
], |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@override |
||||||
|
void didChangeDependencies() { |
||||||
|
WidgetsBinding.instance.addPostFrameCallback(_getContainerHeight); |
||||||
|
super.didChangeDependencies(); |
||||||
|
} |
||||||
|
|
||||||
|
_getContainerHeight(_) { |
||||||
|
height = globalKey.currentContext.size.height; |
||||||
|
widget.heightFun(height); |
||||||
|
print("height: $height"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,408 @@ |
|||||||
|
import 'dart:io'; |
||||||
|
import 'package:dio/dio.dart'; |
||||||
|
import 'package:flutter/cupertino.dart'; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter_easyloading/flutter_easyloading.dart'; |
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
||||||
|
import 'package:flutter_svg/flutter_svg.dart'; |
||||||
|
import 'package:huixiang/generated/l10n.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/base_data.dart'; |
||||||
|
import 'package:huixiang/retrofit/data/upload_result.dart'; |
||||||
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
||||||
|
import 'package:huixiang/utils/font_weight.dart'; |
||||||
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||||
|
import 'package:image_pickers/image_pickers.dart'; |
||||||
|
import 'package:shared_preferences/shared_preferences.dart'; |
||||||
|
|
||||||
|
class ReleaseDynamic extends StatefulWidget { |
||||||
|
@override |
||||||
|
State<StatefulWidget> createState() { |
||||||
|
return _ReleaseDynamic(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _ReleaseDynamic extends State<ReleaseDynamic> { |
||||||
|
int selectCount = 9; |
||||||
|
List<Medias> mediaPaths = []; |
||||||
|
bool isRelease = false; |
||||||
|
int dynamicType = 0; |
||||||
|
TextEditingController textEditingController = TextEditingController(); |
||||||
|
ApiService apiService; |
||||||
|
|
||||||
|
@override |
||||||
|
void initState() { |
||||||
|
super.initState(); |
||||||
|
|
||||||
|
SharedPreferences.getInstance().then((value) { |
||||||
|
apiService = ApiService( |
||||||
|
Dio(), |
||||||
|
context: context, |
||||||
|
token: value.getString("token"), |
||||||
|
showLoading: false, |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Scaffold( |
||||||
|
appBar: MyAppBar( |
||||||
|
title: "写动态", |
||||||
|
titleColor: Colors.black, |
||||||
|
leadingColor: Colors.black, |
||||||
|
background: Colors.white, |
||||||
|
action: Container( |
||||||
|
alignment: Alignment.center, |
||||||
|
child: Container( |
||||||
|
width: 46.w, |
||||||
|
height: 24.h, |
||||||
|
alignment: Alignment.center, |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: isRelease ? Color(0xFF32A060) : Color(0xFFD8D8D8), |
||||||
|
borderRadius: BorderRadius.circular(4), |
||||||
|
), |
||||||
|
child: Text( |
||||||
|
"发布", |
||||||
|
style: TextStyle( |
||||||
|
color: isRelease ? Colors.white : Color(0xFFA0A0A0), |
||||||
|
fontSize: 14.sp, |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
onTap: () { |
||||||
|
if (!isRelease) { |
||||||
|
SmartDialog.showToast("请输入您此刻的想法!~"); |
||||||
|
return; |
||||||
|
} |
||||||
|
releaseDynamic(); |
||||||
|
}, |
||||||
|
), |
||||||
|
body: Container( |
||||||
|
child: Column( |
||||||
|
children: [ |
||||||
|
buildEdit(), |
||||||
|
GridView.builder( |
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( |
||||||
|
crossAxisCount: 3, |
||||||
|
crossAxisSpacing: 12.w, |
||||||
|
mainAxisSpacing: 12.w, |
||||||
|
childAspectRatio: 1, |
||||||
|
), |
||||||
|
padding: EdgeInsets.all(16), |
||||||
|
shrinkWrap: true, |
||||||
|
physics: NeverScrollableScrollPhysics(), |
||||||
|
itemBuilder: (context, position) { |
||||||
|
if (mediaPaths.length > position) { |
||||||
|
return imageItem(mediaPaths[position]); |
||||||
|
} else { |
||||||
|
return addImageItem(); |
||||||
|
} |
||||||
|
}, |
||||||
|
itemCount: (mediaPaths.length == 0) |
||||||
|
? 1 |
||||||
|
: ((dynamicType == 2) |
||||||
|
? 1 |
||||||
|
: mediaPaths.length >= 9 |
||||||
|
? 9 |
||||||
|
: (mediaPaths.length + 1)), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
releaseDynamic() async { |
||||||
|
String dynamicText = textEditingController.text; |
||||||
|
if (dynamicText == null || dynamicText == "") { |
||||||
|
SmartDialog.showToast("请输入您此刻的想法!~"); |
||||||
|
return; |
||||||
|
} |
||||||
|
EasyLoading.show(status: S.of(context).zhengzaijiazai); |
||||||
|
|
||||||
|
fileUpload().then((value) async { |
||||||
|
String subjectType = "text"; |
||||||
|
if (dynamicType == 0) { |
||||||
|
subjectType = "text"; |
||||||
|
} else if (dynamicType == 1) { |
||||||
|
subjectType = "image"; |
||||||
|
} else if (dynamicType == 2) { |
||||||
|
subjectType = "video"; |
||||||
|
} |
||||||
|
|
||||||
|
List<String> remoteImageUrls = []; |
||||||
|
String remoteVideoUrl = ""; |
||||||
|
if (mediaPaths.length > 0) { |
||||||
|
if (dynamicType == 1) { |
||||||
|
remoteImageUrls = mediaPaths.map((e) => e.remotePath).toList(); |
||||||
|
} else if (dynamicType == 2) { |
||||||
|
remoteVideoUrl = mediaPaths[0].remotePath; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
BaseData<String> baseData = await apiService.trend({ |
||||||
|
"images": remoteImageUrls, |
||||||
|
"subject": dynamicText, |
||||||
|
"subjectType": subjectType, |
||||||
|
"video": remoteVideoUrl, |
||||||
|
}).catchError((onError) { |
||||||
|
EasyLoading.dismiss(); |
||||||
|
}); |
||||||
|
if (baseData.isSuccess) {} |
||||||
|
EasyLoading.dismiss(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
///文件上传 |
||||||
|
Future<void> fileUpload() async { |
||||||
|
if (mediaPaths != null && mediaPaths.length > 0) { |
||||||
|
await Future.forEach(mediaPaths, (element) async { |
||||||
|
if ((element.remotePath == null || element.remotePath == "") && |
||||||
|
(element != null && |
||||||
|
element.path != null && |
||||||
|
element.path != "" && |
||||||
|
await File(element.path).exists())) { |
||||||
|
BaseData<UploadResult> baseData = await apiService.upload( |
||||||
|
File(element.path), |
||||||
|
123123123, |
||||||
|
); |
||||||
|
if (baseData != null && baseData.isSuccess) { |
||||||
|
UploadResult uploadResult = baseData.data; |
||||||
|
mediaPaths[mediaPaths.indexOf(element)].remotePath = uploadResult.url; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Widget imageItem(Medias media) { |
||||||
|
return InkWell( |
||||||
|
onTap: () { |
||||||
|
showDeletePicker(media); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
decoration: BoxDecoration( |
||||||
|
borderRadius: BorderRadius.circular(4), |
||||||
|
), |
||||||
|
alignment: Alignment.center, |
||||||
|
child: ClipRRect( |
||||||
|
borderRadius: BorderRadius.circular(4), |
||||||
|
child: Image.file( |
||||||
|
File(media.galleryMode == GalleryMode.video |
||||||
|
? media.thumbPath |
||||||
|
: media.path), |
||||||
|
fit: BoxFit.cover, |
||||||
|
width: double.infinity, |
||||||
|
height: double.infinity, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
///显示图片选择方式 |
||||||
|
showImagePicker() { |
||||||
|
if (dynamicType == 1) { |
||||||
|
getImageOrVideo(GalleryMode.image); |
||||||
|
return; |
||||||
|
} |
||||||
|
showCupertinoModalPopup( |
||||||
|
context: context, |
||||||
|
builder: (context) { |
||||||
|
return CupertinoActionSheet( |
||||||
|
title: Text("选择媒体文件"), |
||||||
|
actions: [ |
||||||
|
CupertinoActionSheetAction( |
||||||
|
child: Text("照片"), |
||||||
|
onPressed: () { |
||||||
|
getImageOrVideo(GalleryMode.image); |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}, |
||||||
|
isDefaultAction: true, |
||||||
|
isDestructiveAction: false, |
||||||
|
), |
||||||
|
CupertinoActionSheetAction( |
||||||
|
child: Text("视频"), |
||||||
|
onPressed: () { |
||||||
|
getImageOrVideo(GalleryMode.video); |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}, |
||||||
|
isDefaultAction: true, |
||||||
|
isDestructiveAction: false, |
||||||
|
), |
||||||
|
], |
||||||
|
cancelButton: CupertinoActionSheetAction( |
||||||
|
onPressed: () { |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}, |
||||||
|
child: Text(S.of(context).quxiao), |
||||||
|
isDestructiveAction: true, |
||||||
|
), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
///显示图片选择方式 |
||||||
|
showDeletePicker(Medias media) { |
||||||
|
showCupertinoModalPopup( |
||||||
|
context: context, |
||||||
|
builder: (context) { |
||||||
|
return CupertinoActionSheet( |
||||||
|
title: Text("动态"), |
||||||
|
actions: [ |
||||||
|
CupertinoActionSheetAction( |
||||||
|
child: Text("删除"), |
||||||
|
onPressed: () { |
||||||
|
mediaPaths.remove(media); |
||||||
|
if (mediaPaths.length == 0) { |
||||||
|
dynamicType = 0; |
||||||
|
} |
||||||
|
selectCount = 9 - mediaPaths.length; |
||||||
|
Navigator.of(context).pop(); |
||||||
|
setState(() {}); |
||||||
|
}, |
||||||
|
isDefaultAction: true, |
||||||
|
isDestructiveAction: false, |
||||||
|
), |
||||||
|
], |
||||||
|
cancelButton: CupertinoActionSheetAction( |
||||||
|
onPressed: () { |
||||||
|
Navigator.of(context).pop(); |
||||||
|
}, |
||||||
|
child: Text(S.of(context).quxiao), |
||||||
|
isDestructiveAction: true, |
||||||
|
), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
Widget addImageItem() { |
||||||
|
return InkWell( |
||||||
|
onTap: () { |
||||||
|
showImagePicker(); |
||||||
|
}, |
||||||
|
child: Container( |
||||||
|
decoration: BoxDecoration( |
||||||
|
color: Color(0xFFF2F2F2), |
||||||
|
borderRadius: BorderRadius.circular(4), |
||||||
|
), |
||||||
|
alignment: Alignment.center, |
||||||
|
child: Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||||
|
children: [ |
||||||
|
SvgPicture.asset( |
||||||
|
"assets/svg/zhaopianshipin.svg", |
||||||
|
width: 48, |
||||||
|
height: 48, |
||||||
|
fit: BoxFit.contain, |
||||||
|
), |
||||||
|
Text( |
||||||
|
"照片/视频", |
||||||
|
style: TextStyle( |
||||||
|
fontWeight: MyFontWeight.semi_bold, |
||||||
|
fontSize: 15.sp, |
||||||
|
color: Color(0xFFCDCCCC), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
Future getImageOrVideo(GalleryMode galleryMode) async { |
||||||
|
if (selectCount == 0) return; |
||||||
|
List<Media> medias = await ImagePickers.pickerPaths( |
||||||
|
galleryMode: galleryMode, |
||||||
|
selectCount: (galleryMode == GalleryMode.video) ? 1 : selectCount, |
||||||
|
showGif: true, |
||||||
|
showCamera: false, |
||||||
|
compressSize: 500, |
||||||
|
uiConfig: UIConfig( |
||||||
|
uiThemeColor: Color(0xFFFFFFFF), |
||||||
|
), |
||||||
|
cropConfig: CropConfig( |
||||||
|
enableCrop: false, |
||||||
|
width: 200, |
||||||
|
height: 200, |
||||||
|
), |
||||||
|
); |
||||||
|
|
||||||
|
mediaPaths.addAll(medias.map((e) => Medias(e)).toList()); |
||||||
|
selectCount = 9 - mediaPaths.length; |
||||||
|
|
||||||
|
if (mediaPaths.length > 0) { |
||||||
|
if (galleryMode == GalleryMode.image) { |
||||||
|
dynamicType = 1; |
||||||
|
} else { |
||||||
|
dynamicType = 2; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
setState(() {}); |
||||||
|
} |
||||||
|
|
||||||
|
///动态输入框 |
||||||
|
Widget buildEdit() { |
||||||
|
return Container( |
||||||
|
height: 174.h, |
||||||
|
margin: EdgeInsets.symmetric(horizontal: 16.w), |
||||||
|
decoration: BoxDecoration( |
||||||
|
border: Border( |
||||||
|
bottom: BorderSide( |
||||||
|
width: 1.w, |
||||||
|
color: Color(0xFFD8D8D8), |
||||||
|
style: BorderStyle.solid, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
child: TextField( |
||||||
|
controller: textEditingController, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
fontWeight: MyFontWeight.medium, |
||||||
|
color: Color(0xFF4C4C4C), |
||||||
|
), |
||||||
|
onChanged: (text) { |
||||||
|
bool release = text != "" && text != null; |
||||||
|
if (release != isRelease) { |
||||||
|
isRelease = release; |
||||||
|
setState(() {}); |
||||||
|
} |
||||||
|
}, |
||||||
|
decoration: InputDecoration( |
||||||
|
contentPadding: EdgeInsets.symmetric( |
||||||
|
vertical: 18.h, |
||||||
|
), |
||||||
|
errorBorder: InputBorder.none, |
||||||
|
focusedBorder: InputBorder.none, |
||||||
|
enabledBorder: InputBorder.none, |
||||||
|
hintText: "此时此刻的想法~", |
||||||
|
hintStyle: TextStyle( |
||||||
|
fontSize: 14.sp, |
||||||
|
color: Color(0xFFA29E9E), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Medias { |
||||||
|
// Media media; |
||||||
|
|
||||||
|
Medias(Media media) { |
||||||
|
this.thumbPath = media.thumbPath; |
||||||
|
this.path = media.path; |
||||||
|
this.galleryMode = media.galleryMode; |
||||||
|
} |
||||||
|
|
||||||
|
String thumbPath; |
||||||
|
String path; |
||||||
|
GalleryMode galleryMode; |
||||||
|
String remotePath; |
||||||
|
} |
Loading…
Reference in new issue