You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
346 lines
11 KiB
346 lines
11 KiB
3 years ago
|
import 'dart:async';
|
||
|
|
||
|
import 'package:teso/Classes/TesoUser.dart';
|
||
|
import 'package:teso/Classes/ChatMessage.dart';
|
||
|
import 'package:teso/Pages/PageWidgets/ChatScreen/bottomBar.dart';
|
||
|
import 'package:teso/Pages/PageWidgets/ChatScreen/header.dart';
|
||
|
import 'package:teso/Pages/PageWidgets/ChatScreen/recipient.dart';
|
||
|
import 'package:teso/Pages/PageWidgets/ChatScreen/sender.dart';
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||
|
import 'dart:io';
|
||
|
import 'dart:convert';
|
||
|
import 'dart:ui';
|
||
|
import 'package:intl/intl.dart';
|
||
|
import 'package:teso/providers/user_provider.dart';
|
||
|
import 'package:provider/provider.dart';
|
||
|
import 'package:teso/util/consts.dart';
|
||
|
import 'package:http/http.dart' as http;
|
||
|
|
||
|
class ChatScreen extends StatefulWidget {
|
||
|
final TesoUser user;
|
||
|
|
||
|
const ChatScreen({Key key, this.user}) : super(key: key);
|
||
|
@override
|
||
|
_ChatScreenState createState() => _ChatScreenState(user: this.user);
|
||
|
}
|
||
|
|
||
|
class _ChatScreenState extends State<ChatScreen> {
|
||
|
final datakey = new GlobalKey();
|
||
|
TesoUser user;
|
||
|
_ChatScreenState({this.user});
|
||
|
TextEditingController controller = new TextEditingController();
|
||
|
bool first = true;
|
||
|
String id;
|
||
|
|
||
|
List<QueryDocumentSnapshot> listMessage = new List.from([]);
|
||
|
int _limit = 20;
|
||
|
final int _limitIncrement = 20;
|
||
|
String groupChatId;
|
||
|
SharedPreferences prefs;
|
||
|
final ScrollController listScrollController = ScrollController();
|
||
|
File imageFile;
|
||
|
bool isLoading;
|
||
|
bool isShowSticker;
|
||
|
String imageUrl;
|
||
|
TesoUser currentUser;
|
||
|
Future<TesoUser> _future;
|
||
|
Timer timer;
|
||
|
int counter = 0;
|
||
|
|
||
|
_scrollListener() {
|
||
|
if (listScrollController.offset >=
|
||
|
listScrollController.position.maxScrollExtent &&
|
||
|
!listScrollController.position.outOfRange) {
|
||
|
print("reach the bottom");
|
||
|
setState(() {
|
||
|
print("reach the bottom");
|
||
|
_limit += _limitIncrement;
|
||
|
});
|
||
|
}
|
||
|
if (listScrollController.offset <=
|
||
|
listScrollController.position.minScrollExtent &&
|
||
|
!listScrollController.position.outOfRange) {
|
||
|
print("reach the top");
|
||
|
setState(() {
|
||
|
print("reach the top");
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void sendMessage(String content, int type) {
|
||
|
if (content.trim() != '') {
|
||
|
controller.clear();
|
||
|
|
||
|
var documentReference = FirebaseFirestore.instance
|
||
|
.collection('messages')
|
||
|
.doc(groupChatId)
|
||
|
.collection(groupChatId)
|
||
|
.doc(DateTime.now().millisecondsSinceEpoch.toString());
|
||
|
|
||
|
FirebaseFirestore.instance.runTransaction((transaction) async {
|
||
|
transaction.set(
|
||
|
documentReference,
|
||
|
{
|
||
|
'idFrom': id,
|
||
|
'idTo': user.userGUID,
|
||
|
'timestamp': DateTime.now().millisecondsSinceEpoch.toString(),
|
||
|
'content': content.trim(),
|
||
|
'type': type,
|
||
|
'read': false
|
||
|
},
|
||
|
);
|
||
|
});
|
||
|
|
||
|
var inboxReference1 = FirebaseFirestore.instance
|
||
|
.collection('inbox')
|
||
|
.doc(id)
|
||
|
.collection("lastMessage")
|
||
|
.doc(groupChatId);
|
||
|
|
||
|
FirebaseFirestore.instance.runTransaction((transaction) async {
|
||
|
transaction.set(
|
||
|
inboxReference1,
|
||
|
{
|
||
|
'senderID': id,
|
||
|
'peerID': user.userGUID,
|
||
|
'timestamp': DateTime.now().millisecondsSinceEpoch.toString(),
|
||
|
'content': content.trim(),
|
||
|
'firstname': user.firstname,
|
||
|
'surname': user.lastname,
|
||
|
'thumbnail': user.thumbnail_dp,
|
||
|
'username': user.username,
|
||
|
'read': false
|
||
|
},
|
||
|
);
|
||
|
});
|
||
|
var inboxReference2 = FirebaseFirestore.instance
|
||
|
.collection('inbox')
|
||
|
.doc(user.userGUID)
|
||
|
.collection("lastMessage")
|
||
|
.doc(groupChatId);
|
||
|
|
||
|
FirebaseFirestore.instance.runTransaction((transaction) async {
|
||
|
transaction.set(
|
||
|
inboxReference2,
|
||
|
{
|
||
|
'senderID': id,
|
||
|
'peerID': id,
|
||
|
'timestamp': DateTime.now().millisecondsSinceEpoch.toString(),
|
||
|
'content': content.trim(),
|
||
|
'firstname': currentUser.firstname,
|
||
|
'surname': currentUser.lastname,
|
||
|
'thumbnail': currentUser.thumbnail_dp,
|
||
|
'username': currentUser.username,
|
||
|
'read': false
|
||
|
},
|
||
|
);
|
||
|
});
|
||
|
listScrollController.animateTo(0.0,
|
||
|
duration: Duration(milliseconds: 300), curve: Curves.easeOut);
|
||
|
} else {
|
||
|
// Fluttertoast.showToast(
|
||
|
// msg: 'Nothing to send',
|
||
|
// backgroundColor: Colors.black,
|
||
|
// textColor: Colors.red);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void readMessage(DocumentReference reference) {
|
||
|
reference.update({"read": true});
|
||
|
|
||
|
FirebaseFirestore.instance
|
||
|
.collection('inbox')
|
||
|
.doc(id)
|
||
|
.collection("lastMessage")
|
||
|
.doc(groupChatId)
|
||
|
.update({"read": true});
|
||
|
|
||
|
FirebaseFirestore.instance
|
||
|
.collection('inbox')
|
||
|
.doc(user.userGUID)
|
||
|
.collection("lastMessage")
|
||
|
.doc(groupChatId)
|
||
|
.update({"read": true});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
readLocal();
|
||
|
listScrollController.addListener(_scrollListener);
|
||
|
controller.addListener(() {
|
||
|
if (controller.text.isNotEmpty) {
|
||
|
isTyping(true);
|
||
|
} else {
|
||
|
isTyping(false);
|
||
|
}
|
||
|
});
|
||
|
currentUser = Provider.of<UserProvider>(context, listen: false).currentUser;
|
||
|
_future = findUser();
|
||
|
timer = Timer.periodic(Duration(seconds: 30), (Timer t) => addValue());
|
||
|
}
|
||
|
|
||
|
void addValue() {
|
||
|
setState(() {
|
||
|
counter++;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
readLocal() async {
|
||
|
prefs = await SharedPreferences.getInstance();
|
||
|
id = prefs.getString('id') ?? '';
|
||
|
if (id.hashCode <= user.userGUID.hashCode) {
|
||
|
groupChatId = id + user.userGUID;
|
||
|
} else {
|
||
|
groupChatId = user.userGUID + id;
|
||
|
}
|
||
|
FirebaseFirestore.instance
|
||
|
.collection('users')
|
||
|
.doc(id)
|
||
|
.update({'chattingWith': user.userGUID, 'typing': false});
|
||
|
|
||
|
setState(() {});
|
||
|
}
|
||
|
|
||
|
void isTyping(bool value) {
|
||
|
FirebaseFirestore.instance
|
||
|
.collection('users')
|
||
|
.doc(id)
|
||
|
.update({'chattingWith': user.userGUID, 'typing': value});
|
||
|
}
|
||
|
|
||
|
Future<TesoUser> findUser() async {
|
||
|
TesoUser loadedUser;
|
||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
|
|
||
|
Map<String, String> requestHeaders = {
|
||
|
'Content-type': 'application/json',
|
||
|
'Authorization': prefs.getString('tokensTeso')
|
||
|
};
|
||
|
|
||
|
String auth = user.userGUID;
|
||
|
var register2 = serverLocation + 'users/finduser';
|
||
|
var client1 = await http.post(Uri.parse(register2),
|
||
|
body: json.encode(auth), headers: requestHeaders);
|
||
|
|
||
|
if (client1.statusCode == 200) {
|
||
|
Map handler = jsonDecode(client1.body);
|
||
|
TesoUser tokenHandler = TesoUser.fromJSON(handler);
|
||
|
setState(() {
|
||
|
user = tokenHandler;
|
||
|
loadedUser = user;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return loadedUser;
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
listScrollController.dispose();
|
||
|
controller.dispose();
|
||
|
timer?.cancel();
|
||
|
FirebaseFirestore.instance
|
||
|
.collection('users')
|
||
|
.doc(id)
|
||
|
.update({'chattingWith': "", 'typing': false});
|
||
|
|
||
|
super.dispose();
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return Scaffold(
|
||
|
appBar: PreferredSize(
|
||
|
preferredSize: Size.fromHeight(90),
|
||
|
child: FutureBuilder(
|
||
|
future: _future,
|
||
|
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
|
||
|
if (snapshot.hasData == null ||
|
||
|
snapshot.connectionState == ConnectionState.waiting) {
|
||
|
return buildChatHead(context, user);
|
||
|
} else {
|
||
|
return buildChatHead(context, user);
|
||
|
}
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
body: Container(
|
||
|
height: MediaQuery.of(context).size.height,
|
||
|
child: Stack(
|
||
|
children: [
|
||
|
Container(
|
||
|
height: MediaQuery.of(context).size.height,
|
||
|
width: MediaQuery.of(context).size.width,
|
||
|
margin: EdgeInsets.only(bottom: 60),
|
||
|
child: StreamBuilder(
|
||
|
stream: FirebaseFirestore.instance
|
||
|
.collection('messages')
|
||
|
.doc(groupChatId)
|
||
|
.collection(groupChatId)
|
||
|
.orderBy('timestamp', descending: true)
|
||
|
.limit(_limit)
|
||
|
.snapshots(),
|
||
|
builder: (context, snapshot) {
|
||
|
if (!snapshot.hasData) {
|
||
|
return Center(
|
||
|
child: CircularProgressIndicator(
|
||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||
|
Theme.of(context).primaryColor)));
|
||
|
} else if (snapshot.data == null || listMessage == null) {
|
||
|
return Center(
|
||
|
child: CircularProgressIndicator(
|
||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||
|
Theme.of(context).primaryColor)));
|
||
|
} else {
|
||
|
listMessage = snapshot.data.docs;
|
||
|
return ListView.builder(
|
||
|
padding: EdgeInsets.all(10.0),
|
||
|
itemCount: listMessage.length,
|
||
|
itemBuilder: (context, index) {
|
||
|
if (snapshot.data.docs[index].data()['idTo'] == id &&
|
||
|
snapshot.data.docs[index].data()['read'] == false) {
|
||
|
readMessage(listMessage[index].reference);
|
||
|
}
|
||
|
int timeInMillis = int.parse(
|
||
|
snapshot.data.docs[index].data()['timestamp']);
|
||
|
var date =
|
||
|
DateTime.fromMillisecondsSinceEpoch(timeInMillis);
|
||
|
var formattedDate =
|
||
|
DateFormat("yyyy-MM-dd HH:mm:ss").format(date);
|
||
|
ChatMessage message = new ChatMessage();
|
||
|
message.idFrom =
|
||
|
snapshot.data.docs[index].data()['idFrom'];
|
||
|
message.content =
|
||
|
snapshot.data.docs[index].data()['content'];
|
||
|
message.idTo = snapshot.data.docs[index].data()['idTo'];
|
||
|
message.timestamp = DateTime.parse(formattedDate);
|
||
|
message.type = int.parse(snapshot.data.docs[index]
|
||
|
.data()['type']
|
||
|
.toString());
|
||
|
if (snapshot.data.docs[index].data()['idFrom'] == id) {
|
||
|
return buildSender(context, message);
|
||
|
} else {
|
||
|
return buildRecipient(context, message);
|
||
|
}
|
||
|
},
|
||
|
reverse: true,
|
||
|
controller: listScrollController,
|
||
|
);
|
||
|
}
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
Align(
|
||
|
alignment: Alignment.bottomCenter,
|
||
|
child: buildBottom(context, controller, sendMessage),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|