Connect backend to UI
This commit is contained in:
@@ -27,6 +27,14 @@ public class ActionHandler {
|
|||||||
public static volatile boolean forceExitChat = false;
|
public static volatile boolean forceExitChat = false;
|
||||||
public static ActionHandler instance;
|
public static ActionHandler instance;
|
||||||
|
|
||||||
|
//use for UI
|
||||||
|
private volatile String lastStatus = "error"; // success | error
|
||||||
|
private volatile String lastMessage = "";
|
||||||
|
|
||||||
|
public String getLastStatus() { return lastStatus; }
|
||||||
|
public String getLastMessage() { return lastMessage; }
|
||||||
|
public boolean wasSuccess() { return "success".equalsIgnoreCase(lastStatus); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -42,6 +50,17 @@ public class ActionHandler {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void login(String username , String password){
|
||||||
|
JSONObject request = new JSONObject();
|
||||||
|
request.put("action", "login");
|
||||||
|
request.put("user_id", JSONObject.NULL);
|
||||||
|
request.put("username", username);
|
||||||
|
request.put("password", password);
|
||||||
|
request.put("profile_name", JSONObject.NULL);
|
||||||
|
|
||||||
|
this.send(request);
|
||||||
|
|
||||||
|
}
|
||||||
public void loginHandler() {
|
public void loginHandler() {
|
||||||
System.out.println("Login form: \n");
|
System.out.println("Login form: \n");
|
||||||
System.out.print("Username: ");
|
System.out.print("Username: ");
|
||||||
@@ -197,7 +216,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void addContact(UUID contactId) {
|
public void addContact(UUID contactId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "add_contact");
|
req.put("action", "add_contact");
|
||||||
req.put("user_id", Session.currentUser.getString("user_id"));
|
req.put("user_id", Session.currentUser.getString("user_id"));
|
||||||
@@ -206,7 +225,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void joinGroupOrChannel(String type, String uuid) {
|
public void joinGroupOrChannel(String type, String uuid) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "join_" + type);
|
req.put("action", "join_" + type);
|
||||||
req.put("user_id", Session.getUserUUID());
|
req.put("user_id", Session.getUserUUID());
|
||||||
@@ -216,7 +235,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private ChatEntry fetchChatInfo(String receiverId, String receiverType) {
|
public ChatEntry fetchChatInfo(String receiverId, String receiverType) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_chat_info");
|
req.put("action", "get_chat_info");
|
||||||
req.put("receiver_id", receiverId);
|
req.put("receiver_id", receiverId);
|
||||||
@@ -256,7 +275,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void refreshChatList() {
|
public void refreshChatList() {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_chat_list");
|
req.put("action", "get_chat_list");
|
||||||
req.put("user_id", Session.currentUser.getString("user_id"));
|
req.put("user_id", Session.currentUser.getString("user_id"));
|
||||||
@@ -325,21 +344,38 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ChatEntry parseChatEntry(JSONObject chat) {
|
private ChatEntry parseChatEntry(JSONObject chat) {
|
||||||
ChatEntry entry = new ChatEntry(
|
UUID internalId = null;
|
||||||
UUID.fromString(chat.getString("internal_id")),
|
try { internalId = UUID.fromString(chat.getString("internal_id")); } catch (Exception ignored) {}
|
||||||
chat.getString("id"),
|
|
||||||
chat.getString("name"),
|
|
||||||
chat.optString("image_url", ""),
|
|
||||||
chat.getString("type"),
|
|
||||||
chat.isNull("last_message_time") ? null : LocalDateTime.parse(chat.getString("last_message_time")),
|
|
||||||
chat.optBoolean("is_owner", false),
|
|
||||||
chat.optBoolean("is_admin", false)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (chat.has("other_user_id") && !chat.isNull("other_user_id")) {
|
String id = chat.optString("id", "");
|
||||||
entry.setOtherUserId(UUID.fromString(chat.getString("other_user_id")));
|
String name = chat.optString("name", "");
|
||||||
|
String imageUrl = chat.optString("image_url", "");
|
||||||
|
String type = chat.optString("type", "");
|
||||||
|
boolean isOwner = chat.optBoolean("is_owner", false);
|
||||||
|
boolean isAdmin = chat.optBoolean("is_admin", false);
|
||||||
|
|
||||||
|
LocalDateTime lastTime = null;
|
||||||
|
String lts = chat.optString("last_message_time", null);
|
||||||
|
if (lts != null && !"null".equalsIgnoreCase(lts)) {
|
||||||
|
try { lastTime = LocalDateTime.parse(lts); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatEntry entry = new ChatEntry(internalId, id, name, imageUrl, type, lastTime, isOwner, isAdmin);
|
||||||
|
|
||||||
|
entry.setUnreadCount(chat.optInt("unread_count", 0));
|
||||||
|
String preview = chat.optString("last_message_preview", null);
|
||||||
|
if (preview != null && !"null".equalsIgnoreCase(preview)) {
|
||||||
|
entry.setLastMessagePreview(preview);
|
||||||
|
}
|
||||||
|
|
||||||
|
String other = chat.optString("other_user_id", null);
|
||||||
|
if (other != null && !"null".equalsIgnoreCase(other)) {
|
||||||
|
try { entry.setOtherUserId(UUID.fromString(other)); } catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chat.has("is_saved_messages")) {
|
||||||
|
entry.setSavedMessages(chat.optBoolean("is_saved_messages", false));
|
||||||
}
|
}
|
||||||
entry.setSavedMessages(chat.optBoolean("is_saved_messages", false));
|
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@@ -433,7 +469,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void send(JSONObject request) {
|
public void send(JSONObject request) {
|
||||||
try {
|
try {
|
||||||
if (!request.has("action") || request.isNull("action")) {
|
if (!request.has("action") || request.isNull("action")) {
|
||||||
System.err.println("❌ Invalid request: missing action.");
|
System.err.println("❌ Invalid request: missing action.");
|
||||||
@@ -471,6 +507,12 @@ public class ActionHandler {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
status = response.optString("status","error");
|
||||||
|
String message = response.optString("message","");
|
||||||
|
this.lastStatus = status;
|
||||||
|
this.lastMessage = message;
|
||||||
|
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "login":
|
case "login":
|
||||||
case "register":
|
case "register":
|
||||||
@@ -1057,7 +1099,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void viewProfile(UUID targetId) {
|
public void viewProfile(UUID targetId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_profile");
|
req.put("action", "view_profile");
|
||||||
req.put("target_id", targetId.toString());
|
req.put("target_id", targetId.toString());
|
||||||
@@ -1085,7 +1127,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void startPrivateChat(ContactEntry contact) {
|
public void startPrivateChat(ContactEntry contact) {
|
||||||
UUID myId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
UUID myId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||||||
UUID contactId = contact.getContactId();
|
UUID contactId = contact.getContactId();
|
||||||
|
|
||||||
@@ -1115,10 +1157,10 @@ public class ActionHandler {
|
|||||||
);
|
);
|
||||||
entry.setOtherUserId(contactId);
|
entry.setOtherUserId(contactId);
|
||||||
|
|
||||||
Session.chatList.add(0, entry); // اضافه به اول لیست
|
Session.chatList.add(0, entry);
|
||||||
System.out.println("✅ Chat with " + contact.getProfileName() + " started.");
|
System.out.println("✅ Chat with " + contact.getProfileName() + " started.");
|
||||||
|
|
||||||
openChat(entry); // 👈 مستقیم وارد چت شو (اختیاری)
|
openChat(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1239,7 +1281,7 @@ public class ActionHandler {
|
|||||||
System.out.println("\nYour Chats:");
|
System.out.println("\nYour Chats:");
|
||||||
System.out.println("0. 📦 Archived Chats");
|
System.out.println("0. 📦 Archived Chats");
|
||||||
|
|
||||||
// پیدا کردن Saved در لیست
|
//find save messages chat
|
||||||
Integer savedIdxInActive = null;
|
Integer savedIdxInActive = null;
|
||||||
for (int i = 0; i < Session.activeChats.size(); i++) {
|
for (int i = 0; i < Session.activeChats.size(); i++) {
|
||||||
if (Session.activeChats.get(i).isSavedMessages()) {
|
if (Session.activeChats.get(i).isSavedMessages()) {
|
||||||
@@ -1248,23 +1290,19 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// مپ شمارهٔ نمایش → ایندکس واقعی در activeChats
|
|
||||||
Map<Integer, Integer> displayToActive = new HashMap<>();
|
Map<Integer, Integer> displayToActive = new HashMap<>();
|
||||||
|
|
||||||
int displayIndex = 1;
|
int displayIndex = 1;
|
||||||
|
|
||||||
// چاپ Saved (در صورت وجود) و ثبت در مپ
|
|
||||||
if (savedIdxInActive != null) {
|
if (savedIdxInActive != null) {
|
||||||
ChatEntry saved = Session.activeChats.get(savedIdxInActive);
|
ChatEntry saved = Session.activeChats.get(savedIdxInActive);
|
||||||
String last = (saved.getLastMessageTime() == null) ? "No messages yet" : saved.getLastMessageTime().toString();
|
String last = (saved.getLastMessageTime() == null) ? "No messages yet" : saved.getLastMessageTime().toString();
|
||||||
System.out.println(displayIndex + ". 💾 Saved Messages - Last: " + last);
|
System.out.println(displayIndex + ". 💾 Saved Messages - Last: " + last);
|
||||||
|
|
||||||
// نکتهٔ کلیدی: مپ کن تا مثل بقیه با openChat باز شود
|
|
||||||
displayToActive.put(displayIndex, savedIdxInActive);
|
displayToActive.put(displayIndex, savedIdxInActive);
|
||||||
displayIndex++;
|
displayIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// چاپ بقیهٔ چتها + ثبت مپ
|
|
||||||
for (int i = 0; i < Session.activeChats.size(); i++) {
|
for (int i = 0; i < Session.activeChats.size(); i++) {
|
||||||
if (savedIdxInActive != null && i == savedIdxInActive) continue;
|
if (savedIdxInActive != null && i == savedIdxInActive) continue;
|
||||||
|
|
||||||
@@ -1276,7 +1314,6 @@ public class ActionHandler {
|
|||||||
displayIndex++;
|
displayIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// انتخاب
|
|
||||||
System.out.print("Select a chat by number: ");
|
System.out.print("Select a chat by number: ");
|
||||||
int choice;
|
int choice;
|
||||||
try {
|
try {
|
||||||
@@ -1298,11 +1335,11 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChatEntry selected = Session.activeChats.get(activeIdx);
|
ChatEntry selected = Session.activeChats.get(activeIdx);
|
||||||
openChat(selected); // برای Saved هم همین مسیر اجرا میشود
|
openChat(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void showArchivedChats() {
|
public void showArchivedChats() {
|
||||||
if (Session.archivedChats == null || Session.archivedChats.isEmpty()) {
|
if (Session.archivedChats == null || Session.archivedChats.isEmpty()) {
|
||||||
System.out.println("📭 No archived chats.");
|
System.out.println("📭 No archived chats.");
|
||||||
return;
|
return;
|
||||||
@@ -1340,7 +1377,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void openChat(ChatEntry chat) {
|
public void openChat(ChatEntry chat) {
|
||||||
|
|
||||||
//for private chats only
|
//for private chats only
|
||||||
if (chat.getType().equalsIgnoreCase("private")) {
|
if (chat.getType().equalsIgnoreCase("private")) {
|
||||||
@@ -1573,7 +1610,7 @@ public class ActionHandler {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
private boolean showPrivateChatMenu(ChatEntry chat) {
|
public boolean showPrivateChatMenu(ChatEntry chat) {
|
||||||
|
|
||||||
if (forceExitChat) {
|
if (forceExitChat) {
|
||||||
forceExitChat = false;
|
forceExitChat = false;
|
||||||
@@ -1677,7 +1714,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private JSONObject getGroupPermissions(UUID groupId) {
|
public JSONObject getGroupPermissions(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_group_permissions");
|
req.put("action", "get_group_permissions");
|
||||||
req.put("group_id", groupId.toString());
|
req.put("group_id", groupId.toString());
|
||||||
@@ -1691,7 +1728,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private boolean showGroupChatMenu(ChatEntry chat) {
|
public boolean showGroupChatMenu(ChatEntry chat) {
|
||||||
if (forceExitChat) {
|
if (forceExitChat) {
|
||||||
forceExitChat = false;
|
forceExitChat = false;
|
||||||
System.out.println("🚪 Exiting chat due to real-time update.");
|
System.out.println("🚪 Exiting chat due to real-time update.");
|
||||||
@@ -1804,7 +1841,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private boolean showChannelChatMenu(ChatEntry chat) {
|
public boolean showChannelChatMenu(ChatEntry chat) {
|
||||||
if (forceExitChat) {
|
if (forceExitChat) {
|
||||||
forceExitChat = false;
|
forceExitChat = false;
|
||||||
System.out.println("🚪 Exiting chat due to real-time update.");
|
System.out.println("🚪 Exiting chat due to real-time update.");
|
||||||
@@ -1962,7 +1999,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void transferOwnershipAndLeave(UUID groupId) {
|
public void transferOwnershipAndLeave(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_group_admins");
|
req.put("action", "view_group_admins");
|
||||||
req.put("group_id", groupId.toString());
|
req.put("group_id", groupId.toString());
|
||||||
@@ -2042,7 +2079,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void removeMemberFromGroup(UUID groupId) {
|
public void removeMemberFromGroup(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_group_members");
|
req.put("action", "view_group_members");
|
||||||
req.put("group_id", groupId.toString());
|
req.put("group_id", groupId.toString());
|
||||||
@@ -2103,7 +2140,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void addAdminToChannel(UUID channelId) {
|
public void addAdminToChannel(UUID channelId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_channel_subscribers");
|
req.put("action", "view_channel_subscribers");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -2180,7 +2217,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void addAdminToGroup(UUID groupId) {
|
public void addAdminToGroup(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_group_members");
|
req.put("action", "view_group_members");
|
||||||
req.put("group_id", groupId.toString());
|
req.put("group_id", groupId.toString());
|
||||||
@@ -2242,7 +2279,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void viewGroupMembers(UUID groupId) {
|
public void viewGroupMembers(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_group_members");
|
req.put("action", "view_group_members");
|
||||||
req.put("group_id", groupId.toString());
|
req.put("group_id", groupId.toString());
|
||||||
@@ -2270,7 +2307,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void removeSubscriberFromChannel(UUID channelId) {
|
public void removeSubscriberFromChannel(UUID channelId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_channel_subscribers");
|
req.put("action", "view_channel_subscribers");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -2330,7 +2367,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void transferChannelOwnershipAndLeave(UUID channelId) {
|
public void transferChannelOwnershipAndLeave(UUID channelId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_channel_admins");
|
req.put("action", "view_channel_admins");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -2413,7 +2450,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void deleteChannel(UUID channelId) {
|
public void deleteChannel(UUID channelId) {
|
||||||
System.out.print("Are you sure you want to delete the channel? (yes/no): ");
|
System.out.print("Are you sure you want to delete the channel? (yes/no): ");
|
||||||
String confirm = scanner.nextLine().trim().toLowerCase();
|
String confirm = scanner.nextLine().trim().toLowerCase();
|
||||||
|
|
||||||
@@ -2436,7 +2473,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void deleteGroup(UUID groupId) {
|
public void deleteGroup(UUID groupId) {
|
||||||
System.out.print("Are you sure you want to delete the group? (yes/no): ");
|
System.out.print("Are you sure you want to delete the group? (yes/no): ");
|
||||||
String confirm = scanner.nextLine().trim().toLowerCase();
|
String confirm = scanner.nextLine().trim().toLowerCase();
|
||||||
|
|
||||||
@@ -2458,7 +2495,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteChat(UUID targetId, boolean both) {
|
public void deleteChat(UUID targetId, boolean both) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "delete_private_chat");
|
req.put("action", "delete_private_chat");
|
||||||
req.put("chat_id", targetId.toString());
|
req.put("chat_id", targetId.toString());
|
||||||
@@ -2475,7 +2512,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void toggleBlock(UUID userId) {
|
public void toggleBlock(UUID userId) {
|
||||||
|
|
||||||
|
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
@@ -2497,7 +2534,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void leaveChat(UUID id, String type) {
|
public void leaveChat(UUID id, String type) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "leave_chat");
|
req.put("action", "leave_chat");
|
||||||
req.put("user_id", Session.getUserUUID());
|
req.put("user_id", Session.getUserUUID());
|
||||||
@@ -2518,7 +2555,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void removeAdminFromGroup(UUID groupId) {
|
public void removeAdminFromGroup(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_group_admins");
|
req.put("action", "view_group_admins");
|
||||||
req.put("group_id", groupId.toString());
|
req.put("group_id", groupId.toString());
|
||||||
@@ -2578,7 +2615,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void removeAdminFromChannel(UUID channelId) {
|
public void removeAdminFromChannel(UUID channelId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_channel_admins");
|
req.put("action", "view_channel_admins");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -2642,7 +2679,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void addMemberToGroup(UUID groupId, UUID userId) {
|
public void addMemberToGroup(UUID groupId, UUID userId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "add_member_to_group");
|
req.put("action", "add_member_to_group");
|
||||||
req.put("group_id", groupId.toString());
|
req.put("group_id", groupId.toString());
|
||||||
@@ -2654,7 +2691,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSubscriberToChannel(UUID channelId, UUID targetUserId) {
|
public void addSubscriberToChannel(UUID channelId, UUID targetUserId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "add_subscriber_to_channel");
|
req.put("action", "add_subscriber_to_channel");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -2670,7 +2707,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GroupInfo(UUID groupId){
|
public void GroupInfo(UUID groupId){
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_chat_info");
|
req.put("action", "get_chat_info");
|
||||||
req.put("receiver_id", groupId.toString());
|
req.put("receiver_id", groupId.toString());
|
||||||
@@ -2699,7 +2736,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editGroupInfo(UUID groupId) {
|
public void editGroupInfo(UUID groupId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_chat_info");
|
req.put("action", "get_chat_info");
|
||||||
req.put("receiver_id", groupId.toString());
|
req.put("receiver_id", groupId.toString());
|
||||||
@@ -2775,7 +2812,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void viewChannelSubscribers(UUID channelId) {
|
public void viewChannelSubscribers(UUID channelId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_channel_subscribers");
|
req.put("action", "view_channel_subscribers");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -2797,7 +2834,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChannelInfo(UUID channelInternalId){
|
public void ChannelInfo(UUID channelInternalId){
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_chat_info");
|
req.put("action", "get_chat_info");
|
||||||
req.put("receiver_id", channelInternalId.toString());
|
req.put("receiver_id", channelInternalId.toString());
|
||||||
@@ -2826,7 +2863,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void editChannelInfo(UUID channelInternalId) {
|
public void editChannelInfo(UUID channelInternalId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_chat_info");
|
req.put("action", "get_chat_info");
|
||||||
req.put("receiver_id", channelInternalId.toString());
|
req.put("receiver_id", channelInternalId.toString());
|
||||||
@@ -2901,7 +2938,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private JSONObject getResponse() {
|
public JSONObject getResponse() {
|
||||||
try {
|
try {
|
||||||
return TelegramClient.responseQueue.take();
|
return TelegramClient.responseQueue.take();
|
||||||
|
|
||||||
@@ -2931,7 +2968,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void editAdminPermissions(UUID chatId, String chatType) {
|
public void editAdminPermissions(UUID chatId, String chatType) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", chatType.equals("group") ? "view_group_admins" : "view_channel_admins");
|
req.put("action", chatType.equals("group") ? "view_group_admins" : "view_channel_admins");
|
||||||
req.put(chatType + "_id", chatId.toString());
|
req.put(chatType + "_id", chatId.toString());
|
||||||
@@ -3028,7 +3065,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void viewChannelAdmins(UUID channelId) {
|
public void viewChannelAdmins(UUID channelId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_channel_admins");
|
req.put("action", "view_channel_admins");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -3053,7 +3090,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private JSONObject getChannelPermissions(UUID channelId) {
|
public JSONObject getChannelPermissions(UUID channelId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_channel_permissions");
|
req.put("action", "get_channel_permissions");
|
||||||
req.put("channel_id", channelId.toString());
|
req.put("channel_id", channelId.toString());
|
||||||
@@ -3353,7 +3390,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void startMenuRefresherThread() {
|
public void startMenuRefresherThread() {
|
||||||
Thread refresher = new Thread(() -> {
|
Thread refresher = new Thread(() -> {
|
||||||
System.out.println("🟡 Refresher tick. refreshCurrentChatMenu = " + Session.refreshCurrentChatMenu);
|
System.out.println("🟡 Refresher tick. refreshCurrentChatMenu = " + Session.refreshCurrentChatMenu);
|
||||||
|
|
||||||
@@ -3382,7 +3419,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void openForeignChat(ChatEntry chat) {
|
public void openForeignChat(ChatEntry chat) {
|
||||||
System.out.println("🔍 Opening " + chat.getType() + " chat (not in your chat list)");
|
System.out.println("🔍 Opening " + chat.getType() + " chat (not in your chat list)");
|
||||||
|
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
@@ -3446,7 +3483,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void viewUserProfile(UUID userId) {
|
public void viewUserProfile(UUID userId) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "view_profile");
|
req.put("action", "view_profile");
|
||||||
req.put("target_id", userId.toString());
|
req.put("target_id", userId.toString());
|
||||||
@@ -3471,7 +3508,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void viewGroupOrChannelInfo(UUID id, String type) {
|
public void viewGroupOrChannelInfo(UUID id, String type) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_chat_info");
|
req.put("action", "get_chat_info");
|
||||||
req.put("receiver_id", id.toString());
|
req.put("receiver_id", id.toString());
|
||||||
@@ -3496,7 +3533,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
public void toggleArchive(UUID chatId, String chatType) {
|
public void toggleArchive(UUID chatId, String chatType) {
|
||||||
// پیدا کردن چت از Session.chatList
|
|
||||||
Optional<ChatEntry> optional = Session.chatList.stream()
|
Optional<ChatEntry> optional = Session.chatList.stream()
|
||||||
.filter(c -> c.getId().equals(chatId))
|
.filter(c -> c.getId().equals(chatId))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
@@ -3522,7 +3559,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void archiveChat(UUID chatId, String chatType) {
|
public void archiveChat(UUID chatId, String chatType) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "archive_chat");
|
req.put("action", "archive_chat");
|
||||||
req.put("chat_id", chatId.toString());
|
req.put("chat_id", chatId.toString());
|
||||||
@@ -3531,7 +3568,7 @@ public class ActionHandler {
|
|||||||
if (res != null) System.out.println(res.getString("message"));
|
if (res != null) System.out.println(res.getString("message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unarchiveChat(UUID chatId, String chatType) {
|
public void unarchiveChat(UUID chatId, String chatType) {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "unarchive_chat");
|
req.put("action", "unarchive_chat");
|
||||||
req.put("chat_id", chatId.toString());
|
req.put("chat_id", chatId.toString());
|
||||||
@@ -3663,7 +3700,6 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 فقط ارسال پیام با chat_id و receiver_type
|
|
||||||
JSONObject messageJson = new JSONObject();
|
JSONObject messageJson = new JSONObject();
|
||||||
messageJson.put("action", "send_message");
|
messageJson.put("action", "send_message");
|
||||||
messageJson.put("receiver_type", receiverType);
|
messageJson.put("receiver_type", receiverType);
|
||||||
@@ -3683,7 +3719,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshContactList() {
|
public void refreshContactList() {
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_contact_list");
|
req.put("action", "get_contact_list");
|
||||||
req.put("user_id", Session.currentUser.getString("user_id"));
|
req.put("user_id", Session.currentUser.getString("user_id"));
|
||||||
@@ -3741,7 +3777,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void viewMessagesInChat(ChatEntry chat) {
|
public void viewMessagesInChat(ChatEntry chat) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int limit = 10;
|
int limit = 10;
|
||||||
|
|
||||||
@@ -3910,7 +3946,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editMessage(UUID messageId) {
|
public void editMessage(UUID messageId) {
|
||||||
System.out.print("📝 Enter new content: ");
|
System.out.print("📝 Enter new content: ");
|
||||||
String newContent = scanner.nextLine().trim();
|
String newContent = scanner.nextLine().trim();
|
||||||
|
|
||||||
@@ -3934,7 +3970,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void reactToMessage(UUID messageId) {
|
public void reactToMessage(UUID messageId) {
|
||||||
System.out.print("😊 Enter your reaction (e.g., ❤️, 👍, 😂): ");
|
System.out.print("😊 Enter your reaction (e.g., ❤️, 👍, 😂): ");
|
||||||
String reaction = scanner.nextLine().trim();
|
String reaction = scanner.nextLine().trim();
|
||||||
|
|
||||||
@@ -3957,7 +3993,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void forwardMessage(UUID originalMessageId) {
|
public void forwardMessage(UUID originalMessageId) {
|
||||||
System.out.println("\n📤 Select a chat to forward this message to:");
|
System.out.println("\n📤 Select a chat to forward this message to:");
|
||||||
|
|
||||||
List<ChatEntry> chatList = Session.chatList;
|
List<ChatEntry> chatList = Session.chatList;
|
||||||
@@ -4001,7 +4037,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void replyToMessage(UUID messageId) {
|
public void replyToMessage(UUID messageId) {
|
||||||
System.out.print("💬 Enter your reply: ");
|
System.out.print("💬 Enter your reply: ");
|
||||||
String content = scanner.nextLine().trim();
|
String content = scanner.nextLine().trim();
|
||||||
|
|
||||||
@@ -4030,7 +4066,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void deleteMessage(UUID messageId) {
|
public void deleteMessage(UUID messageId) {
|
||||||
System.out.println("\n🗑️ Delete Message Options:");
|
System.out.println("\n🗑️ Delete Message Options:");
|
||||||
System.out.println("1. Delete for yourself (one-sided)");
|
System.out.println("1. Delete for yourself (one-sided)");
|
||||||
System.out.println("2. Delete for everyone (global) [only if allowed]");
|
System.out.println("2. Delete for everyone (global) [only if allowed]");
|
||||||
@@ -4078,7 +4114,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSidebarMenu() {
|
public void showSidebarMenu() {
|
||||||
System.out.println("\n--- Sidebar Menu ---");
|
System.out.println("\n--- Sidebar Menu ---");
|
||||||
System.out.println("1. View Profile");
|
System.out.println("1. View Profile");
|
||||||
System.out.println("2. New Group");
|
System.out.println("2. New Group");
|
||||||
|
|||||||
@@ -1,3 +1,129 @@
|
|||||||
|
//package org.to.telegramfinalproject.Client;
|
||||||
|
//
|
||||||
|
//import org.json.JSONObject;
|
||||||
|
//
|
||||||
|
//import java.io.BufferedReader;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStreamReader;
|
||||||
|
//import java.io.PrintWriter;
|
||||||
|
//import java.net.Socket;
|
||||||
|
//import java.util.Map;
|
||||||
|
//import java.util.Scanner;
|
||||||
|
//import java.util.UUID;
|
||||||
|
//import java.util.concurrent.BlockingQueue;
|
||||||
|
//import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
//import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
//
|
||||||
|
//public class TelegramClient {
|
||||||
|
// private static final String SERVER_HOST = "localhost";
|
||||||
|
// private static final int SERVER_PORT = 8000;
|
||||||
|
// private static Socket socket;
|
||||||
|
// private BufferedReader in;
|
||||||
|
// private PrintWriter out;
|
||||||
|
// private final Scanner scanner;
|
||||||
|
// private ActionHandler handler;
|
||||||
|
// public static BlockingQueue<JSONObject> responseQueue = new LinkedBlockingQueue<>();
|
||||||
|
// public static UUID loggedInUserId = null;
|
||||||
|
// public static final Map<String, BlockingQueue<JSONObject>> pendingResponses = new ConcurrentHashMap<>();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private static TelegramClient instance;
|
||||||
|
//
|
||||||
|
// public TelegramClient() {
|
||||||
|
// this.scanner = new Scanner(System.in);
|
||||||
|
// instance = this;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static TelegramClient getInstance() {
|
||||||
|
// return instance;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void start() {
|
||||||
|
// try {
|
||||||
|
// socket = new Socket(SERVER_HOST, SERVER_PORT);
|
||||||
|
// in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
// out = new PrintWriter(socket.getOutputStream(), true);
|
||||||
|
// System.out.println("✅ Connected to Telegram Server");
|
||||||
|
// handler = new ActionHandler(out, in, scanner);
|
||||||
|
//
|
||||||
|
// Thread listenerThread = new Thread(new IncomingMessageListener(in));
|
||||||
|
// listenerThread.setDaemon(true);
|
||||||
|
// listenerThread.start();
|
||||||
|
//
|
||||||
|
// showMainMenu();
|
||||||
|
//
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// System.err.println("❌ Error connecting to server: " + e.getMessage());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private void showMainMenu() throws IOException {
|
||||||
|
// while (true) {
|
||||||
|
// System.out.println("Main Menu:");
|
||||||
|
// System.out.println("1. Register");
|
||||||
|
// System.out.println("2. Login");
|
||||||
|
// System.out.println("3. Exit");
|
||||||
|
// System.out.print("Choose an option: ");
|
||||||
|
// String choice = scanner.nextLine();
|
||||||
|
//
|
||||||
|
// switch (choice) {
|
||||||
|
// case "1" -> handler.register();
|
||||||
|
// case "2" -> {
|
||||||
|
// handler.loginHandler();
|
||||||
|
// if (Session.currentUser != null) {
|
||||||
|
// System.out.println("✅ Login successful.");
|
||||||
|
// new Thread(new ActionHandler.ChatStateMonitor(out)).start();
|
||||||
|
//// new Thread(new ActionHandler.CurrentChatMenuRefresher(this.handler)).start();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// UUID internalId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||||||
|
// loggedInUserId = internalId;
|
||||||
|
//
|
||||||
|
// handler.userMenu(internalId);
|
||||||
|
// } else {
|
||||||
|
// System.out.println("❌ Login failed.");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// case "3" -> {
|
||||||
|
// System.out.println("Exiting...");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// default -> System.out.println("Invalid choice.");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static void send(JSONObject req) {
|
||||||
|
// try {
|
||||||
|
// responseQueue.clear(); // optional: clear old responses
|
||||||
|
// getInstance().out.println(req.toString());
|
||||||
|
// System.out.println("📤 [SEND] " + req.toString(2));
|
||||||
|
//
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// System.err.println("❌ Error sending request: " + e.getMessage());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// public static Socket getSocket() {
|
||||||
|
// return socket;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static void main(String[] args) {
|
||||||
|
// new TelegramClient().start();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public PrintWriter getOut() {
|
||||||
|
// return out;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
package org.to.telegramfinalproject.Client;
|
package org.to.telegramfinalproject.Client;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
@@ -7,6 +133,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -17,46 +144,79 @@ import java.util.concurrent.LinkedBlockingQueue;
|
|||||||
public class TelegramClient {
|
public class TelegramClient {
|
||||||
private static final String SERVER_HOST = "localhost";
|
private static final String SERVER_HOST = "localhost";
|
||||||
private static final int SERVER_PORT = 8000;
|
private static final int SERVER_PORT = 8000;
|
||||||
|
|
||||||
|
private static TelegramClient instance;
|
||||||
|
|
||||||
private static Socket socket;
|
private static Socket socket;
|
||||||
private BufferedReader in;
|
private BufferedReader in;
|
||||||
private PrintWriter out;
|
private PrintWriter out;
|
||||||
|
|
||||||
|
|
||||||
private final Scanner scanner;
|
private final Scanner scanner;
|
||||||
private ActionHandler handler;
|
private ActionHandler handler;
|
||||||
public static BlockingQueue<JSONObject> responseQueue = new LinkedBlockingQueue<>();
|
|
||||||
public static UUID loggedInUserId = null;
|
public static final BlockingQueue<JSONObject> responseQueue = new LinkedBlockingQueue<>();
|
||||||
public static final Map<String, BlockingQueue<JSONObject>> pendingResponses = new ConcurrentHashMap<>();
|
public static final Map<String, BlockingQueue<JSONObject>> pendingResponses = new ConcurrentHashMap<>();
|
||||||
|
public static UUID loggedInUserId = null;
|
||||||
|
|
||||||
|
private volatile boolean listenerStarted = false;
|
||||||
private static TelegramClient instance;
|
|
||||||
|
|
||||||
public TelegramClient() {
|
public TelegramClient() {
|
||||||
this.scanner = new Scanner(System.in);
|
this.scanner = new Scanner(System.in);
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TelegramClient getInstance() {
|
public static synchronized TelegramClient getInstance() {
|
||||||
|
if (instance == null) instance = new TelegramClient();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void startConsole() {
|
||||||
try {
|
try {
|
||||||
socket = new Socket(SERVER_HOST, SERVER_PORT);
|
connectIfNeeded();
|
||||||
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
initHandlerIfNeeded();
|
||||||
out = new PrintWriter(socket.getOutputStream(), true);
|
startListenerOnce();
|
||||||
System.out.println("✅ Connected to Telegram Server");
|
|
||||||
handler = new ActionHandler(out, in, scanner);
|
|
||||||
|
|
||||||
Thread listenerThread = new Thread(new IncomingMessageListener(in));
|
|
||||||
listenerThread.setDaemon(true);
|
|
||||||
listenerThread.start();
|
|
||||||
|
|
||||||
showMainMenu();
|
showMainMenu();
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println("❌ Error connecting to server: " + e.getMessage());
|
System.err.println("❌ Error connecting to server: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void start() { startConsole(); }
|
||||||
|
|
||||||
|
//UI only
|
||||||
|
public static synchronized TelegramClient getOrInitForUI() throws IOException {
|
||||||
|
TelegramClient cli = getInstance();
|
||||||
|
cli.connectIfNeeded();
|
||||||
|
cli.initHandlerIfNeeded();
|
||||||
|
cli.startListenerOnce();
|
||||||
|
return cli;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void connectIfNeeded() throws IOException {
|
||||||
|
if (socket != null && socket.isConnected() && !socket.isClosed()) return;
|
||||||
|
|
||||||
|
socket = new Socket(SERVER_HOST, SERVER_PORT);
|
||||||
|
in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
|
||||||
|
out = new PrintWriter(socket.getOutputStream(), true);
|
||||||
|
System.out.println("✅ Connected to Telegram Server");
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void initHandlerIfNeeded() {
|
||||||
|
if (handler == null) {
|
||||||
|
handler = new ActionHandler(out, in, scanner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startListenerOnce() {
|
||||||
|
if (listenerStarted) return;
|
||||||
|
listenerStarted = true;
|
||||||
|
Thread listenerThread = new Thread(new IncomingMessageListener(in), "socket-listener");
|
||||||
|
listenerThread.setDaemon(true);
|
||||||
|
listenerThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
//console
|
||||||
private void showMainMenu() throws IOException {
|
private void showMainMenu() throws IOException {
|
||||||
while (true) {
|
while (true) {
|
||||||
System.out.println("Main Menu:");
|
System.out.println("Main Menu:");
|
||||||
@@ -73,8 +233,6 @@ public class TelegramClient {
|
|||||||
if (Session.currentUser != null) {
|
if (Session.currentUser != null) {
|
||||||
System.out.println("✅ Login successful.");
|
System.out.println("✅ Login successful.");
|
||||||
new Thread(new ActionHandler.ChatStateMonitor(out)).start();
|
new Thread(new ActionHandler.ChatStateMonitor(out)).start();
|
||||||
// new Thread(new ActionHandler.CurrentChatMenuRefresher(this.handler)).start();
|
|
||||||
|
|
||||||
|
|
||||||
UUID internalId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
UUID internalId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||||||
loggedInUserId = internalId;
|
loggedInUserId = internalId;
|
||||||
@@ -95,28 +253,21 @@ public class TelegramClient {
|
|||||||
|
|
||||||
public static void send(JSONObject req) {
|
public static void send(JSONObject req) {
|
||||||
try {
|
try {
|
||||||
responseQueue.clear(); // optional: clear old responses
|
responseQueue.clear();
|
||||||
getInstance().out.println(req.toString());
|
getInstance().out.println(req.toString());
|
||||||
System.out.println("📤 [SEND] " + req.toString(2));
|
System.out.println("📤 [SEND] " + req.toString(2));
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("❌ Error sending request: " + e.getMessage());
|
System.err.println("❌ Error sending request: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferedReader getIn() { return in; }
|
||||||
|
public PrintWriter getOut() { return out; }
|
||||||
|
public ActionHandler getHandler() { return handler; }
|
||||||
public static Socket getSocket() {
|
public static Socket getSocket() { return socket; }
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
new TelegramClient().start();
|
new TelegramClient().startConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrintWriter getOut() {
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1057,4 +1057,73 @@ public class MessageDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Message getLastMessage(UUID targetId, String type) {
|
||||||
|
final String sql =
|
||||||
|
"SELECT * FROM messages " +
|
||||||
|
"WHERE receiver_type = ? AND receiver_id = ? " +
|
||||||
|
"ORDER BY send_at DESC LIMIT 1";
|
||||||
|
|
||||||
|
try (Connection conn = ConnectionDb.connect();
|
||||||
|
PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
ps.setString(1, type.toLowerCase()); // "private" | "group" | "channel"
|
||||||
|
ps.setObject(2, targetId);
|
||||||
|
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
return rs.next() ? mapRow(rs) : null;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getUnreadCount(UUID me, UUID targetId, String type) {
|
||||||
|
final String sql =
|
||||||
|
"SELECT COUNT(*) FROM messages " +
|
||||||
|
"WHERE receiver_type = ? AND receiver_id = ? " +
|
||||||
|
"AND sender_id <> ? " +
|
||||||
|
"AND (status IS NULL OR status <> 'SEEN')";
|
||||||
|
|
||||||
|
try (Connection conn = ConnectionDb.connect();
|
||||||
|
PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||||
|
|
||||||
|
ps.setString(1, type.toLowerCase());
|
||||||
|
ps.setObject(2, targetId);
|
||||||
|
ps.setObject(3, me);
|
||||||
|
|
||||||
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
|
return rs.next() ? rs.getInt(1) : 0;
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Message mapRow(ResultSet rs) throws SQLException {
|
||||||
|
Message m = new Message();
|
||||||
|
m.setMessage_id((UUID) rs.getObject("message_id"));
|
||||||
|
m.setSender_id((UUID) rs.getObject("sender_id"));
|
||||||
|
m.setReceiver_id((UUID) rs.getObject("receiver_id"));
|
||||||
|
m.setReceiver_type(rs.getString("receiver_type"));
|
||||||
|
if ("private".equalsIgnoreCase(m.getReceiver_type())) {
|
||||||
|
m.setReceiver_id(m.getReceiver_id());
|
||||||
|
} else {
|
||||||
|
m.setReceiver_id(null);
|
||||||
|
}
|
||||||
|
m.setMessage_type(rs.getString("message_type"));
|
||||||
|
m.setContent(rs.getString("content"));
|
||||||
|
Timestamp ts = rs.getTimestamp("send_at");
|
||||||
|
if (ts != null) m.setSend_at(ts.toLocalDateTime());
|
||||||
|
m.setIs_edited(rs.getBoolean("is_edited"));
|
||||||
|
m.setStatus(rs.getString("status"));
|
||||||
|
Object rtid = rs.getObject("reply_to_id");
|
||||||
|
m.setReply_to_id(rtid == null ? null : (UUID) rtid);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,17 @@ public class ChatEntry {
|
|||||||
private JSONObject permissions;
|
private JSONObject permissions;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// private UUID otherUserId;
|
||||||
|
private int unreadCount;
|
||||||
|
private String lastMessagePreview;
|
||||||
|
private String lastMessageType; // TEXT / IMAGE / AUDIO / VIDEO / ...
|
||||||
|
private UUID lastMessageSenderId;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ChatEntry(UUID internalId, String displayId, String name, String imageUrl, String type, LocalDateTime lastMessageTime) {
|
public ChatEntry(UUID internalId, String displayId, String name, String imageUrl, String type, LocalDateTime lastMessageTime) {
|
||||||
this.internalId = internalId;
|
this.internalId = internalId;
|
||||||
this.displayId = displayId;
|
this.displayId = displayId;
|
||||||
@@ -149,4 +160,17 @@ public class ChatEntry {
|
|||||||
public void setSavedMessages(boolean savedMessages) {
|
public void setSavedMessages(boolean savedMessages) {
|
||||||
this.savedMessages = savedMessages;
|
this.savedMessages = savedMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int getUnreadCount() { return unreadCount; }
|
||||||
|
public void setUnreadCount(int unreadCount) { this.unreadCount = unreadCount; }
|
||||||
|
|
||||||
|
public String getLastMessagePreview() { return lastMessagePreview; }
|
||||||
|
public void setLastMessagePreview(String lastMessagePreview) { this.lastMessagePreview = lastMessagePreview; }
|
||||||
|
|
||||||
|
public String getLastMessageType() { return lastMessageType; }
|
||||||
|
public void setLastMessageType(String lastMessageType) { this.lastMessageType = lastMessageType; }
|
||||||
|
|
||||||
|
public UUID getLastMessageSenderId() { return lastMessageSenderId; }
|
||||||
|
public void setLastMessageSenderId(UUID lastMessageSenderId) { this.lastMessageSenderId = lastMessageSenderId; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,6 +186,12 @@ public class JsonUtil {
|
|||||||
obj.put("is_owner", entry.isOwner());
|
obj.put("is_owner", entry.isOwner());
|
||||||
obj.put("is_admin", entry.isAdmin());
|
obj.put("is_admin", entry.isAdmin());
|
||||||
obj.put("is_saved_messages", entry.isSavedMessages());
|
obj.put("is_saved_messages", entry.isSavedMessages());
|
||||||
|
obj.put("unread_count", entry.getUnreadCount());
|
||||||
|
obj.put("last_message_preview", entry.getLastMessagePreview());
|
||||||
|
obj.put("last_message_type", entry.getLastMessageType());
|
||||||
|
obj.put("last_message_sender_id",
|
||||||
|
entry.getLastMessageSenderId() != null ? entry.getLastMessageSenderId().toString() : JSONObject.NULL);
|
||||||
|
|
||||||
|
|
||||||
jsonArray.put(obj);
|
jsonArray.put(obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ public class Message {
|
|||||||
this.edited_at = editedAt;
|
this.edited_at = editedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Message() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ✅ Getters & Setters
|
// ✅ Getters & Setters
|
||||||
@@ -203,4 +206,6 @@ public class Message {
|
|||||||
return is_deleted_globally;
|
return is_deleted_globally;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void receiver_id(UUID receiverId) {this.receiver_id = receiverId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,78 +125,6 @@ public class ClientHandler implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// for (Contact contact : contacts) {
|
|
||||||
// User target = userDatabase.findByInternalUUID(contact.getContact_id());
|
|
||||||
// if (target == null) continue;
|
|
||||||
// LocalDateTime last = MessageDatabase.getLastMessageTimeBetween(user.getInternal_uuid(), target.getInternal_uuid(), "private");
|
|
||||||
//
|
|
||||||
//// chatList.add(new ChatEntry(
|
|
||||||
//// target.getInternal_uuid(), // internal UUID
|
|
||||||
//// target.getUser_id(), // public display ID
|
|
||||||
//// target.getProfile_name(),
|
|
||||||
//// target.getImage_url(),
|
|
||||||
//// "private",
|
|
||||||
//// last,
|
|
||||||
//// false,
|
|
||||||
//// false
|
|
||||||
//// ));
|
|
||||||
//
|
|
||||||
// UUID targetId = target.getInternal_uuid();
|
|
||||||
//
|
|
||||||
// ChatEntry entry = new ChatEntry(
|
|
||||||
// targetId,
|
|
||||||
// target.getUser_id(),
|
|
||||||
// target.getProfile_name(),
|
|
||||||
// target.getImage_url(),
|
|
||||||
// "private",
|
|
||||||
// last,
|
|
||||||
// false,
|
|
||||||
// false
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// List<PrivateChat> privateChats = PrivateChatDatabase.findChatsOfUser(currentUser.getInternal_uuid());
|
|
||||||
// for (PrivateChat chat : privateChats) {
|
|
||||||
// UUID otherId = chat.getUser1_id().equals(currentUser.getInternal_uuid()) ?
|
|
||||||
// chat.getUser2_id() : chat.getUser1_id();
|
|
||||||
//
|
|
||||||
// User otherUser = userDatabase.findByInternalUUID(otherId);
|
|
||||||
// if (otherUser == null) continue;
|
|
||||||
//
|
|
||||||
// LocalDateTime lastMessageTime = MessageDatabase.getLastMessageTime(chat.getChat_id(), "private");
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// ChatEntry entry = new ChatEntry(
|
|
||||||
// chat.getChat_id(),
|
|
||||||
// otherUser.getUser_id(),
|
|
||||||
// otherUser.getProfile_name(),
|
|
||||||
// otherUser.getImage_url(),
|
|
||||||
// "private",
|
|
||||||
// lastMessageTime,
|
|
||||||
// false,
|
|
||||||
// false
|
|
||||||
// );
|
|
||||||
// entry.setOtherUserId(otherId);
|
|
||||||
//
|
|
||||||
// if (currentUser.getInternal_uuid() == otherId) {
|
|
||||||
// entry.setSavedMessages(true);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (archivedChatIds.contains(chat.getChat_id())) {
|
|
||||||
// archivedChatList.add(entry);
|
|
||||||
// chatList.add(entry);
|
|
||||||
// } else {
|
|
||||||
// activeChatList.add(entry);
|
|
||||||
// chatList.add(entry);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
List<PrivateChat> privateChats = PrivateChatDatabase.findChatsOfUser(currentUser.getInternal_uuid());
|
List<PrivateChat> privateChats = PrivateChatDatabase.findChatsOfUser(currentUser.getInternal_uuid());
|
||||||
|
|
||||||
ChatEntry savedEntry = null;
|
ChatEntry savedEntry = null;
|
||||||
@@ -229,10 +157,12 @@ public class ClientHandler implements Runnable {
|
|||||||
);
|
);
|
||||||
entry.setOtherUserId(otherId);
|
entry.setOtherUserId(otherId);
|
||||||
if (isSelf) {
|
if (isSelf) {
|
||||||
entry.setSavedMessages(true); // فلگ مهم
|
entry.setSavedMessages(true);
|
||||||
savedEntry = entry; // برای بردن به اول لیست
|
savedEntry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enrichChatEntry(entry, user.getInternal_uuid());
|
||||||
|
|
||||||
if (!isSelf && archivedChatIds.contains(chat.getChat_id())) {
|
if (!isSelf && archivedChatIds.contains(chat.getChat_id())) {
|
||||||
archivedChatList.add(entry);
|
archivedChatList.add(entry);
|
||||||
} else {
|
} else {
|
||||||
@@ -270,6 +200,7 @@ public class ClientHandler implements Runnable {
|
|||||||
isOwner,
|
isOwner,
|
||||||
isAdmin
|
isAdmin
|
||||||
);
|
);
|
||||||
|
enrichChatEntry(entry, user.getInternal_uuid());
|
||||||
|
|
||||||
if (archivedChatIds.contains(group.getInternal_uuid())) {
|
if (archivedChatIds.contains(group.getInternal_uuid())) {
|
||||||
archivedChatList.add(entry);
|
archivedChatList.add(entry);
|
||||||
@@ -309,6 +240,8 @@ public class ClientHandler implements Runnable {
|
|||||||
isAdmin
|
isAdmin
|
||||||
);
|
);
|
||||||
|
|
||||||
|
enrichChatEntry(entry, user.getInternal_uuid());
|
||||||
|
|
||||||
if (archivedChatIds.contains(channel.getInternal_uuid())) {
|
if (archivedChatIds.contains(channel.getInternal_uuid())) {
|
||||||
archivedChatList.add(entry);
|
archivedChatList.add(entry);
|
||||||
chatList.add(entry);
|
chatList.add(entry);
|
||||||
@@ -774,9 +707,9 @@ public class ClientHandler implements Runnable {
|
|||||||
|
|
||||||
ChatEntry entry = new ChatEntry(
|
ChatEntry entry = new ChatEntry(
|
||||||
chat.getChat_id(),
|
chat.getChat_id(),
|
||||||
otherUser.getUser_id(),
|
isSavedMessages ? "Saved Messages" : otherUser.getUser_id(),
|
||||||
otherUser.getProfile_name(),
|
isSavedMessages ? "Saved Messages" : otherUser.getProfile_name(),
|
||||||
otherUser.getImage_url(),
|
isSavedMessages ? null : otherUser.getImage_url(),
|
||||||
"private",
|
"private",
|
||||||
lastMessageTime,
|
lastMessageTime,
|
||||||
false,
|
false,
|
||||||
@@ -784,18 +717,20 @@ public class ClientHandler implements Runnable {
|
|||||||
);
|
);
|
||||||
entry.setOtherUserId(otherId);
|
entry.setOtherUserId(otherId);
|
||||||
|
|
||||||
|
|
||||||
// Mark it as saved messages if it's the special self-chat
|
// Mark it as saved messages if it's the special self-chat
|
||||||
if (isSavedMessages) {
|
if (isSavedMessages) {
|
||||||
entry.setSavedMessages(true);
|
entry.setSavedMessages(true);
|
||||||
}
|
}
|
||||||
|
enrichChatEntry(entry, currentUser.getInternal_uuid());
|
||||||
|
|
||||||
if (archivedChatIds.contains(chat.getChat_id())) {
|
if (archivedChatIds.contains(chat.getChat_id()) && !isSavedMessages) {
|
||||||
archivedChatList.add(entry);
|
archivedChatList.add(entry);
|
||||||
chatList.add(entry);
|
|
||||||
} else {
|
} else {
|
||||||
activeChatList.add(entry);
|
activeChatList.add(entry);
|
||||||
chatList.add(entry);
|
|
||||||
}
|
}
|
||||||
|
chatList.add(entry);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -826,6 +761,8 @@ public class ClientHandler implements Runnable {
|
|||||||
isAdmin
|
isAdmin
|
||||||
);
|
);
|
||||||
|
|
||||||
|
enrichChatEntry(entry, currentUser.getInternal_uuid());
|
||||||
|
|
||||||
if (archivedChatIds.contains(group.getInternal_uuid())) {
|
if (archivedChatIds.contains(group.getInternal_uuid())) {
|
||||||
archivedChatList.add(entry);
|
archivedChatList.add(entry);
|
||||||
chatList.add(entry);
|
chatList.add(entry);
|
||||||
@@ -863,6 +800,7 @@ public class ClientHandler implements Runnable {
|
|||||||
isOwner,
|
isOwner,
|
||||||
isAdmin
|
isAdmin
|
||||||
);
|
);
|
||||||
|
enrichChatEntry(entry, currentUser.getInternal_uuid());
|
||||||
|
|
||||||
if (archivedChatIds.contains(channel.getInternal_uuid())) {
|
if (archivedChatIds.contains(channel.getInternal_uuid())) {
|
||||||
archivedChatList.add(entry);
|
archivedChatList.add(entry);
|
||||||
@@ -2855,4 +2793,38 @@ public class ClientHandler implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void enrichChatEntry(ChatEntry e, UUID me) {
|
||||||
|
// آخرین پیام
|
||||||
|
Message last = MessageDatabase.getLastMessage(e.getId(), e.getType());
|
||||||
|
if (last != null) {
|
||||||
|
e.setLastMessageTime(String.valueOf(last.getSend_at()));
|
||||||
|
e.setLastMessagePreview(buildPreview(last));
|
||||||
|
e.setLastMessageType(last.getMessage_type());
|
||||||
|
e.setLastMessageSenderId(last.getSender_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
// تعداد نخواندهها
|
||||||
|
int unread = MessageDatabase.getUnreadCount(me, e.getId(), e.getType());
|
||||||
|
e.setUnreadCount(unread);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildPreview(Message m) {
|
||||||
|
String t = m.getMessage_type();
|
||||||
|
if ("TEXT".equalsIgnoreCase(t)) {
|
||||||
|
String c = m.getContent();
|
||||||
|
if (c == null) return "";
|
||||||
|
// پیشنمایش کوتاه
|
||||||
|
return c.length() > 120 ? c.substring(0, 120) + "…" : c;
|
||||||
|
}
|
||||||
|
switch (t) {
|
||||||
|
case "IMAGE": return "[Image]";
|
||||||
|
case "AUDIO": return "[Audio]";
|
||||||
|
case "VIDEO": return "[Video]";
|
||||||
|
case "FILE": return "[File]";
|
||||||
|
default: return "[Message]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// org.to.telegramfinalproject.UI.AppRouter
|
||||||
|
package org.to.telegramfinalproject.UI;
|
||||||
|
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
public final class AppRouter {
|
||||||
|
private static Stage stage;
|
||||||
|
private static Scene scene;
|
||||||
|
|
||||||
|
private AppRouter() {}
|
||||||
|
|
||||||
|
public static void init(Stage st, Scene sc) {
|
||||||
|
stage = st;
|
||||||
|
scene = sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showIntro() { setRoot("/org/to/telegramfinalproject/Fxml/intro.fxml"); }
|
||||||
|
public static void showLogin() { setRoot("/org/to/telegramfinalproject/Fxml/login_view.fxml"); }
|
||||||
|
public static void showRegister(){ setRoot("/org/to/telegramfinalproject/Fxml/register_view.fxml"); }
|
||||||
|
public static void showMain() { setRoot("/org/to/telegramfinalproject/Fxml/main.fxml"); }
|
||||||
|
|
||||||
|
private static void setRoot(String fxmlPath) {
|
||||||
|
try {
|
||||||
|
System.out.println("Router: setRoot -> " + fxmlPath);
|
||||||
|
FXMLLoader fx = new FXMLLoader(AppRouter.class.getResource(fxmlPath));
|
||||||
|
Parent root = fx.load();
|
||||||
|
if (scene != null) scene.setRoot(root);
|
||||||
|
else if (stage != null) stage.setScene(new Scene(root, 1480, 820));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -23,4 +23,11 @@ public class ChatItemController {
|
|||||||
unreadCount.setVisible(unread > 0);
|
unreadCount.setVisible(unread > 0);
|
||||||
unreadCount.setText(String.valueOf(unread));
|
unreadCount.setText(String.valueOf(unread));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUnread(int unread) {
|
||||||
|
boolean show = unread > 0;
|
||||||
|
unreadCount.setVisible(show);
|
||||||
|
unreadCount.setManaged(show);
|
||||||
|
if (show) unreadCount.setText(String.valueOf(unread));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,38 +10,62 @@ import javafx.scene.layout.Region;
|
|||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.shape.Circle;
|
import javafx.scene.shape.Circle;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.to.telegramfinalproject.Client.ActionHandler;
|
||||||
|
import org.to.telegramfinalproject.Models.ChatEntry;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ChatPageController {
|
public class ChatPageController {
|
||||||
|
|
||||||
// ===== messages area =====
|
// ===== messages area =====
|
||||||
@FXML private VBox messageContainer;
|
@FXML
|
||||||
@FXML private ScrollPane messageScrollPane;
|
private VBox messageContainer;
|
||||||
|
@FXML
|
||||||
|
private ScrollPane messageScrollPane;
|
||||||
|
|
||||||
// ===== input area =====
|
// ===== input area =====
|
||||||
@FXML private TextArea messageInput;
|
@FXML
|
||||||
@FXML private Button sendButton;
|
private TextArea messageInput;
|
||||||
|
@FXML
|
||||||
|
private Button sendButton;
|
||||||
|
|
||||||
@FXML private Button attachmentButton;
|
@FXML
|
||||||
@FXML private ImageView attachmentIcon; // <ImageView> inside the attachment button
|
private Button attachmentButton;
|
||||||
|
@FXML
|
||||||
|
private ImageView attachmentIcon; // <ImageView> inside the attachment button
|
||||||
|
|
||||||
// ===== header =====
|
// ===== header =====
|
||||||
@FXML private ImageView userAvatar; // 36x36 in the FXML
|
@FXML
|
||||||
@FXML private Label chatTitle; // contact/group title
|
private ImageView userAvatar; // 36x36 in the FXML
|
||||||
@FXML private Label chatStatus; // last seen / online
|
@FXML
|
||||||
|
private Label chatTitle; // contact/group title
|
||||||
|
@FXML
|
||||||
|
private Label chatStatus; // last seen / online
|
||||||
|
|
||||||
@FXML private Button searchInChatButton; // magnifier button
|
@FXML
|
||||||
@FXML private ImageView searchIcon;
|
private Button searchInChatButton; // magnifier button
|
||||||
|
@FXML
|
||||||
|
private ImageView searchIcon;
|
||||||
|
|
||||||
@FXML private Button moreButton; // 3-dots button
|
@FXML
|
||||||
@FXML private ImageView moreIcon;
|
private Button moreButton; // 3-dots button
|
||||||
@FXML private ContextMenu moreMenu;
|
@FXML
|
||||||
@FXML private MenuItem viewProfileItem;
|
private ImageView moreIcon;
|
||||||
@FXML private MenuItem deleteChatItem;
|
@FXML
|
||||||
|
private ContextMenu moreMenu;
|
||||||
|
@FXML
|
||||||
|
private MenuItem viewProfileItem;
|
||||||
|
@FXML
|
||||||
|
private MenuItem deleteChatItem;
|
||||||
|
|
||||||
// ===== send icon =====
|
// ===== send icon =====
|
||||||
@FXML private ImageView sendIcon;
|
@FXML
|
||||||
|
private ImageView sendIcon;
|
||||||
|
|
||||||
// ===== state =====
|
// ===== state =====
|
||||||
private String chatName;
|
private String chatName;
|
||||||
@@ -49,9 +73,26 @@ public class ChatPageController {
|
|||||||
|
|
||||||
// Where your icons live
|
// Where your icons live
|
||||||
private static final String ICON_BASE = "/org/to/telegramfinalproject/Icons/";
|
private static final String ICON_BASE = "/org/to/telegramfinalproject/Icons/";
|
||||||
|
private ChatEntry currentChat;
|
||||||
|
private UUID me;
|
||||||
|
|
||||||
|
private void initCurrentUserId() {
|
||||||
|
try {
|
||||||
|
// از سشنی که سمت کلاینت داری:
|
||||||
|
String meStr = org.to.telegramfinalproject.Client.Session
|
||||||
|
.currentUser.getString("internal_uuid");
|
||||||
|
me = UUID.fromString(meStr);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
me = null; // اگر به هر دلیلی نبود، خروجیها رو ورودی فرض نکن
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
|
||||||
|
initCurrentUserId();
|
||||||
|
|
||||||
// Send button
|
// Send button
|
||||||
if (sendButton != null) {
|
if (sendButton != null) {
|
||||||
sendButton.setOnAction(e -> sendMessage());
|
sendButton.setOnAction(e -> sendMessage());
|
||||||
@@ -162,7 +203,9 @@ public class ChatPageController {
|
|||||||
MainController.getInstance().showSearchPanel();
|
MainController.getInstance().showSearchPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called by main controller when opening a chat. */
|
/**
|
||||||
|
* Called by main controller when opening a chat.
|
||||||
|
*/
|
||||||
public void setChat(String chatName, String avatarPath) {
|
public void setChat(String chatName, String avatarPath) {
|
||||||
this.chatName = chatName;
|
this.chatName = chatName;
|
||||||
|
|
||||||
@@ -210,14 +253,16 @@ public class ChatPageController {
|
|||||||
|
|
||||||
// ----- UI helpers -----
|
// ----- UI helpers -----
|
||||||
|
|
||||||
/** Add a normal message bubble (very simple for now). */
|
/**
|
||||||
|
* Add a normal message bubble (very simple for now).
|
||||||
|
*/
|
||||||
public void addMessage(String sender, String content) {
|
public void addMessage(String sender, String content) {
|
||||||
Label msg = new Label(sender + ": " + content);
|
Label msg = new Label(sender + ": " + content);
|
||||||
msg.setWrapText(true);
|
msg.setWrapText(true);
|
||||||
|
|
||||||
boolean dark = themeManager.isDarkMode();
|
boolean dark = themeManager.isDarkMode();
|
||||||
String bubbleColor = dark ? "#20405a" : "#4fa8f0";
|
String bubbleColor = dark ? "#20405a" : "#4fa8f0";
|
||||||
String textColor = dark ? "#e8f1f8" : "#0f141a";
|
String textColor = dark ? "#e8f1f8" : "#0f141a";
|
||||||
msg.setStyle(
|
msg.setStyle(
|
||||||
"-fx-background-color: " + bubbleColor + ";" +
|
"-fx-background-color: " + bubbleColor + ";" +
|
||||||
"-fx-text-fill: " + textColor + ";" +
|
"-fx-text-fill: " + textColor + ";" +
|
||||||
@@ -235,7 +280,9 @@ public class ChatPageController {
|
|||||||
messageScrollPane.setVvalue(1.0);
|
messageScrollPane.setVvalue(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update all header/footer icons according to current theme. */
|
/**
|
||||||
|
* Update all header/footer icons according to current theme.
|
||||||
|
*/
|
||||||
private void syncIconsWithTheme() {
|
private void syncIconsWithTheme() {
|
||||||
boolean dark = themeManager.isDarkMode();
|
boolean dark = themeManager.isDarkMode();
|
||||||
// We use “_light” icons on dark backgrounds, and “_dark” on light backgrounds.
|
// We use “_light” icons on dark backgrounds, and “_dark” on light backgrounds.
|
||||||
@@ -274,4 +321,153 @@ public class ChatPageController {
|
|||||||
}
|
}
|
||||||
return new Image(url.toExternalForm());
|
return new Image(url.toExternalForm());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showChat(ChatEntry entry) {
|
||||||
|
this.currentChat = entry;
|
||||||
|
|
||||||
|
// Header
|
||||||
|
chatTitle.setText(entry.getName());
|
||||||
|
chatStatus.setText(""); // اگر last seen داری اینجا بگذار
|
||||||
|
if (entry.getImageUrl() != null && !entry.getImageUrl().isEmpty()) {
|
||||||
|
try {
|
||||||
|
userAvatar.setImage(new Image(entry.getImageUrl())); // یا لود از ریسورس خودت
|
||||||
|
userAvatar.setClip(new Circle(18, 18, 18));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageContainer.getChildren().clear();
|
||||||
|
loadMessages(entry);
|
||||||
|
|
||||||
|
// مارک بهعنوان خوانده
|
||||||
|
markAsRead(entry);
|
||||||
|
|
||||||
|
// فوکوس روی ورودی
|
||||||
|
Platform.runLater(() -> messageInput.requestFocus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadMessages(ChatEntry entry) {
|
||||||
|
JSONObject req = new JSONObject();
|
||||||
|
req.put("action", "get_messages");
|
||||||
|
req.put("receiver_id", String.valueOf(entry.getId()));
|
||||||
|
req.put("receiver_type", entry.getType());
|
||||||
|
req.put("limit", 50);
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
JSONObject resp;
|
||||||
|
try {
|
||||||
|
resp = org.to.telegramfinalproject.Client.ActionHandler.sendWithResponse(req);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (resp == null) return;
|
||||||
|
|
||||||
|
// بدون opt* :
|
||||||
|
String status = "";
|
||||||
|
try {
|
||||||
|
status = resp.getString("status");
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
if (!"success".equals(status)) return;
|
||||||
|
|
||||||
|
JSONObject data = null;
|
||||||
|
try {
|
||||||
|
data = resp.getJSONObject("data");
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
|
JSONArray arr = null;
|
||||||
|
try {
|
||||||
|
arr = data.getJSONArray("messages");
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
if (arr == null) return;
|
||||||
|
|
||||||
|
JSONArray finalArr = arr;
|
||||||
|
Platform.runLater(() -> renderMessages(finalArr));
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void renderMessages(JSONArray arr) {
|
||||||
|
messageContainer.getChildren().clear();
|
||||||
|
for (int i = 0; i < arr.length(); i++) {
|
||||||
|
JSONObject m = arr.getJSONObject(i);
|
||||||
|
String senderId = m.optString("sender_id", "");
|
||||||
|
String type = m.optString("message_type", "TEXT");
|
||||||
|
String content = m.optString("content", "");
|
||||||
|
|
||||||
|
boolean outgoing = false;
|
||||||
|
if (me != null && senderId != null && !senderId.isEmpty()) {
|
||||||
|
try {
|
||||||
|
outgoing = me.equals(UUID.fromString(senderId));
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String text;
|
||||||
|
switch (type.toUpperCase()) {
|
||||||
|
case "TEXT":
|
||||||
|
text = content;
|
||||||
|
break;
|
||||||
|
case "IMAGE":
|
||||||
|
text = "[Image]";
|
||||||
|
break;
|
||||||
|
case "AUDIO":
|
||||||
|
text = "[Audio]";
|
||||||
|
break;
|
||||||
|
case "VIDEO":
|
||||||
|
text = "[Video]";
|
||||||
|
break;
|
||||||
|
case "FILE":
|
||||||
|
text = "[File]";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
text = "[Message]";
|
||||||
|
}
|
||||||
|
addBubble(outgoing, text);
|
||||||
|
}
|
||||||
|
messageScrollPane.layout();
|
||||||
|
messageScrollPane.setVvalue(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void markAsRead(ChatEntry entry) {
|
||||||
|
JSONObject readReq = new JSONObject();
|
||||||
|
readReq.put("action", "mark_as_read");
|
||||||
|
readReq.put("receiver_id", entry.getId().toString()); // ⛳️ internal_id
|
||||||
|
readReq.put("receiver_type", entry.getType());
|
||||||
|
ActionHandler.sendWithResponse(readReq);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBubble(boolean outgoing, String content) {
|
||||||
|
Label msg = new Label(content);
|
||||||
|
msg.setWrapText(true);
|
||||||
|
|
||||||
|
boolean dark = themeManager.isDarkMode();
|
||||||
|
String mine = dark ? "#2b7cff" : "#d8ecff";
|
||||||
|
String theirs = dark ? "#2c333a" : "#ffffff";
|
||||||
|
String bg = outgoing ? mine : theirs;
|
||||||
|
|
||||||
|
msg.setStyle(
|
||||||
|
"-fx-background-color:" + bg + ";" +
|
||||||
|
"-fx-padding:8 12;" +
|
||||||
|
"-fx-background-radius:12;" +
|
||||||
|
"-fx-max-width: 520;"
|
||||||
|
);
|
||||||
|
msg.setMinHeight(Region.USE_PREF_SIZE);
|
||||||
|
|
||||||
|
javafx.scene.layout.HBox row = new javafx.scene.layout.HBox(msg);
|
||||||
|
row.setFillHeight(true);
|
||||||
|
row.setSpacing(6);
|
||||||
|
row.setAlignment(outgoing
|
||||||
|
? javafx.geometry.Pos.CENTER_RIGHT
|
||||||
|
: javafx.geometry.Pos.CENTER_LEFT);
|
||||||
|
|
||||||
|
messageContainer.getChildren().add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,25 +118,34 @@ public class IntroController {
|
|||||||
slider.setDaemon(true);
|
slider.setDaemon(true);
|
||||||
slider.start();
|
slider.start();
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// @FXML
|
||||||
|
// private void handleStartMessaging(ActionEvent event) {
|
||||||
|
// try {
|
||||||
|
// FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/login_view.fxml"));
|
||||||
|
// Scene loginScene = new Scene(loader.load());
|
||||||
|
//
|
||||||
|
// // Get the current stage and its dimensions
|
||||||
|
// Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
|
||||||
|
// double currentWidth = stage.getWidth();
|
||||||
|
// double currentHeight = stage.getHeight();
|
||||||
|
//
|
||||||
|
// // Set the new scene and apply the previous size
|
||||||
|
// stage.setScene(loginScene);
|
||||||
|
// stage.setWidth(currentWidth);
|
||||||
|
// stage.setHeight(currentHeight);
|
||||||
|
// stage.show();
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void handleStartMessaging(ActionEvent event) {
|
private void handleStartMessaging(ActionEvent event) {
|
||||||
try {
|
AppRouter.showLogin(); // همون Scene میمونه، فقط Root عوض میشه
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/login_view.fxml"));
|
|
||||||
Scene loginScene = new Scene(loader.load());
|
|
||||||
|
|
||||||
// Get the current stage and its dimensions
|
|
||||||
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
|
|
||||||
double currentWidth = stage.getWidth();
|
|
||||||
double currentHeight = stage.getHeight();
|
|
||||||
|
|
||||||
// Set the new scene and apply the previous size
|
|
||||||
stage.setScene(loginScene);
|
|
||||||
stage.setWidth(currentWidth);
|
|
||||||
stage.setHeight(currentHeight);
|
|
||||||
stage.show();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FXML private void goRegister() { AppRouter.showRegister(); }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import javafx.scene.control.*;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.to.telegramfinalproject.Client.ActionHandler;
|
||||||
import org.to.telegramfinalproject.Client.ClientConnection;
|
import org.to.telegramfinalproject.Client.ClientConnection;
|
||||||
|
import org.to.telegramfinalproject.Client.Session;
|
||||||
|
import org.to.telegramfinalproject.Client.TelegramClient;
|
||||||
import org.to.telegramfinalproject.Database.userDatabase;
|
import org.to.telegramfinalproject.Database.userDatabase;
|
||||||
import org.to.telegramfinalproject.Models.User;
|
import org.to.telegramfinalproject.Models.User;
|
||||||
import org.to.telegramfinalproject.Security.PasswordHashing;
|
import org.to.telegramfinalproject.Security.PasswordHashing;
|
||||||
@@ -23,7 +26,7 @@ public class LoginController {
|
|||||||
@FXML private PasswordField passwordField;
|
@FXML private PasswordField passwordField;
|
||||||
@FXML private TextField visiblePasswordField;
|
@FXML private TextField visiblePasswordField;
|
||||||
|
|
||||||
@FXML private Button togglePasswordBtn;
|
@FXML private Button toggleVisibilityBtn;
|
||||||
@FXML private Label errorLabel;
|
@FXML private Label errorLabel;
|
||||||
|
|
||||||
private ClientConnection connection;
|
private ClientConnection connection;
|
||||||
@@ -48,60 +51,119 @@ public class LoginController {
|
|||||||
visiblePasswordField.setManaged(passwordVisible);
|
visiblePasswordField.setManaged(passwordVisible);
|
||||||
passwordField.setVisible(!passwordVisible);
|
passwordField.setVisible(!passwordVisible);
|
||||||
passwordField.setManaged(!passwordVisible);
|
passwordField.setManaged(!passwordVisible);
|
||||||
togglePasswordBtn.setText(passwordVisible ? "👁" : "👁");
|
toggleVisibilityBtn.setText(passwordVisible ? "👁" : "👁");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @FXML
|
||||||
|
// private void handleLogin() {
|
||||||
|
// String username = usernameField.getText();
|
||||||
|
// String password = passwordField.getText();
|
||||||
|
//
|
||||||
|
// // 1. Check for empty fields
|
||||||
|
// if (username.isEmpty() || password.isEmpty()) {
|
||||||
|
// showError("Please fill in all required fields.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 2. Check if username exists
|
||||||
|
// userDatabase userDb = new userDatabase();
|
||||||
|
// if (!userDb.existsByUsername(username)) {
|
||||||
|
// showError("This username doesn’t exist.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 3. Check if password is correct
|
||||||
|
// User user = userDb.findByUsername(username);
|
||||||
|
// if (!PasswordHashing.verify(password, user.getPassword())) {
|
||||||
|
// showError("Incorrect password.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 4. Attempt to send to server
|
||||||
|
// try {
|
||||||
|
// JSONObject request = new JSONObject();
|
||||||
|
// request.put("action", "login");
|
||||||
|
// request.put("user_id", JSONObject.NULL);
|
||||||
|
// request.put("username", username);
|
||||||
|
// request.put("password", password);
|
||||||
|
// request.put("profile_name", JSONObject.NULL);
|
||||||
|
//
|
||||||
|
// if (connection != null) {
|
||||||
|
// connection.send(request.toString());
|
||||||
|
// String responseStr = connection.receive();
|
||||||
|
// JSONObject response = new JSONObject(responseStr);
|
||||||
|
// System.out.println("Status: " + response.getString("status"));
|
||||||
|
// System.out.println("Message: " + response.getString("message"));
|
||||||
|
//
|
||||||
|
// // Simulate successful login (since main.fxml isn’t ready)
|
||||||
|
// Alert alert = new Alert(Alert.AlertType.INFORMATION, "Login successful!");
|
||||||
|
// alert.show();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// } catch (Exception ex) {
|
||||||
|
// showError("Unable to connect to server. Please try again later.");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// LoginController.java (متد اصلی)
|
||||||
@FXML
|
@FXML
|
||||||
private void handleLogin() {
|
private void handleLogin() {
|
||||||
String username = usernameField.getText();
|
String u = usernameField.getText().trim();
|
||||||
String password = passwordField.getText();
|
String p = passwordField.getText();
|
||||||
|
if (u.isEmpty() || p.isEmpty()) { showError("Please fill in all required fields."); return; }
|
||||||
|
|
||||||
// 1. Check for empty fields
|
setUiBusy(true);
|
||||||
if (username.isEmpty() || password.isEmpty()) {
|
|
||||||
showError("Please fill in all required fields.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Check if username exists
|
new Thread(() -> {
|
||||||
userDatabase userDb = new userDatabase();
|
try {
|
||||||
if (!userDb.existsByUsername(username)) {
|
var cli = org.to.telegramfinalproject.Client.TelegramClient.getOrInitForUI();
|
||||||
showError("This username doesn’t exist.");
|
var handler = cli.getHandler();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Check if password is correct
|
// بساز و بفرست — همون send خودت که Session رو پر میکند
|
||||||
User user = userDb.findByUsername(username);
|
// org.json.JSONObject req = new org.json.JSONObject()
|
||||||
if (!PasswordHashing.verify(password, user.getPassword())) {
|
// .put("action","login")
|
||||||
showError("Incorrect password.");
|
// .put("username", u)
|
||||||
return;
|
// .put("password", p);
|
||||||
}
|
//
|
||||||
|
// handler.send(req); // ⬅️ بلاکینگ؛ پس درستش کردیم که تو Thread هست
|
||||||
|
|
||||||
// 4. Attempt to send to server
|
|
||||||
try {
|
|
||||||
JSONObject request = new JSONObject();
|
|
||||||
request.put("action", "login");
|
|
||||||
request.put("user_id", JSONObject.NULL);
|
|
||||||
request.put("username", username);
|
|
||||||
request.put("password", password);
|
|
||||||
request.put("profile_name", JSONObject.NULL);
|
|
||||||
|
|
||||||
if (connection != null) {
|
handler.login(u,p);
|
||||||
connection.send(request.toString());
|
|
||||||
String responseStr = connection.receive();
|
|
||||||
JSONObject response = new JSONObject(responseStr);
|
|
||||||
System.out.println("Status: " + response.getString("status"));
|
|
||||||
System.out.println("Message: " + response.getString("message"));
|
|
||||||
|
|
||||||
// Simulate successful login (since main.fxml isn’t ready)
|
javafx.application.Platform.runLater(() -> {
|
||||||
Alert alert = new Alert(Alert.AlertType.INFORMATION, "Login successful!");
|
setUiBusy(false);
|
||||||
alert.show();
|
|
||||||
|
if (!handler.wasSuccess() || Session.currentUser == null) {
|
||||||
|
showError(handler.getLastMessage().isEmpty() ? "Login failed." : handler.getLastMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// موفق: Session از داخل send پر شده
|
||||||
|
goMain(); // بدون Alert → مستقیم به main.fxml
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
javafx.application.Platform.runLater(() -> {
|
||||||
|
setUiBusy(false);
|
||||||
|
showError("Connection error.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}, "login-thread").start();
|
||||||
} catch (Exception ex) {
|
|
||||||
showError("Unable to connect to server. Please try again later.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void goMain() {
|
||||||
|
AppRouter.showMain();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setUiBusy(boolean b) {
|
||||||
|
usernameField.setDisable(b);
|
||||||
|
passwordField.setDisable(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void switchToRegister() throws IOException {
|
private void switchToRegister() throws IOException {
|
||||||
switchScene("register_view.fxml");
|
switchScene("register_view.fxml");
|
||||||
|
|||||||
@@ -13,8 +13,15 @@ import javafx.scene.layout.Pane;
|
|||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
import org.to.telegramfinalproject.Models.ChatEntry;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class MainController {
|
public class MainController {
|
||||||
|
|
||||||
@@ -57,10 +64,14 @@ public class MainController {
|
|||||||
public static MainController getInstance() {
|
public static MainController getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
private final Map<UUID, ChatItemController> itemControllers = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
addSampleChats();
|
// addSampleChats();
|
||||||
|
populateChatListFromSession();
|
||||||
|
|
||||||
|
|
||||||
// Register the scene for automatic CSS updates
|
// Register the scene for automatic CSS updates
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
@@ -138,58 +149,155 @@ public class MainController {
|
|||||||
scrollPane.setManaged(true);
|
scrollPane.setManaged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSampleChats() {
|
// private void addSampleChats() {
|
||||||
addChat("Archived Chats", "Your archived chats", "10:45", 0);
|
// addChat("Archived Chats", "Your archived chats", "10:45", 0);
|
||||||
addChat("Saved Messages", "Keep messages for later", "Yesterday", 0);
|
// addChat("Saved Messages", "Keep messages for later", "Yesterday", 0);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
addChat("Alice", "Hey, how are you?", "14:12", 3);
|
// addChat("Alice", "Hey, how are you?", "14:12", 3);
|
||||||
addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
// addChat("Bob", "Let's meet tomorrow", "12:08", 1);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
private final DateTimeFormatter timeFmt = DateTimeFormatter.ofPattern("HH:mm");
|
||||||
|
private final DateTimeFormatter dayFmt = DateTimeFormatter.ofPattern("dd/MM"); // همون سال
|
||||||
|
private final DateTimeFormatter fullDateFmt= DateTimeFormatter.ofPattern("yyyy/MM/dd"); // سال متفاوت
|
||||||
|
|
||||||
|
private String formatListTimestamp(LocalDateTime ts) {
|
||||||
|
if (ts == null) return "";
|
||||||
|
LocalDate today = LocalDate.now();
|
||||||
|
LocalDate d = ts.toLocalDate();
|
||||||
|
|
||||||
|
if (d.isEqual(today)) {
|
||||||
|
// امروز → فقط ساعت
|
||||||
|
return timeFmt.format(ts);
|
||||||
|
}
|
||||||
|
// اگر همان سال است → تاریخ کوتاه + ساعت
|
||||||
|
if (d.getYear() == today.getYear()) {
|
||||||
|
return dayFmt.format(ts) + " " + timeFmt.format(ts); // مثال: 15/08 13:28
|
||||||
|
}
|
||||||
|
// سال متفاوت → تاریخ کامل + ساعت
|
||||||
|
return fullDateFmt.format(ts) + " " + timeFmt.format(ts); // مثال: 2024/12/31 21:10
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addChat(String name, String lastMsg, String time, int unread) {
|
|
||||||
try {
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/chat_item.fxml"));
|
|
||||||
Node chatItem = loader.load();
|
|
||||||
ChatItemController controller = loader.getController();
|
|
||||||
controller.setChatData(name, lastMsg, time, unread);
|
|
||||||
|
|
||||||
chatItem.setOnMouseClicked(e -> openChat(name));
|
|
||||||
chatListContainer.getChildren().add(chatItem);
|
private void populateChatListFromSession() {
|
||||||
} catch (IOException e) {
|
chatListContainer.getChildren().clear();
|
||||||
e.printStackTrace();
|
|
||||||
|
var list = (org.to.telegramfinalproject.Client.Session.activeChats != null
|
||||||
|
&& !org.to.telegramfinalproject.Client.Session.activeChats.isEmpty())
|
||||||
|
? org.to.telegramfinalproject.Client.Session.activeChats
|
||||||
|
: org.to.telegramfinalproject.Client.Session.chatList;
|
||||||
|
|
||||||
|
if (list == null || list.isEmpty()) return;
|
||||||
|
|
||||||
|
for (ChatEntry c : list) {
|
||||||
|
addChatNode(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openChat(String chatName) {
|
|
||||||
|
// private void addChatNode(ChatEntry chat ) {
|
||||||
|
// try {
|
||||||
|
// FXMLLoader fx = new FXMLLoader(getClass().getResource(
|
||||||
|
// "/org/to/telegramfinalproject/Fxml/chat_item.fxml"));
|
||||||
|
// Node item = fx.load();
|
||||||
|
// ChatItemController cc = fx.getController();
|
||||||
|
//
|
||||||
|
// String lastPreview = "";
|
||||||
|
// String time = (chat.getLastMessageTime() != null)
|
||||||
|
// ? timeFmt.format(chat.getLastMessageTime()) : "";
|
||||||
|
//
|
||||||
|
// cc.setChatData(chat.getName(), lastPreview, time, 0);
|
||||||
|
//
|
||||||
|
// item.setOnMouseClicked(e -> openChat(String.valueOf(chat)));
|
||||||
|
// chatListContainer.getChildren().add(item);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void addChatNode(ChatEntry chat) {
|
||||||
|
try {
|
||||||
|
FXMLLoader fx = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/chat_item.fxml"));
|
||||||
|
Node item = fx.load();
|
||||||
|
ChatItemController cc = fx.getController();
|
||||||
|
|
||||||
|
String preview = chat.getLastMessagePreview() == null ? "" : chat.getLastMessagePreview();
|
||||||
|
String time = formatListTimestamp(chat.getLastMessageTime());
|
||||||
|
|
||||||
|
cc.setChatData(chat.getName(), preview, time, chat.getUnreadCount());
|
||||||
|
item.setOnMouseClicked(e -> openChat(chat));
|
||||||
|
chatListContainer.getChildren().add(item);
|
||||||
|
|
||||||
|
itemControllers.put(chat.getId(), cc);
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String mapTypeToLabel(String t) {
|
||||||
|
switch (t.toUpperCase()) {
|
||||||
|
case "IMAGE": return "[Image]";
|
||||||
|
case "AUDIO": return "[Audio]";
|
||||||
|
case "VIDEO": return "[Video]";
|
||||||
|
case "FILE": return "[File]";
|
||||||
|
default: return "[Message]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// private void addChat(String name, String lastMsg, String time, int unread) {
|
||||||
|
// try {
|
||||||
|
// FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/chat_item.fxml"));
|
||||||
|
// Node chatItem = loader.load();
|
||||||
|
// ChatItemController controller = loader.getController();
|
||||||
|
// controller.setChatData(name, lastMsg, time, unread);
|
||||||
|
//
|
||||||
|
// chatItem.setOnMouseClicked(e -> openChat(name));
|
||||||
|
// chatListContainer.getChildren().add(chatItem);
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void openChat(ChatEntry chat) {
|
||||||
try {
|
try {
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/chat_page.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/to/telegramfinalproject/Fxml/chat_page.fxml"));
|
||||||
Node chatPage = loader.load();
|
Node chatPage = loader.load();
|
||||||
|
|
||||||
ChatPageController controller = loader.getController();
|
ChatPageController controller = loader.getController();
|
||||||
controller.setChat("Alice", "/org/to/telegramfinalproject/Avatars/profile_test.png");
|
controller.showChat(chat); // ✅ متد جدید در ChatPageController
|
||||||
|
|
||||||
|
chatDisplayArea.getChildren().setAll(chatPage);
|
||||||
|
|
||||||
chatDisplayArea.getChildren().clear();
|
// اختیاری: صفر کردن badge و مارککردن بهعنوان خوانده در UI
|
||||||
chatDisplayArea.getChildren().add(chatPage);
|
ChatItemController item = itemControllers.get(chat.getId());
|
||||||
|
if (item != null) item.setUnread(0);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException ex) {
|
||||||
e.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void toggleSidebar() {
|
private void toggleSidebar() {
|
||||||
if (isSidebarOpen) {
|
if (isSidebarOpen) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.to.telegramfinalproject.UI;
|
|||||||
import javafx.animation.TranslateTransition;
|
import javafx.animation.TranslateTransition;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
@@ -12,12 +13,16 @@ import javafx.scene.layout.Region;
|
|||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
public class SidebarMenuController {
|
public class SidebarMenuController {
|
||||||
|
|
||||||
private static final String ICON_PATH = "/org/to/telegramfinalproject/Icons/";
|
private static final String ICON_PATH = "/org/to/telegramfinalproject/Icons/";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@FXML private VBox sidebarRoot;
|
@FXML private VBox sidebarRoot;
|
||||||
@FXML private ImageView profileImage;
|
@FXML private ImageView profileImage;
|
||||||
@FXML private Label usernameLabel;
|
@FXML private Label usernameLabel;
|
||||||
@@ -176,4 +181,8 @@ public class SidebarMenuController {
|
|||||||
private void openSettings() { System.out.println("Opening Settings..."); }
|
private void openSettings() { System.out.println("Opening Settings..."); }
|
||||||
private void openTelegramFeatures() { System.out.println("Opening Telegram Features..."); }
|
private void openTelegramFeatures() { System.out.println("Opening Telegram Features..."); }
|
||||||
private void openTelegramQnA() { System.out.println("Opening Telegram Q&A..."); }
|
private void openTelegramQnA() { System.out.println("Opening Telegram Q&A..."); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,36 @@
|
|||||||
package org.to.telegramfinalproject.UI;
|
package org.to.telegramfinalproject.UI;//package org.to.telegramfinalproject.UI;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//import javafx.application.Application;
|
||||||
|
//import javafx.fxml.FXMLLoader;
|
||||||
|
//import javafx.scene.Scene;
|
||||||
|
//import javafx.scene.image.Image;
|
||||||
|
//import javafx.stage.Stage;
|
||||||
|
//
|
||||||
|
//import java.io.IOException;
|
||||||
|
//
|
||||||
|
//public class TelegramApplication extends Application {
|
||||||
|
// @Override
|
||||||
|
// public void start(Stage stage) throws IOException {
|
||||||
|
// FXMLLoader fxmlLoader = new FXMLLoader(TelegramApplication.class.getResource("/org/to/telegramfinalproject/Fxml/main.fxml"));
|
||||||
|
// Scene scene = new Scene(fxmlLoader.load(), 1480, 820);
|
||||||
|
//
|
||||||
|
// scene.getStylesheets().add(getClass().getResource("/org/to/telegramfinalproject/CSS/light_theme.css").toExternalForm());
|
||||||
|
//
|
||||||
|
// stage.setTitle("Telegram");
|
||||||
|
// stage.setScene(scene);
|
||||||
|
//
|
||||||
|
// // Add icon to the stage
|
||||||
|
// Image icon = new Image(TelegramApplication.class.getResourceAsStream("/org/to/telegramfinalproject/Images/telegram_icon.png"));
|
||||||
|
// stage.getIcons().add(icon);
|
||||||
|
//
|
||||||
|
// stage.show();
|
||||||
|
// }
|
||||||
|
// public static void main(String[] args) {
|
||||||
|
// launch();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
@@ -6,28 +38,31 @@ import javafx.fxml.FXMLLoader;
|
|||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import org.to.telegramfinalproject.UI.AppRouter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class TelegramApplication extends Application {
|
public class TelegramApplication extends Application {
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(TelegramApplication.class.getResource("/org/to/telegramfinalproject/Fxml/main.fxml"));
|
// اول intro.fxml
|
||||||
Scene scene = new Scene(fxmlLoader.load(), 1480, 820);
|
FXMLLoader fx = new FXMLLoader(
|
||||||
|
TelegramApplication.class.getResource("/org/to/telegramfinalproject/Fxml/intro.fxml"));
|
||||||
|
Scene scene = new Scene(fx.load(), 1480, 820);
|
||||||
|
|
||||||
scene.getStylesheets().add(getClass().getResource("/org/to/telegramfinalproject/CSS/light_theme.css").toExternalForm());
|
scene.getStylesheets().add(
|
||||||
|
getClass().getResource("/org/to/telegramfinalproject/CSS/light_theme.css").toExternalForm()
|
||||||
|
);
|
||||||
|
|
||||||
stage.setTitle("Telegram");
|
stage.setTitle("Telegram");
|
||||||
|
stage.getIcons().add(new Image(
|
||||||
|
TelegramApplication.class.getResourceAsStream("/org/to/telegramfinalproject/Images/telegram_icon.png")
|
||||||
|
));
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
|
|
||||||
// Add icon to the stage
|
|
||||||
Image icon = new Image(TelegramApplication.class.getResourceAsStream("/org/to/telegramfinalproject/Images/telegram_icon.png"));
|
|
||||||
stage.getIcons().add(icon);
|
|
||||||
|
|
||||||
stage.show();
|
stage.show();
|
||||||
}
|
|
||||||
public static void main(String[] args) {
|
AppRouter.init(stage, scene);
|
||||||
launch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public static void main(String[] args) { launch(); }
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user