| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- import 'dart:convert';
- import 'package:flutter/services.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/cupertino.dart';
- import 'package:fluttertoast/fluttertoast.dart';
- import 'package:image_picker/image_picker.dart';
- import 'package:twongCustomer/routes/utils.dart';
- import 'package:twongCustomer/utils/loading.dart';
- import '../utils/http.dart';
- import '../utils/cache.dart';
- import '../utils/emoji.dart';
- import '../models/index.dart';
- import '../utils/events.dart';
- import '../utils/size_fit.dart';
- class ChatPage extends StatefulWidget{
- final UserInfo user;
- ChatPage(this.user, {Key key}): super(key: key);
- @override
- State<StatefulWidget> createState() {
- return _ChatPageState();
- }
- }
- class _ChatPageState extends State<ChatPage> with WidgetsBindingObserver {
- UserInfo user;
- FocusNode _inputFocus = new FocusNode();
- List<List<String>> emojis = new List<List<String>>();
- List<HttpMessage> _messageList = new List<HttpMessage>();
- ScrollController _scrollController = new ScrollController();
- TextEditingController _textController = new TextEditingController();
- @override
- void initState() {
- super.initState();
- WidgetsBinding.instance.addObserver(this);
- initData();
- initEventListener();
- Events.fire(ClearUnread(widget.user.uid));
- }
- @override
- void didChangeAppLifecycleState(AppLifecycleState state) {
- print("--" + state.toString());
- switch (state) {
- case AppLifecycleState.inactive: // 处于这种状态的应用程序应该假设它们可能在任何时候暂停。
- break;
- case AppLifecycleState.resumed:// 应用程序可见,前台
- break;
- case AppLifecycleState.paused: // 应用程序不可见,后台
- break;
- case AppLifecycleState.detached:
- break;
- }
- }
- @override
- void dispose() {
- super.dispose();
- print("chat dispose");
- }
- void initData() {
- initEmojis();
- user = AppData.get("info");
- // Loading.show(context);
- Http.getHistory(widget.user.uid).then((list) {
- if (!mounted) return;
- setState(() {
- _messageList = list;
- });
- Loading.hide(context);
- }).catchError((err) {
- Loading.hide(context);
- Fluttertoast.showToast(msg: "获取聊天记录失败");
- print("history err: " + err.toString());
- });
- }
- void initEmojis() {
- var idx = 1;
- var page = 0;
- emojis.add(new List<String>());
- for(var item in EmojiConf.list) {
- emojis[page].add(item);
- if(idx % 24 == 0){
- page++;
- emojis.add(new List<String>());
- }
- idx++;
- }
- }
- void initEventListener() {
- Events.on<UserMessage>().listen((event) {
- if(!mounted) return;
- setState(() {
- _messageList.add(event.message);
- _scrollController.animateTo(0,
- duration: const Duration(milliseconds: 300),
- curve: Curves.easeOut,
- );
- });
- });
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- resizeToAvoidBottomInset: true,
- appBar: AppBar(
- centerTitle: true,
- title: Text(widget.user.username),
- actions: [
- IconButton(icon: Icon(Icons.more_horiz_outlined, size: 34), onPressed: () {
- RouterUtils.toUserInfo(context, widget.user);
- }),
- Container(width: 6)
- ],
- ),
- body: SafeArea(
- child: ListView(children: <Widget>[
- Container(
- height: 500,
- child: ListView.builder(
- reverse: true,
- controller: _scrollController,
- physics: BouncingScrollPhysics(),
- itemCount: _messageList.length,
- itemBuilder: (context, i) {
- return _buildMessage(i);
- },
- ),
- ),
- // Divider(height: 1.0),
- _buildComposer(),
- ]),
- )
- );
- }
- Widget _buildAvatar(String url) {
- return Container(
- padding: EdgeInsets.only(top: 4),
- child: ClipRRect(
- borderRadius: BorderRadius.circular(20),
- child: Image.network(url, width: 40, height: 40)
- ));
- }
- Widget _buildMsgBody(bool visitor, HttpMessage msg) {
- // print("build msg: " + user.toJson().toString());
- return Flexible(child: Container(
- margin: EdgeInsets.only(left: 10, right: 10),
- child: Column(
- crossAxisAlignment: visitor ? CrossAxisAlignment.start : CrossAxisAlignment
- .end,
- children: [
- Text(visitor ? msg.visitor_name : user.name, textAlign: TextAlign.right,),
- Container(
- margin: EdgeInsets.only(top: 6),
- padding: EdgeInsets.all(10),
- decoration: BoxDecoration(
- color: _getBackground(visitor, msg),
- borderRadius: BorderRadius.all(Radius.circular(20))
- ),
- child: _buildMsgContent(msg)
- )
- ],
- ),
- ));
- }
- Color _getBackground(bool visitor, HttpMessage msg) {
- if(msg.content.startsWith("face[")) {
- return visitor ? Colors.cyanAccent : Colors.greenAccent;
- }
- if(msg.content.startsWith("img[")) {
- return null;
- }
- if(msg.content.startsWith("product[")) {
- return Colors.white70;
- }
- if(msg.content.startsWith("order[")) {
- return null;
- }
- return visitor ? Colors.cyanAccent : Colors.greenAccent;
- }
- Widget _buildMsgContent(HttpMessage msg) {
- if(msg.content.startsWith("face[")) {
- var name = msg.content.substring(5, msg.content.length - 1);
- return Container( height: 32, width: 32, child: Image.asset("assets/emojis/" + name + ".png"));
- }
- if(msg.content.startsWith("img[")) {
- var url = msg.content.substring(4, msg.content.length - 1);
- return Image.network(url);
- }
- if(msg.content.startsWith("product[")) {
- var url = msg.content.substring(8, msg.content.length - 1);
- print(url);
- var product = Product.fromJson(json.decode(url));
- return _buildProduct(product);
- }
- if(msg.content.startsWith("order[")) {
- var url = msg.content.substring(6, msg.content.length - 1);
- print(url);
- var order = Order.fromJson(json.decode(url));
- return _buildOrder(order);
- }
- return Text(msg.content);
- }
- Widget _buildOrder(Order order) {
- return Container(
- padding: EdgeInsets.all(10.px),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(4.px)
- ),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text("订单号:"),
- Row(
- children: [
- Expanded(child: Text(order.order_id, style: TextStyle(decoration:
- TextDecoration.underline, fontWeight: FontWeight.bold))),
- GestureDetector(
- onTap: () {
- Clipboard.setData(ClipboardData(text: order.order_id))
- .then((value) => Fluttertoast.showToast(msg: "复制成功!"));
- },
- child: Container(
- padding: EdgeInsets.only(left: 8.px,right: 8.px, top: 2.px, bottom: 2.px),
- decoration: BoxDecoration(
- color: Colors.blue,
- borderRadius: BorderRadius.circular(4.px)
- ),
- child: Text("复制", style: TextStyle(color: Colors.white)),
- ),
- )
- ],
- )
- ],
- ));
- }
- Widget _buildProduct(Product product) {
- return Container(
- padding: EdgeInsets.all(4.px),
- child: Column(
- children: [
- Image.network(product.image),
- Text(product.store_name, style: TextStyle(fontWeight: FontWeight.bold)),
- Row(
- children: [
- Expanded(child: RichText(
- text: TextSpan(
- text: "会员价:",
- style: TextStyle(color: Colors.black, fontSize: 14.px),
- children: [
- TextSpan(
- text: "¥",
- style: TextStyle(color: Colors.black, fontSize: 12.px),
- ),
- TextSpan(
- text: product.vip_price,
- style: TextStyle(color: Colors.red, fontSize: 16.px)
- )
- ]
- ),
- )),
- Expanded(child: RichText(
- text: TextSpan(
- text: "售价:",
- style: TextStyle(color: Colors.black, fontSize: 14.px),
- children: [
- TextSpan(
- text: "¥",
- style: TextStyle(color: Colors.black, fontSize: 12.px),
- ),
- TextSpan(
- text: product.price,
- style: TextStyle(color: Colors.red, fontSize: 16.px)
- )
- ]
- ),
- )),
- ],
- )
- ],
- ),
- );
- }
- Widget _buildMessage(idx) {
- var msg = _messageList[_messageList.length - idx - 1];
- var visitor = msg.mes_type == "visitor";
- var customer = AppData.get("info") as UserInfo;
- // print(msg.toJson());
- return Container(
- padding: EdgeInsets.all(10),
- alignment: visitor ? Alignment.topLeft : Alignment.topRight,
- child: visitor ? Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- _buildAvatar(visitor ? msg.visitor_avator : customer.avator),
- _buildMsgBody(visitor, msg)
- ],
- ): Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- _buildMsgBody(visitor, msg),
- _buildAvatar(customer.avator)
- ],
- )
- );
- }
- Widget _buildComposer() {
- return Container(
- alignment: Alignment.center,
- height: 45.0,
- width: double.infinity,
- margin: EdgeInsets.all(3.0),
- child: Row(
- children: <Widget>[
- IconButton(icon: Icon(
- Icons.emoji_emotions, color: Colors.black26, size: 30,),
- onPressed: _openFaces),
- Expanded(
- child: TextField(
- focusNode: _inputFocus,
- textInputAction: TextInputAction.send,
- controller: _textController,
- onSubmitted: _submitMsg,
- decoration: InputDecoration(
- contentPadding: EdgeInsets.all(10.0),
- hintText: "想说点儿什么?",
- fillColor: Colors.white,
- filled: true,
- border: OutlineInputBorder(
- borderSide: BorderSide.none,
- borderRadius: BorderRadius.all(Radius.circular(5)),
- ),
- ),
- ),
- ),
- IconButton(
- icon: Icon(Icons.add_circle_outline),
- onPressed: _openAction,
- color: Colors.black26,
- ),
- ],
- ),
- );
- }
- void _submitMsg(String txt) async {
- var tem = _textController.text;
- _textController.text = "";
- FocusScope.of(context).requestFocus(_inputFocus);
- await Http.sendMsg(widget.user.uid, txt).then((res) {
- var msg = HttpMessage();
- msg.content = txt;
- Events.fire(UserMessage(msg));
- }).catchError((err) {
- print(err);
- _textController.text = tem;
- Fluttertoast.showToast(msg: "发送失败!");
- });
- }
- void _submitFace(String name) async {
- var code = "face[$name]";
- await Http.sendMsg(widget.user.uid, code).then((res) {
- var msg = HttpMessage();
- msg.content = code;
- Events.fire(UserMessage(msg));
- Navigator.pop(context);
- }).catchError((err) {
- print(err);
- Fluttertoast.showToast(msg: "发送失败!");
- });
- }
- Widget _getAvatar(String name) {
- return InkWell(onTap: () => _submitFace(name), child: CircleAvatar(child:
- Container(child: Image.asset("assets/emojis/" + name + ".png"),
- margin: EdgeInsets.all(8)), radius: 20, backgroundColor: Colors.transparent));
- }
- Future _openFaces () {
- var pageWidgets = List<Widget>();
- for(var item in emojis) {
- var faceWidgets = List<Widget>();
- for(var face in item) {
- faceWidgets.add(_getAvatar(face));
- }
- pageWidgets.add(GridView(
- gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: 8, //横轴三个子widget
- childAspectRatio: 1 //宽高比为1时,子widget
- ),
- children: faceWidgets,
- ));
- }
- return showModalBottomSheet(
- context: context,
- isScrollControlled: true,
- builder: (BuildContext context) {
- return Container(
- height: 160,
- child: PageView(
- children: pageWidgets,
- ),
- );
- });
- }
- Future _openAction() {
- return showModalBottomSheet(
- context: context,
- builder: (BuildContext context) {
- return SafeArea(child: Column(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- new ListTile(
- leading: Icon(Icons.photo_camera),
- title: Text("相机拍摄"),
- onTap: () async {
- var image = await ImagePicker.pickImage(
- source: ImageSource.camera);
- Navigator.pop(context);
- },
- ),
- new ListTile(
- leading: Icon(Icons.photo_library),
- title: Text("照片库"),
- onTap: () async {
- var image = await ImagePicker.pickImage(
- source: ImageSource.gallery);
- Navigator.pop(context);
- },
- ),
- ],
- ));
- });
- }
- }
|