diff --git a/app/schemas/io.github.chronosx88.influence.helpers.RoomHelper/2.json b/app/schemas/io.github.chronosx88.influence.helpers.RoomHelper/2.json
index 03323fe..4454e73 100644
--- a/app/schemas/io.github.chronosx88.influence.helpers.RoomHelper/2.json
+++ b/app/schemas/io.github.chronosx88.influence.helpers.RoomHelper/2.json
@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 2,
- "identityHash": "aa6543fc56b99224739cb0b53a63d48e",
+ "identityHash": "a24b31a8e1f482a72f55843041945d5b",
"entities": [
{
"tableName": "messages",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `chatID` TEXT, `sender` TEXT, `timestamp` INTEGER NOT NULL, `text` TEXT)",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `chatID` TEXT, `sender` TEXT, `timestamp` INTEGER NOT NULL, `text` TEXT, `isSent` INTEGER NOT NULL, `isRead` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
@@ -43,6 +43,18 @@
"columnName": "text",
"affinity": "TEXT",
"notNull": false
+ },
+ {
+ "fieldPath": "isSent",
+ "columnName": "isSent",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isRead",
+ "columnName": "isRead",
+ "affinity": "INTEGER",
+ "notNull": true
}
],
"primaryKey": {
@@ -102,7 +114,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
- "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"aa6543fc56b99224739cb0b53a63d48e\")"
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"a24b31a8e1f482a72f55843041945d5b\")"
]
}
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 633096d..53e778d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,6 +18,9 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/ItemClickListener.java b/app/src/main/java/io/github/chronosx88/influence/contracts/ItemClickListener.java
new file mode 100644
index 0000000..1788dfd
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/ItemClickListener.java
@@ -0,0 +1,7 @@
+package io.github.chronosx88.influence.contracts;
+
+import android.view.View;
+
+public interface ItemClickListener {
+ void onItemClick(View view, int position);
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatLogicContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatLogicContract.java
new file mode 100644
index 0000000..ab26d70
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatLogicContract.java
@@ -0,0 +1,9 @@
+package io.github.chronosx88.influence.contracts.chatactivity;
+
+import net.tomp2p.peers.PeerAddress;
+
+import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
+
+public interface ChatLogicContract {
+ void sendMessage(PeerAddress address, MessageEntity message);
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatPresenterContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatPresenterContract.java
new file mode 100644
index 0000000..9668c33
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatPresenterContract.java
@@ -0,0 +1,6 @@
+package io.github.chronosx88.influence.contracts.chatactivity;
+
+public interface ChatPresenterContract {
+ void sendMessage(String text);
+ void updateAdapter();
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatViewContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatViewContract.java
new file mode 100644
index 0000000..4600a7a
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/chatactivity/ChatViewContract.java
@@ -0,0 +1,10 @@
+package io.github.chronosx88.influence.contracts.chatactivity;
+
+import java.util.List;
+
+import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
+
+public interface ChatViewContract {
+ void updateMessageList(MessageEntity message);
+ void updateMessageList(List messages);
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/chatlist/ChatListViewContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/chatlist/ChatListViewContract.java
index 69baa1a..acf1740 100644
--- a/app/src/main/java/io/github/chronosx88/influence/contracts/chatlist/ChatListViewContract.java
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/chatlist/ChatListViewContract.java
@@ -1,5 +1,7 @@
package io.github.chronosx88.influence.contracts.chatlist;
+import android.content.Intent;
+
import java.util.List;
import io.github.chronosx88.influence.helpers.ChatListAdapter;
@@ -7,5 +9,6 @@ import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
public interface ChatListViewContract {
void setRecycleAdapter(ChatListAdapter adapter);
+ void startActivity(Intent intent);
void updateChatList(ChatListAdapter adapter, List chats);
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/main/MainViewContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/main/MainViewContract.java
deleted file mode 100644
index 189e9a9..0000000
--- a/app/src/main/java/io/github/chronosx88/influence/contracts/main/MainViewContract.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package io.github.chronosx88.influence.contracts.main;
-
-public interface MainViewContract {
- //
-}
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/main/MainLogicContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainLogicContract.java
similarity index 57%
rename from app/src/main/java/io/github/chronosx88/influence/contracts/main/MainLogicContract.java
rename to app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainLogicContract.java
index 0d9517b..497828a 100644
--- a/app/src/main/java/io/github/chronosx88/influence/contracts/main/MainLogicContract.java
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainLogicContract.java
@@ -1,4 +1,4 @@
-package io.github.chronosx88.influence.contracts.main;
+package io.github.chronosx88.influence.contracts.mainactivity;
public interface MainLogicContract {
void initPeer();
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/main/MainPresenterContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainPresenterContract.java
similarity index 58%
rename from app/src/main/java/io/github/chronosx88/influence/contracts/main/MainPresenterContract.java
rename to app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainPresenterContract.java
index 3ff5969..23ff888 100644
--- a/app/src/main/java/io/github/chronosx88/influence/contracts/main/MainPresenterContract.java
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainPresenterContract.java
@@ -1,4 +1,4 @@
-package io.github.chronosx88.influence.contracts.main;
+package io.github.chronosx88.influence.contracts.mainactivity;
public interface MainPresenterContract {
void initPeer();
diff --git a/app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainViewContract.java b/app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainViewContract.java
new file mode 100644
index 0000000..8f290ff
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/contracts/mainactivity/MainViewContract.java
@@ -0,0 +1,5 @@
+package io.github.chronosx88.influence.contracts.mainactivity;
+
+public interface MainViewContract {
+ //
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/ChatAdapter.java b/app/src/main/java/io/github/chronosx88/influence/helpers/ChatAdapter.java
new file mode 100644
index 0000000..4ead9c5
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/ChatAdapter.java
@@ -0,0 +1,84 @@
+package io.github.chronosx88.influence.helpers;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import de.hdodenhof.circleimageview.CircleImageView;
+import io.github.chronosx88.influence.R;
+import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
+
+public class ChatAdapter extends RecyclerView.Adapter {
+ private final static int RIGHT_ITEM = 0;
+ private final static int LEFT_ITEM = 1;
+ private final static int TECHNICAL_MESSAGE = 2; // TODO
+
+ private final static Context context = AppHelper.getContext();
+ private ArrayList messages = new ArrayList<>();
+
+ @NonNull
+ @Override
+ public ChatAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ if(viewType == RIGHT_ITEM) {
+ return new ChatAdapter.ViewHolder(LayoutInflater.from(context).inflate(R.layout.message_right_item, parent, false));
+ } else {
+ return new ChatAdapter.ViewHolder(LayoutInflater.from(context).inflate(R.layout.message_left_item, parent, false));
+ }
+ }
+
+ public void addMessage(MessageEntity message) {
+ messages.add(message);
+ }
+
+ public void addMessages(List messages) {
+ this.messages.addAll(messages);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ChatAdapter.ViewHolder holder, int position) {
+ // Setting message text
+ holder.messageText.setText(messages.get(position).text);
+
+ // Setting message time (HOUR:MINUTE)
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date(messages.get(position).timestamp));
+ String time = calendar.get(Calendar.HOUR) + ":" + calendar.get(Calendar.MINUTE);
+ holder.messageTime.setText(time);
+ }
+
+ @Override
+ public int getItemCount() {
+ return messages.size();
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if(messages.get(position).sender.equals(AppHelper.getPeerID())) {
+ return RIGHT_ITEM;
+ } else {
+ return LEFT_ITEM;
+ }
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+ TextView messageText;
+ CircleImageView profileImage;
+ TextView messageTime;
+
+ public ViewHolder(View itemView) {
+ super(itemView);
+ messageText = itemView.findViewById(R.id.message_text);
+ profileImage = itemView.findViewById(R.id.profile_image);
+ messageTime = itemView.findViewById(R.id.message_time);
+ }
+ }
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/ChatListAdapter.java b/app/src/main/java/io/github/chronosx88/influence/helpers/ChatListAdapter.java
index 90771a5..29942aa 100644
--- a/app/src/main/java/io/github/chronosx88/influence/helpers/ChatListAdapter.java
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/ChatListAdapter.java
@@ -12,11 +12,17 @@ import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import io.github.chronosx88.influence.R;
+import io.github.chronosx88.influence.contracts.ItemClickListener;
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
public class ChatListAdapter extends RecyclerView.Adapter {
List chatList = new ArrayList<>();
public int onClickPosition = -1;
+ private ItemClickListener itemClickListener;
+
+ public ChatListAdapter(ItemClickListener itemClickListener) {
+ this.itemClickListener = itemClickListener;
+ }
@NonNull
@Override
@@ -41,6 +47,10 @@ public class ChatListAdapter extends RecyclerView.Adapter {
+ itemClickListener.onItemClick(v, getAdapterPosition());
+ });
}
public void onLongClick(int position) {
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java b/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java
index 5061110..ca4472f 100644
--- a/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java
@@ -37,15 +37,43 @@ public class LocalDBWrapper {
* @param chatID ID of the chat in which need to create a message
* @param sender Message sender (username)
* @param text Message text (or technical info if technical message type)
- * @return
+ * @return Message ID (in local DB)
*/
- public static boolean createMessageEntry(int type, String chatID, String sender, String text) {
+ public static long createMessageEntry(int type, String chatID, String sender, String text) {
List chatEntities = AppHelper.getChatDB().chatDao().getChatByChatID(chatID);
if(chatEntities.size() < 1) {
Log.e(LOG_TAG, "Failed to create message entry because chat " + chatID + " doesn't exists!");
- return false;
+ return -1;
}
- dbInstance.messageDao().insertMessage(new MessageEntity(type, chatID, sender, new Date().getTime(), text));
- return true;
+ MessageEntity message = new MessageEntity(type, chatID, sender, new Date().getTime(), text, false, false);
+ return dbInstance.messageDao().insertMessage(message);
+ }
+
+ public static MessageEntity getMessageByID(long id) {
+ List messages = dbInstance.messageDao().getMessageByID(id);
+ if(messages.isEmpty()) {
+ return null;
+ }
+ return messages.get(0);
+ }
+
+ public static List getMessagesByChatID(String chatID) {
+ List messages = dbInstance.messageDao().getMessagesByChatID(chatID);
+ if(messages.isEmpty()) {
+ return null;
+ }
+ return messages;
+ }
+
+ public static ChatEntity getChatByChatID(String chatID) {
+ List chats = dbInstance.chatDao().getChatByChatID(chatID);
+ if(chats.isEmpty()) {
+ return null;
+ }
+ return chats.get(0);
+ }
+
+ public static void updateChatEntry(long id, boolean isSent) {
+ dbInstance.messageDao().updateMessage(id, isSent);
}
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/MessageTypes.java b/app/src/main/java/io/github/chronosx88/influence/helpers/MessageTypes.java
new file mode 100644
index 0000000..579ae88
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/MessageTypes.java
@@ -0,0 +1,5 @@
+package io.github.chronosx88.influence.helpers;
+
+public class MessageTypes {
+ public static final int USUAL_MESSAGE = 0x0;
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java b/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java
index c8ae371..cbc8259 100644
--- a/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java
@@ -6,25 +6,21 @@ import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
-import net.tomp2p.dht.FutureGet;
-import net.tomp2p.dht.FuturePut;
-import net.tomp2p.dht.FutureRemove;
import net.tomp2p.dht.PeerDHT;
-import net.tomp2p.futures.FuturePing;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.Number640;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.storage.Data;
import java.io.IOException;
-import java.util.List;
import java.util.Map;
import io.github.chronosx88.influence.contracts.observer.NetworkObserver;
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
import io.github.chronosx88.influence.helpers.actions.UIActions;
import io.github.chronosx88.influence.models.NewChatRequestMessage;
-import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
+import io.github.chronosx88.influence.models.SendMessage;
+import io.github.chronosx88.influence.models.SuccessfullySentMessage;
public class NetworkHandler implements NetworkObserver {
private final static String LOG_TAG = "NetworkHandler";
@@ -54,6 +50,19 @@ public class NetworkHandler implements NetworkObserver {
ObservableUtils.notifyUI(UIActions.SUCCESSFUL_CREATE_CHAT);
break;
}
+
+ case NetworkActions.NEW_MESSAGE: {
+ SendMessage sendMessage = gson.fromJson((String) object, SendMessage.class);
+ long messageID = LocalDBWrapper.createMessageEntry(sendMessage.getMessageType(), sendMessage.getChatID(), sendMessage.getSenderID(), sendMessage.getText());
+ ObservableUtils.notifyUI(UIActions.MESSAGE_RECEIVED, messageID);
+ sendMessageReceived(sendMessage);
+ break;
+ }
+
+ case NetworkActions.MESSAGE_SENT: {
+ SuccessfullySentMessage successfullySentMessage = gson.fromJson((String) object, SuccessfullySentMessage.class);
+ LocalDBWrapper.updateChatEntry(successfullySentMessage.getMessageID(), true);
+ }
}
}).start();
}
@@ -64,7 +73,6 @@ public class NetworkHandler implements NetworkObserver {
}
-
private void handleIncomingChatRequest(String chatID, PeerAddress chatStarterAddress) {
NewChatRequestMessage newChatRequestMessage = new NewChatRequestMessage(chatID, AppHelper.getPeerID(), peerDHT.peerAddress());
newChatRequestMessage.setAction(NetworkActions.SUCCESSFULL_CREATE_CHAT);
@@ -115,7 +123,7 @@ public class NetworkHandler implements NetworkObserver {
.awaitUninterruptibly();
}
- ObservableUtils.notifyUI(UIActions.NEW_CHAT);
+ ObservableUtils.notifyUI(UIActions.SUCCESSFUL_CREATE_CHAT);
}
}
}
@@ -132,19 +140,25 @@ public class NetworkHandler implements NetworkObserver {
e.printStackTrace();
}
- LocalDBWrapper.createChatEntry(
- newChatRequestMessage.getChatID(),
+ /*LocalDBWrapper.createChatEntry(
+ newChatRequestMessage.getMessageID(),
newChatRequestMessage.getSenderID(),
newChatRequestMessage.getSenderPeerAddress()
- );
+ );*/
+
+ Log.i(LOG_TAG, "Chat " + newChatRequestMessage.getChatID() + " successfully accepted!");
peerDHT.remove(Number160.createHash(AppHelper.getPeerID() + "_pendingAcceptedChats"))
.contentKey(Number160.createHash(newChatRequestMessage.getChatID()))
.start()
.awaitUninterruptibly();
- ObservableUtils.notifyUI(UIActions.NEW_CHAT);
+ ObservableUtils.notifyUI(UIActions.SUCCESSFUL_CREATE_CHAT);
}
}
}
+
+ private void sendMessageReceived(SendMessage sendMessage) {
+ P2PUtils.send(sendMessage.getSenderPeerAddress(), gson.toJson(new SuccessfullySentMessage(AppHelper.getPeerID(), AppHelper.getPeerDHT().peerAddress(), sendMessage.getMessageID())));
+ }
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java b/app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java
index 6a02596..182bda3 100644
--- a/app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java
@@ -8,4 +8,18 @@ public class ObservableUtils {
jsonObject.addProperty("action", action);
AppHelper.getObservable().notifyUIObservers(jsonObject);
}
+
+ public static void notifyUI(int action, String additional) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("action", action);
+ jsonObject.addProperty("additional", additional);
+ AppHelper.getObservable().notifyUIObservers(jsonObject);
+ }
+
+ public static void notifyUI(int action, long additional) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("action", action);
+ jsonObject.addProperty("additional", additional);
+ AppHelper.getObservable().notifyUIObservers(jsonObject);
+ }
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/P2PUtils.java b/app/src/main/java/io/github/chronosx88/influence/helpers/P2PUtils.java
index adcfb1b..dfb48d9 100644
--- a/app/src/main/java/io/github/chronosx88/influence/helpers/P2PUtils.java
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/P2PUtils.java
@@ -5,6 +5,7 @@ import com.google.gson.Gson;
import net.tomp2p.dht.FutureGet;
import net.tomp2p.dht.FuturePut;
import net.tomp2p.dht.PeerDHT;
+import net.tomp2p.futures.FutureDirect;
import net.tomp2p.futures.FuturePing;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.Number640;
@@ -59,4 +60,14 @@ public class P2PUtils {
}
return null;
}
+
+ public static boolean send(PeerAddress address, String data) {
+ FutureDirect futureDirect = peerDHT
+ .peer()
+ .sendDirect(address)
+ .object(data)
+ .start()
+ .awaitUninterruptibly();
+ return futureDirect.isSuccess();
+ }
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java b/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java
index 459b8ed..b791d6f 100644
--- a/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java
+++ b/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java
@@ -10,4 +10,5 @@ public class UIActions {
public static final int NEW_CHAT = 0x6;
public static final int PEER_NOT_EXIST = 0x7;
public static final int SUCCESSFUL_CREATE_CHAT = 0x8;
+ public static final int MESSAGE_RECEIVED = 0x9;
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/logic/ChatLogic.java b/app/src/main/java/io/github/chronosx88/influence/logic/ChatLogic.java
new file mode 100644
index 0000000..88cdea9
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/logic/ChatLogic.java
@@ -0,0 +1,33 @@
+package io.github.chronosx88.influence.logic;
+
+import com.google.gson.Gson;
+
+import net.tomp2p.peers.PeerAddress;
+
+import io.github.chronosx88.influence.contracts.chatactivity.ChatLogicContract;
+import io.github.chronosx88.influence.helpers.AppHelper;
+import io.github.chronosx88.influence.helpers.P2PUtils;
+import io.github.chronosx88.influence.models.SendMessage;
+import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
+
+public class ChatLogic implements ChatLogicContract {
+ private static Gson gson = new Gson();
+ @Override
+ public void sendMessage(PeerAddress address, MessageEntity message) {
+ new Thread(() -> {
+ P2PUtils
+ .send(address, gson.toJson(
+ new SendMessage(
+ AppHelper.getPeerID(),
+ AppHelper.getPeerDHT().peerAddress(),
+ message.id,
+ message.timestamp,
+ message.type,
+ message.chatID,
+ message.text
+ )
+ ));
+ }).start();
+ // TODO: put message into DHT if user is offline
+ }
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java b/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java
index 4e955be..a281c3e 100644
--- a/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java
+++ b/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java
@@ -7,7 +7,6 @@ import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
-import net.tomp2p.dht.FuturePut;
import net.tomp2p.dht.PeerBuilderDHT;
import net.tomp2p.dht.PeerDHT;
import net.tomp2p.futures.FutureBootstrap;
@@ -33,7 +32,7 @@ import java.security.spec.DSAPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.util.UUID;
-import io.github.chronosx88.influence.contracts.main.MainLogicContract;
+import io.github.chronosx88.influence.contracts.mainactivity.MainLogicContract;
import io.github.chronosx88.influence.helpers.AppHelper;
import io.github.chronosx88.influence.helpers.DSAKey;
import io.github.chronosx88.influence.helpers.KeyPairManager;
diff --git a/app/src/main/java/io/github/chronosx88/influence/models/SendMessage.java b/app/src/main/java/io/github/chronosx88/influence/models/SendMessage.java
new file mode 100644
index 0000000..388402d
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/models/SendMessage.java
@@ -0,0 +1,64 @@
+package io.github.chronosx88.influence.models;
+
+import net.tomp2p.peers.PeerAddress;
+
+import java.io.Serializable;
+
+import io.github.chronosx88.influence.helpers.actions.NetworkActions;
+
+public class SendMessage extends BasicNetworkMessage implements Serializable {
+ private long messageID;
+ private long timestamp;
+ private int messageType;
+ private String chatID;
+ private String text;
+
+ public SendMessage(String senderID, PeerAddress senderPeerAddress, long messageID,long timestamp, int messageType, String chatID, String text) {
+ super(NetworkActions.NEW_MESSAGE, senderID, senderPeerAddress);
+ this.messageID = messageID;
+ this.timestamp = timestamp;
+ this.messageType = messageType;
+ this.chatID = chatID;
+ this.text = text;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public int getMessageType() {
+ return messageType;
+ }
+
+ public String getChatID() {
+ return chatID;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public void setMessageType(int messageType) {
+ this.messageType = messageType;
+ }
+
+ public void setChatID(String chatID) {
+ this.chatID = chatID;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public long getMessageID() {
+ return messageID;
+ }
+
+ public void setMessageID(long messageID) {
+ this.messageID = messageID;
+ }
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/models/SuccessfullySentMessage.java b/app/src/main/java/io/github/chronosx88/influence/models/SuccessfullySentMessage.java
new file mode 100644
index 0000000..da24345
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/models/SuccessfullySentMessage.java
@@ -0,0 +1,24 @@
+package io.github.chronosx88.influence.models;
+
+import net.tomp2p.peers.PeerAddress;
+
+import java.io.Serializable;
+
+import io.github.chronosx88.influence.helpers.actions.NetworkActions;
+
+public class SuccessfullySentMessage extends BasicNetworkMessage implements Serializable {
+ private long messageID;
+
+ public SuccessfullySentMessage(String senderID, PeerAddress senderPeerAddress, long messageID) {
+ super(NetworkActions.MESSAGE_SENT, senderID, senderPeerAddress);
+ this.messageID = messageID;
+ }
+
+ public long getMessageID() {
+ return messageID;
+ }
+
+ public void setMessageID(long messageID) {
+ this.messageID = messageID;
+ }
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java b/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java
index a93d7c8..5bbb1ca 100644
--- a/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java
+++ b/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java
@@ -10,10 +10,10 @@ import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
@Dao
public interface MessageDao {
@Insert
- void insertMessage(MessageEntity chatModel);
+ long insertMessage(MessageEntity chatModel);
@Query("DELETE FROM messages WHERE id = :msgID")
- void deleteMessage(String msgID);
+ void deleteMessage(long msgID);
@Query("DELETE FROM messages WHERE chatID = :chatID")
void deleteMessagesByChatID(String chatID);
@@ -22,5 +22,11 @@ public interface MessageDao {
List getMessagesByChatID(String chatID);
@Query("SELECT * FROM messages WHERE id = :id")
- List getMessageByID(String id);
+ List getMessageByID(long id);
+
+ @Query("UPDATE messages SET isSent = :isSent WHERE id = :msgID")
+ void updateMessage(long msgID, boolean isSent);
+
+ @Query("UPDATE messages SET text = :text WHERE id = :msgID")
+ void updateMessage(long msgID, String text);
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/models/roomEntities/MessageEntity.java b/app/src/main/java/io/github/chronosx88/influence/models/roomEntities/MessageEntity.java
index facffe6..479b4cb 100644
--- a/app/src/main/java/io/github/chronosx88/influence/models/roomEntities/MessageEntity.java
+++ b/app/src/main/java/io/github/chronosx88/influence/models/roomEntities/MessageEntity.java
@@ -7,41 +7,23 @@ import androidx.room.PrimaryKey;
@Entity(tableName = "messages")
public class MessageEntity {
- @PrimaryKey(autoGenerate = true) public int id;
+ @PrimaryKey(autoGenerate = true) public long id;
@ColumnInfo public int type;
@ColumnInfo public String chatID;
@ColumnInfo public String sender;
@ColumnInfo public long timestamp;
@ColumnInfo public String text;
+ @ColumnInfo public boolean isSent;
+ @ColumnInfo public boolean isRead;
- public MessageEntity(int type, String chatID, String sender, long timestamp, String text) {
+ public MessageEntity(int type, String chatID, String sender, long timestamp, String text, boolean isSent, boolean isRead) {
this.type = type;
this.chatID = chatID;
this.sender = sender;
this.timestamp = timestamp;
this.text = text;
- }
-
- public int getId() {
- return id;
- }
-
- public int getType() { return type; }
-
- public String getChatID() {
- return chatID;
- }
-
- public long getTimestamp() {
- return timestamp;
- }
-
- public String getSender() {
- return sender;
- }
-
- public String getText() {
- return text;
+ this.isSent = isSent;
+ this.isRead = isRead;
}
@NonNull
diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java
index b62c90b..b42c15b 100644
--- a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java
+++ b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java
@@ -1,5 +1,6 @@
package io.github.chronosx88.influence.presenters;
+import android.content.Intent;
import android.view.MenuItem;
import net.tomp2p.dht.FutureRemove;
@@ -10,8 +11,10 @@ import io.github.chronosx88.influence.contracts.chatlist.ChatListPresenterContra
import io.github.chronosx88.influence.contracts.chatlist.ChatListViewContract;
import io.github.chronosx88.influence.helpers.AppHelper;
import io.github.chronosx88.influence.helpers.ChatListAdapter;
+import io.github.chronosx88.influence.helpers.LocalDBWrapper;
import io.github.chronosx88.influence.logic.ChatListLogic;
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
+import io.github.chronosx88.influence.views.ChatActivity;
public class ChatListPresenter implements ChatListPresenterContract {
private ChatListViewContract view;
@@ -20,7 +23,9 @@ public class ChatListPresenter implements ChatListPresenterContract {
public ChatListPresenter(ChatListViewContract view) {
this.view = view;
- chatListAdapter = new ChatListAdapter();
+ chatListAdapter = new ChatListAdapter((v, p)-> {
+ openChat(chatListAdapter.getChatEntity(p).chatID);
+ });
this.logic = new ChatListLogic();
this.view.setRecycleAdapter(chatListAdapter);
}
@@ -32,7 +37,10 @@ public class ChatListPresenter implements ChatListPresenterContract {
@Override
public void openChat(String chatID) {
- // TODO
+ Intent intent = new Intent(AppHelper.getContext(), ChatActivity.class);
+ intent.putExtra("chatID", chatID);
+ intent.putExtra("contactUsername", LocalDBWrapper.getChatByChatID(chatID).name);
+ view.startActivity(intent);
}
@Override
@@ -43,6 +51,7 @@ public class ChatListPresenter implements ChatListPresenterContract {
new Thread(() -> {
ChatEntity chat = chatListAdapter.getItem(chatListAdapter.onClickPosition);
AppHelper.getChatDB().chatDao().deleteChat(chat.chatID);
+ AppHelper.getChatDB().messageDao().deleteMessagesByChatID(chat.chatID);
view.updateChatList(chatListAdapter, logic.loadAllChats());
}).start();
}
diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.java b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.java
new file mode 100644
index 0000000..626a00b
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.java
@@ -0,0 +1,62 @@
+package io.github.chronosx88.influence.presenters;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+import net.tomp2p.peers.PeerAddress;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.github.chronosx88.influence.contracts.chatactivity.ChatLogicContract;
+import io.github.chronosx88.influence.contracts.chatactivity.ChatPresenterContract;
+import io.github.chronosx88.influence.contracts.chatactivity.ChatViewContract;
+import io.github.chronosx88.influence.contracts.observer.Observer;
+import io.github.chronosx88.influence.helpers.AppHelper;
+import io.github.chronosx88.influence.helpers.LocalDBWrapper;
+import io.github.chronosx88.influence.helpers.MessageTypes;
+import io.github.chronosx88.influence.helpers.Serializer;
+import io.github.chronosx88.influence.helpers.actions.UIActions;
+import io.github.chronosx88.influence.logic.ChatLogic;
+import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
+
+public class ChatPresenter implements ChatPresenterContract, Observer {
+ private ChatLogicContract logic;
+ private ChatViewContract view;
+ private PeerAddress receiverAddress;
+ private String chatID;
+ private Gson gson;
+
+ public ChatPresenter(ChatViewContract view, String chatID) {
+ this.logic = new ChatLogic();
+ this.view = view;
+ this.chatID = chatID;
+ this.receiverAddress = (PeerAddress) Serializer.deserialize(LocalDBWrapper.getChatByChatID(chatID).getPeerAddress());
+ AppHelper.getObservable().register(this);
+ gson = new Gson();
+ }
+
+ @Override
+ public void sendMessage(String text) {
+ long messageID = LocalDBWrapper.createMessageEntry(MessageTypes.USUAL_MESSAGE, chatID, AppHelper.getPeerID(), text);
+ MessageEntity message = LocalDBWrapper.getMessageByID(messageID);
+ logic.sendMessage(receiverAddress, message);
+ view.updateMessageList(message);
+ }
+
+ @Override
+ public void handleEvent(JsonObject object) {
+ switch (object.get("action").getAsInt()) {
+ case UIActions.MESSAGE_RECEIVED: {
+ MessageEntity messageEntity = LocalDBWrapper.getMessageByID(object.get("additional").getAsInt());
+ view.updateMessageList(messageEntity);
+ }
+ }
+ }
+
+ @Override
+ public void updateAdapter() {
+ List entities = LocalDBWrapper.getMessagesByChatID(chatID);
+ view.updateMessageList(entities == null ? new ArrayList<>() : entities);
+ }
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/MainPresenter.java b/app/src/main/java/io/github/chronosx88/influence/presenters/MainPresenter.java
index c51f552..c24d6a7 100644
--- a/app/src/main/java/io/github/chronosx88/influence/presenters/MainPresenter.java
+++ b/app/src/main/java/io/github/chronosx88/influence/presenters/MainPresenter.java
@@ -1,8 +1,8 @@
package io.github.chronosx88.influence.presenters;
-import io.github.chronosx88.influence.contracts.main.MainLogicContract;
-import io.github.chronosx88.influence.contracts.main.MainPresenterContract;
-import io.github.chronosx88.influence.contracts.main.MainViewContract;
+import io.github.chronosx88.influence.contracts.mainactivity.MainLogicContract;
+import io.github.chronosx88.influence.contracts.mainactivity.MainPresenterContract;
+import io.github.chronosx88.influence.contracts.mainactivity.MainViewContract;
import io.github.chronosx88.influence.logic.MainLogic;
public class MainPresenter implements MainPresenterContract {
diff --git a/app/src/main/java/io/github/chronosx88/influence/views/ChatActivity.java b/app/src/main/java/io/github/chronosx88/influence/views/ChatActivity.java
new file mode 100644
index 0000000..8180435
--- /dev/null
+++ b/app/src/main/java/io/github/chronosx88/influence/views/ChatActivity.java
@@ -0,0 +1,72 @@
+package io.github.chronosx88.influence.views;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import java.util.List;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import io.github.chronosx88.influence.R;
+import io.github.chronosx88.influence.contracts.chatactivity.ChatViewContract;
+import io.github.chronosx88.influence.helpers.ChatAdapter;
+import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
+import io.github.chronosx88.influence.presenters.ChatPresenter;
+
+public class ChatActivity extends AppCompatActivity implements ChatViewContract {
+ private ChatAdapter chatAdapter;
+ private RecyclerView messageList;
+ private ImageButton sendMessageButton;
+ private EditText messageTextEdit;
+ private TextView contactUsernameTextView;
+ private ChatPresenter presenter;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_chat);
+
+ Intent intent = getIntent();
+
+ presenter = new ChatPresenter(this, intent.getStringExtra("chatID"));
+
+ Toolbar toolbar = findViewById(R.id.toolbar_chat_activity);
+ setSupportActionBar(toolbar);
+ messageList = findViewById(R.id.message_list);
+ chatAdapter = new ChatAdapter();
+ presenter.updateAdapter();
+ messageList.setAdapter(chatAdapter);
+ messageList.setLayoutManager(new LinearLayoutManager(this));
+ contactUsernameTextView = findViewById(R.id.appbar_username);
+ messageTextEdit = findViewById(R.id.message_input);
+ sendMessageButton = findViewById(R.id.send_button);
+ sendMessageButton.setOnClickListener((v) -> {
+ presenter.sendMessage(messageTextEdit.getText().toString());
+ });
+ contactUsernameTextView.setText(intent.getStringExtra("contactUsername"));
+
+
+ }
+
+ @Override
+ public void updateMessageList(MessageEntity message) {
+ runOnUiThread(() -> {
+ chatAdapter.addMessage(message);
+ chatAdapter.notifyDataSetChanged();
+ });
+ }
+
+ @Override
+ public void updateMessageList(List messages) {
+ runOnUiThread(() -> {
+ chatAdapter.addMessages(messages);
+ chatAdapter.notifyDataSetChanged();
+ });
+ }
+}
diff --git a/app/src/main/java/io/github/chronosx88/influence/views/MainActivity.java b/app/src/main/java/io/github/chronosx88/influence/views/MainActivity.java
index b9edbd6..100d6da 100644
--- a/app/src/main/java/io/github/chronosx88/influence/views/MainActivity.java
+++ b/app/src/main/java/io/github/chronosx88/influence/views/MainActivity.java
@@ -13,8 +13,8 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import io.github.chronosx88.influence.R;
-import io.github.chronosx88.influence.contracts.main.MainPresenterContract;
-import io.github.chronosx88.influence.contracts.main.MainViewContract;
+import io.github.chronosx88.influence.contracts.mainactivity.MainPresenterContract;
+import io.github.chronosx88.influence.contracts.mainactivity.MainViewContract;
import io.github.chronosx88.influence.contracts.observer.Observer;
import io.github.chronosx88.influence.helpers.AppHelper;
import io.github.chronosx88.influence.helpers.actions.UIActions;
diff --git a/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java b/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java
index fcf4251..0038231 100644
--- a/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java
+++ b/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java
@@ -68,8 +68,10 @@ public class ChatListFragment extends Fragment implements ChatListViewContract,
@Override
public void handleEvent(JsonObject object) {
switch (object.get("action").getAsInt()) {
+ case UIActions.SUCCESSFUL_CREATE_CHAT:
case UIActions.NEW_CHAT: {
presenter.updateChatList();
+ break;
}
}
}
diff --git a/app/src/main/res/drawable/ic_send_green_24dp.xml b/app/src/main/res/drawable/ic_send_green_24dp.xml
new file mode 100644
index 0000000..475c0fa
--- /dev/null
+++ b/app/src/main/res/drawable/ic_send_green_24dp.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_chat.xml b/app/src/main/res/layout/activity_chat.xml
new file mode 100644
index 0000000..a8b9192
--- /dev/null
+++ b/app/src/main/res/layout/activity_chat.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/message_left_item.xml b/app/src/main/res/layout/message_left_item.xml
index 0b43940..9b2a1cd 100644
--- a/app/src/main/res/layout/message_left_item.xml
+++ b/app/src/main/res/layout/message_left_item.xml
@@ -11,27 +11,27 @@
diff --git a/app/src/main/res/layout/message_right_item.xml b/app/src/main/res/layout/message_right_item.xml
index 0ccac27..7ed414a 100644
--- a/app/src/main/res/layout/message_right_item.xml
+++ b/app/src/main/res/layout/message_right_item.xml
@@ -25,7 +25,7 @@
android:layout_toLeftOf="@id/profile_image"
android:layout_marginEnd="4dp"
android:layout_marginTop="7dp"
- android:id="@+id/message_text_right"
+ android:id="@+id/message_text"
android:textSize="18sp"
android:paddingEnd="50dp"
android:textColor="#ffffff"
@@ -33,9 +33,9 @@
@android:color/transparent
+
+
+
+