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

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),
),
],
),
),
);
}
}