# Conflicts: # src/main/java/org/to/telegramfinalproject/Client/ActionHandler.java # src/main/java/org/to/telegramfinalproject/Client/IncomingMessageListener.java # src/main/java/org/to/telegramfinalproject/Client/TelegramClient.java # src/main/java/org/to/telegramfinalproject/Database/MessageDatabase.java # src/main/java/org/to/telegramfinalproject/Server/ClientHandler.java
4573 lines
175 KiB
Java
4573 lines
175 KiB
Java
package org.to.telegramfinalproject.Client;
|
||
|
||
import org.json.JSONArray;
|
||
import org.json.JSONObject;
|
||
import org.to.telegramfinalproject.Models.ChatEntry;
|
||
import org.to.telegramfinalproject.Models.ContactEntry;
|
||
import org.to.telegramfinalproject.Models.SearchRequestModel;
|
||
|
||
import java.io.*;
|
||
import java.nio.file.Files;
|
||
import java.nio.file.Path;
|
||
import java.nio.file.Paths;
|
||
import java.time.LocalDateTime;
|
||
import java.util.*;
|
||
import java.util.concurrent.BlockingQueue;
|
||
import java.util.concurrent.LinkedBlockingQueue;
|
||
|
||
|
||
public class ActionHandler {
|
||
private final PrintWriter out;
|
||
private final BufferedReader in;
|
||
private final Scanner scanner;
|
||
public static volatile boolean forceExitChat = false;
|
||
public static ActionHandler instance;
|
||
private final DataOutputStream outBin;
|
||
|
||
//use for UI
|
||
private volatile String lastStatus = "error"; // success | error
|
||
private volatile String lastMessage = "";
|
||
// ===== UI hook for search results =====
|
||
|
||
|
||
|
||
|
||
|
||
public String getLastStatus() { return lastStatus; }
|
||
public String getLastMessage() { return lastMessage; }
|
||
public boolean wasSuccess() { return "success".equalsIgnoreCase(lastStatus); }
|
||
|
||
|
||
|
||
// private void handleRealTime(JSONObject json) throws IOException {
|
||
// IncomingMessageListener listener = new IncomingMessageListener(this.in);
|
||
// listener.handleRealTimeEvent (json);
|
||
// }
|
||
|
||
// ActionHandler.java
|
||
private void handleRealTime(JSONObject json) throws IOException {
|
||
IncomingMessageListener listener = TelegramClient.getInstance().getListener();
|
||
if (listener != null) {
|
||
listener.handleRealTimeEvent(json);
|
||
} else {
|
||
System.err.println("[RT] Listener not ready; dropping RT event: " + json);
|
||
}
|
||
}
|
||
|
||
public ActionHandler(PrintWriter out, BufferedReader in, DataOutputStream outBin, Scanner scanner) {
|
||
this.out = out;
|
||
this.in = in;
|
||
this.outBin = outBin;
|
||
this.scanner = scanner;
|
||
ActionHandler.instance = this;
|
||
}
|
||
|
||
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() {
|
||
System.out.println("Login form: \n");
|
||
System.out.print("Username: ");
|
||
String username = this.scanner.nextLine();
|
||
System.out.print("Password: ");
|
||
String password = this.scanner.nextLine();
|
||
|
||
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 register() {
|
||
System.out.println("Register form: \n");
|
||
|
||
String username, user_id, password, profile_name;
|
||
|
||
while (true) {
|
||
System.out.print("Username: ");
|
||
username = scanner.nextLine().trim();
|
||
if (username.isEmpty()) {
|
||
System.out.println("❌ Username cannot be empty.");
|
||
continue;
|
||
}
|
||
|
||
System.out.print("User id: ");
|
||
user_id = scanner.nextLine().trim();
|
||
if (user_id.isEmpty()) {
|
||
System.out.println("❌ User ID cannot be empty.");
|
||
continue;
|
||
}
|
||
|
||
System.out.print("Password: ");
|
||
password = scanner.nextLine();
|
||
if (password.isEmpty()) {
|
||
System.out.println("❌ Password cannot be empty.");
|
||
continue;
|
||
}
|
||
|
||
System.out.print("Profile name: ");
|
||
profile_name = scanner.nextLine().trim();
|
||
if (profile_name.isEmpty()) {
|
||
System.out.println("❌ Profile name cannot be empty.");
|
||
continue;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
|
||
JSONObject request = new JSONObject();
|
||
request.put("action", "register");
|
||
request.put("user_id", user_id);
|
||
request.put("username", username);
|
||
request.put("password", password);
|
||
request.put("profile_name", profile_name);
|
||
|
||
this.send(request);
|
||
}
|
||
|
||
public void search() {
|
||
System.out.print("Enter keyword to search: ");
|
||
String keyword = scanner.nextLine();
|
||
|
||
if (Session.currentUser == null || !Session.currentUser.has("user_id")) {
|
||
System.out.println("You must be logged in to search.");
|
||
return;
|
||
}
|
||
|
||
String userId = Session.currentUser.getString("user_id");
|
||
SearchRequestModel model = new SearchRequestModel("search", keyword, userId);
|
||
send(model.toJson());
|
||
}
|
||
|
||
public void searchUI(String keyword) {
|
||
|
||
if (Session.currentUser == null || !Session.currentUser.has("user_id")) {
|
||
System.out.println("You must be logged in to search.");
|
||
return;
|
||
}
|
||
|
||
String userId = Session.currentUser.getString("user_id");
|
||
SearchRequestModel model = new SearchRequestModel("search", keyword, userId);
|
||
send(model.toJson());
|
||
}
|
||
|
||
|
||
public void searchInUsers(){
|
||
System.out.println("Enter keyword to search: ");
|
||
String keyword = scanner.nextLine();
|
||
if (Session.currentUser == null || !Session.currentUser.has("user_id")) {
|
||
System.out.println("You must be logged in to search.");
|
||
return;
|
||
}
|
||
String userId = Session.currentUser.getString("user_id");
|
||
SearchRequestModel model = new SearchRequestModel("searchInUsers", keyword, userId);
|
||
send(model.toJson());
|
||
|
||
}
|
||
|
||
|
||
public void searchEligibleUsers(String entityType, UUID entityId) {
|
||
System.out.print("Enter keyword to search: ");
|
||
String keyword = scanner.nextLine().trim();
|
||
|
||
if (Session.currentUser == null || !Session.currentUser.has("user_id")) {
|
||
System.out.println("You must be logged in to search.");
|
||
return;
|
||
}
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "searchEligibleUsers");
|
||
req.put("keyword", keyword);
|
||
req.put("user_id", Session.currentUser.getString("user_id"));
|
||
req.put("entity_id", entityId.toString());
|
||
req.put("entity_type", entityType); // group or channel
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ " + (res != null ? res.getString("message") : "No response received."));
|
||
return;
|
||
}
|
||
|
||
JSONArray results = res.getJSONObject("data").getJSONArray("results");
|
||
if (results.isEmpty()) {
|
||
System.out.println("⚠️ No eligible users found.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("\nEligible Users:");
|
||
for (int i = 0; i < results.length(); i++) {
|
||
JSONObject user = results.getJSONObject(i);
|
||
System.out.println((i + 1) + ". " + user.getString("name") + " (ID: " + user.getString("id") + ")");
|
||
}
|
||
|
||
System.out.print("Select a user to add (or 0 to cancel): ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid input.");
|
||
return;
|
||
}
|
||
|
||
if (choice < 0 || choice >= results.length()) {
|
||
System.out.println("Cancelled.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = results.getJSONObject(choice);
|
||
UUID targetUUID = UUID.fromString(selected.getString("uuid"));
|
||
|
||
if (entityType.equals("group")) {
|
||
addMemberToGroup(entityId, targetUUID);
|
||
} else if (entityType.equals("channel")) {
|
||
addSubscriberToChannel(entityId, targetUUID);
|
||
}
|
||
}
|
||
|
||
|
||
public void addContact(UUID contactId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "add_contact");
|
||
req.put("user_id", Session.currentUser.getString("user_id"));
|
||
req.put("contact_id", contactId.toString());
|
||
send(req);
|
||
}
|
||
|
||
|
||
public void joinGroupOrChannel(String type, String uuid) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "join_" + type);
|
||
req.put("user_id", Session.getUserUUID());
|
||
req.put("id", uuid);
|
||
send(req);
|
||
}
|
||
|
||
|
||
|
||
public ChatEntry fetchChatInfo(String receiverId, String receiverType) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_info");
|
||
req.put("receiver_id", receiverId);
|
||
req.put("receiver_type", receiverType);
|
||
out.println(req.toString());
|
||
|
||
try {
|
||
JSONObject response = TelegramClient.responseQueue.take();
|
||
if (response != null && response.getString("status").equals("success")) {
|
||
JSONObject data = response.getJSONObject("data");
|
||
|
||
return new ChatEntry(
|
||
UUID.fromString(data.getString("internal_id")),
|
||
receiverId,
|
||
data.getString("name"),
|
||
data.optString("image_url", ""),
|
||
receiverType,
|
||
null,
|
||
data.optBoolean("is_owner", false),
|
||
data.optBoolean("is_admin", false)
|
||
);
|
||
|
||
}
|
||
} catch (Exception e) {
|
||
System.err.println("Error fetching chat info: " + e.getMessage());
|
||
}
|
||
|
||
//if invalid make unknown modle
|
||
return new ChatEntry(
|
||
UUID.randomUUID(),
|
||
receiverId,
|
||
"[Unknown " + receiverType + "]",
|
||
"",
|
||
receiverType,
|
||
null
|
||
);
|
||
}
|
||
|
||
|
||
public void refreshChatList() {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_list");
|
||
req.put("user_id", Session.currentUser.getString("user_id"));
|
||
out.println(req.toString());
|
||
|
||
try {
|
||
JSONObject response = TelegramClient.responseQueue.take();
|
||
|
||
if (response != null && response.getString("status").equals("success")) {
|
||
if (response.has("data") && !response.isNull("data")) {
|
||
JSONObject data = response.getJSONObject("data");
|
||
|
||
if ((!data.has("active_chat_list") || data.isNull("active_chat_list")) &&
|
||
(!data.has("archived_chat_list") || data.isNull("archived_chat_list"))) {
|
||
System.out.println("❌ No chat list found in response data.");
|
||
return;
|
||
}
|
||
|
||
List<ChatEntry> activeChats = new ArrayList<>();
|
||
List<ChatEntry> archivedChats = new ArrayList<>();
|
||
|
||
// 📁 Parse active chat list
|
||
if (data.has("active_chat_list") && !data.isNull("active_chat_list")) {
|
||
JSONArray activeJson = data.getJSONArray("active_chat_list");
|
||
for (Object obj : activeJson) {
|
||
JSONObject chat = (JSONObject) obj;
|
||
ChatEntry entry = parseChatEntry(chat);
|
||
activeChats.add(entry);
|
||
}
|
||
}
|
||
|
||
// 📁 Parse archived chat list
|
||
if (data.has("archived_chat_list") && !data.isNull("archived_chat_list")) {
|
||
JSONArray archivedJson = data.getJSONArray("archived_chat_list");
|
||
for (Object obj : archivedJson) {
|
||
JSONObject chat = (JSONObject) obj;
|
||
ChatEntry entry = parseChatEntry(chat);
|
||
archivedChats.add(entry);
|
||
}
|
||
}
|
||
|
||
Session.chatList = new ArrayList<>();
|
||
Session.chatList.addAll(activeChats);
|
||
Session.chatList.addAll(archivedChats);
|
||
|
||
Session.activeChats = activeChats;
|
||
Session.archivedChats = archivedChats;
|
||
|
||
System.out.println("✅ Chat list updated.");
|
||
System.out.println("📂 Active Chats: " + activeChats.size());
|
||
System.out.println("📁 Archived Chats: " + archivedChats.size());
|
||
} else {
|
||
System.out.println("⚠️ Response has no data object.");
|
||
}
|
||
} else {
|
||
if (response.has("message") && !response.isNull("message")) {
|
||
System.out.println("❌ Failed to refresh chat list: " + response.getString("message"));
|
||
} else {
|
||
System.out.println("❌ Failed to refresh chat list.");
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
System.err.println("❌ Error during refreshChatList: " + e.getMessage());
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
private ChatEntry parseChatEntry(JSONObject chat) {
|
||
UUID internalId = null;
|
||
try { internalId = UUID.fromString(chat.getString("internal_id")); } catch (Exception ignored) {}
|
||
|
||
String id = chat.optString("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));
|
||
}
|
||
|
||
return entry;
|
||
}
|
||
|
||
|
||
|
||
public void createGroup() {
|
||
String groupId = null;
|
||
|
||
while (groupId == null){
|
||
System.out.print("Enter group ID: ");
|
||
String input = scanner.nextLine();
|
||
if (!input.trim().isEmpty()) {
|
||
groupId = input;
|
||
} else {
|
||
System.out.println("Group ID can't be empty.");
|
||
}
|
||
|
||
}
|
||
|
||
String groupName = null;
|
||
while (groupName == null) {
|
||
System.out.print("Enter group name: ");
|
||
String input = scanner.nextLine();
|
||
if (!input.trim().isEmpty()) {
|
||
groupName = input;
|
||
} else {
|
||
System.out.println("Group name can't be empty.");
|
||
}
|
||
}
|
||
System.out.print("Enter image URL (optional): ");
|
||
String imageUrl = scanner.nextLine();
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "create_group");
|
||
req.put("user_id", Session.getUserUUID());
|
||
req.put("group_id", groupId);
|
||
req.put("group_name", groupName);
|
||
req.put("image_url", imageUrl.isBlank() ? JSONObject.NULL : imageUrl);
|
||
|
||
send(req);
|
||
}
|
||
|
||
|
||
|
||
public void createChannel() {
|
||
String channelId = null;
|
||
|
||
while (channelId == null){
|
||
System.out.print("Enter channel ID: ");
|
||
String input = scanner.nextLine();
|
||
if (!input.trim().isEmpty()) {
|
||
channelId = input;
|
||
} else {
|
||
System.out.println("Channel ID can't be empty.");
|
||
}
|
||
|
||
}
|
||
String channelName = null;
|
||
while (channelName == null) {
|
||
System.out.print("Enter channel name: ");
|
||
String input = scanner.nextLine();
|
||
if (!input.trim().isEmpty()) {
|
||
channelName = input;
|
||
} else {
|
||
System.out.println("Channel name can't be empty.");
|
||
}
|
||
}
|
||
System.out.print("Enter image URL (optional): ");
|
||
String imageUrl = scanner.nextLine();
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "create_channel");
|
||
req.put("user_id", Session.getUserUUID());
|
||
req.put("channel_id", channelId);
|
||
req.put("channel_name", channelName);
|
||
req.put("image_url", imageUrl.isBlank() ? JSONObject.NULL : imageUrl);
|
||
|
||
send(req);
|
||
}
|
||
|
||
public void addMember(UUID memberId){
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "add_member");
|
||
req.put("user_id", Session.currentUser.getString("user_id"));
|
||
//req.put("group/channel",)
|
||
req.put("member_id", memberId.toString());
|
||
send(req);
|
||
}
|
||
|
||
|
||
|
||
|
||
public void send(JSONObject request) {
|
||
try {
|
||
if (!request.has("action") || request.isNull("action")) {
|
||
System.err.println("❌ Invalid request: missing action.");
|
||
return;
|
||
}
|
||
|
||
String action = request.getString("action");
|
||
this.out.println(request.toString());
|
||
|
||
JSONObject response = null;
|
||
|
||
while (true) {
|
||
JSONObject incoming = TelegramClient.responseQueue.take();
|
||
|
||
if (incoming.has("status")) {
|
||
response = incoming;
|
||
break;
|
||
} else {
|
||
//real time
|
||
handleRealTime(incoming);
|
||
}
|
||
}
|
||
|
||
if (response == null) {
|
||
System.out.println("⚠️ No usable response received.");
|
||
return;
|
||
}
|
||
|
||
if (response.has("message") && !response.isNull("message")) {
|
||
System.out.println("✅ Server Response: " + response.getString("message"));
|
||
}
|
||
|
||
String status = response.optString("status", "error");
|
||
if (!"success".equals(status) || !response.has("data") || response.isNull("data"))
|
||
return;
|
||
|
||
|
||
status = response.optString("status","error");
|
||
String message = response.optString("message","");
|
||
this.lastStatus = status;
|
||
this.lastMessage = message;
|
||
|
||
|
||
switch (action) {
|
||
case "login":
|
||
case "register":
|
||
Session.currentUser = response.getJSONObject("data");
|
||
|
||
//for downloaded medias
|
||
UUID accountId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||
Session.downloadsIndex = new DownloadsIndex(accountId);
|
||
|
||
|
||
|
||
JSONArray chatListJson = Session.currentUser.getJSONArray("chat_list");
|
||
JSONArray Archived = Session.currentUser.getJSONArray("archived_chat_list");
|
||
JSONArray Active = Session.currentUser.getJSONArray("active_chat_list");
|
||
JSONArray contactList = Session.currentUser.getJSONArray("contact_list");
|
||
// List<ChatEntry> chatList = new ArrayList<>();
|
||
//
|
||
//
|
||
// for (Object obj : chatListJson) {
|
||
// JSONObject chat = (JSONObject) obj;
|
||
//
|
||
// ChatEntry entry = new ChatEntry(
|
||
// UUID.fromString(chat.getString("internal_id")),
|
||
// 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")) {
|
||
// entry.setOtherUserId(UUID.fromString(chat.getString("other_user_id")));
|
||
// }
|
||
//
|
||
// if (chat.has("is_saved_messages")) {
|
||
// entry.setSavedMessages(chat.getBoolean("is_saved_messages"));
|
||
// }
|
||
//
|
||
// chatList.add(entry);
|
||
//
|
||
// }
|
||
//
|
||
// List<ChatEntry> archivedChats = new ArrayList<>();
|
||
// for (Object obj : Archived){
|
||
// JSONObject chat = (JSONObject) obj;
|
||
//
|
||
// ChatEntry entry = new ChatEntry(
|
||
// UUID.fromString(chat.getString("internal_id")),
|
||
// 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")) {
|
||
// entry.setOtherUserId(UUID.fromString(chat.getString("other_user_id")));
|
||
// }
|
||
// archivedChats.add(entry);
|
||
//
|
||
// }
|
||
//
|
||
// List<ChatEntry> activeChats = new ArrayList<>();
|
||
// for (Object obj : Active){
|
||
// JSONObject chat = (JSONObject) obj;
|
||
//
|
||
// ChatEntry entry = new ChatEntry(
|
||
// UUID.fromString(chat.getString("internal_id")),
|
||
// 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")) {
|
||
// entry.setOtherUserId(UUID.fromString(chat.getString("other_user_id")));
|
||
// }
|
||
//
|
||
// activeChats.add(entry);
|
||
//
|
||
// }
|
||
|
||
List<ChatEntry> chatList = new ArrayList<>();
|
||
for (Object obj : chatListJson) {
|
||
chatList.add(parseChatEntry((JSONObject) obj));
|
||
}
|
||
|
||
List<ChatEntry> archivedChats = new ArrayList<>();
|
||
for (Object obj : Archived) {
|
||
archivedChats.add(parseChatEntry((JSONObject) obj));
|
||
}
|
||
|
||
List<ChatEntry> activeChats = new ArrayList<>();
|
||
for (Object obj : Active) {
|
||
activeChats.add(parseChatEntry((JSONObject) obj));
|
||
}
|
||
|
||
|
||
Session.contactEntries.clear();
|
||
for (Object obj : contactList) {
|
||
JSONObject c = (JSONObject) obj;
|
||
|
||
ContactEntry entry = new ContactEntry(
|
||
UUID.fromString(c.getString("contact_id")),
|
||
c.getString("user_id"),
|
||
c.getString("contact_displayId"),
|
||
c.getString("profile_name"),
|
||
c.optString("image_url", ""),
|
||
c.optBoolean("is_blocked", false),
|
||
c.isNull("last_seen")
|
||
? null
|
||
: LocalDateTime.parse(c.getString("last_seen"))
|
||
);
|
||
Session.contactEntries.add(entry);
|
||
}
|
||
|
||
|
||
|
||
Session.activeChats = activeChats;
|
||
Session.archivedChats = archivedChats;
|
||
Session.chatList = chatList;
|
||
break;
|
||
|
||
case "searchInUsers":
|
||
JSONArray result = response.getJSONObject("data").getJSONArray("results");
|
||
if (result.isEmpty()){
|
||
System.out.println("No results found.");
|
||
}
|
||
else{
|
||
System.out.println("Search Results:");
|
||
for (int i = 0 ; i < result.length(); i++){
|
||
JSONObject item = result.getJSONObject(i);
|
||
String type = item.getString("type");
|
||
if(type.equals("user")){
|
||
System.out.println((i + 1) + ". [" + type + "] "
|
||
+ item.getString("name") + " (ID: " + item.getString("id") + ")");
|
||
}
|
||
}
|
||
System.out.print("Select a result number to interact(0 for return): ");
|
||
int index = Integer.parseInt(scanner.nextLine()) - 1;
|
||
if (index < 0 || index >= result.length()) return;
|
||
JSONObject selected = result.getJSONObject(index);
|
||
String userId = selected.getString("id");
|
||
String uuid = selected.getString("uuid");
|
||
UUID memberId = UUID.fromString(uuid);
|
||
addMember(memberId);
|
||
}
|
||
break;
|
||
case "search" :
|
||
|
||
|
||
JSONArray results = response.getJSONObject("data").getJSONArray("results");
|
||
|
||
if (results.isEmpty()) {
|
||
System.out.println("No results found.");
|
||
} else {
|
||
System.out.println("\nSearch Results:");
|
||
for (int i = 0; i < results.length(); i++) {
|
||
JSONObject item = results.getJSONObject(i);
|
||
String type = item.getString("type");
|
||
|
||
if (type.equals("message")) {
|
||
String senderName = item.optString("sender_name", item.optString("sender", "Unknown"));
|
||
String time = item.optString("time", "Unknown time");
|
||
String content = item.optString("content", "[No content]");
|
||
String context = "";
|
||
|
||
if (item.has("group_name")) {
|
||
context = " in group: " + item.getString("group_name");
|
||
} else if (item.has("channel_name")) {
|
||
context = " in channel: " + item.getString("channel_name");
|
||
}
|
||
|
||
System.out.println((i + 1) + ". [message] \"" + content + "\""
|
||
+ " (from: " + senderName + context + ", at: " + time + ")");
|
||
} else {
|
||
System.out.println((i + 1) + ". [" + type + "] "
|
||
+ item.getString("name") + " (ID: " + item.getString("id") + ")");
|
||
}
|
||
|
||
}
|
||
|
||
System.out.print("Select a result number to interact (or 0 to exit): ");
|
||
int index = Integer.parseInt(scanner.nextLine()) - 1;
|
||
if (index == -1) {
|
||
System.out.println("Exit...");
|
||
return;
|
||
}
|
||
if (index < -1 || index >= results.length()) return;
|
||
|
||
JSONObject selected = results.getJSONObject(index);
|
||
String type = selected.getString("type");
|
||
|
||
switch (type) {
|
||
case "user" -> {
|
||
String uuidStr = selected.getString("uuid");
|
||
UUID uuid = UUID.fromString(uuidStr);
|
||
|
||
System.out.println("🔍 Looking for chat with internal_id='" + uuid + "' type='private'");
|
||
|
||
ChatEntry existing = Session.chatList.stream()
|
||
.filter(c -> c.getId().equals(uuid) && c.getType().equals("private"))
|
||
.findFirst()
|
||
.orElse(null);
|
||
|
||
if (existing != null) {
|
||
openChat(existing);
|
||
} else {
|
||
ChatEntry preview = new ChatEntry();
|
||
preview.setId(String.valueOf(uuid));
|
||
preview.setDisplayId(selected.getString("id"));
|
||
preview.setName(selected.getString("name"));
|
||
preview.setType("private");
|
||
|
||
openForeignChat(preview);
|
||
}
|
||
// else {
|
||
// System.out.println("ℹ Trying to add contact...");
|
||
// addContact(uuid);
|
||
//
|
||
// refreshChatList();
|
||
// System.out.println("🔄 Rechecking chat list...");
|
||
//
|
||
// existing = Session.chatList.stream()
|
||
// .filter(c -> c.getId().equals(uuid) && c.getType().equals("private"))
|
||
// .findFirst()
|
||
// .orElse(null);
|
||
//
|
||
// if (existing != null) {
|
||
// openChat(existing);
|
||
// } else {
|
||
// System.out.println("❌ Failed to open chat. Try again later.");
|
||
// }
|
||
// }
|
||
}
|
||
|
||
case "group", "channel" -> {
|
||
String uuidStr = selected.getString("uuid");
|
||
UUID uuid = UUID.fromString(uuidStr);
|
||
|
||
System.out.println("🔍 Looking for chat with internal_id='" + uuid + "' type='" + type + "'");
|
||
|
||
ChatEntry existing = Session.chatList.stream()
|
||
.filter(c -> c.getId().equals(uuid) && c.getType().equals(type))
|
||
.findFirst()
|
||
.orElse(null);
|
||
|
||
if (existing != null) {
|
||
openChat(existing);
|
||
}else {
|
||
ChatEntry preview = new ChatEntry();
|
||
preview.setId(String.valueOf(uuid));
|
||
preview.setDisplayId(selected.getString("id"));
|
||
preview.setName(selected.getString("name"));
|
||
preview.setType(type);
|
||
|
||
openForeignChat(preview);
|
||
}
|
||
// else {
|
||
// System.out.println("ℹ Trying to join " + type + "...");
|
||
// joinGroupOrChannel(type, uuidStr);
|
||
//
|
||
// refreshChatList();
|
||
// System.out.println("🔄 Rechecking chat list...");
|
||
//
|
||
// existing = Session.chatList.stream()
|
||
// .filter(c -> c.getId().equals(uuid) && c.getType().equals(type))
|
||
// .findFirst()
|
||
// .orElse(null);
|
||
//
|
||
// if (existing != null) {
|
||
// openChat(existing);
|
||
// } else {
|
||
// System.out.println("❌ Failed to open " + type + ". Try again later.");
|
||
// }
|
||
// }
|
||
}
|
||
|
||
case "message" -> {
|
||
String receiverId = selected.getString("receiver_id");
|
||
String receiverType = selected.getString("receiver_type");
|
||
String senderName = selected.optString("sender_name", "Unknown");
|
||
String content = selected.optString("content", "[No content]");
|
||
String time = selected.optString("time", "Unknown time");
|
||
|
||
String context = "";
|
||
if (receiverType.equals("group")) {
|
||
context = "in group: " + selected.optString("group_name", "Unknown group");
|
||
} else if (receiverType.equals("channel")) {
|
||
context = "in channel: " + selected.optString("channel_name", "Unknown channel");
|
||
}
|
||
|
||
System.out.println("📩 Message preview:");
|
||
System.out.println("From: " + senderName);
|
||
if (!context.isEmpty()) System.out.println(context);
|
||
System.out.println("Time: " + time);
|
||
System.out.println("Content: \"" + content + "\"");
|
||
|
||
System.out.println("🔍 Looking for chat with displayId='" + receiverId + "' type='" + receiverType + "'");
|
||
|
||
ChatEntry chat = Session.chatList.stream()
|
||
.filter(c -> c.getDisplayId().equals(receiverId) && c.getType().equals(receiverType))
|
||
.findFirst()
|
||
.orElseGet(() -> fetchChatInfo(receiverId, receiverType));
|
||
|
||
openChat(chat);
|
||
}
|
||
|
||
|
||
default -> System.out.println("No interaction available for type: " + type);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
break;
|
||
|
||
|
||
case "create_group":
|
||
case "create_channel":
|
||
if (response.has("data")) {
|
||
JSONObject chatJson = response.getJSONObject("data");
|
||
|
||
ChatEntry chat = new ChatEntry(
|
||
UUID.fromString(chatJson.getString("internal_id")),
|
||
chatJson.getString("id"),
|
||
chatJson.getString("name"),
|
||
chatJson.optString("image_url", ""),
|
||
chatJson.getString("type"),
|
||
null,
|
||
chatJson.optBoolean("is_owner", false),
|
||
chatJson.optBoolean("is_admin", false)
|
||
);
|
||
|
||
|
||
refreshChatList();
|
||
System.out.println("✅ Created and opening chat...");
|
||
refreshChatList();
|
||
openChat(chat);
|
||
}
|
||
|
||
break;
|
||
|
||
case "get_messages":
|
||
JSONArray messages = response.getJSONObject("data").getJSONArray("messages");
|
||
System.out.println("\n🔓 Messages fetched:");
|
||
System.out.println("─────────────────────────────────────────────");
|
||
for (int i = 0; i < messages.length(); i++) {
|
||
|
||
JSONObject m = messages.getJSONObject(i);
|
||
String senderId = m.getString("sender_id");
|
||
String senderName = m.optString("sender_name", "Other");
|
||
String content = m.getString("content");
|
||
String time = m.getString("send_at");
|
||
|
||
String label = senderId.equals(Session.currentUser.getString("internal_uuid")) ? "You" : senderName;
|
||
System.out.println("[" + time + "] " + label + ": " + content);
|
||
}
|
||
System.out.println("─────────────────────────────────────────────");
|
||
break;
|
||
|
||
|
||
case "logout":
|
||
Session.currentUser = null;
|
||
Session.chatList = null;
|
||
break;
|
||
}
|
||
|
||
} catch (Exception e) {
|
||
System.err.println("❌ Error during send(): " + e.getMessage());
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
public void userMenu(UUID internal_uuid) throws IOException {
|
||
while (true) {
|
||
|
||
|
||
if (Session.backToChatList) {
|
||
Session.backToChatList = false;
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
|
||
System.out.println("\nUser Menu:");
|
||
System.out.println("1. Show chat list");
|
||
System.out.println("2. Search");
|
||
System.out.println("3. Create Channel");
|
||
System.out.println("4. Create group");
|
||
System.out.println("5. View contacts");
|
||
System.out.println("6. Show sidebar menu");
|
||
System.out.println("7. Logout");
|
||
System.out.print("Choose an option: ");
|
||
String choice = scanner.nextLine();
|
||
|
||
switch (choice) {
|
||
case "1" -> {
|
||
Session.inChatListMenu = true;
|
||
showChatListAndSelect();
|
||
Session.inChatListMenu = false;
|
||
}
|
||
case "2" -> search();
|
||
case "3" -> createChannel();
|
||
case "4" -> createGroup();
|
||
case "5" -> showContactList();
|
||
case "6" -> showSidebarMenu();
|
||
case "7" -> {
|
||
logout();
|
||
return;
|
||
}
|
||
default -> System.out.println("Invalid choice.");
|
||
}
|
||
}
|
||
}
|
||
|
||
// public void showContactList() {
|
||
// List<ContactEntry> contacts = Session.contactEntries;
|
||
// if (contacts.isEmpty()) {
|
||
// System.out.println("📭 You have no contacts.");
|
||
// return;
|
||
// }
|
||
//
|
||
// System.out.println("👥 Your Contacts:");
|
||
// for (int i = 0; i < contacts.size(); i++) {
|
||
// System.out.println((i + 1) + ". " + contacts.get(i));
|
||
// }
|
||
//
|
||
// System.out.print("Select a contact (0 to go back): ");
|
||
// int choice = scanner.nextInt();
|
||
// scanner.nextLine();
|
||
//
|
||
// if (choice == 0) return;
|
||
// if (choice < 1 || choice > contacts.size()) {
|
||
// System.out.println("❌ Invalid choice.");
|
||
// return;
|
||
// }
|
||
//
|
||
// ContactEntry selected = contacts.get(choice - 1);
|
||
// System.out.println("\n📇 What do you want to do with " + selected.getProfileName() + "?");
|
||
// System.out.println("1. View Profile");
|
||
// System.out.println("2. Send Message");
|
||
// System.out.print("Enter your choice: ");
|
||
// int action = scanner.nextInt();
|
||
// scanner.nextLine();
|
||
//
|
||
// switch (action) {
|
||
// case 1 -> viewProfile(selected.getContactId());
|
||
// case 2 -> startPrivateChat(selected);
|
||
// default -> System.out.println("❌ Invalid option.");
|
||
// }
|
||
// }
|
||
|
||
public void showContactList() {
|
||
System.out.println("1. View All Contacts");
|
||
System.out.println("2. Search Contacts");
|
||
System.out.println("Choose an option: (0 to go back)");
|
||
int option = scanner.nextInt();
|
||
scanner.nextLine();
|
||
|
||
// Handle invalid input
|
||
while (option < 0 || option > 2) {
|
||
System.out.println("Invalid choice. Try again: ");
|
||
option = scanner.nextInt();
|
||
scanner.nextLine();
|
||
}
|
||
|
||
List<ContactEntry> contacts;
|
||
|
||
if (option == 0) {
|
||
return;
|
||
}
|
||
else if (option == 1) {
|
||
contacts = Session.contactEntries;
|
||
|
||
} else if (option == 2) {
|
||
contacts = new ArrayList<>();
|
||
|
||
System.out.print("Enter name or user ID to search: ");
|
||
String searchTerm = scanner.nextLine();
|
||
|
||
// Handle invalid input
|
||
while (searchTerm.isEmpty()) {
|
||
System.out.print("Search key can not be empty. Try again: ");
|
||
searchTerm = scanner.nextLine();
|
||
}
|
||
|
||
// Send a request to server
|
||
JSONObject request = new JSONObject();
|
||
request.put("action", "search_contacts");
|
||
request.put("user_id", Session.getUserUUID());
|
||
request.put("search_term", searchTerm);
|
||
|
||
JSONObject response = ActionHandler.sendWithResponse(request);
|
||
|
||
if (!response.optString("status", "fail").equals("success")) {
|
||
System.out.println("Failed to search contacts: " + response.optString("message", "Unknown error"));
|
||
return;
|
||
}
|
||
|
||
JSONObject data = response.getJSONObject("data");
|
||
JSONArray contactsJson = data.getJSONArray("contacts");
|
||
|
||
for (int i = 0; i < contactsJson.length(); i++) {
|
||
JSONObject contact = contactsJson.getJSONObject(i);
|
||
|
||
UUID contactId = UUID.fromString(contact.getString("contact_id"));
|
||
String userId = contact.getString("user_id");
|
||
String contact_displayId = contact.getString("contact_display_id");
|
||
String profileName = contact.getString("profile_name");
|
||
String imageUrl = contact.optString("image_url", "");
|
||
boolean isBlocked = contact.getBoolean("is_blocked");
|
||
String lastSeenString = contact.getString("last_seen");
|
||
LocalDateTime lastSeen = null;
|
||
if (lastSeenString != null) {
|
||
lastSeen = LocalDateTime.parse(lastSeenString);
|
||
}
|
||
|
||
contacts.add(new ContactEntry(contactId, userId, contact_displayId, profileName, imageUrl, isBlocked, lastSeen));
|
||
}
|
||
|
||
} else {
|
||
System.out.println("❌ Invalid choice.");
|
||
return;
|
||
}
|
||
|
||
if (contacts.isEmpty()) {
|
||
System.out.println("📭 No contacts found.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("👥 Your Contacts:");
|
||
for (int i = 0; i < contacts.size(); i++) {
|
||
System.out.println((i + 1) + ". " + contacts.get(i));
|
||
}
|
||
|
||
System.out.print("Select a contact (0 to go back): ");
|
||
int choice = scanner.nextInt();
|
||
scanner.nextLine();
|
||
|
||
if (choice == 0) return;
|
||
if (choice < 1 || choice > contacts.size()) {
|
||
System.out.println("❌ Invalid choice.");
|
||
return;
|
||
}
|
||
|
||
ContactEntry selected = contacts.get(choice - 1);
|
||
System.out.println("\n📇 What do you want to do with " + selected.getProfileName() + "?");
|
||
System.out.println("1. View Profile");
|
||
System.out.println("2. Send Message");
|
||
System.out.println("3. Remove Contact");
|
||
System.out.print("Enter your choice: ");
|
||
int action = scanner.nextInt();
|
||
scanner.nextLine();
|
||
|
||
switch (action) {
|
||
case 1 -> viewProfile(selected.getContactId());
|
||
case 2 -> startPrivateChat(selected);
|
||
case 3 -> {
|
||
// Send a request to server
|
||
JSONObject request = new JSONObject();
|
||
request.put("action", "remove_contact");
|
||
request.put("user_id", Session.getUserUUID()); // Current user
|
||
request.put("contact_id", selected.getContactId().toString()); // Contact to remove
|
||
|
||
JSONObject response = ActionHandler.sendWithResponse(request);
|
||
|
||
if ("success".equals(response.optString("status"))) {
|
||
System.out.println("✅ Contact removed successfully.");
|
||
Session.contactEntries.remove(selected); // Remove from local session list
|
||
} else {
|
||
System.out.println("❌ Failed to remove contact: " +
|
||
response.optString("message", "Unknown error"));
|
||
}
|
||
}
|
||
|
||
default -> System.out.println("❌ Invalid option.");
|
||
}
|
||
}
|
||
|
||
|
||
public void viewProfile(UUID targetId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_profile");
|
||
req.put("target_id", targetId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch profile.");
|
||
return;
|
||
}
|
||
|
||
JSONObject data = res.getJSONObject("data");
|
||
String profileName = data.getString("profile_name");
|
||
String userId = data.getString("user_id");
|
||
String bio = data.optString("bio", "(no bio)");
|
||
String imageUrl = data.optString("image_url", "(no image)");
|
||
boolean isOnline = data.getBoolean("is_online");
|
||
String lastSeen = data.getString("last_seen");
|
||
|
||
System.out.println("\n📄 Profile Info:");
|
||
System.out.println("Name: " + profileName);
|
||
System.out.println("User ID: " + userId);
|
||
System.out.println("Bio: " + bio);
|
||
System.out.println("Image: " + imageUrl);
|
||
System.out.println("Status: " + (isOnline ? "🟢 Online" : "🔘 Last seen at " + lastSeen));
|
||
}
|
||
|
||
|
||
public void startPrivateChat(ContactEntry contact) {
|
||
UUID myId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||
UUID contactId = contact.getContactId();
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_or_create_private_chat");
|
||
req.put("user1", myId.toString());
|
||
req.put("user2", contactId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to create or fetch private chat.");
|
||
return;
|
||
}
|
||
|
||
JSONObject data = res.getJSONObject("data");
|
||
UUID chatId = UUID.fromString(data.getString("chat_id"));
|
||
|
||
ChatEntry entry = new ChatEntry(
|
||
chatId,
|
||
contact.getUserId(),
|
||
contact.getProfileName(),
|
||
contact.getImageUrl(),
|
||
"private",
|
||
null,
|
||
false,
|
||
false
|
||
);
|
||
entry.setOtherUserId(contactId);
|
||
|
||
Session.chatList.add(0, entry);
|
||
System.out.println("✅ Chat with " + contact.getProfileName() + " started.");
|
||
|
||
openChat(entry);
|
||
}
|
||
|
||
|
||
|
||
// public void showChatListAndSelect() {
|
||
//
|
||
//
|
||
// List<ChatEntry> chatList = Session.getChatList();
|
||
// if (chatList.isEmpty()) {
|
||
// System.out.println("📭 You have no chats.");
|
||
// return;
|
||
// }
|
||
//
|
||
// System.out.println("\nYour Chats:");
|
||
// for (int i = 0; i < chatList.size(); i++) {
|
||
// ChatEntry entry = chatList.get(i);
|
||
// String last = entry.getLastMessageTime() == null ? "No messages yet" : entry.getLastMessageTime().toString();
|
||
// System.out.printf("%d. [%s] %s - Last: %s\n", i + 1, entry.getType(), entry.getName(), last);
|
||
// }
|
||
//
|
||
// System.out.print("Select a chat by number: ");
|
||
// int choice = Integer.parseInt(scanner.nextLine());
|
||
// if (choice < 1 || choice > chatList.size()) {
|
||
// System.out.println("❌ Invalid choice.");
|
||
// return;
|
||
// }
|
||
//
|
||
// openChat(chatList.get(choice - 1));
|
||
// }
|
||
|
||
|
||
// public void showChatListAndSelect() {
|
||
// if (Session.activeChats == null || Session.activeChats.isEmpty()) {
|
||
// System.out.println("No active chats.");
|
||
// return;
|
||
// }
|
||
//
|
||
// System.out.println("\nYour Chats:");
|
||
// System.out.println("0. 📦 Archived Chats");
|
||
//
|
||
// // Track index dynamically
|
||
// int index = 1;
|
||
//
|
||
// // Check if Saved Messages exists in the list
|
||
// int savedMessagesIndex = -1;
|
||
// for (int i = 0; i < Session.activeChats.size(); i++) {
|
||
// ChatEntry entry = Session.activeChats.get(i);
|
||
//
|
||
// if (entry.isSavedMessages()) {
|
||
// savedMessagesIndex = index;
|
||
// System.out.println(index + ". 📦 Saved Messages Chat");
|
||
// index++;
|
||
// break;
|
||
// }
|
||
// }
|
||
//
|
||
// // Print the rest of the chats
|
||
// for (int i = 0; i < Session.activeChats.size(); i++) {
|
||
// ChatEntry entry = Session.activeChats.get(i);
|
||
// if (entry.isSavedMessages()) {
|
||
// continue; // Already printed above
|
||
// }
|
||
//
|
||
// String time = (entry.getLastMessageTime() == null)
|
||
// ? "No messages yet"
|
||
// : entry.getLastMessageTime().toString();
|
||
// System.out.println(index + ". [" + entry.getType() + "] " +
|
||
// entry.getName() + " - Last: " + time);
|
||
// index++;
|
||
// }
|
||
//
|
||
// System.out.print("Select a chat by number: ");
|
||
// int choice = Integer.parseInt(scanner.nextLine());
|
||
//
|
||
// if (choice == 0) {
|
||
// showArchivedChats();
|
||
// return;
|
||
// }
|
||
//
|
||
// if (choice == savedMessagesIndex) {
|
||
// new SidebarHandler(scanner, this).getSavedMessagesData(Session.getUserUUID());
|
||
// return;
|
||
// }
|
||
//
|
||
// // Adjust for Saved Messages if it was in the list
|
||
// int baseIndex = (savedMessagesIndex != -1 && choice > savedMessagesIndex) ? 1 : 0;
|
||
// int chatIndex = choice - 1 - baseIndex;
|
||
//
|
||
// if (chatIndex < 0 || chatIndex >= Session.activeChats.size()) {
|
||
// System.out.println("Invalid selection.");
|
||
// return;
|
||
// }
|
||
//
|
||
// // Find the actual index of the chat, skipping the saved_messages entry
|
||
// int actualIndex = 0;
|
||
// for (int i = 0; i < Session.activeChats.size(); i++) {
|
||
// if (Session.activeChats.get(i).getType().equalsIgnoreCase("saved_messages")) {
|
||
// continue; // Skip saved_messages
|
||
// }
|
||
// if (actualIndex == chatIndex) {
|
||
// break;
|
||
// }
|
||
// actualIndex++;
|
||
// }
|
||
//
|
||
// ChatEntry selected = Session.activeChats.get(actualIndex);
|
||
// openChat(selected);
|
||
// }
|
||
|
||
|
||
|
||
public void showChatListAndSelect() {
|
||
if (Session.activeChats == null || Session.activeChats.isEmpty()) {
|
||
System.out.println("📭 You have no chats.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("\nYour Chats:");
|
||
System.out.println("0. 📦 Archived Chats");
|
||
|
||
//find save messages chat
|
||
Integer savedIdxInActive = null;
|
||
for (int i = 0; i < Session.activeChats.size(); i++) {
|
||
if (Session.activeChats.get(i).isSavedMessages()) {
|
||
savedIdxInActive = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
Map<Integer, Integer> displayToActive = new HashMap<>();
|
||
|
||
int displayIndex = 1;
|
||
|
||
if (savedIdxInActive != null) {
|
||
ChatEntry saved = Session.activeChats.get(savedIdxInActive);
|
||
String last = (saved.getLastMessageTime() == null) ? "No messages yet" : saved.getLastMessageTime().toString();
|
||
System.out.println(displayIndex + ". 💾 Saved Messages - Last: " + last);
|
||
|
||
displayToActive.put(displayIndex, savedIdxInActive);
|
||
displayIndex++;
|
||
}
|
||
|
||
for (int i = 0; i < Session.activeChats.size(); i++) {
|
||
if (savedIdxInActive != null && i == savedIdxInActive) continue;
|
||
|
||
ChatEntry e = Session.activeChats.get(i);
|
||
String last = (e.getLastMessageTime() == null) ? "No messages yet" : e.getLastMessageTime().toString();
|
||
System.out.println(displayIndex + ". [" + e.getType() + "] " + e.getName() + " - Last: " + last);
|
||
|
||
displayToActive.put(displayIndex, i);
|
||
displayIndex++;
|
||
}
|
||
|
||
System.out.print("Select a chat by number: ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine().trim());
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
if (choice == 0) {
|
||
showArchivedChats();
|
||
return;
|
||
}
|
||
|
||
Integer activeIdx = displayToActive.get(choice);
|
||
if (activeIdx == null) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
ChatEntry selected = Session.activeChats.get(activeIdx);
|
||
openChat(selected);
|
||
}
|
||
|
||
|
||
public void showArchivedChats() {
|
||
if (Session.archivedChats == null || Session.archivedChats.isEmpty()) {
|
||
System.out.println("📭 No archived chats.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("\n📦 Archived Chats:");
|
||
for (int i = 0; i < Session.archivedChats.size(); i++) {
|
||
ChatEntry entry = Session.archivedChats.get(i);
|
||
String time = (entry.getLastMessageTime() == null)
|
||
? "No messages yet"
|
||
: entry.getLastMessageTime().toString();
|
||
System.out.println((i + 1) + ". [" + entry.getType() + "] " +
|
||
entry.getName() + " - Last: " + time);
|
||
}
|
||
|
||
System.out.print("Select a chat by number (or 0 to return): ");
|
||
int choice = Integer.parseInt(scanner.nextLine());
|
||
|
||
if (choice == 0) {
|
||
System.out.println("🔙 Returning to main chat list...");
|
||
return;
|
||
}
|
||
|
||
int index = choice - 1;
|
||
|
||
if (index < 0 || index >= Session.archivedChats.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
ChatEntry selected = Session.archivedChats.get(index);
|
||
openChat(selected);
|
||
}
|
||
|
||
|
||
|
||
|
||
public void openChat(ChatEntry chat) {
|
||
|
||
//for private chats only
|
||
if (chat.getType().equalsIgnoreCase("private")) {
|
||
JSONObject reqTarget = new JSONObject();
|
||
reqTarget.put("action", "get_private_chat_target");
|
||
reqTarget.put("chat_id", chat.getId());
|
||
|
||
JSONObject resTarget = sendWithResponse(reqTarget);
|
||
if (resTarget == null || !resTarget.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch target user for private chat.");
|
||
return;
|
||
}
|
||
String otherUserId = resTarget.getJSONObject("data").getString("target_id");
|
||
chat.setOtherUserId(UUID.fromString(otherUserId));
|
||
}
|
||
|
||
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_messages");
|
||
req.put("receiver_id",chat.getId());
|
||
req.put("receiver_type", chat.getType());
|
||
// String type = chat.getType();
|
||
// UUID chatId = chat.getId();
|
||
// if (type.equals("private")) {
|
||
// UUID myId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||
// UUID otherUserId = chat.getId();
|
||
//
|
||
// JSONObject getChatIdReq = new JSONObject();
|
||
// getChatIdReq.put("action", "get_or_create_private_chat");
|
||
// getChatIdReq.put("user1", myId.toString());
|
||
// getChatIdReq.put("user2", otherUserId.toString());
|
||
//
|
||
// JSONObject chatIdRes = sendWithResponse(getChatIdReq);
|
||
// if (chatIdRes == null || !chatIdRes.getString("status").equals("success")) {
|
||
// System.out.println("❌ Failed to fetch private chat ID.");
|
||
// return;
|
||
// }
|
||
//
|
||
// Session.currentPrivateChatUserId = otherUserId;
|
||
// chatId = UUID.fromString(chatIdRes.getJSONObject("data").getString("chat_id"));
|
||
// chat.setId(String.valueOf(chatId));
|
||
//
|
||
// }
|
||
|
||
|
||
|
||
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch messages.");
|
||
return;
|
||
}
|
||
|
||
JSONArray messages = res.getJSONObject("data").getJSONArray("messages");
|
||
System.out.println("\n🔓 Messages fetched:");
|
||
System.out.println("─────────────────────────────────────────────");
|
||
for (int i = 0; i < messages.length(); i++) {
|
||
JSONObject m = messages.getJSONObject(i);
|
||
String senderId = m.getString("sender_id");
|
||
String senderName = m.optString("sender_name", "Other");
|
||
String content = m.optString("content", "");
|
||
String time = m.getString("send_at");
|
||
|
||
String label = senderId.equals(Session.currentUser.getString("internal_uuid")) ? "You" : senderName;
|
||
System.out.println("[" + time + "] " + label + ": " + content);
|
||
}
|
||
System.out.println("─────────────────────────────────────────────");
|
||
|
||
if (chat.getType().equals("private") && chat.getOtherUserId() == null) {
|
||
for (ContactEntry contact : Session.contactEntries) {
|
||
if (contact.getContactId().equals(chat.getId())) {
|
||
chat.setOtherUserId(contact.getContactId());
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
boolean stayInChat = true;
|
||
|
||
|
||
Session.currentChatId = chat.getId().toString();
|
||
Session.currentChatEntry = chat;
|
||
Session.currentChatType = chat.getType().toLowerCase();
|
||
Session.inChatMenu = true;
|
||
startMenuRefresherThread();
|
||
|
||
|
||
while (stayInChat) {
|
||
if (forceExitChat) {
|
||
System.out.println("⚠️ You have been removed from this chat or chat was deleted. Returning to chat list...");
|
||
forceExitChat = false;
|
||
break;
|
||
}
|
||
|
||
System.out.println("\n📍 Entered Chat:");
|
||
System.out.println("🔷 Name: " + chat.getName());
|
||
System.out.println("────────────────────────────────────────────");
|
||
|
||
switch (chat.getType().trim().toLowerCase()) {
|
||
case "private" -> stayInChat = showPrivateChatMenu(chat);
|
||
case "group" -> stayInChat = showGroupChatMenu(chat);
|
||
case "channel" -> stayInChat = showChannelChatMenu(chat);
|
||
default -> {
|
||
System.out.println("❗ Unknown chat type: " + chat.getType());
|
||
stayInChat = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
Session.inChatMenu = false;
|
||
Session.currentChatId = null;
|
||
Session.currentChatEntry = null;
|
||
Session.currentChatType = null;
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// private boolean showPrivateChatMenu(ChatEntry chat) {
|
||
//
|
||
// if (forceExitChat) {
|
||
// forceExitChat = false;
|
||
// System.out.println("🚪 Exiting chat due to real-time update.");
|
||
// return false;
|
||
// }
|
||
//
|
||
//
|
||
// JSONObject reqTarget = new JSONObject();
|
||
// reqTarget.put("action", "get_private_chat_target");
|
||
// reqTarget.put("chat_id", chat.getId());
|
||
//
|
||
// JSONObject resTarget = sendWithResponse(reqTarget);
|
||
// if (resTarget == null || !resTarget.getString("status").equals("success")) {
|
||
// System.out.println("❌ Failed to fetch target user for private chat.");
|
||
// return false;
|
||
// }
|
||
//
|
||
// String otherUserId = resTarget.getJSONObject("data").getString("target_id");
|
||
// chat.setOtherUserId(UUID.fromString(otherUserId));
|
||
//
|
||
//
|
||
// JSONObject req = new JSONObject();
|
||
// req.put("action", "view_profile");
|
||
// req.put("target_id", chat.getOtherUserId()); // internal UUID
|
||
//
|
||
// JSONObject res = sendWithResponse(req);
|
||
//
|
||
// if (res.getString("status").equals("success")) {
|
||
// JSONObject data = res.getJSONObject("data");
|
||
//
|
||
// System.out.println("\n💬 Private Chat with: " + data.getString("profile_name"));
|
||
//
|
||
// if (data.getBoolean("is_online")) {
|
||
// System.out.println("✅ Status: Online");
|
||
// } else {
|
||
// System.out.println("📅 Last seen: " + data.getString("last_seen"));
|
||
// }
|
||
//
|
||
// System.out.println("────────────────────────────────────────────");
|
||
// }
|
||
//
|
||
//
|
||
// System.out.println("1. Send message");
|
||
// System.out.println("2. Block/Unblock");
|
||
// System.out.println("3. Delete chat (one-sided)");
|
||
// System.out.println("4. Delete chat (both sides)");
|
||
// System.out.println("5. View profile");
|
||
// System.out.println("6. Archive/Unarchived");
|
||
// System.out.println("7. View messages");
|
||
// System.out.println("8. Back");
|
||
//
|
||
//
|
||
// String input = scanner.nextLine();
|
||
// switch (input) {
|
||
// case "1" -> sendMessage(chat.getId(), "private");
|
||
// case "2" -> toggleBlock(chat.getOtherUserId());
|
||
// case "3" -> {
|
||
// deleteChat(chat.getId(), false);
|
||
// return true;
|
||
// }
|
||
// case "4" -> {
|
||
// deleteChat(chat.getId(), true);
|
||
// return true;
|
||
// }
|
||
// case "5" -> {
|
||
// JSONObject reqProfile = new JSONObject();
|
||
// reqProfile.put("action", "view_profile");
|
||
// reqProfile.put("target_id", chat.getOtherUserId());
|
||
//
|
||
// JSONObject resProfile = sendWithResponse(reqProfile);
|
||
//
|
||
// if (resProfile.getString("status").equals("success")) {
|
||
// JSONObject profile = resProfile.getJSONObject("data");
|
||
// System.out.println("\n👤 Profile Info:");
|
||
// System.out.println("🔷 Name: " + profile.optString("profile_name", "Unknown"));
|
||
// System.out.println("📄 Bio: " + profile.optString("bio", "No bio set"));
|
||
// System.out.println("🖼️ Image URL: " + profile.optString("image_url", "N/A"));
|
||
//
|
||
// if (profile.getBoolean("is_online")) {
|
||
// System.out.println("✅ Status: Online");
|
||
// } else {
|
||
// System.out.println("📅 Last seen: " + profile.optString("last_seen", "Unknown"));
|
||
// }
|
||
// System.out.println("────────────────────────────────────────────");
|
||
// } else {
|
||
// System.out.println("❌ Could not load profile.");
|
||
// }
|
||
// return true;
|
||
// }
|
||
//
|
||
// case "6" ->{
|
||
// toggleArchive(chat.getId() , "private");
|
||
//
|
||
// return true;
|
||
// }
|
||
// case "7" ->{
|
||
// viewMessagesInChat(chat);
|
||
// }
|
||
//
|
||
// case "8" -> {
|
||
// return false;
|
||
// }
|
||
// default -> System.out.println("Invalid choice.");
|
||
// }
|
||
// return true;
|
||
// }
|
||
|
||
|
||
public boolean showPrivateChatMenu(ChatEntry chat) {
|
||
|
||
if (forceExitChat) {
|
||
forceExitChat = false;
|
||
System.out.println("🚪 Exiting chat due to real-time update.");
|
||
return false;
|
||
}
|
||
|
||
UUID chatId = chat.getId();
|
||
|
||
if (chat.getOtherUserId() == null) {
|
||
JSONObject reqTarget = new JSONObject()
|
||
.put("action", "get_private_chat_target")
|
||
.put("chat_id", chatId.toString());
|
||
|
||
JSONObject resTarget = sendWithResponse(reqTarget);
|
||
if (resTarget == null || !"success".equals(resTarget.optString("status"))) {
|
||
System.out.println("❌ Failed to fetch target user for private chat.");
|
||
return false;
|
||
}
|
||
chat.setOtherUserId(UUID.fromString(resTarget.getJSONObject("data").getString("target_id")));
|
||
}
|
||
|
||
UUID me = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||
boolean isSaved = chat.isSavedMessages() || me.equals(chat.getOtherUserId());
|
||
|
||
System.out.println();
|
||
if (isSaved) {
|
||
System.out.println("💬 Private Chat with: Saved Messages");
|
||
System.out.println("────────────────────────────────────────────");
|
||
} else {
|
||
JSONObject req = new JSONObject()
|
||
.put("action", "view_profile")
|
||
.put("target_id", chat.getOtherUserId());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null && "success".equals(res.optString("status"))) {
|
||
JSONObject data = res.getJSONObject("data");
|
||
System.out.println("\n💬 Private Chat with: " + data.optString("profile_name", chat.getName()));
|
||
if (data.optBoolean("is_online", false)) System.out.println("✅ Status: Online");
|
||
else System.out.println("📅 Last seen: " + data.optString("last_seen", "Unknown"));
|
||
System.out.println("────────────────────────────────────────────");
|
||
}
|
||
}
|
||
|
||
if (isSaved) {
|
||
System.out.println("1. Send message");
|
||
System.out.println("2. View messages");
|
||
System.out.println("3. Back");
|
||
|
||
String input = scanner.nextLine().trim();
|
||
switch (input) {
|
||
case "1" -> sendMessageInteractive(chatId, "private");
|
||
case "2" -> { viewMessagesInChat(chat); }
|
||
case "3" -> { return false; }
|
||
default -> System.out.println("Invalid choice.");
|
||
}
|
||
return true;
|
||
}
|
||
|
||
System.out.println("1. Send message");
|
||
System.out.println("2. Block/Unblock");
|
||
System.out.println("3. Delete chat (one-sided)");
|
||
System.out.println("4. Delete chat (both sides)");
|
||
System.out.println("5. View profile");
|
||
System.out.println("6. Archive/Unarchived");
|
||
System.out.println("7. View messages");
|
||
System.out.println("8. Back");
|
||
|
||
String input = scanner.nextLine().trim();
|
||
switch (input) {
|
||
case "1" -> sendMessageInteractive(chat.getId(), "private");
|
||
case "2" -> toggleBlock(chat.getOtherUserId());
|
||
case "3" -> { deleteChat(chatId, false); return true; }
|
||
case "4" -> { deleteChat(chatId, true); return true; }
|
||
case "5" -> {
|
||
JSONObject reqProfile = new JSONObject()
|
||
.put("action", "view_profile")
|
||
.put("target_id", chat.getOtherUserId());
|
||
|
||
JSONObject resProfile = sendWithResponse(reqProfile);
|
||
if (resProfile != null && "success".equals(resProfile.optString("status"))) {
|
||
JSONObject profile = resProfile.getJSONObject("data");
|
||
System.out.println("\n👤 Profile Info:");
|
||
System.out.println("🔷 Name: " + profile.optString("profile_name", "Unknown"));
|
||
System.out.println("📄 Bio: " + profile.optString("bio", "No bio set"));
|
||
System.out.println("🖼️ Image URL: " + profile.optString("image_url", "N/A"));
|
||
if (profile.optBoolean("is_online", false)) System.out.println("✅ Status: Online");
|
||
else System.out.println("📅 Last seen: " + profile.optString("last_seen", "Unknown"));
|
||
System.out.println("────────────────────────────────────────────");
|
||
} else {
|
||
System.out.println("❌ Could not load profile.");
|
||
}
|
||
return true;
|
||
}
|
||
case "6" -> { toggleArchive(chatId, "private"); return true; }
|
||
case "7" -> { viewMessagesInChat(chat); break; }
|
||
case "8" -> { return false; }
|
||
default -> System.out.println("Invalid choice.");
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
public JSONObject getGroupPermissions(UUID groupId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_group_permissions");
|
||
req.put("group_id", groupId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
return new JSONObject();
|
||
}
|
||
return res.getJSONObject("data");
|
||
}
|
||
|
||
|
||
|
||
public boolean showGroupChatMenu(ChatEntry chat) {
|
||
if (forceExitChat) {
|
||
forceExitChat = false;
|
||
System.out.println("🚪 Exiting chat due to real-time update.");
|
||
return false;
|
||
}
|
||
|
||
boolean isAdmin = chat.isAdmin();
|
||
boolean isOwner = chat.isOwner();
|
||
JSONObject perms = getGroupPermissions(chat.getId());
|
||
|
||
System.out.println("\n--- Group Chat Menu ---");
|
||
System.out.println("1. Send Message");
|
||
System.out.println("2. View Members");
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
|
||
System.out.println("3. Add Member");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_edit_group", false))) {
|
||
System.out.println("4. Edit Group Info");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
|
||
System.out.println("5. Add Admin");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
|
||
System.out.println("6. Remove Admin");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
|
||
System.out.println("7. Remove member");
|
||
}
|
||
if (isOwner) {
|
||
System.out.println("8. Delete Group");
|
||
System.out.println("9. Leave Group (Transfer ownership required)");
|
||
} else {
|
||
System.out.println("9. Leave Group");
|
||
}
|
||
System.out.println("10. View Profile");
|
||
|
||
if (isOwner) {
|
||
System.out.println("11. Edit Admin Permissions");
|
||
}
|
||
|
||
System.out.println("12. Archive/Unarchived");
|
||
System.out.println("13. View messages");
|
||
|
||
System.out.println("0. Back to Chat List");
|
||
|
||
String input = scanner.nextLine();
|
||
switch (input) {
|
||
case "1" -> sendMessageInteractive(chat.getId(), "group");
|
||
case "2" -> viewGroupMembers(chat.getId());
|
||
case "3" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false)))
|
||
searchEligibleUsers("group", chat.getId());
|
||
else System.out.println("❌ You don't have permission.");
|
||
}
|
||
case "4" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_edit_group", false))) editGroupInfo(chat.getId());
|
||
else System.out.println("❌ You don't have permission.");
|
||
}
|
||
case "5" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) addAdminToGroup(chat.getId());
|
||
else System.out.println("❌ You don't have permission.");
|
||
}
|
||
case "6" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) removeAdminFromGroup(chat.getId());
|
||
else System.out.println("❌ You don't have permission.");
|
||
}
|
||
case "7" ->{
|
||
if(isOwner || (isAdmin && perms.optBoolean("can_remove_members",false))) removeMemberFromGroup(chat.getId());
|
||
}
|
||
case "8" -> {
|
||
if (isOwner) deleteGroup(chat.getId());
|
||
else System.out.println("❌ You don't have permission.");
|
||
return false;
|
||
}
|
||
case "9" -> {
|
||
if (isOwner) {
|
||
transferOwnershipAndLeave(chat.getId());
|
||
} else {
|
||
leaveChat(chat.getId(), "group");
|
||
//refreshChatList();
|
||
}
|
||
return false;
|
||
}
|
||
case "10" ->{
|
||
GroupInfo(chat.getId());
|
||
}
|
||
case "11" -> {
|
||
if (isOwner) {
|
||
editAdminPermissions(chat.getId(), "group");
|
||
}
|
||
}
|
||
|
||
case "12"->{
|
||
toggleArchive(chat.getId() , "group");
|
||
}
|
||
|
||
case "13" ->{
|
||
viewMessagesInChat(chat);
|
||
}
|
||
|
||
case "0" -> {
|
||
return false;
|
||
}
|
||
default -> System.out.println("Invalid choice.");
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
|
||
public boolean showChannelChatMenu(ChatEntry chat) {
|
||
if (forceExitChat) {
|
||
forceExitChat = false;
|
||
System.out.println("🚪 Exiting chat due to real-time update.");
|
||
return false;
|
||
}
|
||
|
||
chat = fetchChatInfo(chat.getId().toString(), chat.getType());
|
||
boolean isAdmin = chat.isAdmin();
|
||
boolean isOwner = chat.isOwner();
|
||
|
||
JSONObject perms = getChannelPermissions(chat.getId());
|
||
|
||
System.out.println("\n--- Channel Menu ---");
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
|
||
System.out.println("1. Send Post");
|
||
}
|
||
|
||
if (isOwner || isAdmin) {
|
||
System.out.println("2. View Subscribers");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
|
||
System.out.println("3. Add Subscriber");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
|
||
System.out.println("4. Remove Subscriber");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_edit_channel", false))) {
|
||
System.out.println("5. Edit Channel Info");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
|
||
System.out.println("6. Add Admin");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
|
||
System.out.println("7. Remove Admin");
|
||
}
|
||
|
||
if (isOwner) {
|
||
System.out.println("8. Delete Channel");
|
||
System.out.println("9. Leave Channel (Transfer ownership required)");
|
||
} else {
|
||
System.out.println("8. Leave Channel");
|
||
}
|
||
|
||
System.out.println("10. View Profile");
|
||
if (isOwner) {
|
||
System.out.println("11. Edit Admin Permissions");
|
||
}
|
||
|
||
System.out.println("12. Archive/Unarchived");
|
||
System.out.println("13. View messages");
|
||
System.out.println("0. Back to Chat List");
|
||
|
||
String input = scanner.nextLine();
|
||
switch (input) {
|
||
case "1" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
|
||
sendMessageInteractive(chat.getId(), "channel");
|
||
} else {
|
||
System.out.println("❌ You don't have permission to post.");
|
||
}
|
||
}
|
||
case "2" -> {
|
||
if (isOwner || isAdmin) {
|
||
viewChannelSubscribers(chat.getId());
|
||
} else {
|
||
System.out.println("❌ You don't have permission to view subscribers.");
|
||
}
|
||
}
|
||
case "3" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
|
||
searchEligibleUsers("channel", chat.getId());
|
||
} else {
|
||
System.out.println("❌ You don't have permission to add subscribers.");
|
||
}
|
||
}
|
||
case "4" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
|
||
removeSubscriberFromChannel(chat.getId());
|
||
} else {
|
||
System.out.println("❌ You don't have permission to remove subscribers.");
|
||
}
|
||
}
|
||
case "5" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_edit_channel", false))) {
|
||
editChannelInfo(chat.getId());
|
||
} else {
|
||
System.out.println("❌ You don't have permission to edit channel info.");
|
||
}
|
||
}
|
||
case "6" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
|
||
addAdminToChannel(chat.getId());
|
||
} else {
|
||
System.out.println("❌ You don't have permission to add admins.");
|
||
}
|
||
}
|
||
case "7" -> {
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
|
||
removeAdminFromChannel(chat.getId());
|
||
} else {
|
||
System.out.println("❌ You don't have permission to remove admins.");
|
||
}
|
||
}
|
||
case "8" -> {
|
||
if (isOwner) {
|
||
deleteChannel(chat.getId());
|
||
return false;
|
||
} else {
|
||
leaveChat(chat.getId(), "channel");
|
||
return false;
|
||
}
|
||
}
|
||
case "9" -> {
|
||
if (isOwner) {
|
||
transferChannelOwnershipAndLeave(chat.getId());
|
||
return false;
|
||
} else {
|
||
System.out.println("❌ You don't have permission.");
|
||
}
|
||
}
|
||
case "10"->{
|
||
ChannelInfo(chat.getId());
|
||
}
|
||
case "11" -> {
|
||
if (isOwner) {
|
||
editAdminPermissions(chat.getId(), "channel");
|
||
}
|
||
}
|
||
|
||
case "12"->{
|
||
toggleArchive(chat.getId() , "channel");
|
||
}
|
||
case "13" ->{
|
||
viewMessagesInChat(chat);
|
||
}
|
||
|
||
case "0" -> {
|
||
return false;
|
||
}
|
||
default -> System.out.println("Invalid choice.");
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public void transferOwnershipAndLeave(UUID groupId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_group_admins");
|
||
req.put("group_id", groupId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch admins.");
|
||
return;
|
||
}
|
||
|
||
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||
|
||
if (admins.length() == 0) {
|
||
System.out.println("⚠️ No other admins available. You cannot leave without promoting someone to owner.");
|
||
return;
|
||
}
|
||
|
||
UUID currentUserId = UUID.fromString(Session.getUserUUID());
|
||
boolean success = false;
|
||
|
||
while (!success) {
|
||
System.out.println("\n--- Admins List ---");
|
||
for (int i = 0; i < admins.length(); i++) {
|
||
JSONObject admin = admins.getJSONObject(i);
|
||
System.out.printf("%d. %s (%s)%s\n", i + 1,
|
||
admin.getString("profile_name"),
|
||
admin.getString("user_id"),
|
||
admin.getString("user_id").equals(currentUserId.toString()) ? " 👑 (You)" : "");
|
||
}
|
||
System.out.println("0. Cancel");
|
||
|
||
System.out.print("Select a new owner by number: ");
|
||
String input = scanner.nextLine().trim();
|
||
|
||
if (input.equals("0")) {
|
||
System.out.println("❌ Ownership transfer canceled.");
|
||
return;
|
||
}
|
||
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(input) - 1;
|
||
} catch (NumberFormatException e) {
|
||
System.out.println("❗ Invalid input. Please enter a number.");
|
||
continue;
|
||
}
|
||
|
||
if (choice < 0 || choice >= admins.length()) {
|
||
System.out.println("❗ Invalid selection. Please try again.");
|
||
continue;
|
||
}
|
||
|
||
JSONObject selected = admins.getJSONObject(choice);
|
||
String newOwnerId = selected.getString("user_id");
|
||
|
||
if (newOwnerId.equals(currentUserId.toString())) {
|
||
System.out.println("⚠️ You cannot transfer ownership to yourself. Please select a different admin.");
|
||
continue;
|
||
}
|
||
|
||
JSONObject promoteReq = new JSONObject();
|
||
promoteReq.put("action", "transfer_group_ownership");
|
||
promoteReq.put("group_id", groupId.toString());
|
||
promoteReq.put("new_owner_user_id", newOwnerId);
|
||
|
||
JSONObject promoteRes = sendWithResponse(promoteReq);
|
||
if (promoteRes == null || !promoteRes.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to transfer ownership.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("✅ Ownership transferred successfully.");
|
||
success = true;
|
||
}
|
||
|
||
leaveChat(groupId, "group");
|
||
}
|
||
|
||
|
||
public void removeMemberFromGroup(UUID groupId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_group_members");
|
||
req.put("group_id", groupId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch members.");
|
||
return;
|
||
}
|
||
|
||
JSONArray members = res.getJSONObject("data").getJSONArray("members");
|
||
List<JSONObject> eligible = new ArrayList<>();
|
||
|
||
System.out.println("\n--- Members List ---");
|
||
for (int i = 0; i < members.length(); i++) {
|
||
JSONObject m = members.getJSONObject(i);
|
||
String role = m.getString("role");
|
||
String profileName = m.getString("profile_name");
|
||
String userId = m.getString("user_id");
|
||
|
||
if (role.equals("owner")) continue;
|
||
|
||
eligible.add(m);
|
||
System.out.println((eligible.size()) + ". " + profileName + " (" + userId + ") [" + role + "]");
|
||
}
|
||
|
||
if (eligible.isEmpty()) {
|
||
System.out.println("⚠️ No removable members.");
|
||
return;
|
||
}
|
||
|
||
System.out.print("Select a member to remove: ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid input.");
|
||
return;
|
||
}
|
||
|
||
if (choice < 0 || choice >= eligible.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = eligible.get(choice);
|
||
String targetInternalUUID = selected.getString("internal_uuid");
|
||
|
||
JSONObject removeReq = new JSONObject();
|
||
removeReq.put("action", "remove_member_from_group");
|
||
removeReq.put("group_id", groupId.toString());
|
||
removeReq.put("user_id", targetInternalUUID);
|
||
|
||
JSONObject removeRes = sendWithResponse(removeReq);
|
||
if (removeRes != null)
|
||
System.out.println(removeRes.getString("message"));
|
||
}
|
||
|
||
|
||
|
||
public void addAdminToChannel(UUID channelId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_channel_subscribers");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch subscribers.");
|
||
return;
|
||
}
|
||
|
||
JSONArray subscribers = res.getJSONObject("data").getJSONArray("subscribers");
|
||
List<JSONObject> eligible = new ArrayList<>();
|
||
|
||
System.out.println("\n--- Subscribers List ---");
|
||
for (int i = 0; i < subscribers.length(); i++) {
|
||
JSONObject s = subscribers.getJSONObject(i);
|
||
String role = s.getString("role");
|
||
String profileName = s.getString("profile_name");
|
||
String userId = s.getString("user_id");
|
||
|
||
if (role.equals("subscriber")) {
|
||
eligible.add(s);
|
||
System.out.printf("%d. %s (%s)\n", eligible.size(), profileName, userId);
|
||
}
|
||
}
|
||
|
||
if (eligible.isEmpty()) {
|
||
System.out.println("⚠️ No eligible subscribers to promote.");
|
||
return;
|
||
}
|
||
|
||
System.out.print("Select a subscriber to promote to admin: ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid input.");
|
||
return;
|
||
}
|
||
|
||
if (choice < 0 || choice >= eligible.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = eligible.get(choice);
|
||
String targetInternalUUID = selected.getString("internal_uuid");
|
||
|
||
JSONObject permissions = new JSONObject();
|
||
System.out.print("Can post? (true/false): ");
|
||
permissions.put("can_post", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can edit channel info? (true/false): ");
|
||
permissions.put("can_edit_channel", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can add members? (true/false): ");
|
||
permissions.put("can_add_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can remove members? (true/false): ");
|
||
permissions.put("can_remove_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can add admins? (true/false): ");
|
||
permissions.put("can_add_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can remove admins? (true/false): ");
|
||
permissions.put("can_remove_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
JSONObject promoteReq = new JSONObject();
|
||
promoteReq.put("action", "add_admin_to_channel");
|
||
promoteReq.put("channel_id", channelId.toString());
|
||
promoteReq.put("target_user_id", targetInternalUUID);
|
||
promoteReq.put("permissions", permissions);
|
||
|
||
JSONObject promoteRes = sendWithResponse(promoteReq);
|
||
if (promoteRes != null)
|
||
System.out.println(promoteRes.getString("message"));
|
||
}
|
||
|
||
|
||
|
||
|
||
public void addAdminToGroup(UUID groupId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_group_members");
|
||
req.put("group_id", groupId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch members.");
|
||
return;
|
||
}
|
||
|
||
JSONArray members = res.getJSONObject("data").getJSONArray("members");
|
||
List<JSONObject> eligible = new ArrayList<>();
|
||
|
||
System.out.println("\n--- Members List ---");
|
||
for (int i = 0; i < members.length(); i++) {
|
||
JSONObject m = members.getJSONObject(i);
|
||
if (m.getString("role").equals("member")) {
|
||
eligible.add(m);
|
||
System.out.println((eligible.size()) + ". " + m.getString("profile_name") + " (" + m.getString("user_id") + ")");
|
||
}
|
||
}
|
||
|
||
if (eligible.isEmpty()) {
|
||
System.out.println("⚠️ No eligible members.");
|
||
return;
|
||
}
|
||
|
||
System.out.print("Select a member to promote: ");
|
||
int choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
if (choice < 0 || choice >= eligible.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = eligible.get(choice);
|
||
String targetInternalUUID = selected.getString("internal_uuid");
|
||
|
||
JSONObject permissions = new JSONObject();
|
||
System.out.print("Can add members? (true/false): ");
|
||
permissions.put("can_add_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can remove members? (true/false): ");
|
||
permissions.put("can_remove_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can add admins? (true/false): ");
|
||
permissions.put("can_add_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can remove admins? (true/false): ");
|
||
permissions.put("can_remove_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
System.out.print("Can edit group info? (true/false): ");
|
||
permissions.put("can_edit_group", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
JSONObject promoteReq = new JSONObject();
|
||
promoteReq.put("action", "add_admin_to_group");
|
||
promoteReq.put("group_id", groupId.toString());
|
||
promoteReq.put("user_id", targetInternalUUID);
|
||
promoteReq.put("permissions", permissions);
|
||
|
||
JSONObject promoteRes = sendWithResponse(promoteReq);
|
||
if (promoteRes != null)
|
||
System.out.println(promoteRes.getString("message"));
|
||
}
|
||
|
||
|
||
public void viewGroupMembers(UUID groupId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_group_members");
|
||
req.put("group_id", groupId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null) return;
|
||
|
||
if (res.getString("status").equals("success")) {
|
||
JSONArray members = res.getJSONObject("data").getJSONArray("members");
|
||
|
||
System.out.println("\n--- Group Members ---");
|
||
for (int i = 0; i < members.length(); i++) {
|
||
JSONObject m = members.getJSONObject(i);
|
||
String name = m.getString("profile_name");
|
||
String userId = m.getString("user_id");
|
||
String role = m.getString("role");
|
||
System.out.printf("- %s (ID: %s) [%s]\n", name, userId, role);
|
||
}
|
||
} else {
|
||
System.out.println("❌ Failed to fetch members.");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public void removeSubscriberFromChannel(UUID channelId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_channel_subscribers");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch subscribers.");
|
||
return;
|
||
}
|
||
|
||
JSONArray subscribers = res.getJSONObject("data").getJSONArray("subscribers");
|
||
List<JSONObject> eligible = new ArrayList<>();
|
||
|
||
System.out.println("\n--- Subscribers List ---");
|
||
for (int i = 0; i < subscribers.length(); i++) {
|
||
JSONObject s = subscribers.getJSONObject(i);
|
||
String role = s.getString("role");
|
||
String profileName = s.getString("profile_name");
|
||
String userId = s.getString("user_id");
|
||
|
||
if (role.equals("owner")) continue;
|
||
|
||
eligible.add(s);
|
||
System.out.println((eligible.size()) + ". " + profileName + " (" + userId + ") [" + role + "]");
|
||
}
|
||
|
||
if (eligible.isEmpty()) {
|
||
System.out.println("⚠️ No removable subscribers.");
|
||
return;
|
||
}
|
||
|
||
System.out.print("Select a subscriber to remove: ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid input.");
|
||
return;
|
||
}
|
||
|
||
if (choice < 0 || choice >= eligible.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = eligible.get(choice);
|
||
String targetInternalUUID = selected.getString("internal_uuid");
|
||
|
||
JSONObject removeReq = new JSONObject();
|
||
removeReq.put("action", "remove_subscriber_from_channel");
|
||
removeReq.put("channel_id", channelId.toString());
|
||
removeReq.put("user_id", targetInternalUUID);
|
||
|
||
JSONObject removeRes = sendWithResponse(removeReq);
|
||
if (removeRes != null)
|
||
System.out.println(removeRes.getString("message"));
|
||
}
|
||
|
||
|
||
public void transferChannelOwnershipAndLeave(UUID channelId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_channel_admins");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch admins.");
|
||
return;
|
||
}
|
||
|
||
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||
|
||
if (admins.length() == 0) {
|
||
System.out.println("⚠️ No admins available. You cannot leave without transferring ownership.");
|
||
return;
|
||
}
|
||
|
||
UUID currentUserId = UUID.fromString(Session.getUserUUID());
|
||
boolean success = false;
|
||
|
||
while (!success) {
|
||
System.out.println("\n--- Admins List ---");
|
||
for (int i = 0; i < admins.length(); i++) {
|
||
JSONObject admin = admins.getJSONObject(i);
|
||
System.out.printf("%d. %s (%s)%s\n", i + 1,
|
||
admin.getString("profile_name"),
|
||
admin.getString("user_id"),
|
||
admin.getString("internal_uuid").equals(currentUserId.toString()) ? " 👑 (You)" : "");
|
||
}
|
||
System.out.println("0. Cancel");
|
||
|
||
System.out.print("Select a new owner by number: ");
|
||
String input = scanner.nextLine().trim();
|
||
|
||
if (input.equals("0")) {
|
||
System.out.println("❌ Ownership transfer canceled.");
|
||
return;
|
||
}
|
||
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(input) - 1;
|
||
} catch (NumberFormatException e) {
|
||
System.out.println("❗ Invalid input. Please enter a number.");
|
||
continue;
|
||
}
|
||
|
||
if (choice < 0 || choice >= admins.length()) {
|
||
System.out.println("❗ Invalid selection. Please try again.");
|
||
continue;
|
||
}
|
||
|
||
JSONObject selected = admins.getJSONObject(choice);
|
||
String newOwnerId = selected.getString("internal_uuid");
|
||
|
||
if (newOwnerId.equals(currentUserId.toString())) {
|
||
System.out.println("⚠️ You cannot transfer ownership to yourself. Please select a different admin.");
|
||
continue;
|
||
}
|
||
|
||
// Send transfer request
|
||
JSONObject promoteReq = new JSONObject();
|
||
promoteReq.put("action", "transfer_channel_ownership");
|
||
promoteReq.put("channel_id", channelId.toString());
|
||
promoteReq.put("new_owner_user_id", newOwnerId);
|
||
|
||
JSONObject promoteRes = sendWithResponse(promoteReq);
|
||
if (promoteRes == null || !promoteRes.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to transfer ownership.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("✅ Ownership transferred successfully.");
|
||
success = true; // Break loop
|
||
}
|
||
|
||
// Continue execution after successful ownership transfer
|
||
leaveChat(channelId, "channel");
|
||
}
|
||
|
||
|
||
|
||
public void deleteChannel(UUID channelId) {
|
||
System.out.print("Are you sure you want to delete the channel? (yes/no): ");
|
||
String confirm = scanner.nextLine().trim().toLowerCase();
|
||
|
||
if (!confirm.equals("yes")) {
|
||
System.out.println("❌ Delete cancelled.");
|
||
return;
|
||
}
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "delete_channel");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null && res.getString("status").equals("success")) {
|
||
System.out.println("✅ Channel deleted successfully.");
|
||
refreshChatList();
|
||
} else {
|
||
System.out.println("❌ Failed to delete channel.");
|
||
}
|
||
}
|
||
|
||
|
||
public void deleteGroup(UUID groupId) {
|
||
System.out.print("Are you sure you want to delete the group? (yes/no): ");
|
||
String confirm = scanner.nextLine().trim().toLowerCase();
|
||
|
||
if (!confirm.equals("yes")) {
|
||
System.out.println("❌ Delete cancelled.");
|
||
return;
|
||
}
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "delete_group");
|
||
req.put("group_id", groupId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null && res.getString("status").equals("success")) {
|
||
System.out.println("✅ Group deleted successfully.");
|
||
refreshChatList();
|
||
} else {
|
||
System.out.println("❌ Failed to delete group.");
|
||
}
|
||
}
|
||
|
||
public void deleteChat(UUID targetId, boolean both) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "delete_private_chat");
|
||
req.put("chat_id", targetId.toString());
|
||
req.put("both", both);
|
||
send(req);
|
||
|
||
JSONObject resp = sendWithResponse(req);
|
||
if (resp.getString("status").equals("success")) {
|
||
System.out.println("✅ Chat deleted successfully.");
|
||
} else {
|
||
System.out.println("⚠️ Failed to delete chat.");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
public void toggleBlock(UUID userId) {
|
||
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "toggle_block");
|
||
req.put("user_id", Session.getUserUUID());
|
||
req.put("target_id", userId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null) return;
|
||
|
||
String status = res.getString("status");
|
||
String message = res.getString("message");
|
||
|
||
if (status.equals("success")) {
|
||
System.out.println("🔒 " + message);
|
||
} else {
|
||
System.out.println("❌ " + message);
|
||
}
|
||
}
|
||
|
||
|
||
public void leaveChat(UUID id, String type) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "leave_chat");
|
||
req.put("user_id", Session.getUserUUID());
|
||
req.put("chat_id", id.toString());
|
||
req.put("chat_type", type);
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null) return;
|
||
|
||
String status = res.getString("status");
|
||
String message = res.getString("message");
|
||
|
||
if (status.equals("success")) {
|
||
System.out.println("✅ You left the chat.");
|
||
} else {
|
||
System.out.println("❌ " + message);
|
||
}
|
||
}
|
||
|
||
|
||
public void removeAdminFromGroup(UUID groupId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_group_admins");
|
||
req.put("group_id", groupId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch admins.");
|
||
return;
|
||
}
|
||
|
||
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||
List<JSONObject> eligible = new ArrayList<>();
|
||
|
||
System.out.println("\n--- Admins List ---");
|
||
for (int i = 0; i < admins.length(); i++) {
|
||
JSONObject admin = admins.getJSONObject(i);
|
||
String role = admin.getString("role");
|
||
String profileName = admin.getString("profile_name");
|
||
String userId = admin.getString("user_id");
|
||
|
||
if (!role.equals("owner")) {
|
||
eligible.add(admin);
|
||
System.out.printf("%d. %s (%s)\n", eligible.size(), profileName, userId);
|
||
}
|
||
}
|
||
|
||
if (eligible.isEmpty()) {
|
||
System.out.println("⚠️ No removable admins.");
|
||
return;
|
||
}
|
||
|
||
System.out.print("Select an admin to remove: ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid input.");
|
||
return;
|
||
}
|
||
|
||
if (choice < 0 || choice >= eligible.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = eligible.get(choice);
|
||
String targetInternalUUID = selected.getString("user_id");
|
||
|
||
JSONObject removeReq = new JSONObject();
|
||
removeReq.put("action", "remove_admin_from_group");
|
||
removeReq.put("group_id", groupId.toString());
|
||
removeReq.put("target_user_id", targetInternalUUID);
|
||
|
||
JSONObject removeRes = sendWithResponse(removeReq);
|
||
if (removeRes != null)
|
||
System.out.println(removeRes.getString("message"));
|
||
}
|
||
|
||
|
||
public void removeAdminFromChannel(UUID channelId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_channel_admins");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch admins.");
|
||
return;
|
||
}
|
||
|
||
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||
List<JSONObject> eligible = new ArrayList<>();
|
||
|
||
System.out.println("\n--- Admins List ---");
|
||
for (int i = 0; i < admins.length(); i++) {
|
||
JSONObject admin = admins.getJSONObject(i);
|
||
String role = admin.getString("role");
|
||
String profileName = admin.getString("profile_name");
|
||
String userId = admin.getString("user_id");
|
||
|
||
if (!role.equals("owner")) {
|
||
eligible.add(admin);
|
||
System.out.printf("%d. %s (%s)\n", eligible.size(), profileName, userId);
|
||
}
|
||
}
|
||
|
||
if (eligible.isEmpty()) {
|
||
System.out.println("⚠️ No removable admins.");
|
||
return;
|
||
}
|
||
|
||
System.out.print("Select an admin to remove: ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid input.");
|
||
return;
|
||
}
|
||
|
||
if (choice < 0 || choice >= eligible.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = eligible.get(choice);
|
||
String targetInternalUUID = selected.getString("internal_uuid");
|
||
|
||
JSONObject removeReq = new JSONObject();
|
||
removeReq.put("action", "remove_admin_from_channel");
|
||
removeReq.put("channel_id", channelId.toString());
|
||
removeReq.put("target_user_id", targetInternalUUID);
|
||
|
||
JSONObject removeRes = sendWithResponse(removeReq);
|
||
if (removeRes != null)
|
||
System.out.println(removeRes.getString("message"));
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public void addMemberToGroup(UUID groupId, UUID userId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "add_member_to_group");
|
||
req.put("group_id", groupId.toString());
|
||
req.put("user_id", userId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null) {
|
||
System.out.println(res.getString("message"));
|
||
}
|
||
}
|
||
|
||
public void addSubscriberToChannel(UUID channelId, UUID targetUserId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "add_subscriber_to_channel");
|
||
req.put("channel_id", channelId.toString());
|
||
req.put("user_id", targetUserId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null) return;
|
||
|
||
if (res.getString("status").equals("success")) {
|
||
System.out.println("✅ Subscriber added successfully.");
|
||
} else {
|
||
System.out.println("❌ " + res.getString("message"));
|
||
}
|
||
}
|
||
|
||
public void GroupInfo(UUID groupId){
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_info");
|
||
req.put("receiver_id", groupId.toString());
|
||
req.put("receiver_type", "group");
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch group info.");
|
||
return;
|
||
}
|
||
|
||
JSONObject data = res.getJSONObject("data");
|
||
|
||
String currentId = data.getString("id");
|
||
String currentName = data.getString("name");
|
||
String currentDesc = data.optString("description", null);
|
||
String currentImage = data.optString("image_url", null);
|
||
|
||
System.out.println("\n--- Group Info ---");
|
||
System.out.println("1. Group ID: " + currentId);
|
||
System.out.println("2. Name: " + currentName);
|
||
System.out.println("3. Description: " + currentDesc);
|
||
System.out.println("4. Image URL: " + currentImage);
|
||
System.out.println("────────────────────────────────────────────");
|
||
|
||
|
||
}
|
||
|
||
public void editGroupInfo(UUID groupId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_info");
|
||
req.put("receiver_id", groupId.toString());
|
||
req.put("receiver_type", "group");
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch group info.");
|
||
return;
|
||
}
|
||
|
||
JSONObject data = res.getJSONObject("data");
|
||
|
||
String currentId = data.getString("id");
|
||
String currentName = data.getString("name");
|
||
String currentDesc = data.optString("description", null);
|
||
String currentImage = data.optString("image_url", null);
|
||
|
||
System.out.println("\n--- Current Group Info ---");
|
||
System.out.println("1. Group ID: " + currentId);
|
||
System.out.println("2. Name: " + currentName);
|
||
System.out.println("3. Description: " + currentDesc);
|
||
System.out.println("4. Image URL: " + currentImage);
|
||
System.out.println("0. Cancel");
|
||
|
||
System.out.print("Select the field you want to edit (0-4): ");
|
||
String choice = scanner.nextLine().trim();
|
||
|
||
String newGroupId = currentId;
|
||
String newName = currentName;
|
||
String newDesc = currentDesc;
|
||
String newImage = currentImage;
|
||
|
||
switch (choice) {
|
||
case "1" -> {
|
||
System.out.print("Enter new Group ID: ");
|
||
newGroupId = scanner.nextLine().trim();
|
||
}
|
||
case "2" -> {
|
||
System.out.print("Enter new Group Name: ");
|
||
newName = scanner.nextLine().trim();
|
||
}
|
||
case "3" -> {
|
||
System.out.print("Enter new Description: ");
|
||
newDesc = scanner.nextLine().trim();
|
||
}
|
||
case "4" -> {
|
||
System.out.print("Enter new Image URL: ");
|
||
newImage = scanner.nextLine().trim();
|
||
}
|
||
case "0" -> {
|
||
System.out.println("Cancelled.");
|
||
return;
|
||
}
|
||
default -> {
|
||
System.out.println("Invalid choice.");
|
||
return;
|
||
}
|
||
}
|
||
|
||
JSONObject editReq = new JSONObject();
|
||
editReq.put("action", "edit_group_info");
|
||
editReq.put("group_id", groupId.toString()); // internal_uuid
|
||
editReq.put("new_group_id", newGroupId);
|
||
editReq.put("name", newName);
|
||
editReq.put("description", newDesc);
|
||
editReq.put("image_url", newImage);
|
||
|
||
JSONObject editRes = sendWithResponse(editReq);
|
||
if (editRes != null)
|
||
System.out.println(editRes.getString("message"));
|
||
}
|
||
|
||
|
||
|
||
public void viewChannelSubscribers(UUID channelId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_channel_subscribers");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null) return;
|
||
|
||
if (res.getString("status").equals("success")) {
|
||
JSONObject data = res.getJSONObject("data");
|
||
JSONArray subs = data.getJSONArray("subscribers");
|
||
|
||
System.out.println("--- Subscribers ---");
|
||
for (int i = 0; i < subs.length(); i++) {
|
||
JSONObject s = subs.getJSONObject(i);
|
||
System.out.println("- " + s.getString("profile_name"));
|
||
}
|
||
} else {
|
||
System.out.println("❌ Failed to load subscribers.");
|
||
}
|
||
}
|
||
|
||
public void ChannelInfo(UUID channelInternalId){
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_info");
|
||
req.put("receiver_id", channelInternalId.toString());
|
||
req.put("receiver_type", "channel");
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch channel info.");
|
||
return;
|
||
}
|
||
|
||
JSONObject data = res.getJSONObject("data");
|
||
|
||
String currentId = data.getString("id");
|
||
String currentName = data.getString("name");
|
||
String currentDesc = data.optString("description", null);
|
||
String currentImage = data.optString("image_url", null);
|
||
|
||
System.out.println("\n--- Channel Info ---");
|
||
System.out.println("1. Channel ID: " + currentId);
|
||
System.out.println("2. Name: " + currentName);
|
||
System.out.println("3. Description: " + currentDesc);
|
||
System.out.println("4. Image URL: " + currentImage);
|
||
System.out.println("────────────────────────────────────────────");
|
||
|
||
}
|
||
|
||
|
||
public void editChannelInfo(UUID channelInternalId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_info");
|
||
req.put("receiver_id", channelInternalId.toString());
|
||
req.put("receiver_type", "channel");
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch channel info.");
|
||
return;
|
||
}
|
||
|
||
JSONObject data = res.getJSONObject("data");
|
||
|
||
String currentId = data.getString("id");
|
||
String currentName = data.getString("name");
|
||
String currentDesc = data.optString("description", null);
|
||
String currentImage = data.optString("image_url", null);
|
||
|
||
System.out.println("\n--- Current Channel Info ---");
|
||
System.out.println("1. Channel ID: " + currentId);
|
||
System.out.println("2. Name: " + currentName);
|
||
System.out.println("3. Description: " + currentDesc);
|
||
System.out.println("4. Image URL: " + currentImage);
|
||
System.out.println("0. Cancel");
|
||
|
||
System.out.print("Select the field you want to edit (0-4): ");
|
||
String choice = scanner.nextLine().trim();
|
||
|
||
String newChannelId = currentId;
|
||
String newName = currentName;
|
||
String newDesc = currentDesc;
|
||
String newImage = currentImage;
|
||
|
||
switch (choice) {
|
||
case "1" -> {
|
||
System.out.print("Enter new Channel ID: ");
|
||
newChannelId = scanner.nextLine().trim();
|
||
}
|
||
case "2" -> {
|
||
System.out.print("Enter new Channel Name: ");
|
||
newName = scanner.nextLine().trim();
|
||
}
|
||
case "3" -> {
|
||
System.out.print("Enter new Description: ");
|
||
newDesc = scanner.nextLine().trim();
|
||
}
|
||
case "4" -> {
|
||
System.out.print("Enter new Image URL: ");
|
||
newImage = scanner.nextLine().trim();
|
||
}
|
||
case "0" -> {
|
||
System.out.println("Cancelled.");
|
||
return;
|
||
}
|
||
default -> {
|
||
System.out.println("Invalid choice.");
|
||
return;
|
||
}
|
||
}
|
||
|
||
JSONObject editReq = new JSONObject();
|
||
editReq.put("action", "edit_channel_info");
|
||
editReq.put("channel_id", channelInternalId.toString()); // internal_uuid
|
||
editReq.put("new_channel_id", newChannelId);
|
||
editReq.put("name", newName);
|
||
editReq.put("description", newDesc);
|
||
editReq.put("image_url", newImage);
|
||
|
||
JSONObject editRes = sendWithResponse(editReq);
|
||
if (editRes != null)
|
||
System.out.println(editRes.getString("message"));
|
||
}
|
||
|
||
|
||
public JSONObject getResponse() {
|
||
try {
|
||
return TelegramClient.responseQueue.take();
|
||
|
||
} catch (InterruptedException e) {
|
||
throw new RuntimeException("Failed to get server response");
|
||
}
|
||
}
|
||
|
||
|
||
public void logout() {
|
||
if (Session.currentUser != null && Session.currentUser.has("user_id")) {
|
||
JSONObject request = new JSONObject();
|
||
request.put("action", "logout");
|
||
request.put("user_id", Session.currentUser.getString("internal_uuid"));
|
||
|
||
send(request);
|
||
Session.currentUser = null;
|
||
Session.chatList = null;
|
||
} else {
|
||
System.out.println("Not logged in.");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public void editAdminPermissions(UUID chatId, String chatType) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", chatType.equals("group") ? "view_group_admins" : "view_channel_admins");
|
||
req.put(chatType + "_id", chatId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch admins.");
|
||
return;
|
||
}
|
||
|
||
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||
List<JSONObject> editableAdmins = new ArrayList<>();
|
||
|
||
System.out.println("\n--- Admins List ---");
|
||
for (int i = 0; i < admins.length(); i++) {
|
||
JSONObject admin = admins.getJSONObject(i);
|
||
if (!admin.getString("role").equals("owner")) {
|
||
editableAdmins.add(admin);
|
||
System.out.printf("%d. %s (%s)\n", editableAdmins.size(),
|
||
admin.getString("profile_name"),
|
||
admin.getString("user_id"));
|
||
}
|
||
}
|
||
|
||
if (editableAdmins.isEmpty()) {
|
||
System.out.println("⚠️ No editable admins found.");
|
||
return;
|
||
}
|
||
|
||
System.out.print("Select an admin to edit permissions: ");
|
||
int choice;
|
||
try {
|
||
choice = Integer.parseInt(scanner.nextLine()) - 1;
|
||
} catch (Exception e) {
|
||
System.out.println("❌ Invalid input.");
|
||
return;
|
||
}
|
||
|
||
if (choice < 0 || choice >= editableAdmins.size()) {
|
||
System.out.println("❌ Invalid selection.");
|
||
return;
|
||
}
|
||
|
||
JSONObject selected = editableAdmins.get(choice);
|
||
String adminId = selected.getString("user_id");
|
||
|
||
JSONObject permissions = new JSONObject();
|
||
|
||
if (chatType.equals("channel")) {
|
||
System.out.print("Can post? (true/false): ");
|
||
permissions.put("can_post", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can edit channel info? (true/false): ");
|
||
permissions.put("can_edit_channel", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can add members? (true/false): ");
|
||
permissions.put("can_add_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can remove members? (true/false): ");
|
||
permissions.put("can_remove_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can add admins? (true/false): ");
|
||
permissions.put("can_add_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can remove admins? (true/false): ");
|
||
permissions.put("can_remove_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
} else {
|
||
System.out.print("Can add members? (true/false): ");
|
||
permissions.put("can_add_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can remove members? (true/false): ");
|
||
permissions.put("can_remove_members", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can add admins? (true/false): ");
|
||
permissions.put("can_add_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can remove admins? (true/false): ");
|
||
permissions.put("can_remove_admins", Boolean.parseBoolean(scanner.nextLine()));
|
||
|
||
System.out.print("Can edit group info? (true/false): ");
|
||
permissions.put("can_edit_group", Boolean.parseBoolean(scanner.nextLine()));
|
||
}
|
||
|
||
JSONObject updateReq = new JSONObject();
|
||
updateReq.put("action", "edit_admin_permissions");
|
||
updateReq.put("chat_id", chatId.toString());
|
||
updateReq.put("chat_type", chatType);
|
||
updateReq.put("admin_id", adminId);
|
||
updateReq.put("permissions", permissions);
|
||
|
||
JSONObject updateRes = sendWithResponse(updateReq);
|
||
if (updateRes != null)
|
||
System.out.println(updateRes.getString("message"));
|
||
}
|
||
|
||
|
||
public void viewChannelAdmins(UUID channelId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_channel_admins");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null) return;
|
||
|
||
if (res.getString("status").equals("success")) {
|
||
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||
|
||
System.out.println("\n--- Channel Admins ---");
|
||
for (int i = 0; i < admins.length(); i++) {
|
||
JSONObject a = admins.getJSONObject(i);
|
||
System.out.printf("- %s (%s) [%s]\n",
|
||
a.getString("profile_name"),
|
||
a.getString("user_id"),
|
||
a.getString("role"));
|
||
}
|
||
} else {
|
||
System.out.println("❌ Failed to fetch admins.");
|
||
}
|
||
}
|
||
|
||
|
||
public JSONObject getChannelPermissions(UUID channelId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_channel_permissions");
|
||
req.put("channel_id", channelId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
return new JSONObject();
|
||
}
|
||
return res.getJSONObject("data");
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public void viewAdmins(String type, UUID entityId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", type.equals("group") ? "view_group_admins" : "view_channel_admins");
|
||
req.put(type + "_id", entityId.toString());
|
||
|
||
send(req);
|
||
JSONObject res = getResponse();
|
||
if (res.getString("status").equals("success")) {
|
||
JSONArray admins = res.getJSONObject("data").getJSONArray("admins");
|
||
System.out.println("📋 Admins in this " + type + ":");
|
||
for (int i = 0; i < admins.length(); i++) {
|
||
JSONObject admin = admins.getJSONObject(i);
|
||
System.out.printf("- %s (%s)\n", admin.getString("name"), admin.getString("role"));
|
||
}
|
||
} else {
|
||
System.out.println("❌ " + res.getString("message"));
|
||
}
|
||
}
|
||
|
||
|
||
public static JSONObject sendWithResponse(JSONObject request) {
|
||
try {
|
||
if (!request.has("action") || request.isNull("action")) {
|
||
System.err.println("❌ Invalid request: missing action.");
|
||
return null;
|
||
}
|
||
System.out.println("📤 Sending request to server: " + request.toString(2));
|
||
System.out.println("📤 [sendWithResponse] Action: " + request.optString("action", "unknown") + ", Full: " + request.toString(2));
|
||
|
||
|
||
String requestId = UUID.randomUUID().toString();
|
||
request.put("request_id", requestId);
|
||
|
||
BlockingQueue<JSONObject> queue = new LinkedBlockingQueue<>();
|
||
TelegramClient.pendingResponses.put(requestId, queue);
|
||
|
||
TelegramClient.getInstance().getOut().println(request.toString());
|
||
|
||
// Wait for response
|
||
JSONObject response = queue.take();
|
||
|
||
TelegramClient.pendingResponses.remove(requestId);
|
||
|
||
if (response == null) {
|
||
System.out.println("⚠️ No response received.");
|
||
return null;
|
||
}
|
||
|
||
System.out.println("✅ Server Response: " + response.getString("message"));
|
||
return response;
|
||
|
||
} catch (Exception e) {
|
||
System.err.println("❌ Error during sendWithResponse(): " + e.getMessage());
|
||
e.printStackTrace();
|
||
return null;
|
||
}
|
||
}
|
||
|
||
|
||
public static void requestChatList() {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_list");
|
||
req.put("user_id", Session.getUserUUID());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res.getString("status").equals("success")) {
|
||
JSONArray chats = res.getJSONObject("data").getJSONArray("chat_list");
|
||
Session.updateChatList(chats);
|
||
System.out.println("✅ Chat list updated.");
|
||
} else {
|
||
System.out.println("❌ Failed to update chat list.");
|
||
}
|
||
}
|
||
|
||
|
||
public static void requestChatInfo(String chatId, String chatType) throws IOException {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_info");
|
||
req.put("receiver_id", chatId);
|
||
req.put("receiver_type", chatType);
|
||
TelegramClient.send(req);
|
||
}
|
||
|
||
|
||
|
||
|
||
public static void displayChatList() {
|
||
if (Session.chatList == null || Session.chatList.isEmpty()) {
|
||
System.out.println("\n📭 No chats available.");
|
||
return;
|
||
}
|
||
|
||
|
||
System.out.println("\n💬 Your Chats:");
|
||
System.out.println("0. 📦 Archived chats");
|
||
|
||
int index = 1;
|
||
for (ChatEntry chat : Session.activeChats) {
|
||
String time = (chat.getLastMessageTime() == null)
|
||
? "No messages yet"
|
||
: chat.getLastMessageTime().toString();
|
||
|
||
System.out.printf("%d. [%s] %s (%s) - Last: %s\n",
|
||
index++, chat.getType(), chat.getName(), chat.getDisplayId(), time);
|
||
}
|
||
}
|
||
|
||
|
||
public static class ChatStateMonitor implements Runnable {
|
||
private final PrintWriter out;
|
||
|
||
public ChatStateMonitor(PrintWriter out) {
|
||
this.out = out;
|
||
}
|
||
|
||
@Override
|
||
public void run() {
|
||
while (true) {
|
||
try {
|
||
if (forceExitChat) {
|
||
System.out.println("🚪 You were removed from the chat. Returning to chat list...");
|
||
forceExitChat = false;
|
||
Session.backToChatList = true;
|
||
}
|
||
|
||
if (Session.forceRefreshChatList) {
|
||
Session.forceRefreshChatList = false;
|
||
System.out.println("🔁 Refresh triggered by real-time event.");
|
||
ActionHandler.requestChatList();
|
||
if (Session.inChatListMenu) {
|
||
System.out.println("\n📬 Updated Chat List:");
|
||
ActionHandler.displayChatList(); //Show chats
|
||
System.out.print("Select a chat by number: ");
|
||
}
|
||
}
|
||
|
||
Thread.sleep(300);
|
||
} catch (Exception e) {
|
||
System.out.println("❌ ChatStateMonitor crashed: " + e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
public static class CurrentChatMenuRefresher implements Runnable {
|
||
private final ActionHandler handler;
|
||
|
||
public CurrentChatMenuRefresher(ActionHandler handler) {
|
||
this.handler = handler;
|
||
}
|
||
|
||
@Override
|
||
public void run() {
|
||
System.out.println("🔁 Menu refresher thread running...");
|
||
|
||
while (true) {
|
||
try {
|
||
if (Session.refreshCurrentChatMenu && Session.inChatMenu && Session.currentChatId != null) {
|
||
System.out.println("🔁 [Refresher] Refresh requested. Searching for chat...");
|
||
|
||
|
||
ChatEntry chat = Session.chatList.stream()
|
||
.filter(e -> e.getId().toString().equals(Session.currentChatId))
|
||
.findFirst()
|
||
.orElse(null);
|
||
|
||
if (chat != null) {
|
||
Session.currentChatEntry = chat;
|
||
Session.refreshCurrentChatMenu = false;
|
||
|
||
String type = chat.getType().toLowerCase();
|
||
System.out.println("\n🔁 Your permissions have changed. Menu updated:");
|
||
|
||
if (type.equals("group")) {
|
||
handler.printGroupMenuOnly(chat);
|
||
} else if (type.equals("channel")) {
|
||
handler.printChannelMenuOnly(chat);
|
||
}
|
||
|
||
System.out.print("Select an option: ");
|
||
} else {
|
||
System.out.println("⚠️ No matching chat found for ID: " + Session.currentChatId);
|
||
}
|
||
}
|
||
|
||
Thread.sleep(200);
|
||
} catch (Exception e) {
|
||
System.out.println("❌ CurrentChatMenuRefresher crashed: " + e.getMessage());
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public void printGroupMenuOnly(ChatEntry chat) {
|
||
boolean isAdmin = chat.isAdmin();
|
||
boolean isOwner = chat.isOwner();
|
||
JSONObject perms = getGroupPermissions(chat.getId());
|
||
|
||
System.out.println("\n--- Group Chat Menu (Auto-refreshed) ---");
|
||
System.out.println("1. Send Message");
|
||
System.out.println("2. View Members");
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
|
||
System.out.println("3. Add Member");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_edit_group", false))) {
|
||
System.out.println("4. Edit Group Info");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
|
||
System.out.println("5. Add Admin");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
|
||
System.out.println("6. Remove Admin");
|
||
}
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
|
||
System.out.println("7. Remove member");
|
||
}
|
||
if (isOwner) {
|
||
System.out.println("8. Delete Group");
|
||
System.out.println("9. Leave Group (Transfer ownership required)");
|
||
} else {
|
||
System.out.println("9. Leave Group");
|
||
}
|
||
|
||
System.out.println("0. Back to Chat List");
|
||
}
|
||
|
||
|
||
public void printChannelMenuOnly(ChatEntry chat) {
|
||
boolean isAdmin = chat.isAdmin();
|
||
boolean isOwner = chat.isOwner();
|
||
JSONObject perms = getChannelPermissions(chat.getId());
|
||
|
||
System.out.println("\n--- Channel Menu (Auto-refreshed) ---");
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
|
||
System.out.println("1. Send Post");
|
||
}
|
||
|
||
if (isOwner || isAdmin) {
|
||
System.out.println("2. View Subscribers");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false))) {
|
||
System.out.println("3. Add Subscriber");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_members", false))) {
|
||
System.out.println("4. Remove Subscriber");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_edit_channel", false))) {
|
||
System.out.println("5. Edit Channel Info");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_add_admins", false))) {
|
||
System.out.println("6. Add Admin");
|
||
}
|
||
|
||
if (isOwner || (isAdmin && perms.optBoolean("can_remove_admins", false))) {
|
||
System.out.println("7. Remove Admin");
|
||
}
|
||
|
||
if (isOwner) {
|
||
System.out.println("8. Delete Channel");
|
||
System.out.println("9. Leave Channel (Transfer ownership required)");
|
||
} else {
|
||
System.out.println("8. Leave Channel");
|
||
}
|
||
|
||
System.out.println("0. Back to Chat List");
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public void startMenuRefresherThread() {
|
||
Thread refresher = new Thread(() -> {
|
||
System.out.println("🟡 Refresher tick. refreshCurrentChatMenu = " + Session.refreshCurrentChatMenu);
|
||
|
||
while (true) {
|
||
try {
|
||
Thread.sleep(500);
|
||
if (Session.refreshCurrentChatMenu) {
|
||
Session.refreshCurrentChatMenu = false;
|
||
if (Session.currentChatEntry == null) {
|
||
System.out.println("⚠️ currentChatEntry is null. Skipping...");
|
||
continue;
|
||
}
|
||
|
||
|
||
switch (Session.currentChatEntry.getType()) {
|
||
case "group" -> showGroupChatMenu(Session.currentChatEntry);
|
||
case "channel" -> showChannelChatMenu(Session.currentChatEntry);
|
||
}
|
||
}
|
||
} catch (Exception ignored) {}
|
||
}
|
||
});
|
||
refresher.setDaemon(true);
|
||
refresher.start();
|
||
}
|
||
|
||
|
||
|
||
public void openForeignChat(ChatEntry chat) {
|
||
System.out.println("🔍 Opening " + chat.getType() + " chat (not in your chat list)");
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_messages");
|
||
req.put("receiver_id", chat.getId().toString());
|
||
req.put("receiver_type", chat.getType());
|
||
send(req);
|
||
|
||
switch (chat.getType().toLowerCase()) {
|
||
case "private" -> {
|
||
System.out.println("\n--- Private Chat ---");
|
||
System.out.println("1. View Profile");
|
||
System.out.println("2. Add to Contact");
|
||
System.out.println("0. Back");
|
||
String input = scanner.nextLine();
|
||
switch (input) {
|
||
case "1" ->{
|
||
viewUserProfile(chat.getId());
|
||
openForeignChat(chat);
|
||
|
||
}
|
||
case "2" -> {
|
||
addContact(chat.getId());
|
||
refreshContactList();
|
||
}
|
||
default -> System.out.println("Back...");
|
||
}
|
||
}
|
||
|
||
case "group", "channel" -> {
|
||
System.out.println("\n--- " + chat.getType().substring(0, 1).toUpperCase() + chat.getType().substring(1) + " Preview ---");
|
||
System.out.println("1. View Info");
|
||
System.out.println("2. Join " + chat.getType());
|
||
System.out.println("0. Back");
|
||
String input = scanner.nextLine();
|
||
switch (input) {
|
||
case "1" -> {
|
||
viewGroupOrChannelInfo(chat.getId(), chat.getType());
|
||
openForeignChat(chat);
|
||
}
|
||
|
||
case "2" -> {
|
||
joinGroupOrChannel(chat.getType(), chat.getId().toString());
|
||
refreshChatList();
|
||
ChatEntry joined = Session.chatList.stream()
|
||
.filter(c -> c.getId().equals(chat.getId()) && c.getType().equals(chat.getType()))
|
||
.findFirst().orElse(null);
|
||
if (joined != null) {
|
||
openChat(joined);
|
||
} else {
|
||
System.out.println("❌ Failed to join.");
|
||
}
|
||
}
|
||
default -> System.out.println("Back...");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public void viewUserProfile(UUID userId) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "view_profile");
|
||
req.put("target_id", userId.toString());
|
||
|
||
JSONObject response = sendWithResponse(req);
|
||
|
||
if (response.getString("status").equals("success")) {
|
||
JSONObject profile = response.getJSONObject("data");
|
||
System.out.println("\n👤 Profile Info:");
|
||
System.out.println("🔷 Name: " + profile.getString("profile_name"));
|
||
System.out.println("🔷User ID: "+profile.getString("user_id"));
|
||
System.out.println("📄 Bio: " + profile.optString("bio", "N/A"));
|
||
System.out.println("🖼️ Image URL: " + profile.optString("image_url", "N/A"));
|
||
if (profile.getBoolean("is_online")) {
|
||
System.out.println("✅ Status: Online");
|
||
} else {
|
||
System.out.println("📅 Last seen: " + profile.optString("last_seen", "Unknown"));
|
||
}
|
||
System.out.println("────────────────────────────────────────────");
|
||
} else {
|
||
System.out.println("❌ Could not load profile.");
|
||
}
|
||
}
|
||
|
||
public void viewGroupOrChannelInfo(UUID id, String type) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_info");
|
||
req.put("receiver_id", id.toString());
|
||
req.put("receiver_type", type);
|
||
|
||
JSONObject response = sendWithResponse(req);
|
||
|
||
if (response.getString("status").equals("success")) {
|
||
JSONObject data = response.getJSONObject("data");
|
||
System.out.println("\n📢 " + type.substring(0, 1).toUpperCase() + type.substring(1) + " Info:");
|
||
System.out.println("🔷 Name: " + data.optString("name", "N/A"));
|
||
System.out.println("🆔 ID: " + data.optString("id", "N/A"));
|
||
System.out.println("📄 Description: " + data.optString("description", "N/A"));
|
||
System.out.println("🖼️ Image: " + data.optString("image_url", "N/A"));
|
||
System.out.println("────────────────────────────────────────────");
|
||
} else {
|
||
System.out.println("❌ Failed to fetch " + type + " info.");
|
||
System.out.println("✅ Server Response: " + response.getString("message"));
|
||
}
|
||
}
|
||
|
||
|
||
|
||
public void toggleArchive(UUID chatId, String chatType) {
|
||
|
||
Optional<ChatEntry> optional = Session.chatList.stream()
|
||
.filter(c -> c.getId().equals(chatId))
|
||
.findFirst();
|
||
|
||
if (optional.isEmpty()) {
|
||
System.out.println("❌ Chat not found.");
|
||
return;
|
||
}
|
||
|
||
ChatEntry chat = optional.get();
|
||
|
||
if (chat.isArchived()) {
|
||
unarchiveChat(chatId, chatType);
|
||
chat.setArchived(false);
|
||
System.out.println("✅ Chat unarchived.");
|
||
} else {
|
||
archiveChat(chatId, chatType);
|
||
chat.setArchived(true);
|
||
System.out.println("✅ Chat archived.");
|
||
}
|
||
|
||
Session.refreshChatLists();
|
||
}
|
||
|
||
|
||
public void archiveChat(UUID chatId, String chatType) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "archive_chat");
|
||
req.put("chat_id", chatId.toString());
|
||
req.put("chat_type", chatType);
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null) System.out.println(res.getString("message"));
|
||
}
|
||
|
||
public void unarchiveChat(UUID chatId, String chatType) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "unarchive_chat");
|
||
req.put("chat_id", chatId.toString());
|
||
req.put("chat_type", chatType);
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null) System.out.println(res.getString("message"));
|
||
}
|
||
|
||
|
||
// public void sendMessage(UUID receiverId, String receiverType) {
|
||
// Scanner scanner = new Scanner(System.in);
|
||
//
|
||
// System.out.print("Enter your message: ");
|
||
// String content = scanner.nextLine();
|
||
//
|
||
// System.out.print("Enter message type (TEXT / IMAGE / VIDEO / FILE): ");
|
||
// String messageType = scanner.nextLine();
|
||
// Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "VIDEO", "FILE");
|
||
// while (!allowedTypes.contains(messageType.toUpperCase())) {
|
||
// System.out.println("❌ Invalid message type. Try again (TEXT / IMAGE / VIDEO / FILE): ");
|
||
// messageType = scanner.nextLine();
|
||
// }
|
||
// messageType = messageType.toUpperCase();
|
||
//
|
||
// JSONArray attachmentsArray = new JSONArray();
|
||
//
|
||
// System.out.print("Do you want to attach files? (yes/no): ");
|
||
// if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
||
// while (true) {
|
||
// System.out.print("File URL: ");
|
||
// String fileUrl = scanner.nextLine();
|
||
//
|
||
// System.out.print("File Type (IMAGE / VIDEO / FILE): ");
|
||
// String fileType = scanner.nextLine();
|
||
//
|
||
// JSONObject fileJson = new JSONObject();
|
||
// fileJson.put("file_url", fileUrl);
|
||
// fileJson.put("file_type", fileType);
|
||
// attachmentsArray.put(fileJson);
|
||
//
|
||
// System.out.print("Add another file? (yes/no): ");
|
||
// if (!scanner.nextLine().equalsIgnoreCase("yes")) {
|
||
// break;
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
//
|
||
//
|
||
// JSONObject messageJson = new JSONObject();
|
||
// messageJson.put("action", "send_message");
|
||
// messageJson.put("receiver_type", receiverType);
|
||
// messageJson.put("content", content);
|
||
// messageJson.put("message_type", messageType);
|
||
// if (receiverType.equals("private")) {
|
||
// messageJson.put("receiver_user_id", receiverId.toString());
|
||
// } else {
|
||
// messageJson.put("receiver_id", receiverId.toString());
|
||
// }
|
||
//
|
||
// if (!attachmentsArray.isEmpty()) {
|
||
// messageJson.put("attachments", attachmentsArray);
|
||
// }
|
||
//
|
||
// JSONObject response = sendWithResponse(messageJson);
|
||
// if (response != null && response.getString("status").equals("success")) {
|
||
// System.out.println("✅ Message sent successfully! ID: " + response.getJSONObject("data").getString("message_id"));
|
||
// } else {
|
||
// System.out.println("❌ Failed to send message: " + (response != null ? response.getString("message") : "no response"));
|
||
// }
|
||
//
|
||
// }
|
||
|
||
|
||
|
||
// public void sendMessage(UUID chatId, String receiverType) {
|
||
// Scanner scanner = new Scanner(System.in);
|
||
//
|
||
// System.out.print("Enter your message: ");
|
||
// String content = scanner.nextLine();
|
||
//
|
||
// System.out.print("Enter message type (TEXT / IMAGE / VIDEO / FILE): ");
|
||
// String messageType = scanner.nextLine().toUpperCase();
|
||
// Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "VIDEO", "FILE");
|
||
// while (!allowedTypes.contains(messageType)) {
|
||
// System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / VIDEO / FILE): ");
|
||
// messageType = scanner.nextLine().toUpperCase();
|
||
// }
|
||
//
|
||
// JSONArray attachmentsArray = new JSONArray();
|
||
// System.out.print("Do you want to attach files? (yes/no): ");
|
||
// if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
||
// while (true) {
|
||
// System.out.print("File URL: ");
|
||
// String fileUrl = scanner.nextLine();
|
||
// System.out.print("File Type (IMAGE / VIDEO / FILE): ");
|
||
// String fileType = scanner.nextLine().toUpperCase();
|
||
//
|
||
// JSONObject fileJson = new JSONObject();
|
||
// fileJson.put("file_url", fileUrl);
|
||
// fileJson.put("file_type", fileType);
|
||
// attachmentsArray.put(fileJson);
|
||
//
|
||
// System.out.print("Add another file? (yes/no): ");
|
||
// if (!scanner.nextLine().equalsIgnoreCase("yes")) break;
|
||
// }
|
||
// }
|
||
//
|
||
//
|
||
//
|
||
// JSONObject messageJson = new JSONObject();
|
||
// messageJson.put("action", "send_message");
|
||
// messageJson.put("receiver_type", receiverType);
|
||
// messageJson.put("receiver_id", chatId.toString());
|
||
// messageJson.put("content", content);
|
||
// messageJson.put("message_type", messageType);
|
||
//
|
||
// if (!attachmentsArray.isEmpty()) {
|
||
// messageJson.put("attachments", attachmentsArray);
|
||
// }
|
||
//
|
||
// JSONObject response = sendWithResponse(messageJson);
|
||
// if (response != null && response.getString("status").equals("success")) {
|
||
// System.out.println("✅ Message sent! ID: " + response.getJSONObject("data").getString("message_id"));
|
||
// } else {
|
||
// System.out.println("❌ Failed to send message: " + (response != null ? response.getString("message") : "No response"));
|
||
// }
|
||
// }
|
||
|
||
|
||
// public void sendMessage(UUID chatId, String receiverType) {
|
||
// Scanner scanner = new Scanner(System.in);
|
||
//
|
||
// System.out.print("Enter your message (leave empty if file only): ");
|
||
// String content = scanner.nextLine();
|
||
//
|
||
// System.out.print("Enter message type (TEXT / IMAGE / AUDIO / FILE / GIF): ");
|
||
// String messageType = scanner.nextLine().toUpperCase();
|
||
// Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "AUDIO", "FILE", "GIF");
|
||
// while (!allowedTypes.contains(messageType)) {
|
||
// System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / AUDIO / FILE / GIF): ");
|
||
// messageType = scanner.nextLine().toUpperCase();
|
||
// }
|
||
//
|
||
// JSONArray attachmentsArray = new JSONArray();
|
||
// System.out.print("Attach files? (yes/no): ");
|
||
// if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
||
// while (true) {
|
||
// System.out.println("Paste the JSON you got from /upload (or leave empty to enter minimal fields):");
|
||
// String jsonLine = scanner.nextLine().trim();
|
||
//
|
||
// JSONObject fileJson;
|
||
// if (!jsonLine.isEmpty()) {
|
||
// // انتظار خروجی کامل /upload
|
||
// fileJson = new JSONObject(jsonLine);
|
||
// // اگه خروجی /upload تو ریشهست، تبدیلش کن به ساختار attachment
|
||
// fileJson = new JSONObject()
|
||
// .put("file_url", fileJson.optString("file_url", ""))
|
||
// .put("file_type", fileJson.optString("file_type", "FILE"))
|
||
// .put("file_name", fileJson.optString("file_name", ""))
|
||
// .put("file_size", fileJson.optLong("file_size", 0))
|
||
// .put("mime_type", fileJson.optString("mime_type", ""))
|
||
// .put("width", fileJson.isNull("width") ? JSONObject.NULL : fileJson.optInt("width"))
|
||
// .put("height", fileJson.isNull("height") ? JSONObject.NULL : fileJson.optInt("height"))
|
||
// .put("duration_seconds", fileJson.isNull("duration_seconds") ? JSONObject.NULL : fileJson.optInt("duration_seconds"))
|
||
// .put("thumbnail_url", fileJson.isNull("thumbnail_url") ? JSONObject.NULL : fileJson.optString("thumbnail_url", null));
|
||
// } else {
|
||
// // ورودی حداقلی
|
||
// System.out.print("File URL: ");
|
||
// String fileUrl = scanner.nextLine();
|
||
// System.out.print("File Type (IMAGE / AUDIO / FILE / GIF): ");
|
||
// String fileType = scanner.nextLine().toUpperCase();
|
||
//
|
||
// fileJson = new JSONObject();
|
||
// fileJson.put("file_url", fileUrl);
|
||
// fileJson.put("file_type", fileType);
|
||
// }
|
||
//
|
||
// attachmentsArray.put(fileJson);
|
||
//
|
||
// System.out.print("Add another file? (yes/no): ");
|
||
// if (!scanner.nextLine().equalsIgnoreCase("yes")) break;
|
||
// }
|
||
// }
|
||
//
|
||
// JSONObject messageJson = new JSONObject();
|
||
// messageJson.put("action", "send_message");
|
||
// messageJson.put("receiver_type", receiverType); // "private"/"group"/"channel"
|
||
// messageJson.put("receiver_id", chatId.toString()); // در private = chat_id
|
||
// messageJson.put("content", content);
|
||
// messageJson.put("message_type", messageType);
|
||
// if (attachmentsArray.length() > 0) {
|
||
// messageJson.put("attachments", attachmentsArray);
|
||
// }
|
||
//
|
||
// JSONObject response = sendWithResponse(messageJson);
|
||
// if (response != null && response.getString("status").equals("success")) {
|
||
// System.out.println("✅ Message sent! ID: " + response.getJSONObject("data").getString("message_id"));
|
||
// } else {
|
||
// System.out.println("❌ Failed to send message: " + (response != null ? response.optString("message","No message") : "No response"));
|
||
// }
|
||
// }
|
||
//
|
||
private void refreshContactList() {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_contact_list");
|
||
req.put("user_id", Session.currentUser.getString("user_id"));
|
||
out.println(req.toString());
|
||
|
||
try {
|
||
JSONObject response = TelegramClient.responseQueue.take();
|
||
|
||
if (response != null && response.getString("status").equals("success")) {
|
||
if (response.has("data") && !response.isNull("data")) {
|
||
JSONObject data = response.getJSONObject("data");
|
||
|
||
if (!data.has("contact_list") || data.isNull("contact_list")) {
|
||
System.out.println("❌ contact_list not found in response data.");
|
||
return;
|
||
}
|
||
|
||
JSONArray contactListJson = data.getJSONArray("contact_list");
|
||
List<ContactEntry> contactList = new ArrayList<>();
|
||
|
||
for (Object obj : contactListJson) {
|
||
JSONObject c = (JSONObject) obj;
|
||
|
||
ContactEntry entry = new ContactEntry(
|
||
UUID.fromString(c.getString("contact_id")),
|
||
c.getString("user_id"),
|
||
c.getString("contact_displayId"),
|
||
c.getString("profile_name"),
|
||
c.optString("image_url", ""),
|
||
c.optBoolean("is_blocked", false),
|
||
c.isNull("last_seen")
|
||
? null
|
||
: LocalDateTime.parse(c.getString("last_seen"))
|
||
);
|
||
|
||
contactList.add(entry);
|
||
}
|
||
|
||
Session.contactEntries = contactList;
|
||
System.out.println("✅ Contact list updated. Total: " + contactList.size());
|
||
|
||
} else {
|
||
System.out.println("⚠️ Response has no data object.");
|
||
}
|
||
} else {
|
||
if (response.has("message") && !response.isNull("message")) {
|
||
System.out.println("❌ Failed to refresh contact list: " + response.getString("message"));
|
||
} else {
|
||
System.out.println("❌ Failed to refresh contact list.");
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
System.err.println("❌ Error during refreshContactList: " + e.getMessage());
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
public void viewMessagesInChat(ChatEntry chat) {
|
||
int offset = 0;
|
||
int limit = 10;
|
||
|
||
while (true) {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "get_chat_messages");
|
||
req.put("chat_id", chat.getId());
|
||
req.put("chat_type", chat.getType());
|
||
req.put("offset", offset);
|
||
req.put("limit", limit);
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to fetch messages.");
|
||
return;
|
||
}
|
||
|
||
JSONArray messages = res.getJSONObject("data").getJSONArray("get_chat_messages");
|
||
|
||
if (messages.isEmpty()) {
|
||
if (offset == 0)
|
||
System.out.println("📭 No messages in this chat.");
|
||
else
|
||
System.out.println("📭 No more messages.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("\n📥 Messages:");
|
||
System.out.println("─────────────────────────────────────────────");
|
||
for (int i = 0; i < messages.length(); i++) {
|
||
JSONObject msg = messages.getJSONObject(i);
|
||
String senderName = msg.optString("sender_name", "Unknown");
|
||
String content = msg.optString("content", "(no content)");
|
||
String time = msg.optString("time", "");
|
||
boolean isEdited = msg.optBoolean("is_edited", false);
|
||
String editedAt = msg.optString("edited_at", "");
|
||
String label = isEdited ? "🖊️ (edited at: " + editedAt + ")" : "";
|
||
|
||
// ✅ Forwarded info
|
||
String forwardLabel = "";
|
||
if (msg.optBoolean("is_forwarded", false)) {
|
||
String forwardFrom = msg.optString("forwarded_from_name", "Unknown");
|
||
forwardLabel = "🔁 Forwarded from " + forwardFrom;
|
||
}
|
||
|
||
//for reply
|
||
String replyLabel = "";
|
||
if (msg.has("reply_to_id")) {
|
||
String repliedSender = msg.optString("reply_to_sender", "Unknown");
|
||
String repliedContent = msg.optString("reply_to_content", "...");
|
||
replyLabel = "↪️ Reply to " + repliedSender + ": \"" + repliedContent + "\"";
|
||
}
|
||
|
||
JSONArray atts = msg.optJSONArray("attachments");
|
||
if (atts != null && atts.length() > 0) {
|
||
System.out.println(" 📎 " + atts.length() + " attachment(s)");
|
||
for (int a = 0; a < atts.length(); a++) {
|
||
JSONObject att = atts.getJSONObject(a);
|
||
String fn = att.optString("file_name", "(unnamed)");
|
||
long sz = att.optLong("file_size", 0);
|
||
System.out.printf(" - #%d %s (%s)\n", a + 1, fn, humanSize(sz));
|
||
}
|
||
}
|
||
|
||
|
||
JSONArray reactions = msg.optJSONArray("reactions");
|
||
if (reactions != null && !reactions.isEmpty()) {
|
||
System.out.print(" 💬 Reactions: ");
|
||
for (int j = 0; j < reactions.length(); j++) {
|
||
System.out.print(reactions.getString(j) + " ");
|
||
}
|
||
System.out.println();
|
||
}
|
||
|
||
|
||
System.out.printf("[%d] [%s] %s: \n", i + 1, time, senderName);
|
||
if (!forwardLabel.isEmpty()) System.out.println(forwardLabel);
|
||
if (!replyLabel.isEmpty()) System.out.println(replyLabel);
|
||
System.out.printf("%s %s\n", content, label);
|
||
System.out.println("─────────────────────────────────────────────");
|
||
}
|
||
|
||
System.out.print("""
|
||
💬 Options:
|
||
[number] - Interact with message
|
||
N - Next page (older messages)
|
||
0 - Back to chat menu
|
||
S - Send message
|
||
➤ Choice: """);
|
||
|
||
String input = scanner.nextLine().trim();
|
||
|
||
if (input.equals("0")) return;
|
||
if (input.equalsIgnoreCase("N")) {
|
||
offset += limit;
|
||
continue;
|
||
}
|
||
|
||
if(input.equalsIgnoreCase("S")){
|
||
sendMessageInteractive(chat.getId(), chat.getType());
|
||
}
|
||
try {
|
||
int index = Integer.parseInt(input);
|
||
if (index < 1 || index > messages.length()) {
|
||
System.out.println("❌ Invalid message number.");
|
||
continue;
|
||
}
|
||
|
||
JSONObject selected = messages.getJSONObject(index - 1);
|
||
UUID messageId = UUID.fromString(selected.getString("message_id"));
|
||
UUID senderId = UUID.fromString(selected.getString("sender_id"));
|
||
boolean isSender = senderId.toString().equals(Session.currentUser.getString("internal_uuid"));
|
||
boolean isChannel = chat.getType().equals("channel");
|
||
boolean isOwnerOrAdmin = chat.isOwner() || chat.isAdmin();
|
||
//for media
|
||
JSONArray atts = selected.optJSONArray("attachments");
|
||
boolean hasAttachments = (atts != null && atts.length() > 0);
|
||
|
||
|
||
System.out.println("\n🎯 Selected message by " + selected.getString("sender_name"));
|
||
|
||
// ✔ Show interaction menu based on access
|
||
System.out.println("2. Forward");
|
||
|
||
if (isChannel) {
|
||
if (isOwnerOrAdmin) {
|
||
System.out.println("1. Reply");
|
||
System.out.println("3. React");
|
||
if (isSender) {
|
||
System.out.println("4. Edit");
|
||
}
|
||
System.out.println("5. Delete");
|
||
}
|
||
} else {
|
||
System.out.println("1. Reply");
|
||
System.out.println("3. React");
|
||
if (isSender) {
|
||
System.out.println("4. Edit");
|
||
}
|
||
if (isSender || isOwnerOrAdmin) {
|
||
System.out.println("5. Delete");
|
||
}
|
||
}
|
||
if (hasAttachments) {
|
||
System.out.println("D. Download attachment");
|
||
}
|
||
|
||
System.out.println("0. Back to message list");
|
||
System.out.print("➤ Select an action: ");
|
||
String choice = scanner.nextLine().trim();
|
||
|
||
switch (choice) {
|
||
case "1" -> {
|
||
if (!isChannel || isOwnerOrAdmin)
|
||
replyToMessage(messageId);
|
||
else
|
||
System.out.println("❌ You are not allowed to reply.");
|
||
}
|
||
case "2" -> forwardMessage(messageId);
|
||
case "3" -> {
|
||
if (!isChannel || isOwnerOrAdmin)
|
||
reactToMessage(messageId);
|
||
else
|
||
System.out.println("❌ You are not allowed to react.");
|
||
}
|
||
case "4" -> {
|
||
if (isSender)
|
||
editMessage(messageId);
|
||
else
|
||
System.out.println("❌ You can only edit your own messages.");
|
||
}
|
||
case "5" -> {
|
||
if (!isChannel || isOwnerOrAdmin || isSender)
|
||
deleteMessage(messageId);
|
||
else
|
||
System.out.println("❌ You are not allowed to delete this message.");
|
||
}
|
||
case "0" -> {}
|
||
|
||
case "D", "d" -> {
|
||
if (hasAttachments) {
|
||
downloadAttachmentFlow(chat, selected);
|
||
} else {
|
||
System.out.println("🚫 No attachments to download.");
|
||
}
|
||
}
|
||
|
||
default -> System.out.println("❌ Invalid option.");
|
||
}
|
||
|
||
} catch (NumberFormatException e) {
|
||
System.out.println("❌ Please enter a valid number or command.");
|
||
}
|
||
}
|
||
}
|
||
|
||
public void editMessage(UUID messageId) {
|
||
private void downloadAttachmentFlow(ChatEntry chat, JSONObject msg) {
|
||
JSONArray atts = msg.optJSONArray("attachments");
|
||
if (atts == null || atts.length() == 0) {
|
||
System.out.println("🚫 No attachments.");
|
||
return;
|
||
}
|
||
|
||
int idx = 0;
|
||
if (atts.length() > 1) {
|
||
System.out.print("Which attachment [1.." + atts.length() + "]? ");
|
||
try {
|
||
String ans = scanner.nextLine().trim();
|
||
if (!ans.isEmpty()) {
|
||
int n = Integer.parseInt(ans);
|
||
if (n >= 1 && n <= atts.length()) idx = n - 1;
|
||
}
|
||
} catch (Exception ignored) { idx = 0; }
|
||
}
|
||
|
||
JSONObject att = atts.getJSONObject(idx);
|
||
String mediaKeyStr = att.optString("media_key", "");
|
||
if (mediaKeyStr.isBlank()) {
|
||
System.out.println("❌ Attachment missing media_key.");
|
||
return;
|
||
}
|
||
|
||
UUID mediaKey = UUID.fromString(mediaKeyStr);
|
||
String rawName = att.optString("file_name", mediaKey.toString());
|
||
String fileName = sanitizeFileName(rawName);
|
||
long declaredSize = att.optLong("file_size", 0L);
|
||
|
||
// ~/Downloads/TeleSock/<Account>/<Chat>/
|
||
String accFolder = accountFolderName();
|
||
String chatFolder = chatFolderName(chat);
|
||
Path saveDir = Paths.get(System.getProperty("user.home"),
|
||
"Downloads", "TeleSock", accFolder, chatFolder);
|
||
|
||
System.out.println("👤 AccountFolder = " + accFolder);
|
||
System.out.println("💬 ChatFolder = " + chatFolder);
|
||
System.out.println("📁 SaveDir = " + saveDir);
|
||
|
||
try { Files.createDirectories(saveDir); }
|
||
catch (IOException e) {
|
||
System.out.println("❌ Cannot create folder: " + saveDir + " -> " + e.getMessage());
|
||
return;
|
||
}
|
||
|
||
DownloadsIndex di = Session.downloadsIndex;
|
||
if (di != null) {
|
||
Path existing = di.find(mediaKey);
|
||
if (existing != null) {
|
||
System.out.println("✅ Already downloaded: " + existing);
|
||
return;
|
||
}
|
||
}
|
||
Path target = uniquePath(saveDir, fileName);
|
||
|
||
TelegramClient.mediaBusy.set(true);
|
||
try {
|
||
Path saved = TelegramClient.getDownloader()
|
||
.download(mediaKey, saveDir, target.getFileName().toString());
|
||
|
||
long sizeToRecord = declaredSize > 0 ? declaredSize : Files.size(saved);
|
||
if (di != null) di.put(mediaKey, saved, sizeToRecord);
|
||
|
||
System.out.println("✅ Saved to: " + saved + " (" + humanSize(sizeToRecord) + ")");
|
||
} catch (Exception ex) {
|
||
System.out.println("❌ Download failed: " + ex.getMessage());
|
||
} finally {
|
||
TelegramClient.mediaBusy.set(false);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
private static Path uniquePath(Path dir, String fileName) {
|
||
Path p = dir.resolve(fileName);
|
||
if (!Files.exists(p)) return p;
|
||
|
||
String name = fileName;
|
||
String ext = "";
|
||
int dot = fileName.lastIndexOf('.');
|
||
if (dot > 0 && dot < fileName.length()-1) {
|
||
name = fileName.substring(0, dot);
|
||
ext = fileName.substring(dot); // includes dot
|
||
}
|
||
int i = 1;
|
||
while (true) {
|
||
Path cand = dir.resolve(String.format("%s (%d)%s", name, i, ext));
|
||
if (!Files.exists(cand)) return cand;
|
||
i++;
|
||
}
|
||
}
|
||
|
||
private static String sanitizeFileName(String s) {
|
||
s = s.replace("\\", "/");
|
||
if (s.contains("/")) s = s.substring(s.lastIndexOf('/') + 1);
|
||
s = s.replaceAll("[\\\\/:*?\"<>|]", "_");
|
||
if (s.equals(".") || s.equals("..") || s.isBlank()) s = "file";
|
||
return s;
|
||
}
|
||
|
||
private static String humanSize(long b) {
|
||
if (b <= 0) return "0 B";
|
||
String[] u = {"B","KB","MB","GB","TB"};
|
||
int i = (int) Math.floor(Math.log(b) / Math.log(1024));
|
||
if (i < 0) i = 0;
|
||
if (i >= u.length) i = u.length - 1;
|
||
double v = b / Math.pow(1024, i);
|
||
return String.format("%.1f %s", v, u[i]);
|
||
}
|
||
|
||
|
||
|
||
private void editMessage(UUID messageId) {
|
||
System.out.print("📝 Enter new content: ");
|
||
String newContent = scanner.nextLine().trim();
|
||
|
||
if (newContent.isEmpty()) {
|
||
System.out.println("❌ Content cannot be empty.");
|
||
return;
|
||
}
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "edit_message");
|
||
req.put("message_id", messageId.toString());
|
||
req.put("new_content", newContent);
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res == null || !res.getString("status").equals("success")) {
|
||
System.out.println("❌ Failed to edit message.");
|
||
return;
|
||
}
|
||
|
||
System.out.println("✅ Message updated successfully.");
|
||
}
|
||
|
||
|
||
public void reactToMessage(UUID messageId) {
|
||
System.out.print("😊 Enter your reaction (e.g., ❤️, 👍, 😂): ");
|
||
String reaction = scanner.nextLine().trim();
|
||
|
||
if (reaction.isEmpty()) {
|
||
System.out.println("⚠️ Empty reaction discarded.");
|
||
return;
|
||
}
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "react_to_message");
|
||
req.put("message_id", messageId.toString());
|
||
req.put("reaction", reaction);
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null && res.getString("status").equals("success")) {
|
||
System.out.println("✅ Reaction sent.");
|
||
} else {
|
||
System.out.println("❌ Failed to react to message.");
|
||
}
|
||
}
|
||
|
||
|
||
public void forwardMessage(UUID originalMessageId) {
|
||
System.out.println("\n📤 Select a chat to forward this message to:");
|
||
|
||
List<ChatEntry> chatList = Session.chatList;
|
||
for (int i = 0; i < chatList.size(); i++) {
|
||
ChatEntry c = chatList.get(i);
|
||
System.out.printf("%d. [%s] %s\n", i + 1, c.getType(), c.getName());
|
||
}
|
||
System.out.println("0. Cancel");
|
||
|
||
System.out.print("➤ Enter chat number: ");
|
||
String input = scanner.nextLine().trim();
|
||
|
||
if (input.equals("0")) return;
|
||
|
||
try {
|
||
int choice = Integer.parseInt(input);
|
||
if (choice < 1 || choice > chatList.size()) {
|
||
System.out.println("❌ Invalid choice.");
|
||
return;
|
||
}
|
||
|
||
ChatEntry target = chatList.get(choice - 1);
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "forward_message");
|
||
req.put("target_chat_id", target.getId());
|
||
req.put("target_chat_type", target.getType());
|
||
req.put("original_message_id", originalMessageId.toString());
|
||
req.put("forwarded_by", Session.currentUser.getString("internal_uuid"));
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null && res.getString("status").equals("success")) {
|
||
System.out.println("✅ Message forwarded successfully.");
|
||
} else {
|
||
System.out.println("❌ Failed to forward the message.");
|
||
}
|
||
|
||
} catch (NumberFormatException e) {
|
||
System.out.println("❌ Invalid input.");
|
||
}
|
||
}
|
||
|
||
|
||
public void replyToMessage(UUID messageId) {
|
||
System.out.print("💬 Enter your reply: ");
|
||
String content = scanner.nextLine().trim();
|
||
|
||
if (content.isEmpty()) {
|
||
System.out.println("⚠️ Empty reply discarded.");
|
||
return;
|
||
}
|
||
|
||
UUID chatId = UUID.fromString(Session.currentChatId);
|
||
String chatType = Session.currentChatType;
|
||
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "send_reply_message");
|
||
req.put("receiver_type", chatType);
|
||
req.put("receiver_id", chatId.toString());
|
||
req.put("content", content);
|
||
req.put("reply_to_id", messageId.toString());
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
|
||
if (res != null && res.getString("status").equals("success")) {
|
||
System.out.println("✅ Reply sent.");
|
||
} else {
|
||
System.out.println("❌ Failed to send reply.");
|
||
}
|
||
}
|
||
|
||
|
||
public void deleteMessage(UUID messageId) {
|
||
System.out.println("\n🗑️ Delete Message Options:");
|
||
System.out.println("1. Delete for yourself (one-sided)");
|
||
System.out.println("2. Delete for everyone (global) [only if allowed]");
|
||
System.out.println("0. Cancel");
|
||
|
||
String choice = scanner.nextLine().trim();
|
||
|
||
switch (choice) {
|
||
case "1" -> {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "delete_message");
|
||
req.put("message_id", messageId.toString());
|
||
req.put("delete_type", "one-sided");
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null && res.getString("status").equals("success")) {
|
||
System.out.println("✅ Message deleted for you.");
|
||
} else {
|
||
System.out.println("❌ Failed to delete message.");
|
||
}
|
||
}
|
||
|
||
case "2" -> {
|
||
JSONObject req = new JSONObject();
|
||
req.put("action", "delete_message");
|
||
req.put("message_id", messageId.toString());
|
||
req.put("delete_type", "global");
|
||
|
||
JSONObject res = sendWithResponse(req);
|
||
if (res != null && res.getString("status").equals("success")) {
|
||
System.out.println("✅ Message deleted for everyone.");
|
||
} else {
|
||
System.out.println("❌ Failed to delete message globally.");
|
||
if (res != null) System.out.println("⚠️ " + res.optString("message"));
|
||
}
|
||
}
|
||
|
||
case "0" -> {
|
||
System.out.println("❎ Delete canceled.");
|
||
}
|
||
|
||
default -> {
|
||
System.out.println("❌ Invalid option.");
|
||
}
|
||
}
|
||
}
|
||
|
||
public void showSidebarMenu() {
|
||
System.out.println("\n--- Sidebar Menu ---");
|
||
System.out.println("1. View Profile");
|
||
System.out.println("2. New Group");
|
||
System.out.println("3. New Channel");
|
||
System.out.println("4. View Contacts");
|
||
System.out.println("5. Saved messages");
|
||
System.out.println("6. Settings");
|
||
System.out.println("7. Telegram features");
|
||
System.out.println("8. Telegram Q&A");
|
||
System.out.println("0. Back");
|
||
System.out.println("Choose your action: (0 to 8)");
|
||
|
||
// Handle invalid input
|
||
int action;
|
||
while (true) {
|
||
if (scanner.hasNextInt()) {
|
||
action = scanner.nextInt();
|
||
scanner.nextLine(); // Clear newline
|
||
|
||
if (action >= 0 && action <= 8) {
|
||
break;
|
||
}
|
||
System.out.println("Invalid input. Please enter a number between 0 and 8.");
|
||
} else {
|
||
scanner.nextLine();
|
||
System.out.println("Invalid input. Try again.");
|
||
}
|
||
}
|
||
|
||
SidebarHandler sidebarHandler = new SidebarHandler(scanner, this);
|
||
switch (action) {
|
||
case 0 -> {
|
||
return;
|
||
}
|
||
case 1 -> sidebarHandler.handleSidebarAction(SidebarAction.MY_PROFILE);
|
||
case 2 -> sidebarHandler.handleSidebarAction(SidebarAction.NEW_GROUP);
|
||
case 3 -> sidebarHandler.handleSidebarAction(SidebarAction.NEW_CHANNEL);
|
||
case 4 -> sidebarHandler.handleSidebarAction(SidebarAction.CONTACTS);
|
||
case 5 -> sidebarHandler.handleSidebarAction(SidebarAction.SAVED_MESSAGES);
|
||
case 6 -> sidebarHandler.handleSidebarAction(SidebarAction.SETTINGS);
|
||
case 7 -> sidebarHandler.handleSidebarAction(SidebarAction.FEATURES);
|
||
case 8 -> sidebarHandler.handleSidebarAction(SidebarAction.Q_AND_A);
|
||
default -> System.out.println("Invalid action.");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
public void sendMessageInteractive(UUID receiverId, String receiverType) {
|
||
Scanner sc = new Scanner(System.in);
|
||
|
||
System.out.print("Type (TEXT / IMAGE / AUDIO): ");
|
||
String type = sc.nextLine().trim().toUpperCase();
|
||
while (!Set.of("TEXT","IMAGE","AUDIO").contains(type)) {
|
||
System.out.print("❌ Invalid. Try (TEXT / IMAGE / AUDIO): ");
|
||
type = sc.nextLine().trim().toUpperCase();
|
||
}
|
||
|
||
System.out.print("Text (optional for media; empty = no caption): ");
|
||
String text = sc.nextLine();
|
||
|
||
if ("TEXT".equals(type)) {
|
||
sendTextMessage(receiverId, receiverType, text);
|
||
} else {
|
||
System.out.print("File path: ");
|
||
String path = sc.nextLine().trim();
|
||
File f = new File(path);
|
||
if (!f.isFile()) {
|
||
System.out.println("❌ File not found");
|
||
return;
|
||
}
|
||
try {
|
||
sendMediaMessage(receiverId, receiverType, type, f, text);
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
System.out.println("❌ Media send failed: " + e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
|
||
private void sendTextMessage(UUID receiverId, String receiverType, String content) {
|
||
JSONObject req = new JSONObject()
|
||
.put("action", "send_message")
|
||
.put("receiver_type", receiverType)
|
||
.put("receiver_id", receiverId.toString())
|
||
.put("message_type", "TEXT")
|
||
.put("content", content == null ? "" : content);
|
||
|
||
JSONObject resp = sendWithResponse(req);
|
||
if (resp != null && "success".equalsIgnoreCase(resp.optString("status"))) {
|
||
System.out.println("✅ Sent. id=" + resp.optJSONObject("data").optString("message_id",""));
|
||
} else {
|
||
System.out.println("❌ Failed: " + (resp != null ? resp.optString("message") : "no response"));
|
||
}
|
||
}
|
||
|
||
|
||
public void sendMediaMessage(UUID receiverId, String receiverType, String type /* IMAGE/AUDIO */, File file, String caption) {
|
||
if (file == null) {
|
||
System.out.println("❌ File is null");
|
||
return;
|
||
}
|
||
if (!file.exists()) {
|
||
System.out.println("❌ File not found: " + file.getAbsolutePath());
|
||
return;
|
||
}
|
||
if (file.isDirectory()) {
|
||
System.out.println("❌ Path is a directory, expected a file: " + file.getAbsolutePath());
|
||
return;
|
||
}
|
||
|
||
final UUID messageId = UUID.randomUUID();
|
||
|
||
try {
|
||
String mime = detectMime(file, type.toUpperCase());
|
||
if (mime == null) mime = type.equalsIgnoreCase("IMAGE") ? "image/*" : "audio/*";
|
||
|
||
JSONObject header = new JSONObject()
|
||
.put("message_id", messageId.toString())
|
||
.put("sender_id", TelegramClient.loggedInUserId.toString())
|
||
.put("receiver_type", receiverType) // private|group|channel
|
||
.put("receiver_id", receiverId.toString())
|
||
.put("message_type", type.toUpperCase()) // IMAGE | AUDIO
|
||
.put("file_name", file.getName())
|
||
.put("mime_type", mime)
|
||
.put("text", caption == null ? "" : caption);
|
||
|
||
byte[] headerBytes = header.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
||
long contentLen = file.length();
|
||
|
||
BlockingQueue<JSONObject> q = new LinkedBlockingQueue<>(1);
|
||
TelegramClient.pendingResponses.put(messageId.toString(), q);
|
||
|
||
try {
|
||
|
||
outBin.write("MEDIA\n".getBytes(java.nio.charset.StandardCharsets.US_ASCII));
|
||
outBin.flush();
|
||
|
||
// 2) binary frame: magic + headerLen + header + contentLen + content
|
||
outBin.writeInt(0x4D444D31); // "MDM1"
|
||
outBin.writeInt(headerBytes.length); // headerLen (int)
|
||
outBin.write(headerBytes); // header
|
||
outBin.writeLong(contentLen); // contentLen (long)
|
||
|
||
try (InputStream fis = new BufferedInputStream(new FileInputStream(file))) {
|
||
byte[] buf = new byte[8192];
|
||
int n;
|
||
while ((n = fis.read(buf)) != -1) {
|
||
outBin.write(buf, 0, n);
|
||
}
|
||
}
|
||
outBin.flush();
|
||
|
||
JSONObject ack = q.poll(20, java.util.concurrent.TimeUnit.SECONDS);
|
||
if (ack == null) {
|
||
System.out.println("❌ Media ACK timeout for " + messageId);
|
||
return;
|
||
}
|
||
|
||
String status = ack.optString("status", "error");
|
||
if ("success".equalsIgnoreCase(status)) {
|
||
System.out.println("✅ Media sent. id=" + ack.optString("message_id") +
|
||
" url=" + ack.optString("file_url"));
|
||
} else {
|
||
System.out.println("❌ Media failed: " + ack.optString("message"));
|
||
}
|
||
|
||
} finally {
|
||
TelegramClient.pendingResponses.remove(messageId.toString());
|
||
}
|
||
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
System.out.println("❌ sendMediaMessage error: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
|
||
private static String detectMime(File f, String typeUpper /* IMAGE or AUDIO */) {
|
||
try {
|
||
String m = java.nio.file.Files.probeContentType(f.toPath());
|
||
if (m != null) return m;
|
||
} catch (Exception ignored) {}
|
||
String name = f.getName().toLowerCase();
|
||
if (name.endsWith(".png")) return "image/png";
|
||
if (name.endsWith(".jpg") || name.endsWith(".jpeg")) return "image/jpeg";
|
||
if (name.endsWith(".gif")) return "image/gif";
|
||
if (name.endsWith(".mp3")) return "audio/mpeg";
|
||
if (name.endsWith(".wav")) return "audio/wav";
|
||
if (name.endsWith(".ogg")) return "audio/ogg";
|
||
return typeUpper.equals("IMAGE") ? "image/*" : "audio/*";
|
||
}
|
||
|
||
|
||
|
||
private static String safeName(String s) {
|
||
if (s == null) return "unknown";
|
||
s = s.replace("\\", "/");
|
||
if (s.contains("/")) s = s.substring(s.lastIndexOf('/') + 1);
|
||
s = s.replaceAll("[\\\\/:*?\"<>|]", "_").trim();
|
||
if (s.isEmpty() || s.equals(".") || s.equals("..")) s = "unknown";
|
||
return s;
|
||
}
|
||
|
||
private static String accountFolderName() {
|
||
JSONObject me = Session.currentUser;
|
||
String acc = me.optString("username",
|
||
me.optString("user_id",
|
||
me.optString("profile_name",
|
||
me.optString("internal_uuid", "me"))));
|
||
return safeName(acc);
|
||
}
|
||
|
||
private static String chatFolderName(ChatEntry chat) {
|
||
String name = chat.getName();
|
||
if (name == null || name.isBlank()) {
|
||
name = chat.getDisplayId() != null && !chat.getDisplayId().isBlank()
|
||
? chat.getDisplayId()
|
||
: String.valueOf(chat.getId());
|
||
}
|
||
return safeName(name);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|