123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- import 'package:flutter/material.dart';
- import 'package:flutter_osc/model/api.dart';
- import 'package:flutter_osc/model/constants.dart';
- import 'dart:convert';
- import 'package:flutter_osc/util/DataUtils.dart';
- import 'package:flutter_osc/util/NetUtils.dart';
- import 'package:flutter_osc/widgets/CommonEndLine.dart';
- // 动弹详情
- class TweetDetailPage extends StatefulWidget {
- Map<String, dynamic>? tweetData;
- TweetDetailPage({Key? key, this.tweetData}):super(key: key);
- @override
- State<StatefulWidget> createState() {
- return TweetDetailPageState(tweetData: tweetData);
- }
- }
- class TweetDetailPageState extends State<TweetDetailPage> {
- Map<String, dynamic>? tweetData;
- List? commentList;
- RegExp regExp1 = RegExp("</.*>");
- RegExp regExp2 = RegExp("<.*>");
- TextStyle subtitleStyle = TextStyle(
- fontSize: 12.0,
- color: const Color(0xFFB5BDC0)
- );
- TextStyle contentStyle = TextStyle(
- fontSize: 15.0,
- color: Colors.black
- );
- num curPage = 1;
- ScrollController _controller = ScrollController();
- TextEditingController _inputController = TextEditingController();
- TweetDetailPageState({Key? key, this.tweetData});
- // 获取动弹的回复
- getReply(bool isLoadMore) {
- DataUtils.isLogin().then((isLogin) {
- if (isLogin) {
- DataUtils.getAccessToken().then((token) {
- if (token == null || token.length == 0) {
- return;
- }
- Map<String, String> params = Map();
- var id = this.tweetData!['id'];
- params['id'] = '$id';
- params['catalog'] = '3';// 3是动弹评论
- params['access_token'] = token;
- params['page'] = '$curPage';
- params['pageSize'] = '20';
- params['dataType'] = 'json';
- NetUtils.get(Api.COMMENT_LIST, params: params).then((data) {
- setState(() {
- if (!isLoadMore) {
- commentList = json.decode(data)['commentList'];
- if (commentList == null) {
- commentList = [];
- }
- } else {
- // 加载更多数据
- List list = [];
- list.addAll(commentList!);
- list.addAll(json.decode(data)['commentList']);
- if (list.length >= tweetData!['commentCount']) {
- list.add(Constants.END_LINE_TAG);
- }
- commentList = list;
- }
- });
- });
- });
- }
- });
- }
- @override
- void initState() {
- super.initState();
- getReply(false);
- _controller.addListener(() {
- var max = _controller.position.maxScrollExtent;
- var pixels = _controller.position.pixels;
- if (max == pixels && commentList!.length < tweetData!['commentCount']) {
- // scroll to end, load next page
- curPage++;
- getReply(true);
- }
- });
- }
- @override
- Widget build(BuildContext context) {
- var _body = commentList == null ? Center(
- child: CircularProgressIndicator(),
- ) : ListView.builder(
- itemCount: commentList!.length == 0 ? 1 : commentList!.length * 2,
- itemBuilder: renderListItem,
- controller: _controller,
- );
- return Scaffold(
- appBar: AppBar(
- title: Text("动弹详情", style: TextStyle(color: Colors.white)),
- iconTheme: IconThemeData(color: Colors.white),
- actions: <Widget>[
- IconButton(
- icon: Icon(Icons.send),
- onPressed: () {
- // 回复楼主
- showReplyBottomView(context, true);
- },
- )
- ],
- ),
- body: _body
- );
- }
- Widget renderListItem(BuildContext context, int i) {
- if (i == 0) {
- return getTweetView(this.tweetData!);
- }
- i -= 1;
- if (i.isOdd) {
- return Divider(height: 1.0,);
- }
- i ~/= 2;
- return _renderCommentRow(context, i);
- }
- // 渲染评论列表
- _renderCommentRow(context, i) {
- var listItem = commentList![i];
- if (listItem is String && listItem == Constants.END_LINE_TAG) {
- return CommonEndLine();
- }
- String avatar = listItem['commentPortrait'];
- String author = listItem['commentAuthor'];
- String date = listItem['pubDate'];
- String content = listItem['content'];
- content = clearHtmlContent(content);
- var row = Row(
- children: [
- Padding(
- padding: const EdgeInsets.all(10.0),
- child: Image.network(avatar, width: 35.0, height: 35.0,)
- ),
- Expanded(
- child: Container(
- margin: const EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 5.0),
- child: Column(
- children: [
- Row(
- children: [
- Expanded(
- child: Text(author, style: TextStyle(color: const Color(0xFF63CA6C)),),
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
- child: Text(date, style: subtitleStyle,)
- )
- ],
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
- child: Row(
- children: [
- Expanded(
- child: Text(content, style: contentStyle,)
- )
- ],
- )
- )
- ],
- ),
- )
- )
- ],
- );
- return Builder(
- builder: (ctx) {
- return InkWell(
- onTap: () {
- showReplyBottomView(ctx, false, data: listItem);
- },
- child: row,
- );
- },
- );
- }
- showReplyBottomView(ctx, bool isMainFloor, {data}) {
- String title;
- String authorId;
- if (isMainFloor) {
- title = "@${tweetData!['author']}";
- authorId = "${tweetData!['authorid']}";
- } else {
- title = "@${data['commentAuthor']}";
- authorId = "${data['commentAuthorId']}";
- }
- print("authorId = $authorId");
- showModalBottomSheet(
- context: ctx,
- builder: (sheetCtx) {
- return Container(
- height: 230.0,
- padding: const EdgeInsets.all(20.0),
- child: Column(
- children: [
- Row(
- children: [
- Text(isMainFloor ? "回复楼主" : "回复"),
- Expanded(child: Text(title, style: TextStyle(color: const Color(0xFF63CA6C)),)),
- InkWell(
- child: Container(
- padding: const EdgeInsets.fromLTRB(10.0, 6.0, 10.0, 6.0),
- decoration: BoxDecoration(
- border: Border.all(
- color: const Color(0xFF63CA6C),
- width: 1.0,
- ),
- borderRadius: BorderRadius.all(Radius.circular(6.0))
- ),
- child: Text("发送", style: TextStyle(color: const Color(0xFF63CA6C)),),
- ),
- onTap: () {
- // 发送回复
- sendReply(authorId);
- },
- )
- ],
- ),
- Container(
- height: 10.0,
- ),
- TextField(
- maxLines: 5,
- controller: _inputController,
- decoration: InputDecoration(
- hintText: "说点啥~",
- hintStyle: TextStyle(
- color: const Color(0xFF808080)
- ),
- border: OutlineInputBorder(
- borderRadius: const BorderRadius.all(const Radius.circular(10.0)),
- )
- ),
- )
- ],
- )
- );
- }
- );
- }
- void sendReply(authorId) {
- String replyStr = _inputController.text;
- if (replyStr == null || replyStr.length == 0 || replyStr.trim().length == 0) {
- return;
- } else {
- DataUtils.isLogin().then((isLogin) {
- if (isLogin) {
- DataUtils.getAccessToken().then((token) {
- Map<String, String?> params = Map();
- params['access_token'] = token;
- params['id'] = "${tweetData!['id']}";
- print("id: ${tweetData!['id']}");
- params['catalog'] = "3";
- params['content'] = replyStr;
- params['authorid'] = "$authorId";
- print("authorId: $authorId");
- params['isPostToMyZone'] = "0";
- params['dataType'] = "json";
- NetUtils.get(Api.COMMENT_REPLY, params: params).then((data) {
- if (data != null) {
- var obj = json.decode(data);
- var error = obj['error'];
- if (error != null && error == '200') {
- // 回复成功
- Navigator.of(context).pop();
- getReply(false);
- }
- }
- });
- });
- }
- });
- }
- }
- Widget getTweetView(Map<String, dynamic> listItem) {
- var authorRow = Row(
- children: [
- Container(
- width: 35.0,
- height: 35.0,
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- color: Colors.blue,
- image: DecorationImage(
- image: NetworkImage(listItem['portrait']),
- fit: BoxFit.cover
- ),
- border: Border.all(
- color: Colors.white,
- width: 2.0,
- ),
- ),
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(6.0, 0.0, 0.0, 0.0),
- child: Text(listItem['author'], style: TextStyle(
- fontSize: 16.0,
- ))
- ),
- Expanded(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- Text('${listItem['commentCount']}', style: subtitleStyle,),
- Image.asset('./images/ic_comment.png', width: 20.0, height: 20.0,)
- ],
- ),
- )
- ],
- );
- var _body = listItem['body'];
- _body = clearHtmlContent(_body);
- var contentRow = Row(
- children: [
- Expanded(child: Text(_body),)
- ],
- );
- var timeRow = Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Text(listItem['pubDate'], style: subtitleStyle,)
- ],
- );
- var columns = <Widget>[
- Padding(
- padding: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 2.0),
- child: authorRow,
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(52.0, 0.0, 10.0, 0.0),
- child: contentRow,
- ),
- ];
- String? imgSmall = listItem['imgSmall'];
- if (imgSmall != null && imgSmall.length > 0) {
- // 动弹中有图片
- List<String> list = imgSmall.split(",");
- List<String> imgUrlList = <String>[];
- for (String s in list) {
- if (s.startsWith("http")) {
- imgUrlList.add(s);
- } else {
- imgUrlList.add("https://static.oschina.net/uploads/space/" + s);
- }
- }
- List<Widget> imgList = [];
- List rows = [];
- num len = imgUrlList.length;
- for (var row = 0; row < getRow(len as int); row++) {
- List<Widget> rowArr = [];
- for (var col = 0; col < 3; col++) {
- num index = row * 3 + col;
- num screenWidth = MediaQuery.of(context).size.width;
- double cellWidth = (screenWidth - 100) / 3;
- if (index < len) {
- rowArr.add(Padding(
- padding: const EdgeInsets.all(2.0),
- child: Image.network(imgUrlList[index as int], width: cellWidth, height: cellWidth),
- ));
- }
- }
- rows.add(rowArr);
- }
- for (var row in rows) {
- imgList.add(Row(
- children: row,
- ));
- }
- columns.add(Padding(
- padding: const EdgeInsets.fromLTRB(52.0, 5.0, 10.0, 0.0),
- child: Column(
- children: imgList,
- ),
- ));
- }
- columns.add(Padding(
- padding: const EdgeInsets.fromLTRB(52.0, 10.0, 10.0, 6.0),
- child: timeRow,
- ));
- columns.add(Divider(height: 5.0,));
- columns.add(Container(
- margin: const EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 0.0),
- child: Row(
- children: [
- Container(
- width: 4.0,
- height: 20.0,
- color: const Color(0xFF63CA6C),
- ),
- Expanded(
- flex: 1,
- child: Container(
- height: 20.0,
- color: const Color(0xFFECECEC),
- child: Text("评论列表", style: TextStyle(color: const Color(0xFF63CA6C)),)
- ),
- )
- ],
- ),
- ));
- return Column(
- children: columns,
- );
- }
- int getRow(int n) {
- int a = n % 3;
- int b = n ~/ 3;
- if (a != 0) {
- return b + 1;
- }
- return b;
- }
- // 去掉文本中的html代码
- String clearHtmlContent(String str) {
- if (str.startsWith("<emoji")) {
- return "[emoji]";
- }
- var s = str.replaceAll(regExp1, "");
- s = s.replaceAll(regExp2, "");
- s = s.replaceAll("\n", "");
- return s;
- }
- }
|