Created
May 27, 2021 18:08
-
-
Save dunods/00fbf75b60ddd408bee4f1f31e238dc4 to your computer and use it in GitHub Desktop.
backup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'package:aclub/features/chat/bloc/message.dart'; | |
import 'package:aclub/features/chat/model/message.dart'; | |
import 'package:aclub/features/chat/provider/group_provider.dart'; | |
import 'package:aclub/features/chat/screen/chat/info.dart'; | |
import 'package:aclub/features/chat/screen/chat/search.dart'; | |
import 'package:aclub/features/chat/utils/constant.dart'; | |
import 'package:aclub/features/chat/utils/styles.dart'; | |
import 'package:aclub/src/model/SessionProfile.dart'; | |
import 'package:aclub/utils/Consts/ApiConst.dart'; | |
import 'package:aclub/utils/MyLoader.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:aclub/features/chat/screen/chat/input.dart'; | |
import 'package:aclub/features/chat/screen/chat/thread.dart'; | |
import 'package:focused_menu/modals.dart'; | |
import 'package:grouped_list/grouped_list.dart'; | |
import 'package:jiffy/jiffy.dart'; | |
import 'package:swipe_to/swipe_to.dart'; | |
import 'package:focused_menu/focused_menu.dart'; | |
import 'package:aclub/features/chat/bloc/chat.dart'; | |
import 'package:animate_do/animate_do.dart'; | |
import 'dart:math'; | |
class ChatView extends StatefulWidget { | |
int roomId; | |
int userId; | |
int cbId; | |
SessionProfile profile; | |
ChatView({this.roomId, this.userId, this.cbId, this.profile}); | |
@override | |
_ChatViewState createState() => _ChatViewState(); | |
} | |
class _ChatViewState extends State<ChatView> { | |
GroupProvider groupProvider = GroupProvider(); | |
final focusNode = FocusNode(); | |
Message replyMessage; | |
ChatBloc chatBloc = new ChatBloc(); | |
// ChatBloc chatBloc = new ChatBloc(); | |
MessageBloc messageBloc = new MessageBloc(); | |
ScrollController _scrollController = ScrollController(); | |
String lastCursor; | |
int lenghtMs; | |
String cursorCache; | |
bool _closePinned = true; | |
AnimationController animateController; | |
double _pinnedHeight = 40; | |
String _roomTitle = 'Chat'; | |
String _roomImage; | |
int _scrollIndex; | |
int faker = 0; | |
List pinnedMessage = []; | |
var preoffset; | |
bool loading = false; | |
bool _showJump = false; | |
void scrollToLast() { | |
print("trying to scroll"); | |
Future.delayed(Duration.zero, () { | |
_scrollController.animateTo( | |
(lenghtMs + 1 / lenghtMs) * | |
_scrollController.position.minScrollExtent, | |
duration: const Duration(milliseconds: 300), | |
curve: Curves.easeOut); | |
}); | |
// WidgetsBinding.instance.addPostFrameCallback((_) { | |
// }); | |
} | |
void reload() async {} | |
Widget pinnedIcon = Icon(Icons.keyboard_arrow_down); | |
void expander() async { | |
if (_pinnedHeight == 40) { | |
setState(() { | |
_pinnedHeight = 300; | |
pinnedIcon = Icon(Icons.keyboard_arrow_up); | |
}); | |
} else if (_pinnedHeight == 300) { | |
setState(() { | |
_pinnedHeight = 40; | |
pinnedIcon = Icon(Icons.keyboard_arrow_down); | |
}); | |
} | |
} | |
void jumpToMessage(messageId) async { | |
await chatBloc.jumpId(widget.roomId, messageId); | |
setState(() { | |
widget.cbId = messageId; | |
// _closePinned = false; | |
}); | |
WidgetsBinding.instance.addPostFrameCallback((_) { | |
_scrollController.animateTo( | |
_scrollController.position.maxScrollExtent * 1.2, | |
duration: const Duration(milliseconds: 100), | |
curve: Curves.easeOut); | |
}); | |
} | |
void setScroll(index) async { | |
jumpTest(index); | |
} | |
void jumpTest(index) async { | |
// WidgetsBinding.instance.addPostFrameCallback((_) async { | |
_scrollController.animateTo( | |
_scrollController.position.maxScrollExtent * 0.95, | |
duration: const Duration(milliseconds: 100), | |
curve: Curves.easeOut); | |
// }); | |
} | |
@override | |
void initState() { | |
_scrollInit(); | |
initChat(); | |
super.initState(); | |
focusNode.addListener(_onFocusChange); | |
} | |
void _onFocusChange() { | |
if (focusNode.hasFocus) { | |
setState(() { | |
_showJump = true; | |
}); | |
} else { | |
setState(() { | |
_showJump = false; | |
}); | |
} | |
} | |
@override | |
void dispose() { | |
chatBloc.createCheckpoint(widget.userId, widget.roomId); | |
super.dispose(); | |
} | |
_single(content) { | |
content.removeWhere((person) => person['user']['id'] == widget.userId); | |
return content[0]['user']; | |
} | |
void initChat() async { | |
groupInfo(); | |
// chatBloc.pinnedByRoom(widget.roomId); | |
if (widget.cbId != null) { | |
jumpToMessage(widget.cbId); | |
} else { | |
await chatBloc.initChat(widget.roomId, null); | |
// await chatBloc.getMessageCursor(widget.roomId, '', widget.userId); | |
} | |
chatBloc.chatSubscription(widget.roomId); | |
} | |
void groupInfo() async { | |
var room = await groupProvider.getGroup(widget.roomId); | |
// print(room['participants']['participants']); | |
if (room['type'] == 'GROUP') { | |
setState(() { | |
_roomTitle = room['name']; | |
_roomImage = ChatConst.public_url + '${room['image']}'; | |
}); | |
} else { | |
var user = await _single(room['participants']['participants']); | |
setState(() { | |
_roomTitle = user['member']['member_displayname']; | |
_roomImage = ApiConst.profile_image_path + | |
'${user['member']['member_profile_image']}'; | |
}); | |
} | |
getPinned(); | |
// var getPinned = await chatBloc.pinnedByRoom(widget.roomId); | |
// setState(() { | |
// pinnedMessage = getPinned; | |
// }); | |
} | |
void getPinned() async { | |
var getPinned = await chatBloc.pinnedByRoom(widget.roomId); | |
setState(() { | |
pinnedMessage = getPinned; | |
}); | |
} | |
void jumpLast() async { | |
chatBloc.clear(); | |
await chatBloc.initChat(widget.roomId, null); | |
_scrollController.animateTo(_scrollController.position.minScrollExtent, | |
duration: const Duration(milliseconds: 100), curve: Curves.easeOut); | |
} | |
_filter(String query) async { | |
// userBloc.userFilter(query); | |
// chatBloc.userFilter(query); | |
} | |
_scrollInit() { | |
_scrollController.addListener(() async { | |
if (_showJump == false) { | |
setState(() { | |
_showJump = true; | |
}); | |
} | |
print('pos ${_scrollController.position.pixels}'); | |
print('min ${_scrollController.position.minScrollExtent * 0.7}'); | |
print('max ${_scrollController.position.maxScrollExtent}'); | |
if (_scrollController.position.pixels == | |
_scrollController.position.maxScrollExtent) { | |
await chatBloc.lastById(widget.roomId); | |
} | |
if (_scrollController.position.pixels == | |
_scrollController.position.minScrollExtent | |
// _scrollController.position.maxScrollExtent - | |
// _scrollController.position.pixels >= | |
// 100 | |
) { | |
setState(() { | |
loading = true; | |
}); | |
preoffset = _scrollController.position.extentAfter; | |
// setState(() { | |
// faker = 5; | |
// }); | |
// jumpFront(); | |
// _scrollController.position.maxScrollExtent; | |
// setState(() { | |
// loading = true; | |
// }); | |
await chatBloc.firstById(widget.roomId); | |
await chatBloc.chatSubscription(widget.roomId); | |
setState(() { | |
loading = false; | |
}); | |
} | |
}); | |
} | |
void jumpFront() { | |
print(preoffset); | |
WidgetsBinding.instance.addPostFrameCallback((_) { | |
// if (_scrollController.hasClients) { | |
_scrollController | |
.jumpTo(_scrollController.position.maxScrollExtent - preoffset); | |
// } | |
}); | |
setState(() { | |
faker = 0; | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: _buildBar(context), | |
body: Stack( | |
children: [ | |
Container( | |
child: Stack( | |
children: [ | |
Column( | |
children: [ | |
Expanded( | |
child: Container( | |
padding: EdgeInsets.symmetric(horizontal: 10), | |
decoration: BoxDecoration( | |
color: Color(0xffE5E5E5), | |
), | |
child: ClipRRect( | |
child: listMessage(chatBloc), | |
), | |
), | |
), | |
ChatInput( | |
onCancelReply: cancelReply, | |
replyMessage: replyMessage, | |
// jumper: jumpLast, | |
focusNode: focusNode, | |
userId: widget.userId, | |
roomId: widget.roomId, | |
profile: widget.profile, | |
), | |
// Positioned(top: 100, right: 0, child: Text('woi')) | |
], | |
), | |
Visibility( | |
visible: _showJump, | |
child: Positioned( | |
bottom: 80, | |
right: 0, | |
child: InkWell( | |
onTap: jumpLast, | |
child: Container( | |
padding: EdgeInsets.fromLTRB(10, 0, 10, 0), | |
width: 50.0, | |
height: 50.0, | |
decoration: BoxDecoration( | |
color: Colors.white, | |
borderRadius: BorderRadius.only( | |
topLeft: Radius.circular(15), | |
topRight: Radius.circular(0), | |
bottomLeft: Radius.circular(15), | |
bottomRight: Radius.circular(0), | |
), | |
boxShadow: [ | |
BoxShadow( | |
color: Colors.grey.withOpacity(0.5), | |
spreadRadius: 2, | |
blurRadius: 7, | |
offset: Offset( | |
0, 3), // changes position of shadow | |
), | |
], | |
), | |
child: Icon( | |
Icons.arrow_drop_down_circle_outlined, | |
color: ChatStyles.baseRed, | |
), | |
), | |
)), | |
) | |
], | |
), | |
), | |
if (pinnedMessage.length != 0) | |
Visibility( | |
visible: _closePinned, | |
child: Container( | |
margin: EdgeInsets.all(8), | |
padding: EdgeInsets.fromLTRB(10, 5, 10, 5), | |
width: MediaQuery.of(context).size.width, | |
color: Color(0xffFFCE3F).withOpacity(0.8), | |
height: _pinnedHeight, | |
child: Row( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
children: [ | |
Expanded( | |
child: Wrap( | |
children: [ | |
Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
InkWell( | |
onTap: expander, | |
child: Container( | |
width: | |
MediaQuery.of(context).size.width, | |
child: Container( | |
padding: | |
EdgeInsets.fromLTRB(0, 0, 0, 5), | |
child: ListView.builder( | |
shrinkWrap: true, | |
itemCount: pinnedMessage.length, | |
itemBuilder: | |
(BuildContext context, | |
int index) { | |
return InkWell( | |
onTap: () => { | |
jumpToMessage( | |
pinnedMessage[index] | |
['id']), | |
expander() | |
}, | |
child: Container( | |
// decoration: | |
// BoxDecoration( | |
// border: Border( | |
// bottom: BorderSide( | |
// color: Colors | |
// .grey[ | |
// 850])), | |
// ), | |
padding: | |
EdgeInsets.fromLTRB( | |
0, 4, 0, 4), | |
child: Column( | |
crossAxisAlignment: | |
CrossAxisAlignment | |
.start, | |
children: [ | |
Padding( | |
padding: | |
const EdgeInsets | |
.fromLTRB( | |
0, 2, 0, 2), | |
child: Row( | |
children: [ | |
Padding( | |
padding: | |
const EdgeInsets | |
.fromLTRB( | |
0, | |
0, | |
2, | |
0), | |
child: Transform | |
.rotate( | |
angle: 90 * | |
pi / | |
360, | |
child: Icon( | |
Icons | |
.push_pin, | |
size: 12, | |
), | |
), | |
), | |
Container( | |
constraints: | |
BoxConstraints( | |
maxWidth: | |
200), | |
child: Text( | |
'${pinnedMessage[index]['content']}', | |
maxLines: 1, | |
overflow: | |
TextOverflow | |
.ellipsis, | |
), | |
), | |
], | |
), | |
), | |
Text( | |
'${pinnedMessage[index]['user']['member']['member_displayname']}', | |
style: TextStyle( | |
color: ChatStyles | |
.baseRed), | |
), | |
], | |
), | |
), | |
); | |
}))), | |
), | |
InkWell( | |
onTap: () => { | |
setState(() { | |
_closePinned = false; | |
}), | |
}, | |
child: Text( | |
'Dont Show Again', | |
style: TextStyle( | |
fontSize: 12, | |
fontWeight: FontWeight.w700), | |
), | |
) | |
], | |
) | |
], | |
), | |
), | |
Align( | |
alignment: Alignment.bottomRight, | |
child: InkWell( | |
onTap: expander, | |
child: pinnedIcon, | |
), | |
) | |
], | |
), | |
)), | |
], | |
) | |
// ) | |
); | |
} | |
Widget listMessage(ChatBloc chatBloc) { | |
return StreamBuilder( | |
stream: chatBloc.subject.stream, | |
builder: (BuildContext context, AsyncSnapshot<List<Message>> snapshot) { | |
if (snapshot.hasData) { | |
// if (chatBloc.state.value == 'FETCH') { | |
if (lastCursor != snapshot.data.last.created_at | |
// && lenghtMs != snapshot.data.length | |
) { | |
lastCursor = snapshot.data.last.created_at; | |
lenghtMs = snapshot.data.length; | |
} | |
// } | |
// print(lenghtMs); | |
// print(lastCursor); | |
return GroupedListView<dynamic, DateTime>( | |
key: PageStorageKey<String>('chatList'), | |
semanticChildCount: snapshot.data.length, | |
controller: _scrollController, | |
elements: snapshot.data, | |
reverse: true, | |
groupBy: (element) => DateTime( | |
DateTime.parse('${element.created_at}').year, | |
DateTime.parse('${element.created_at}').month, | |
DateTime.parse('${element.created_at}').day), | |
// element.created_at, | |
groupComparator: (value1, value2) => value1.compareTo(value2), | |
itemComparator: (item1, item2) => item1.id.compareTo(item2.id), | |
order: GroupedListOrder.DESC, | |
useStickyGroupSeparators: false, | |
groupSeparatorBuilder: (DateTime value) { | |
if (loading == false) | |
return Container( | |
child: Align( | |
child: Container( | |
decoration: BoxDecoration( | |
color: Color(0xffFFCE3F).withOpacity(0.7), | |
borderRadius: | |
const BorderRadius.all(Radius.circular(50.0)), | |
), | |
child: Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: Text( | |
'${Jiffy([ | |
value.year, | |
value.month, | |
value.day | |
]).format('MMM dd')}', | |
textAlign: TextAlign.center, | |
style: TextStyle( | |
fontSize: 12, fontWeight: FontWeight.w700), | |
), | |
), | |
), | |
), | |
); | |
}, | |
indexedItemBuilder: (context, element, index) { | |
if (widget.cbId != null) { | |
if (widget.cbId == element.id) { | |
// setScroll(index); | |
_scrollIndex = index; | |
} | |
} | |
return FocusedMenuHolder( | |
child: Column( | |
children: [ | |
if (loading == false) | |
(widget.cbId == null || widget.cbId != element.id) | |
? ChatThread( | |
onSwipeMessage: (element) { | |
replyToMessage(element); | |
// focusNode.requestFocus(); | |
}, | |
userId: widget.userId, | |
message: element, | |
jumpToMessage: this.jumpToMessage) | |
// : (widget.cbId != element.id) | |
// ? ChatThread( | |
// onSwipeMessage: (element) { | |
// replyToMessage(element); | |
// // focusNode.requestFocus(); | |
// }, | |
// userId: widget.userId, | |
// message: element, | |
// jumpToMessage: this.jumpToMessage) | |
: BounceInLeft( | |
controller: (controller) => animateController, | |
manualTrigger: true, | |
animate: | |
widget.cbId == element.id ? true : false, | |
child: ChatThread( | |
onSwipeMessage: (element) { | |
replyToMessage(element); | |
// focusNode.requestFocus(); | |
}, | |
userId: widget.userId, | |
message: element, | |
jumpToMessage: this.jumpToMessage), | |
), | |
if (loading == true) MyLoader() | |
], | |
), | |
menuWidth: MediaQuery.of(context).size.width * 0.50, | |
blurSize: 5.0, | |
menuItemExtent: 45, | |
menuOffset: | |
10.0, // Offset value to show menuItem from the selected item | |
bottomOffsetHeight: 100.0, | |
menuBoxDecoration: BoxDecoration( | |
color: Colors.grey, | |
borderRadius: BorderRadius.all(Radius.circular(15.0))), | |
duration: Duration(milliseconds: 50), | |
animateMenuItems: true, | |
menuItems: <FocusedMenuItem>[ | |
FocusedMenuItem( | |
title: Text("Reply"), | |
trailingIcon: Icon(Icons.reply), | |
onPressed: () async { | |
replyToMessage(element); | |
}), | |
FocusedMenuItem( | |
title: Text("Pinned"), | |
trailingIcon: Icon( | |
Icons.star, | |
color: Colors.yellow[700], | |
), | |
onPressed: () async { | |
await messageBloc.updateMessageById( | |
element.id, true, null); | |
getPinned(); | |
}), | |
if (element.user_id == widget.userId) | |
FocusedMenuItem( | |
title: Text( | |
"Delete", | |
style: TextStyle(color: Colors.redAccent), | |
), | |
trailingIcon: Icon( | |
Icons.delete, | |
color: Colors.redAccent, | |
), | |
onPressed: () async { | |
await messageBloc.updateMessageById( | |
element.id, null, true); | |
}), | |
], | |
onPressed: null, | |
); | |
}); | |
} | |
return Center(child: MyLoader()); | |
}); | |
} | |
void cancelReply() async { | |
jumpLast(); | |
setState(() { | |
replyMessage = null; | |
}); | |
} | |
void replyToMessage(Message message) { | |
setState(() { | |
replyMessage = message; | |
}); | |
} | |
//search bar util | |
final TextEditingController _search = new TextEditingController(); | |
Icon _searchIcon = new Icon(Icons.search); | |
Widget _appBarTitle = new InkWell( | |
child: Container( | |
padding: EdgeInsets.all(5), | |
child: Row( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: [ | |
CircleAvatar( | |
radius: 25, | |
backgroundColor: Colors.transparent, | |
child: Container( | |
decoration: BoxDecoration( | |
color: Colors.grey[200], | |
borderRadius: BorderRadius.circular(50)), | |
width: 50, | |
height: 50, | |
child: Icon( | |
Icons.person, | |
color: Colors.grey[800], | |
), | |
), | |
), | |
Column(children: [Text('chat')]) | |
], | |
), | |
), | |
); | |
// Text( | |
// 'Chat', | |
// style: TextStyle(color: Colors.black, fontSize: 16), | |
// ); | |
//custom appbar | |
Widget _buildBar(BuildContext context) { | |
return new AppBar( | |
centerTitle: false, | |
// title: _appBarTitle, | |
automaticallyImplyLeading: false, | |
flexibleSpace: SafeArea( | |
child: Container( | |
padding: EdgeInsets.only(right: 16), | |
child: Row( | |
children: <Widget>[ | |
IconButton( | |
onPressed: () { | |
Navigator.pop(context); | |
}, | |
icon: Icon( | |
Icons.arrow_back, | |
color: Color(0xffFBA53F), | |
), | |
), | |
SizedBox( | |
width: 2, | |
), | |
InkWell( | |
onTap: () => { | |
// Navigator.of(context).push( | |
// MaterialPageRoute( | |
// builder: (context) => ChatInfo( | |
// roomId: widget.roomId, | |
// userId: widget.userId, | |
// )), | |
// ) | |
}, | |
child: Container( | |
child: CircleAvatar( | |
backgroundColor: Colors.grey[300], | |
backgroundImage: NetworkImage("${_roomImage}"), | |
maxRadius: 20, | |
), | |
)), | |
SizedBox( | |
width: 12, | |
), | |
Expanded( | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
Text( | |
"${_roomTitle}", | |
style: | |
TextStyle(fontSize: 14, fontWeight: FontWeight.w600), | |
), | |
], | |
), | |
), | |
IconButton( | |
icon: _searchIcon, | |
onPressed: () => { | |
Navigator.of(context).pushReplacement( | |
MaterialPageRoute( | |
builder: (context) => ChatSearch( | |
roomId: widget.roomId, | |
userId: widget.userId, | |
)), | |
) | |
}, | |
color: Color(0xffF6403E), | |
), | |
IconButton( | |
icon: Icon( | |
Icons.menu, | |
color: Color(0xffF6403E), | |
), | |
onPressed: () => { | |
Navigator.of(context).push( | |
MaterialPageRoute( | |
builder: (context) => ChatInfo( | |
roomId: widget.roomId, | |
userId: widget.userId, | |
profile: widget.profile, | |
)), | |
) | |
}, | |
color: Color(0xffF6403E), | |
) | |
], | |
), | |
), | |
), | |
// actions: [ | |
// IconButton( | |
// icon: _searchIcon, | |
// onPressed: () => { | |
// Navigator.of(context).push( | |
// MaterialPageRoute( | |
// builder: (context) => ChatSearch( | |
// roomId: widget.roomId, | |
// userId: widget.userId, | |
// )), | |
// ) | |
// }, | |
// color: Color(0xffF6403E), | |
// ), | |
// // IconButton( | |
// // icon: Icon( | |
// // Icons.menu, | |
// // color: Color(0xffF6403E), | |
// // ), | |
// // onPressed: null, | |
// // color: Colors.black), | |
// PopupMenuButton<String>( | |
// icon: Icon( | |
// Icons.menu, | |
// color: Color(0xffF6403E), | |
// ), | |
// onSelected: handleClick, | |
// itemBuilder: (BuildContext context) { | |
// return {'Search', 'Info'}.map((String choice) { | |
// return PopupMenuItem<String>( | |
// value: choice, | |
// child: Text( | |
// choice, | |
// style: TextStyle(color: Colors.black, fontSize: 12), | |
// ), | |
// ); | |
// }).toList(); | |
// }, | |
// ), | |
// ], | |
backgroundColor: Colors.white, | |
iconTheme: IconThemeData(color: Color(0xffFBA53F)), | |
); | |
} | |
void handleClick(String value) { | |
switch (value) { | |
case 'Search': | |
Navigator.of(context).push( | |
MaterialPageRoute( | |
builder: (context) => ChatSearch( | |
roomId: widget.roomId, | |
userId: widget.userId, | |
)), | |
); | |
break; | |
case 'Info': | |
Navigator.of(context).push( | |
MaterialPageRoute(builder: (context) => ChatInfo()), | |
); | |
break; | |
} | |
} | |
//appbar search function | |
void _searchPressed() { | |
setState(() { | |
if (this._searchIcon.icon == Icons.search) { | |
this._searchIcon = new Icon( | |
Icons.close, | |
color: Color(0xffF6403E), | |
); | |
this._appBarTitle = new TextField( | |
controller: _search, | |
onChanged: _filter, | |
decoration: new InputDecoration( | |
prefixIcon: new Icon( | |
Icons.search, | |
color: Color(0xffF6403E), | |
), | |
hintText: 'Search...'), | |
); | |
} else { | |
this._searchIcon = new Icon(Icons.search); | |
this._appBarTitle = new Text( | |
'Chat', | |
style: TextStyle(color: Colors.black, fontSize: 16), | |
); | |
_search.clear(); | |
} | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment