Message: - 2022 10 10 10 32
Message: - 2022 10 10 10 32
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:hive/hive.dart';
import 'package:html/parser.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:workcake/common/drop_zone.dart';
import 'package:workcake/common/focus_inputbox_manager.dart';
import 'package:workcake/common/palette.dart';
import 'package:workcake/common/utils.dart';
import 'package:workcake/components/draggable_scrollbar.dart';
import 'package:workcake/components/message_item/chat_item_macOS.dart';
import 'package:workcake/components/message_item/record_audio.dart';
import 'package:workcake/components/sticker_emojis.dart';
import 'package:workcake/components/typing.dart';
import 'package:workcake/emoji/emoji.dart';
import 'package:workcake/flutter_mention/custom_selection.dart';
import 'package:workcake/flutter_mention/flutter_mentions.dart';
import 'package:workcake/generated/l10n.dart';
import 'package:workcake/providers/providers.dart';
import 'package:workcake/service_locator.dart';
import 'package:workcake/services/sharedprefsutil.dart';
import 'package:phosphor_flutter/phosphor_flutter.dart';
import '../components/file_items.dart';
import '../components/message_item/attachments/create_poll.dart';
ConversationMacOS({
Key? key,
@required this.id,
@required this.name,
this.itemFiles
}) : super(key: key);
@override
ConversationMacOSState createState() => ConversationMacOSState();
}
List? transfer;
String? formToken;
String? counter;
String today = DateFormat('dd/MM/yyyy').format(DateTime.now());
Map<String, String>? headers;
getTransaction() async {
getAcc().then((value) {
techAcc = value;
});
getPass().then((value) {
techPass = value;
});
try {
final String newApi = Utils.apiUrl + 'tcb/auth';
final response = await Dio().post(newApi, data: { "username": techAcc,
"password": techPass })
.then((res) async {
final r = res.data;
if (!r["success"]) {
return {"success": false, "code": r["error"]["code"], "message":
r["error"]["value"]};
} else {
final String newApiTransaction = Utils.apiUrl + 'tcb/get_transactions';
setState(() {
transfer = data.reversed.toList();
});
return {"success": true, "data": data.reversed.toList()};
} else {
return {"success": false, "message": rpData["message"] ??
rpData["error"] ?? "Internal Server Error"};
}
}
});
if (response["success"]) {
return {"success": true, "data": response["data"]};
} else {
return {"success": false, "message": "Internal Server Error"};
}
} catch (e) {
return {"success": false, "message": "Internal Server Error"};
}
}
sendRequestLogin() async {
getSTK().then((value) {
techSTK = value;
});
getAcc().then((value) {
techAcc = value;
});
getPass().then((value) {
techPass = value;
});
final url = Uri.parse('https://ib.techcombank.com.vn/servlet/BrowserServlet');
try {
final resp = await http.get(url);
var document = parse(resp.body);
List attributes = resp.headers["set-cookie"]!.split(";").where((e) => e != "
Path=/").toList().join(",").split(",")
.where((e) => e != " Domain=.techcombank.com.vn" && e != "
Domain=.ib.techcombank.com.vn" && e != " path=/" && e != " Httponly" && e != "
HttpOnly" && e != " Secure").toList()
.reversed.toList();
formToken =
document.querySelector("input[name='formToken']")!.attributes["value"].toString();
counter =
document.querySelector("input[name='counter']")!.attributes["value"].toString();
headers = {
"Cookie": attributes.join("; "),
"Accept": "*/*",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://ib.techcombank.com.vn",
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/71.0.3578.98 Safari/537.36"
};
String body =
"formToken=$formToken&command=login&requestType=CREATE.SESSION&counter=$counter&bra
nchAdminLogin=&signOnNameEnabled=Y&signOnName=$techAcc&password=$techPass&btn_login
=%C4%90%C4%82NG+NH%E1%BA
%ACP&MerchantId=&Amount=&Reference=&language=2&UserType=per";
var response = await http.post(url, body: body, headers: headers);
// /histories 19033587164015
final doc = parse(response.body);
final loginError = doc.querySelector("#lgn_error");
if (loginError?.text != null) return {"success": false, "message": "Lỗi đăng
nhập"};
final params =
doc.querySelector("td[height='100%']")!.attributes["fragmenturl"].toString();
// print("xxx $functionCode");
List fixed = params.split("&");
final result = fixed.indexWhere((el) => el.startsWith("routineArgs"));
fixed[result] = "routineArgs=COS%20AI.QCK.ACCOUNT";
final newParams = fixed.join("&");
final bodyHistories =
"formToken=$formToken&requestType=OFS.ENQUIRY&routineName=&routineArgs=ACCOUNT%20EQ
%20$techSTK%20BOOKING.DATE%20RG%20'$stringAgo%20$stringToday'%20TXN.CNT%20EQ
%2010&application=&ofsOperation=&ofsFunction=&ofsMessage=&version=&transactionId=&c
ommand=globusCommand&operation=&windowName=$mainBodyCode&apiArgument=&name=&enqname
=AI.QCK.TRAN.SEARCH.STMT.TCB&enqaction=SELECTION&dropfield=&previousEnqs=&previousE
nqTitles=&clientStyleSheet=&unlock=&allowResize=YES&companyId=VN0010001&company=BNK
-TECHCOMBANK%20HOI%20SO&user=$techAcc&transSign=&skin=arc-
ib&today=15%2F07%2F2021&release=R18&$compScreen&reqTabid=&compTargets=&EnqParentWin
dow=$stmtsteptwoCode&timing=356-3-3-350-1&pwprocessid=&language=VN&languages=GB
%2CVN&savechanges=YES&staticId=&lockDateTime=&popupDropDown=true&allowcalendar=&all
owdropdowns=&allowcontext=NO&nextStage=&maximize=true&showStatusInfo=NO&languageUnd
efined=Language%20Code%20Not%20Defined&expandMultiString=Expand%20Multi
%20Value&deleteMultiString=Delete%20Value&expandSubString=Expand%20Sub
%20Value&clientExpansion=true&WS_parentWindow=&WS_parent=&WS_dropfield=&WS_doResize
=&WS_initState=ENQ%20AI.QCK.TRAN.SEARCH.STMT.TCB%20ACCOUNT%20EQ%20$techSTK
%20BOOKING.DATE%20RG%20'$stringAgo%20$stringToday'%20TXN.CNT%20EQ
%2010&WS_PauseTime=&WS_multiPane=false&WS_replaceAll=yes&WS_parentComposite=$mainBo
dyCode&WS_delMsgDisplayed=&WS_FragmentName=$mainBodyCode";
try {
var responseZ = await http.post(url, body: bodyHistories, headers: headers)
.timeout(
const Duration(seconds: 10),
onTimeout: () {
return http.Response('Error', 500);
}
);
// Timeout
if (responseZ.statusCode == 500) return getTransaction();
// ignore: close_sinks
final stream =StreamController<List>.broadcast(sync: false);
int count = 0;
var currentScrollTime = "";
var currentTimeMessageToJump = 0;
@override
void initState() {
super.initState();
controller = new ScrollController()..addListener(_scrollListener);
Provider.of<Auth>(context, listen: false).getQueueMessages(widget.id);
RawKeyboard.instance.addListener(handleKey);
RawKeyboard.instance.addListener(keyboardListener);
}
@override
didUpdateWidget(oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.id != widget.id) {
setStreamShow(false);
setState(() {
fileItems = [];
isUpdate = false;
isShowRecord = false;
});
getLastEdited();
Provider.of<Auth>(context, listen: false).getQueueMessages(widget.id);
if (controller.hasClients)
controller.jumpTo(_controller.position.maxScrollExtent);
}
}
onChangeIsSendMessage(bool value) {
isSendMessage = value;
}
setStreamShow(bool value){
streamShowGoUpStatus = value;
streamShowGoUp.add(streamShowGoUpStatus);
}
handleKey(RawKeyEvent keyEvent) {
final isFocus = key.currentState?.focusNode.hasFocus ?? false;
if(keyEvent is RawKeyDownEvent) {
if(isFocus && key.currentState?.controller!.text == "") {
if(keyEvent.isKeyPressed(LogicalKeyboardKey.arrowUp)) {
final messagesData = Provider.of<Messages>(context, listen:
false).data.where((element) => element["channelId"] == widget.id).toList();
final currentUser = Provider.of<User>(context, listen:
false).currentUser;
final data = messagesData.isNotEmpty ? messagesData[0]["messages"] : [];
final dataCurrentUser = data.where((ele) => ele["user_id"] ==
currentUser["id"]).toList();
if (dataCurrentUser.length > 0) {
final msg = dataCurrentUser.first;
Map message = {
"id": msg["id"],
"message": msg["message"],
"avatarUrl": msg["avatar_url"],
"insertedAt": msg["inserted_at"],
"fullName": msg["full_name"],
"attachments": msg["attachments"],
"isChannel": true,
"userId": msg["user_id"],
"channelId": msg["channel_id"],
"workspaceId": msg["workspace_id"],
"reactions": msg["reactions"],
"lastEditedAt": msg["last_edited_at"],
"isUnsent": msg["is_unsent"]
};
message["attachments"].indexWhere((e) => e["type"] == "bot");
if (currentUser["id"] == message["userId"] && message["isChannel"] &&
(message['current_time'] != null && DateTime.now().add(Duration(hours: -
7)).microsecondsSinceEpoch - message['current_time'] < 86400000000))
updateMessage(message);
}
}
}
}
return KeyEventResult.ignored;
}
processFiles(files, isSetstate) async {
fileItems = List.from(files);
if (isSetstate) {
Timer.run(() { this.setState(() {}); });
}
this.setState(() {
fileItems = fileItems.where((e) => e.isNotEmpty).toList();
});
processFilesToInput(fileItems, isSetstate);
}
processFilesToInput(files, isSetstate) {
try {
if(files[0]['type'] == 'text') {
String beforeString = key.currentState!.controller!.text +
( key.currentState!.controller!.text != '' ? '\n' : '');
Timer.run(() {
if (key.currentState != null) key.currentState!.focusNode.requestFocus();
key.currentState!.setMarkUpText(beforeString + files[0]['text']);
});
return;
}
try {
if (index != -1 && file['preview'] == null) {
String message = utf8.decode((file['file'] as List<int>));
file = {
...files[i],
'preview': message.length >= 1000 ? message.substring(0, 1000) +
' ...' : message,
};
}
} catch (err) {}
result += [file];
}
if (isSetstate) {
setState(() {
fileItems += result;
});
} else {
fileItems += result;
}
if (key.currentState != null) key.currentState!.focusNode.requestFocus();
StreamDropzone.instance.initDrop();
onSaveAttachments();
} catch (e, t) {
print("processFiles error: $e, $t");
}
}
@override
void dispose() {
_debounce?.cancel();
controller.dispose();
RawKeyboard.instance.removeListener(handleKey);
RawKeyboard.instance.removeListener(keyboardListener);
super.dispose();
}
getLastEdited() async {
var box = await Hive.openBox('drafts');
var lastEdited = box.get('lastEdited');
var lastEditedFile = box.get('lastEditedFile');
var openSetting = box.get('openSetting');
if (openSetting != null) {
if (openSetting) {
Provider.of<Channels>(context, listen: false).openChannelSetting(true);
}
}
if (indexAttachment != -1) {
files = lastEditedFile[indexAttachment]["files"] ?? [];
}
if (mounted) {
setState(() {
if (key.currentState != null) {
key.currentState!.setMarkUpText(text);
}
textInput = text;
fileItems = files;
});
}
}
}
}
onSaveAttachments() async{
// var box = await Hive.openBox('drafts');
// var lastEditedFile = box.get('lastEditedFile');
// List changes;
// if (lastEditedFile == null) {
// changes = [{
// "id": widget.id,
// "files": fileItems,
// }];
// } else {
// changes = List.from(lastEditedFile);
// final index = changes.indexWhere((e) => e["id"] == widget.id);
// if (index != -1) {
// changes[index] = {
// "id": widget.id,
// "files": fileItems,
// };
// } else {
// changes.add({
// "id": widget.id,
// "files": fileItems,
// });
// }
// }
// box.put('lastEditedFile', changes);
}
saveChangesToHive(str) async {
// var box = await Hive.openBox('drafts');
// var lastEdited = box.get('lastEdited');
// List changes;
// if (lastEdited == null) {
// changes = [{
// "id": widget.id,
// "text": str,
// }];
// } else {
// changes = List.from(lastEdited);
// final index = changes.indexWhere((e) => e["id"] == widget.id);
// if (index != -1) {
// changes[index] = {
// "id": widget.id,
// "text": str,
// };
// } else {
// changes.add({
// "id": widget.id,
// "text": str,
// });
// }
// }
// box.put('lastEdited', changes);
}
handleMessage() {
final auth = Provider.of<Auth>(context, listen: false);
final currentWorkspace = Provider.of<Workspaces>(context, listen:
false).currentWorkspace;
onChangeIsSendMessage(true);
if( Provider.of<Channels>(context, listen: false).currentChannel["id"] != null)
{
Provider.of<Channels>(context, listen:
false).updateLastMessageReaded(Provider.of<Channels>(context, listen:
false).currentChannel["id"], null);
}
if (isShowCommand && commandSelected != null) {
String stringCommand = "/" + commandSelected["short_cut"] + " ";
key.currentState!.controller!.text = stringCommand;
key.currentState!.controller!.selection =
TextSelection.fromPosition(TextPosition(offset:
key.currentState!.controller!.text.length));
setState(() {
suggestCommands = [];
isShowCommand = false;
commandSelected = null;
});
} else {
if (!isUpdate) {
_uploadImage(auth.token, currentWorkspace["id"]);
if(isCodeBlock) handleCodeBlock(false);
} else {
_sendUpdateMessage(auth, currentWorkspace);
}
updateMessage(dataM) {
final messageId = dataM["id"];
final channelId = widget.id;
if (data.isNotEmpty) {
int indexMessage = data.indexWhere((e) => e["id"] == messageId);
if (indexMessage != -1) {
var dataM = data[indexMessage];
var message = dataM["message"];
var mentions = dataM["attachments"] != null ?
dataM["attachments"].where((element) => element["type"] == "mention").toList() :
[];
var sendToChannelFromThread = dataM["attachments"] != null ?
dataM["attachments"].where((element) => element["type"] ==
"send_to_channel_from_thread").toList() : [];
if (mentions.length > 0){
var mentionData = mentions[0]["data"];
message = "";
for(var i= 0; i< mentionData.length ; i++){
if (mentionData[i]["type"] == "text" ) {
message += mentionData[i]["value"];
} else {
message += "=======${mentionData[i]["trigger"] ?? "@"}/$
{mentionData[i]["value"]}^^^^^${mentionData[i]["name"]}^^^^^${mentionData[i]
["type"] ?? ((mentionData[i]["id"].length < 10) ? "all" : "user")}+++++++";
}
}
}
if (sendToChannelFromThread.length == 0) {
// Tat ca file can hien thi
var attOldMessage = dataM["attachments"] != null ?
dataM["attachments"].where((ele) => ele["mime_type"] != "block_code" && ele["type"]
!= "mention").toList() : [];
setState((){
fileItems = attOldMessage;
});
}
key.currentState!.focusNode.requestFocus();
Future.delayed(const Duration(microseconds: 1), () =>
key.currentState!.setMarkUpText(message));
}
setUpdateMessage(dataM, true);
}
}
handleMessageToAttachments(String message) {
String name = Utils.suffixNameFile('message', fileItems);
List<int> bytes = utf8.encode(message);
processFiles([{
"name": '$name.txt',
"mime_type": 'txt',
'type': 'txt',
"path": '',
"bytes": bytes
}], false);
}
_sendUpdateMessage(auth, currentWorkspace) async{
List files = fileItems;
setState(() {
fileItems = [];
});
var result = Provider.of<Messages>(context, listen:
false).checkMentions(key.currentState!.controller!.markupText);
var sendToChannelFromThread = messageUpdate["attachments"] != null ?
messageUpdate["attachments"].where((element) => element["type"] ==
"send_to_channel_from_thread").toList() : [];
var checkingShareMessage = files.where((element) => element["mime_type"] ==
"share").toList();
var message = {
"channel_thread_id": null,
"key": Utils.getRandomString(20),
"message_id": messageUpdate["id"],
"message": result["success"] ? "" : result["data"],
"attachments": sendToChannelFromThread + (result["success"] ? ([] + [{"type":
"mention", "data": result["data"] }]) : []) + checkingShareMessage,
"channel_id": widget.id,
"workspace_id": currentWorkspace["id"],
"user_id": messageUpdate["userId"],
"is_system_message": false
};
Provider.of<Messages>(context, listen:
false).newUpdateChannelMessage(auth.token, message, files);
key.currentState!.controller!.clear();
setUpdateMessage(null, false);
onSaveAttachments();
}
checkCommand(value, context) {
final currentCommand = Provider.of<Channels>(context, listen:
false).currentCommand;
final appInChannel = Provider.of<Channels>(context, listen:
false).appInChannels;
final isBanking = appInChannel.indexWhere((element) => element["app_name"] ==
"BizBanking") != -1;
getSTK().then((value) {
techSTK = value;
});
var lengthA = techAcc.length > 4 ? techAcc.length - 4 : 0;
var newString = techAcc.substring(lengthA);
var command = {
"app_id": "1889cc30-53cb-4a98-8dba-ca33f8bed6ef",
"command_id": "",
"command_params": [{"key": "$techSTK"}],
"description": "***$newString",
"is_removed": false,
"short_cut": "histories"
};
List newResult = !isBanking ? currentCommand : currentCommand + [command];
handleCodeBlock(bool value) {
setState(() {
isCodeBlock = value;
});
}
getSuggestionMentions() {
final auth = Provider.of<Auth>(context, listen: false);
List channelMembers = Provider.of<Channels>(context, listen:
false).channelMember;
List<Map<String, dynamic>> dataList = [{'id': "${widget.id}", 'display': 'all',
'full_name': 'all', 'photo': 'all', "type": "all"}];
getSuggestionIssue() {
List preloadIssues = Provider.of<Workspaces>(context, listen:
false).preloadIssues;
List dataList = [];
dataList += [item];
}
return dataList;
}
_scrollListener() {
final token = Provider.of<Auth>(context, listen: false).token;
final currentChannel = Provider.of<Channels>(context, listen:
false).currentChannel;
final currentWorkspace = Provider.of<Workspaces>(context, listen:
false).currentWorkspace;
final messagesChannel = Provider.of<Messages>(context, listen:
false).getDataMessagesChannel(currentChannel['id']);
// if (scrollDirection != ScrollDirection.idle) {
// double newOffset = controller.offset + (scrollDirection ==
ScrollDirection.reverse ? 40 : -40);
// newOffset = min(controller.position.maxScrollExtent,
max(controller.position.minScrollExtent, newOffset));
// // controller.jumpTo(newOffset);
// Timer(Duration(milliseconds: 0), () {
// controller.animateTo(
// newOffset,
// duration: Duration(milliseconds: 80), curve: Curves.ease
// );
// });
// }
keyboardListener(RawKeyEvent event) {
final keyId = event.logicalKey.keyId;
if (event is RawKeyDownEvent) {
if ((event.isMetaPressed || event.isAltPressed || event.isControlPressed)) {
if(keyId.clamp(32, 126) == keyId) {
return KeyEventResult.handled;
}
} else if (mounted && keyId.clamp(32, 126) == keyId) {
GlobalKey<ScaffoldState> keyScaffold = Provider.of<Auth>(context, listen:
false).keyDrawer;
final selectedTab = Provider.of<User>(context, listen: false).selectedTab;
if (!(FocusManager.instance.primaryFocus?.context?.widget is EditableText)
&& selectedTab == "channel" && keyScaffold.currentState != null && !
keyScaffold.currentState!.isEndDrawerOpen && !Navigator.of(context).canPop() &&
mounted) {
if (key.currentState!.isFocus) return KeyEventResult.ignored;
bool openSearchbar = Provider.of<Windows>(context, listen:
false).openSearchbar;
// final openThread = Provider.of<Messages>(context, listen:
false).openThread;
final isFocusInputThread = Provider.of<Messages>(context, listen:
false).isFocusInputThread;
bool isOtherFocus = Provider.of<Windows>(context, listen:
false).isOtherFocus;
if (!openSearchbar && !isFocusInputThread && key.currentState!= null &&
key.currentState!.controller != null && !isOtherFocus) {
FocusInputStream.instance.focusToMessage();
key.currentState!.controller?.text = key.currentState!.controller!.text
+ event.character!;
}
}
}
}
return KeyEventResult.ignored;
}
removeFile(index) {
List list = fileItems;
list.removeAt(index);
setState(() {
fileItems = list;
});
onSaveAttachments();
}
openFileSelector() async {
try {
var dataFiles = await Utils.openFilePicker([]);
await processFiles(dataFiles, true);
} on Exception catch (e) {
print("$e Cancel");
}
}
selectEmoji(emoji) {
key.currentState!.setMarkUpText((key.currentState?.controller?.markupText ??
'') + emoji.value);
key.currentState!.focusNode.requestFocus();
}
onSelectCommand(commad, commandParams) {
final String space = (commandParams != null && commandParams.length > 0) ? "
" : "";
key.currentState!.setMarkUpText(commad + space);
key.currentState!.focusNode.requestFocus();
}
var c = currentCommand[0];
var newList = [];
if (c["command_params"].length == listParams.length) {
for (int i = 0; i <= listParams.length - 1; i++) {
newList.add({c["command_params"][i]["key"]: listParams[i]});
}
}
c["command"] = message;
c["channel_id"] = widget.id;
c["workspace_id"] = workspaceId;
c["to_command_params"] = newList;
var messageDummy = {
"message": "",
"attachments": [{
"type": "bot",
"data": {...c, "command": message.replaceFirst("/", "")},
"bot": {"id": c["app_id"], "name": c["app_name"]}
}],
"channel_id": widget.id,
"workspace_id": workspaceId,
"key": Utils.getRandomString(20),
"id": Utils.getRandomString(20),
"user_id": auth.userId,
"user": user.currentUser["full_name"] ?? "",
"avatar_url": user.currentUser["avatar_url"] ?? "",
"inserted_at": DateTime.now().add(const Duration(hours: -
7)).toIso8601String(),
"is_system_message": false
};
Provider.of<Messages>(context, listen:
false).checkNewMessage(messageDummy);
if (message.startsWith("/histories")) {
Map transfer = await sendRequestLogin();
if (transfer["success"]) {
for (var i = 0; i < transfer['data'].length; i++) {
c["transfer"] = transfer['data'][i];
var dataMessage = {
"message": "",
"attachments": [{"type": "BizBanking", "data": c }],
"channel_id": widget.id,
"workspace_id": workspaceId,
"key": Utils.getRandomString(20),
};
final url = Utils.apiUrl + 'workspaces/$workspaceId/channels/$
{widget.id}/messages?token=$token';
await http.post(Uri.parse(url), headers: Utils.headers, body:
json.encode(dataMessage));
}
} else {
c["transfer"] = transfer;
var dataMessage = {
"message": "",
"attachments": [{"type": "BizBanking", "data": c}],
"channel_id": widget.id,
"workspace_id": workspaceId,
"key": Utils.getRandomString(20),
};
final url = Utils.apiUrl + 'workspaces/$workspaceId/channels/$
{widget.id}/messages?token=$token';
await http.post(Uri.parse(url), headers: Utils.headers, body:
json.encode(dataMessage));
}
Provider.of<Messages>(context, listen:
false).deleteMessage({...messageDummy, "message_id": messageDummy["id"]});
} else {
Provider.of<Messages>(context, listen: false).excuteCommand(token,
workspaceId, widget.id, {...c, "key": messageDummy["key"]});
}
setState(() {
suggestCommands = [];
});
}
} else {
List list = fileItems;
setState(() {
StreamDropzone.instance.initDrop();
fileItems = [];
});
var result = Provider.of<Messages>(context, listen:
false).checkMentions(key.currentState!.controller!.markupText.trim());
var checkingBlockCode = Provider.of<Messages>(context, listen:
false).regexMessageBlockCode(message);
List data = [];
var checkingShareMessage = list.where((element) => element["mime_type"] ==
"share").toList();
if (isCodeBlock) {
data = [{'type': 'block_code', 'value':
key.currentState!.controller!.text.trimRight()}];
} else if (result['success']) {
for (int i=0; i<result["data"].length; i++) {
if(result["data"][i]['type'] == 'text') {
var blockCode = Provider.of<Messages>(context, listen:
false).regexMessageBlockCode(result["data"][i]['value']);
if (blockCode['success']) {
data = blockCode['data'];
} else {
data.add(result["data"][i]);
}
} else {
data.add(result["data"][i]);
}
}
} else {
if(checkingBlockCode['success']) data = checkingBlockCode['data'];
}
List attachments = [];
if(result['success'] && checkingBlockCode['success']) {
attachments = [{
"type": "mention", "data": data.where((ele) => ele['type'] !=
'block_code').toList()
}, {
"type": "block_code", "data": data.where((ele) => ele['type'] ==
'block_code').toList()
}];
} else {
if(result['success']) {
attachments = [{
"type": "mention", "data": data
}];
} else if (checkingBlockCode['success'] || isCodeBlock) {
attachments = [{
"type": "block_code", "data": data
}];
}
}
var dataMessage = {
"channel_thread_id": null,
"key": Utils.getRandomString(20),
"message": result["success"] || checkingBlockCode["success"]||
isCodeBlock ? "" : result["data"],
"attachments": attachments + checkingShareMessage,
"channel_id": widget.id,
"workspace_id": workspaceId,
"count_child": 0,
"user_id": auth.userId,
"user": user.currentUser["full_name"] ?? "",
"avatar_url": user.currentUser["avatar_url"] ?? "",
"full_name": Utils.getUserNickName(auth.userId) ??
user.currentUser["full_name"] ?? "",
"inserted_at": DateTime.now().add(const Duration(hours: -
7)).toIso8601String(),
"is_system_message": false,
"isDesktop": true
};
key.currentState!.controller!.clear();
handleCodeBlock(false);
list.removeWhere((element) => element["mime_type"] == "share");
if (Utils.checkedTypeEmpty(dataMessage["message"]) ||
dataMessage["attachments"].length > 0 || list.isNotEmpty) {
Provider.of<Messages>(context, listen: false).sendMessageWithImage(list,
dataMessage, token);
}
if (mounted) {
setState(() {
fileItems = [];
});
}
onSaveAttachments();
}
}
selectArrowCommand(value) {
if (suggestCommands.isNotEmpty) {
int index = suggestCommands.indexWhere((e) => e == commandSelected);
var offset = _controller.offset;
if (value == "up") {
setState(() {
commandSelected = index == 0 ? suggestCommands[0] : suggestCommands[index
- 1];
if (index >= 1) _controller.animateTo(offset - 42, duration: const
Duration(milliseconds: 1), curve: Curves.ease);
});
} else {
setState(() {
commandSelected = index == suggestCommands.length - 1 ?
suggestCommands[suggestCommands.length - 1] : suggestCommands[index + 1];
if (index >= 4 && index <= suggestCommands.length - 1)
_controller.animateTo(offset + 46, duration: const Duration(milliseconds: 1),
curve: Curves.ease);
});
}
}
}
print("PPPPPPP $e");
}
}
onShareMessage(attachment) {
List list = fileItems;
final index = list.indexWhere((element) => element["mime_type"] == "share");
if (index != -1) {
list.replaceRange(index, index + 1, [attachment]);
} else {
list.add(attachment);
}
setState(() {
fileItems = list;
});
}
selectSticker(data) {
final auth = Provider.of<Auth>(context, listen: false);
final currentWorkspace = Provider.of<Workspaces>(context, listen:
false).currentWorkspace;
final currentUser = Provider.of<User>(context, listen: false).currentUser;
var dataMessage = {
"channel_thread_id": null,
"key": Utils.getRandomString(20),
"message": "",
"attachments": [{
'type': 'sticker',
'data': data
}],
"channel_id": widget.id,
"workspace_id": currentWorkspace['id'],
"count_child": 0,
"user_id": auth.userId,
"user":currentUser["full_name"] ?? "",
"avatar_url": currentUser["avatar_url"] ?? "",
"full_name": Utils.getUserNickName(auth.userId) ??
currentUser["full_name"] ?? "",
"inserted_at": DateTime.now().add(const Duration(hours: -
7)).toIso8601String(),
"is_system_message": false,
"isDesktop": true
};
return DropZone(
shouldBlock: isEndDrawerOpen,
stream: StreamDropzone.instance.dropped,
builder: (context, files) {
if(files.data != null && files.data.length > 0) processFiles(files.data ??
[], false);
return Stack(
children: [
Column(
children: <Widget>[
(messagesData.isNotEmpty && messagesData[0]["isLoadingDown"] &&
data.length == 0) ? Expanded(
child: Center(
child: SpinKitFadingCircle(
color: isDark ? Colors.white60 : const Color(0xff096DD9),
size: 35,
),
),
) : RenderMessageByDay(
controller: controller, theme: theme, locale: locale,
currentChannel: currentChannel, updateMessage: updateMessage,
keyMessageToJump: keyMessageToJump, messageIdToJump:
messageIdToJump,
onFirstFrameMessageSelectedDone: onFirstFrameMessageSelectedDone,
onShareMessage: onShareMessage
),
Container(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 4),
margin: const EdgeInsets.only(top: 4),
child: (currentChannel["is_archived"] != null &&
currentChannel["is_archived"]) ? Container(
decoration: const BoxDecoration(
border: Border(top: BorderSide(color: Colors.black, width:
0.2)),
),
child: Center(
child: Text(
"You cannot send message on this channel because it has
already been archived.",
style: TextStyle(color: Colors.grey[600], fontSize: 16)
)
)
) : Column (
children:[
fileItems.isNotEmpty ? FileItems(files: fileItems,
removeFile: removeFile, onChangedTypeFile: onChangedTypeFile, setShareMessage:
setShareMessage) : Container(),
isShowRecord
? RecordAudio(onExit: (value) => setState(() =>
isShowRecord = value))
: Container(
decoration: BoxDecoration(
color: isDark ? Palette.backgroundTheardDark :
Colors.transparent,
borderRadius: BorderRadius.circular(4),
border: isDark ? const Border() : Border.all(
color: const Color(0xffA6A6A6), width: 0.5
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlutterMentions(
afterFirstFrame: (){
getLastEdited();
},
parseMention: Provider.of<Messages>(context,
listen: false).checkMentions,
cursorColor: theme == ThemeType.DARK ?
Colors.grey[400]! : Colors.black87,
key: key,
autofocus: true,
isIssues: false,
id: widget.id.toString(),
isDark: isDark,
setUpdateMessage: setUpdateMessage,
isUpdate: isUpdate,
style: TextStyle(fontSize: 15.5, color: theme ==
ThemeType.DARK ? Colors.grey[300] : Colors.grey[800]),
sendMessages: handleMessage,
isCodeBlock: isCodeBlock,
isShowCommand: isShowCommand,
selectArrowCommand: selectArrowCommand,
handleCodeBlock: handleCodeBlock,
handleMessageToAttachments:
handleMessageToAttachments,
decoration: InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
isDense: true,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
contentPadding: const EdgeInsets.only(left: 5,
bottom: 10, top: 18),
hintText: !isUpdate ? !isCodeBlock ? "$
{S.current.typeAMessage}..." : "Block Code..." : "Editing this message...",
hintStyle: TextStyle(color: isDark ? const
Color(0xff9AA5B1) : const Color.fromRGBO(0, 0, 0, 0.65), fontSize: 13.5, height: 1)
),
onChanged: (str) {
saveChangesToHive(key.currentState!.controller!.markupText);
checkCommand(str, context);
setState(() {});
if (str.trim() != "" && str != textInput) {
if (_debounce?.isActive ?? false)
_debounce?.cancel();
_debounce = Timer(const
Duration(milliseconds: 500), () {
auth.channel.push(
event: "on_typing",
payload: {"channel_id":
currentChannel["id"], "workspace_id": currentWorkspace["id"], "user_name":
currentUser["full_name"]}
);
});
}
},
suggestionListDecoration: const BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(8)),
),
onSearchChanged: (trigger, value) { },
mentions: [
Mention(
markupBuilder: (trigger, mention, value,
type) {
final name = Utils.getUserNickName(mention)
?? value;
return
"=======@/$mention^^^^^$name^^^^^$type+++++++";
},
trigger: '@',
style: const TextStyle(color:
Colors.lightBlue),
data: getSuggestionMentions(),
matchAll: true,
),
Mention(
markupBuilder: (trigger, mention, value,
type) {
return
"=======#/$mention^^^^^$value^^^^^$type+++++++";
},
trigger: "#",
style: const TextStyle(color:
Colors.lightBlue),
data: getSuggestionIssue(),
matchAll: true
)
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InputLeading(
openFileSelector: openFileSelector,
selectEmoji: selectEmoji,
showRecordMessage: (value) => setState(() =>
isShowRecord = value),
selectSticker: selectSticker
),
Container(
margin: EdgeInsets.all(4),
child: HoverItem(
colorHover: Palette.hoverColorDefault,
radius: 4.0, isRound: true,
child: InkWell(
child: Container(
padding: EdgeInsets.all(6),
child: Icon(
isUpdate ? Icons.check : Icons.send,
color:
((key.currentState?.controller!.markupText != "" ) || (fileItems.isNotEmpty))
? const Color(0xffFAAD14)
: isDark ? const
Color(0xff9AA5B1) : const Color(0xff616E7C),
size: 18
),
),
onTap: () =>
((key.currentState?.controller!.markupText != "" ) || (fileItems.isNotEmpty)) ?
handleMessage() : null,
),
),
)
],
)
],
)
),
TypingDesktop(id: widget.id)
]
)
),
(data.length > 0 && currentScrollTime != "") ? Positioned(
top: 20, left: 0, right: 0,
child: Center(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal:
10),
decoration: BoxDecoration(
color: isDark ? const Color(0xff1F2933) : Colors.white,
borderRadius: const BorderRadius.all(Radius.circular(20)),
border: Border.all(color: isDark ? const
Color(0xff52606D) : const Color(0xffE4E7EB)),
),
child: Text(currentScrollTime, style: TextStyle(color: isDark
? Colors.white.withOpacity(0.85) : Colors.black.withOpacity(0.65), fontSize:
12.5)),
),
),
) : const SizedBox(),
]
),
AnimatedPositioned(
bottom: 105,
left: 15,
right: 0,
height: suggestCommands.length < 5 ? suggestCommands.length * 43.0 :
214.0,
duration: const Duration(milliseconds: 300),
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(8)),
color: isDark ? const Color(0xff2f3136) : const
Color(0xFFf0f0f0),
boxShadow: suggestCommands.isNotEmpty ?
[
BoxShadow(
color: isDark ? const Color(0xFF262626).withOpacity(0.5) :
Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(0, 3), // changes position of shadow
),
] : [],
),
child: ListView(
controller: _controller,
shrinkWrap: true,
children: [
Column(
children: suggestCommands.map<Widget>((command) {
var string = command["command_params"] != null ?
command["command_params"].map((e) {
return "[${e["key"]}]";
}) : [];
var commandParams = command["command_params"];
return Container(
decoration: command["command_id"] ==
commandSelected["command_id"] ? BoxDecoration(
color: Colors.grey[300]
) : BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey[500]!, width:
0.2),
top: BorderSide(color: Colors.grey[500]!, width: 0.2)
)
),
child: Container(
height: 50,
child: TextButton(
onPressed: (){
onSelectCommand("/" + command["short_cut"],
commandParams);
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"/${command["short_cut"] ?? ""} ",
overflow: TextOverflow.ellipsis,
),
Text(
"${string.join(" ")}",
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Color(0xFF8C8C8C),
fontWeight: FontWeight.w300,
fontSize: 12
)
)
],
),
),
command["description"] != null ? Container(
padding: const EdgeInsets.only(left: 4, top: 2,
bottom: 2),
child: Text(
command["description"],
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Color(0xFF8C8C8C),
fontSize: 12,
fontWeight: FontWeight.w300
),
)
) : Container()
],
),
),
)
);
}).toList(),
),
],
),
)
),
messagesData.isNotEmpty && (messagesData[0]["numberNewMessages"] ?? 0)
> 0 ?
Positioned(
bottom: 100,
height: 50,
left: 0,
right: 0,
child: Center(
child: HoverItem(
child: GestureDetector(
onTap: (){
Provider.of<Messages>(context, listen:
false).resetOneChannelMessage(currentChannel["id"]);
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 5,
horizontal: 10),
decoration: BoxDecoration(
color: theme == ThemeType.DARK ?
Palette.defaultBackgroundDark : Palette.defaultBackgroundLight,
borderRadius: const
BorderRadius.all(Radius.circular(20)),
border: Border.all(color: const Color(0xFFbfbfbf), width:
1),
),
child: Text(
"${messagesData[0]["numberNewMessages"]} new messages",
style: TextStyle(fontSize: 12, color: theme ==
ThemeType.DARK ? Colors.white70 : const Color(0xFF6a6e74)),
),
),
),
),
),
)
: Container(),
StreamBuilder(
stream: streamShowGoUp.stream,
initialData: false,
builder: (context, snapshot) {
bool isShow = (snapshot.data as bool?) ?? false;
return AnimatedPositioned(
duration: const Duration(milliseconds: 300),
top: isShow ? 10 : -50, left: 0, right: 0,
child: Center(
child: HoverItem(
// colorHover: Colors.pink,
child: InkWell(
onTap: () {
setStreamShow(false);
Provider.of<Messages>(context, listen:
false).resetOneChannelMessage(currentChannel["id"]);
},
child: Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: !isDark ? const Color(0xFFbfbfbf) : const
Color(0xff262626)
),
child: const Icon(PhosphorIcons.arrowDown, size: 20)),
),
),
),
);
}
)
]
);
}
);
}
@override
Widget build(BuildContext context) {
final token = Provider.of<Auth>(context).token;
final userId = Provider.of<Auth>(context).userId;
final currentWorkspace = Provider.of<Workspaces>(context, listen:
false).currentWorkspace;
final currentChannel = Provider.of<Channels>(context, listen:
false).currentChannel;
final messagesData = Provider.of<Messages>(context, listen:
false).data.where((element) => element["channelId"] ==
currentChannel["id"]).toList();
final data = messagesData.isNotEmpty ? messagesData[0]["messages"] : [];
try {
if (!messagesData[0]["disableLoadingUp"]) setStreamShow(true);
if (messagesData[0]["disableLoadingUp"] && controller.position.extentBefore <
10) setStreamShow(false);
} catch (e) {
}
return Row(
children: [
LayoutBuilder(
builder: (context, cts) {
if ((data.length) * 15 < cts.maxHeight) {
Provider.of<Messages>(context, listen: false).loadMoreMessages(token,
currentWorkspace["id"], currentChannel["id"], isNotifi: false);
}
return Container(
width: 0,
color: Colors.red,
);
}
),
Expanded(child: _conversation(token, currentWorkspace, data, userId))
],
);
}
}
final openFileSelector;
final selectEmoji;
final showRecordMessage;
final selectSticker;
@override
State<InputLeading> createState() => _InputLeadingState();
}
return Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Container(
width: 30,
height: 30,
margin: const EdgeInsets.only(left: 5),
child: TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(const EdgeInsets.all(0)),
overlayColor: MaterialStateProperty.all(isDark ?
Palette.hoverColorDefault : const Color.fromARGB(255, 166, 164,
164).withOpacity(0.15)),
shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius:
BorderRadius.circular(4.0))),
),
child: Icon(CupertinoIcons.plus, color: isDark ? const
Color(0xff9AA5B1) : const Color.fromRGBO(0, 0, 0, 0.65), size: 18),
onPressed: () {
widget.openFileSelector();
}
)
),
const SizedBox(width: 4),
Container(
width: 30,
height: 30,
child: HoverItem(
colorHover: isDark ? Palette.hoverColorDefault : const
Color.fromARGB(255, 166, 164, 164).withOpacity(0.15),
child: TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(const EdgeInsets.all(0)),
overlayColor: MaterialStateProperty.all(Colors.transparent),
shape:
MaterialStateProperty.all(RoundedRectangleBorder(borderRadius:
BorderRadius.circular(50.0))),
),
child: SvgPicture.asset(
"assets/icons/poll.svg",
color: isDark ? const Color(0xff9AA5B1) : const Color.fromRGBO(0,
0, 0, 0.65),
width: 16, height: 16
),
onPressed: () => createPollDialog(context, isDark)
),
)
),
const SizedBox(width: 4),
if (Platform.isMacOS) Container(
width: 30,
height: 30,
child: HoverItem(
colorHover: isDark ? Palette.hoverColorDefault : const
Color.fromARGB(255, 166, 164, 164).withOpacity(0.15),
child: TextButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(const EdgeInsets.all(0)),
overlayColor: MaterialStateProperty.all(Colors.transparent),
shape:
MaterialStateProperty.all(RoundedRectangleBorder(borderRadius:
BorderRadius.circular(50.0))),
),
child: Icon(CupertinoIcons.mic, color: isDark ? const
Color(0xff9AA5B1) : const Color.fromRGBO(0, 0, 0, 0.65), size: 18),
onPressed: () {
widget.showRecordMessage(true);
}
),
)
),
StickerEmojiWidget(
data: stickers,
selectSticker: widget.selectSticker,
workspaceId: currentWorkspace["id"],
channelId: currentChannel['id'],
onSelect: (emoji){
widget.selectEmoji(emoji);
},
isCreateSticker: true
)
]
);
}
var dataMessage = {
"channel_thread_id": null,
"key": Utils.getRandomString(20),
"message": "",
"attachments": attachments,
"channel_id": currentChannel["id"],
"workspace_id": currentWorkspace["id"],
"count_child": 0,
"user_id": auth.userId,
"user": user.currentUser["full_name"] ?? "",
"avatar_url": user.currentUser["avatar_url"] ?? "",
"full_name": user.currentUser["full_name"] ?? "",
"inserted_at": DateTime.now().add(const Duration(hours: -
7)).toIso8601String(),
"is_system_message": true,
"isDesktop": true
};
@override
State<RenderMessageByDay> createState() => _RenderMessageByDayState();
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.controller.jumpTo(0.000000000001);
});
}
@override
Widget build(BuildContext context) {
final currentChannel = Provider.of<Channels>(context, listen:
true).currentChannel;
final messagesData = Provider.of<Messages>(context, listen:
true).data.where((element) => element["channelId"] ==
currentChannel["id"]).toList();
final data = (messagesData.isNotEmpty ? messagesData[0]["messages"] :
[]).toList();
final userId = Provider.of<Auth>(context, listen: false).userId;
final isDark = Provider.of<Auth>(context, listen: false).theme ==
ThemeType.DARK;
final customColor = Provider.of<User>(context, listen:
false).currentUser["custom_color"];
int index = Provider.of<Messages>(context, listen:
true).data.indexWhere((element) => element["channelId"].toString() ==
currentChannel["id"].toString());
var isFetchingUp = (index == -1 ? false :
Provider.of<Messages>(context).data[index]["isLoadingUp"]) ?? false;
var isFetchingDown = (index == -1 ? false :
Provider.of<Messages>(context).data[index]["isLoadingDown"]) ?? false;
return Expanded(
child: CustomSelectionArea(
child: DraggableScrollbar.rrect(
key: keyScroll,
id: currentChannel["id"],
onChanged: (bool value) {
if(isShow != value) {
setState(() {
isShow = value;
});
}
},
heightScrollThumb: 56,
backgroundColor: Colors.grey[600],
scrollbarTimeToFade: const Duration(seconds: 2),
itemCount: data.length,
controller: widget.controller,
child: Container(
height: double.infinity,
child: ListView.builder(
shrinkWrap: true,
reverse: true,
controller: widget.controller,
itemCount: data.length,
itemBuilder: (context, index) {
var message = data[index];
var isAfterThread = (index + 1) < data.length ? (((data[index + 1]
["count_child"] ?? 0) > 0)) : false;
return ChatItemMacOS(
key: (message["id"] != null && message["id"] != "") ?
Key(message["id"]) : message["message_key"] != null ?
Key( message["message_key"]) : null,
userId: message["user_id"],
isChildMessage: false,
id: message["id"],
isMe: message["user_id"] == userId,
accountType: message["account_type"],
message: message["message"],
avatarUrl: message["avatar_url"],
insertedAt: message["inserted_at"],
lastEditedAt: message["last_edited_at"],
isUnsent: message["is_unsent"],
fullName: Utils.getUserNickName(message["user_id"]) ??
message["full_name"],
attachments: message["attachments"] == null ? [] :
message["attachments"],
isFirst: message["isFirst"],
isLast: message["isLast"],
isChannel: true,
isThread: false,
count: message["count_child"],
infoThread: message["info_thread"] != null ?
message["info_thread"] : [],
success: message["error"] == null ? true : message["error"],
showHeader: false,
showNewUser: message["showNewUser"],
isSystemMessage: message["is_system_message"] ?? false,
isBlur: message["is_blur"],
updateMessage: widget.updateMessage,
reactions: message["reactions"],
snippet: message["snippet"] ?? "",
blockCode: message["block_code"] ?? "",
isViewMention: false,
channelId: currentChannel["id"],
idMessageToJump: widget.messageIdToJump,
onFirstFrameDone: widget.onFirstFrameMessageSelectedDone ,
firstMessage: message["firstMessage"],
onShareMessage: widget.onShareMessage,
isDark: isDark,
customColor: customColor,
currentTime: message["current_time"],
isAfterThread: isAfterThread,
isShow: isShow,
keyScroll: keyScroll,
isFetchingDown: isFetchingDown && index == data.length - 1,
isFetchingUp: isFetchingUp && index == 0,
workspaceId: message['workspace_id'],
);
}
),
)
)
)
);
}
}