123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- import 'dart:async';
- import 'dart:convert';
- import 'dart:math';
- import 'package:cached_network_image/cached_network_image.dart';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/rendering.dart';
- import 'package:flutter/scheduler.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter/widgets.dart';
- import 'package:shared_preferences/shared_preferences.dart';
- import 'package:sport/bean/image.dart' as photo;
- import 'package:sport/bean/message.dart';
- import 'package:sport/bean/post.dart';
- import 'package:sport/bean/post_user.dart';
- import 'package:sport/bean/user_info.dart';
- import 'package:sport/db/message_db.dart';
- import 'package:sport/pages/social/post_detail_page.dart';
- import 'package:sport/pages/social/share_webview.dart';
- import 'package:sport/pages/social/user_detail_page.dart';
- import 'package:sport/pages/my/feedback_page.dart';
- import 'package:sport/provider/lib/view_state_model.dart';
- import 'package:sport/provider/message_model.dart';
- import 'package:sport/provider/user_model.dart';
- import 'package:sport/router/navigator_util.dart';
- import 'package:sport/services/api/inject_api.dart';
- import 'package:sport/services/api/resp.dart';
- import 'package:sport/services/userid.dart';
- import 'package:sport/utils/DateFormat.dart';
- import 'package:sport/utils/toast.dart';
- import 'package:sport/widgets/appbar.dart';
- import 'package:sport/widgets/decoration.dart';
- import 'package:sport/widgets/loading.dart';
- import 'package:sport/widgets/menu_bar.dart';
- import 'package:sport/widgets/space.dart';
- import 'package:sport/widgets/dialog/popupmenu.dart' as menu;
- import 'package:provider/provider.dart';
- import 'gallery_photo_view.dart';
- final List<String> avatarList = [
- "https://wx3.sinaimg.cn/mw1024/a6bdcd78gy1gfna8yznv5j20m90m9tbz.jpg",
- "https://wx2.sinaimg.cn/mw1024/a6bdcd78gy1gfna8x3nbzj20m90m943a.jpg",
- "https://wx3.sinaimg.cn/mw1024/a6bdcd78gy1gfnaavrha3j20m90m9dkj.jpg",
- "https://wx4.sinaimg.cn/mw1024/a6bdcd78gy1gfna8znb76j20m90m978t.jpg",
- "https://wx4.sinaimg.cn/mw1024/a6bdcd78gy1gfna8wnwquj20lr0lradp.jpg",
- "https://wx4.sinaimg.cn/mw1024/a6bdcd78gy1gfna90vpgkj20lr0lrtby.jpg",
- "https://wx1.sinaimg.cn/mw1024/a6bdcd78gy1gfna8y4jb6j20m90m9tcj.jpg",
- "https://wx3.sinaimg.cn/mw1024/a6bdcd78gy1gfnaawemhtj20m90m9q7n.jpg",
- "https://wx4.sinaimg.cn/mw1024/a6bdcd78gy1gfnaaveqmwj20ls0lsn07.jpg",
- "https://wxt.sinaimg.cn/mw1024/a6bdcd78gy1gfnaat7uw5j20ls0lr0w0.jpg",
- "https://wx2.sinaimg.cn/mw1024/a6bdcd78gy1gfnaaubdhhj20m90m9786.jpg",
- ];
- class ChatPage extends StatefulWidget {
- final UserInfo user;
- final Post post; // 分享来的帖子
- final String hash; // 分享来的link
- final String image; // 分享来的图片 ...
- ChatPage(this.user, {this.post, this.hash, this.image});
- @override
- State<StatefulWidget> createState() => _ChatPageState();
- }
- // 服务端的数据 只有 拿了 和 没拿 ,客户端 就是 读了 和没读 ...
- class _ChatPageState extends State<ChatPage>
- with InjectLoginApi, InjectApi, UserId, WidgetsBindingObserver {
- GetMenuController _menuController = new GetMenuController();
- // ScrollController scrollMenuController = new ScrollController();
- StreamSubscription _streamSubscription;
- List<MessageItem> messageList = [];
- // String othersAvatarUrl = "";
- GlobalKey SCROLLVIEW = new GlobalKey();
- double emptyHeight;
- dispose() {
- super.dispose();
- _streamSubscription?.cancel();
- }
- initState() {
- super.initState();
- WidgetsBinding.instance.addObserver(this); // 监听一手自己...
- initMessageList();
- initListen(); // 开启监听... 先试试...
- addPost(); // 这里是分享过来的 ...
- // initScrollBottom();
- // print("${Provider.of<UserModel>(context, listen: false).user.toJson()}");
- // _menuController.scroll();
- }
- // 这个是初始化 聊天列表的...
- initMessageList() async {
- // await Future.delayed(Duration(milliseconds: 1000));
- // List<MessageItem> messageList = [];
- List<MessageItem> data = [];
- var list = await MessageDB().getMessageForUserId(widget.user.id);
- int day = -1;
- for (var item in list) {
- MessageItem _item = MessageItem.fromJson(item);
- if (_item.day != day) {
- day = _item.day;
- data.add(new MessageItem(
- messageType: "time",
- dateTime:
- DateFormat.format(DateTime.parse(_item.message.createdAt))));
- }
- data.add(_item);
- }
- // 读过就操作一手...
- await MessageDB().updateStatus(widget.user.id);
- // messageList.addAll(data);
- int cout = 0;
- data.forEach((element) {
- messageList.insert(0, element);
- });
- // 这里每次都会 拿最新的 而不是添加...
- setState(() {
- messageList = messageList;
- });
- // SchedulerBinding.instance.addPostFrameCallback((_) {
- ////here the sublist is already build
- // scrollMenuController.jumpTo(scrollMenuController.position.maxScrollExtent);
- // print("2222222222222222222222222");
- // print("${scrollMenuController.position.minScrollExtent} - ${scrollMenuController.position.maxScrollExtent}");
- // });
- _menuController.scroll();
- }
- Future addPost() async {
- // 这里是拿到了 帖子
- if (widget.post != null) {
- // 拿到后还得 存
- MessageInstance _instance = (await api.shareForwardSubject(
- int.parse(widget.post.id), widget.user.id))
- .data;
- print(
- "[_instance]${_instance.toJson()}---------------------------------------");
- await MessageDB().insert(new MessageItem(
- message: _instance, status: 0, curId: 0, userId: widget.user.id));
- addMessageToPage(_instance);
- }
- // 也可能是拿到了 link
- else if (widget.hash != null) {
- MessageInstance _instance =
- (await api.getshareForwardSport(widget.hash, widget.user.id)).data;
- await MessageDB().insert(new MessageItem(
- message: _instance, status: 0, curId: 0, userId: widget.user.id));
- addMessageToPage(_instance);
- } else if (widget.image != null) {
- MessageInstance _instance = (await api.postChatSend(
- widget.user.id, "image", '{"url":"${widget.image}"}'))
- .data;
- await MessageDB().insert(new MessageItem(
- message: _instance, status: 0, curId: 0, userId: widget.user.id));
- addMessageToPage(_instance);
- }
- }
- // 在本页中如果收到了就 ...
- initListen() {
- Stream<List<MessageInstance>> queryStream =
- Provider.of<MessageModel>(context, listen: false).queryStream;
- _streamSubscription =
- queryStream.listen((List<MessageInstance> list) async {
- for (MessageInstance item in list) {
- addMessageToPage(item);
- }
- await MessageDB().updateStatus(widget.user.id);
- });
- }
- //
- // initScrollBottom() {
- // _timer = Timer(Duration.zero, () {
- // _menuController.scrollToBottom(context, SCROLLVIEW, true);
- // });
- // }
- MessageItem instanceToItem(MessageInstance _instance) {
- int id = _instance.fromUser.id == int.parse(selfId)
- ? _instance.toUser.id
- : _instance.fromUser.id;
- // 里面收到 直接已读... 好像curId 可以不加 status 也可以不写 ...
- MessageItem item =
- new MessageItem(message: _instance, curId: 0, status: 0, userId: id);
- return item;
- }
- // 各种来自别的地方收到的消息 输出到 页面上
- addMessageToPage(MessageInstance _instance) {
- MessageItem item = instanceToItem(_instance);
- // messageList.insert(0, item);
- // messageList.add(item);
- messageList.insert(0, item); // 到头插...
- setState(() {
- messageList = messageList;
- });
- }
- // 封装的聊天msg
- // @who 判断是用户自己的还是 聊的那个人
- // @msg 信息 聊天的那个
- // @type 聊天的类型 可能是通过分享过来的那种 ? 游戏 或者是 别的 社区 或者是 链接 ?
- Widget _buildChatItem(MessageItem item) {
- // type 是时间 还是 消息...
- print("${item.toJson()}----------------------------------");
- if (item.messageType != null) {
- return Padding(
- padding: EdgeInsets.symmetric(vertical: 5.0),
- child: Center(
- child: Text(
- "${item.dateTime}",
- style: TextStyle(fontSize: 12.0),
- ),
- ),
- );
- }
- GlobalKey anchorKey = GlobalKey();
- MessageInstance data = item.message;
- int who = data.fromUser.id ==
- Provider.of<UserModel>(context, listen: false).user.id
- ? 1
- : 0;
- String userAvatar = data.fromUser.avatar;
- Widget chatItemOfType(String type) {
- List<photo.Image> images = [];
- images.add(photo.Image(id: "1", src: data.data.url));
- // 文本或者是图片...
- if (type == "text" || type == "image") {
- return Column(
- children: <Widget>[
- if (data.data.text != null)
- Text(
- "${data.data.text}",
- style: Theme.of(context)
- .textTheme
- .subtitle1
- .copyWith(fontSize: 16, color: Colors.black),
- ),
- if (data.data.url != null)
- InkWell(
- child: Container(
- constraints: BoxConstraints(
- maxHeight: MediaQuery.of(context).size.height,
- maxWidth: MediaQuery.of(context).size.width,
- ),
- child: CachedNetworkImage(
- imageUrl:
- data.data.url + "?x-oss-process=image/resize,p_10",
- height: 100,
- ),
- ),
- onTap: () {
- Navigator.push(
- context,
- FadeRoute(
- page: GalleryPhotoViewWrapper(
- galleryItems: images,
- backgroundDecoration: const BoxDecoration(
- color: Colors.black,
- ),
- initialIndex: 1,
- scrollDirection: Axis.horizontal,
- loadingBuilder: (_, __) => RequestLoadingWidget(),
- ),
- ),
- );
- },
- )
- ],
- crossAxisAlignment: CrossAxisAlignment.start,
- );
- }
- // 论坛消息 ...
- if (type == "forum-forward") {
- print("[forum-forward]${item.toJson()}----------------------");
- return InkWell(
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: <Widget>[
- ClipRRect(
- child: Image.asset(
- "lib/assets/img/chat.png",
- width: 40,
- height: 40,
- fit: BoxFit.cover,
- ),
- borderRadius: BorderRadius.circular(10),
- ),
- Space(
- width: 10.0,
- ),
- Expanded(
- child: RichText(
- text: TextSpan(children: [
- TextSpan(
- text: "@" + data.data.user.name + ":",
- style: Theme.of(context)
- .textTheme
- .headline6
- .copyWith(color: Color(0xFFFFC400))),
- TextSpan(
- text: "分享了一篇帖子",
- style: Theme.of(context).textTheme.subtitle1),
- ]),
- ),
- )
- ],
- ),
- onTap: () async {
- Post post =
- (await api.getPostDetail("${data.data.subject.id}")).data;
- NavigatorUtil.goPage(
- context, (context) => PostDetailPage(post, false, null));
- },
- );
- }
- // 链接..
- if (type == "share") {
- return InkWell(
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- CachedNetworkImage(
- imageUrl: avatarList[8],
- width: 60.0,
- height: 60.0,
- ),
- Space(
- width: 5.0,
- ),
- Expanded(
- child: RichText(
- text: TextSpan(children: [
- TextSpan(
- text: data.fromUser.name,
- style: Theme.of(context)
- .textTheme
- .headline6
- .copyWith(color: Color(0xFFFFC400))),
- TextSpan(
- text: "分享了他的运动记录,快来围观吧~",
- style: Theme.of(context).textTheme.subtitle1),
- ]),
- ),
- )
- ]),
- onTap: () async {
- await NavigatorUtil.goPage(
- context,
- (context) => WebViewSharePage(
- data.data.url,
- hash: data.data.share.hash,
- ));
- },
- );
- }
- }
- Widget chatContent(){
- return ConstrainedBox(
- constraints:
- BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.6),
- child: Container(
- padding: who == 1
- ? EdgeInsets.fromLTRB(12, 6, 20, 8)
- : EdgeInsets.fromLTRB(20, 6, 12, 8),
- key: anchorKey,
- child: GestureDetector(
- behavior: HitTestBehavior.opaque,
- onLongPressStart: (e) {
- RenderBox renderBox =
- anchorKey.currentContext.findRenderObject();
- var offset = renderBox
- .localToGlobal(Offset(0.0, renderBox.size.height));
- final RelativeRect position = RelativeRect.fromLTRB(
- e.globalPosition.dx, //取点击位置坐弹出x坐标
- offset.dy, //取text高度做弹出y坐标(这样弹出就不会遮挡文本)
- e.globalPosition.dx,
- offset.dy);
- PopupMenuEntry menuItem(
- {String imgUrl, String text, Function callBack}) =>
- menu.PopupMenuItem(
- child: InkWell(
- onTap: () {
- callBack();
- Navigator.pop(context);
- },
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Image.asset(
- "lib/assets/img/$imgUrl",
- width: 24,
- ),
- SizedBox(
- width: 4,
- ),
- Text(
- text,
- )
- ],
- ),
- ),
- );
- showMenu(
- context: context,
- position: position,
- items: <PopupMenuEntry>[
- PopupMenuItem(
- child: Container(
- child: Column(
- children: <Widget>[
- menuItem(
- imgUrl: "linkpop_icon_copy.png",
- text: "复制",
- callBack: () {
- Clipboard.setData(ClipboardData(
- text: '${data.data.text}'));
- ToastUtil.show("复制成功");
- }),
- who == 1
- ? menuItem(
- imgUrl: "linkpop_icon_del.png",
- text: "删除",
- callBack: () async {
- await MessageDB()
- .deleteMessageIdMessage(
- item.messageId);
- messageList.remove(item);
- setState(() {
- messageList = messageList;
- });
- },
- )
- : menuItem(
- imgUrl: "linkpop_icon_modify_1.png",
- text: "举报",
- callBack: () async {
- await api.postForumReport(
- userId: item.userId,
- content:
- "该用户涉嫌发送不良消息内容为:${item.message.data.text}");
- ToastUtil.show("举报已受理...");
- }),
- menuItem(
- imgUrl: "linkpop_icon_cancel.png", text: "取消")
- ],
- ),
- ))
- ],
- );
- },
- child: chatItemOfType(data.type))),
- );
- }
- Widget customPoint(){
- print("[data.type]:${data.type}--------------------");
- if(data.type != "image"){
- return CustomPaint(
- painter: who == 1 ? BubblePainterRight() : BubblePainter(),
- child: chatContent());
- }
- return chatContent();
- };
- Widget spaceItem = Space(
- width: 12,
- );
- String avatarUrl = data.fromUser?.id == int.parse(selfId)
- ? Provider.of<UserModel>(context, listen: false).user?.avatar == null
- ? avatarList[4]
- : Provider.of<UserModel>(context, listen: false).user?.avatar
- : widget.user?.avatar == null
- ? data.fromUser.avatar
- : widget.user?.avatar;
- Widget avatar = InkWell(
- onTap: () async {
- await NavigatorUtil.goPage(
- context,
- (context) => UserDetailPage(PostUser(
- id: "${data.fromUser?.id}",
- name: data.fromUser?.name,
- avatar: avatarUrl)));
- },
- child: CircleAvatar(
- backgroundImage: CachedNetworkImageProvider(avatarUrl),
- radius: 20,
- ),
- );
- List<Widget> chatContentUsr = [customPoint(), spaceItem, avatar];
- List<Widget> chatContentOther = [avatar, spaceItem, customPoint()];
- return Padding(
- padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 12.0),
- child: Row(
- mainAxisAlignment:
- who == 1 ? MainAxisAlignment.end : MainAxisAlignment.start,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: who == 1 ? chatContentUsr : chatContentOther,
- ));
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- appBar: AppBar(
- title: InkWell(
- child: Text(
- "${widget.user.name}${widget.user.id}",
- style: titleStyle,
- ),
- onTap: (){
- NavigatorUtil.goPage(context, (context) => UserDetailPage(PostUser.fromJson({"id":"${widget.user.id}"})));
- },
- ),
- leading: buildBackButton(context),
- ),
- // resizeToAvoidBottomInset: false, // 透传MediaQuery 的高度?
- body: WillPopScope(
- onWillPop: () async {
- // 这是分享.... 只能一步一步pop 出去
- if (widget.post != null ||
- widget.hash != null ||
- widget.image != null) {
- Navigator.pop(context, true);
- return false;
- }
- return true;
- },
- child: MenuBar(
- CustomScrollView(
- key: SCROLLVIEW,
- shrinkWrap: true,
- reverse: true,
- controller: _menuController.scrollMenuController,
- // controller: scrollMenuController,
- slivers: <Widget>[
- if (messageList?.length == 0)
- SliverToBoxAdapter(
- child: Container(),
- ),
- if (messageList?.length != 0)
- SliverList(
- delegate: SliverChildBuilderDelegate((content, index) {
- // MessageInstance data = messageList[index];
- return _buildChatItem(messageList[index]);
- }, childCount: messageList.length),
- ),
- ],
- ),
- menuIdentity:
- new MenuIdentity(menuScene: "chat", userId: widget.user.id),
- inputField: "",
- scrollToBottom: _menuController.scroll, // 暂时可以废弃...
- sendCallBack: addMessageToPage,
- globalkey: SCROLLVIEW,
- )));
- }
- }
|