mirror of
https://github.com/ChronosX88/Influence-P2P.git
synced 2024-11-22 07:12:19 +00:00
[WIP] Made chat works
This commit is contained in:
parent
61e660329d
commit
6a5fdcb733
@ -2,11 +2,11 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"identityHash": "aa6543fc56b99224739cb0b53a63d48e",
|
"identityHash": "a24b31a8e1f482a72f55843041945d5b",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "messages",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "id",
|
"fieldPath": "id",
|
||||||
@ -43,6 +43,18 @@
|
|||||||
"columnName": "text",
|
"columnName": "text",
|
||||||
"affinity": "TEXT",
|
"affinity": "TEXT",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isSent",
|
||||||
|
"columnName": "isSent",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isRead",
|
||||||
|
"columnName": "isRead",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
@ -102,7 +114,7 @@
|
|||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"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\")"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,6 +18,9 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".views.ChatActivity"
|
||||||
|
android:theme="@style/NoWindowActionBar"/>
|
||||||
</application>
|
</application>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
</manifest>
|
</manifest>
|
@ -0,0 +1,7 @@
|
|||||||
|
package io.github.chronosx88.influence.contracts;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public interface ItemClickListener {
|
||||||
|
void onItemClick(View view, int position);
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package io.github.chronosx88.influence.contracts.chatactivity;
|
||||||
|
|
||||||
|
public interface ChatPresenterContract {
|
||||||
|
void sendMessage(String text);
|
||||||
|
void updateAdapter();
|
||||||
|
}
|
@ -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<MessageEntity> messages);
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package io.github.chronosx88.influence.contracts.chatlist;
|
package io.github.chronosx88.influence.contracts.chatlist;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.github.chronosx88.influence.helpers.ChatListAdapter;
|
import io.github.chronosx88.influence.helpers.ChatListAdapter;
|
||||||
@ -7,5 +9,6 @@ import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
|||||||
|
|
||||||
public interface ChatListViewContract {
|
public interface ChatListViewContract {
|
||||||
void setRecycleAdapter(ChatListAdapter adapter);
|
void setRecycleAdapter(ChatListAdapter adapter);
|
||||||
|
void startActivity(Intent intent);
|
||||||
void updateChatList(ChatListAdapter adapter, List<ChatEntity> chats);
|
void updateChatList(ChatListAdapter adapter, List<ChatEntity> chats);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package io.github.chronosx88.influence.contracts.main;
|
|
||||||
|
|
||||||
public interface MainViewContract {
|
|
||||||
//
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.chronosx88.influence.contracts.main;
|
package io.github.chronosx88.influence.contracts.mainactivity;
|
||||||
|
|
||||||
public interface MainLogicContract {
|
public interface MainLogicContract {
|
||||||
void initPeer();
|
void initPeer();
|
@ -1,4 +1,4 @@
|
|||||||
package io.github.chronosx88.influence.contracts.main;
|
package io.github.chronosx88.influence.contracts.mainactivity;
|
||||||
|
|
||||||
public interface MainPresenterContract {
|
public interface MainPresenterContract {
|
||||||
void initPeer();
|
void initPeer();
|
@ -0,0 +1,5 @@
|
|||||||
|
package io.github.chronosx88.influence.contracts.mainactivity;
|
||||||
|
|
||||||
|
public interface MainViewContract {
|
||||||
|
//
|
||||||
|
}
|
@ -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<ChatAdapter.ViewHolder> {
|
||||||
|
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<MessageEntity> 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<MessageEntity> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,11 +12,17 @@ import java.util.List;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import io.github.chronosx88.influence.R;
|
import io.github.chronosx88.influence.R;
|
||||||
|
import io.github.chronosx88.influence.contracts.ItemClickListener;
|
||||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||||
|
|
||||||
public class ChatListAdapter extends RecyclerView.Adapter<ChatListAdapter.ChatListViewHolder> {
|
public class ChatListAdapter extends RecyclerView.Adapter<ChatListAdapter.ChatListViewHolder> {
|
||||||
List<ChatEntity> chatList = new ArrayList<>();
|
List<ChatEntity> chatList = new ArrayList<>();
|
||||||
public int onClickPosition = -1;
|
public int onClickPosition = -1;
|
||||||
|
private ItemClickListener itemClickListener;
|
||||||
|
|
||||||
|
public ChatListAdapter(ItemClickListener itemClickListener) {
|
||||||
|
this.itemClickListener = itemClickListener;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@ -41,6 +47,10 @@ public class ChatListAdapter extends RecyclerView.Adapter<ChatListAdapter.ChatLi
|
|||||||
holder.onLongClick(position);
|
holder.onLongClick(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ChatEntity getChatEntity(int position) {
|
||||||
|
return chatList.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return chatList.size();
|
return chatList.size();
|
||||||
@ -53,6 +63,9 @@ public class ChatListAdapter extends RecyclerView.Adapter<ChatListAdapter.ChatLi
|
|||||||
super(itemView);
|
super(itemView);
|
||||||
chatName = itemView.findViewById(R.id.chat_name);
|
chatName = itemView.findViewById(R.id.chat_name);
|
||||||
itemView.setOnCreateContextMenuListener(this);
|
itemView.setOnCreateContextMenuListener(this);
|
||||||
|
itemView.setOnClickListener((v) -> {
|
||||||
|
itemClickListener.onItemClick(v, getAdapterPosition());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLongClick(int position) {
|
public void onLongClick(int position) {
|
||||||
|
@ -37,15 +37,43 @@ public class LocalDBWrapper {
|
|||||||
* @param chatID ID of the chat in which need to create a message
|
* @param chatID ID of the chat in which need to create a message
|
||||||
* @param sender Message sender (username)
|
* @param sender Message sender (username)
|
||||||
* @param text Message text (or technical info if technical message type)
|
* @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<ChatEntity> chatEntities = AppHelper.getChatDB().chatDao().getChatByChatID(chatID);
|
List<ChatEntity> chatEntities = AppHelper.getChatDB().chatDao().getChatByChatID(chatID);
|
||||||
if(chatEntities.size() < 1) {
|
if(chatEntities.size() < 1) {
|
||||||
Log.e(LOG_TAG, "Failed to create message entry because chat " + chatID + " doesn't exists!");
|
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));
|
MessageEntity message = new MessageEntity(type, chatID, sender, new Date().getTime(), text, false, false);
|
||||||
return true;
|
return dbInstance.messageDao().insertMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MessageEntity getMessageByID(long id) {
|
||||||
|
List<MessageEntity> messages = dbInstance.messageDao().getMessageByID(id);
|
||||||
|
if(messages.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return messages.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<MessageEntity> getMessagesByChatID(String chatID) {
|
||||||
|
List<MessageEntity> messages = dbInstance.messageDao().getMessagesByChatID(chatID);
|
||||||
|
if(messages.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChatEntity getChatByChatID(String chatID) {
|
||||||
|
List<ChatEntity> 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package io.github.chronosx88.influence.helpers;
|
||||||
|
|
||||||
|
public class MessageTypes {
|
||||||
|
public static final int USUAL_MESSAGE = 0x0;
|
||||||
|
}
|
@ -6,25 +6,21 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
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.dht.PeerDHT;
|
||||||
import net.tomp2p.futures.FuturePing;
|
|
||||||
import net.tomp2p.peers.Number160;
|
import net.tomp2p.peers.Number160;
|
||||||
import net.tomp2p.peers.Number640;
|
import net.tomp2p.peers.Number640;
|
||||||
import net.tomp2p.peers.PeerAddress;
|
import net.tomp2p.peers.PeerAddress;
|
||||||
import net.tomp2p.storage.Data;
|
import net.tomp2p.storage.Data;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.github.chronosx88.influence.contracts.observer.NetworkObserver;
|
import io.github.chronosx88.influence.contracts.observer.NetworkObserver;
|
||||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
||||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||||
import io.github.chronosx88.influence.models.NewChatRequestMessage;
|
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 {
|
public class NetworkHandler implements NetworkObserver {
|
||||||
private final static String LOG_TAG = "NetworkHandler";
|
private final static String LOG_TAG = "NetworkHandler";
|
||||||
@ -54,6 +50,19 @@ public class NetworkHandler implements NetworkObserver {
|
|||||||
ObservableUtils.notifyUI(UIActions.SUCCESSFUL_CREATE_CHAT);
|
ObservableUtils.notifyUI(UIActions.SUCCESSFUL_CREATE_CHAT);
|
||||||
break;
|
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();
|
}).start();
|
||||||
}
|
}
|
||||||
@ -64,7 +73,6 @@ public class NetworkHandler implements NetworkObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void handleIncomingChatRequest(String chatID, PeerAddress chatStarterAddress) {
|
private void handleIncomingChatRequest(String chatID, PeerAddress chatStarterAddress) {
|
||||||
NewChatRequestMessage newChatRequestMessage = new NewChatRequestMessage(chatID, AppHelper.getPeerID(), peerDHT.peerAddress());
|
NewChatRequestMessage newChatRequestMessage = new NewChatRequestMessage(chatID, AppHelper.getPeerID(), peerDHT.peerAddress());
|
||||||
newChatRequestMessage.setAction(NetworkActions.SUCCESSFULL_CREATE_CHAT);
|
newChatRequestMessage.setAction(NetworkActions.SUCCESSFULL_CREATE_CHAT);
|
||||||
@ -115,7 +123,7 @@ public class NetworkHandler implements NetworkObserver {
|
|||||||
.awaitUninterruptibly();
|
.awaitUninterruptibly();
|
||||||
}
|
}
|
||||||
|
|
||||||
ObservableUtils.notifyUI(UIActions.NEW_CHAT);
|
ObservableUtils.notifyUI(UIActions.SUCCESSFUL_CREATE_CHAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,19 +140,25 @@ public class NetworkHandler implements NetworkObserver {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDBWrapper.createChatEntry(
|
/*LocalDBWrapper.createChatEntry(
|
||||||
newChatRequestMessage.getChatID(),
|
newChatRequestMessage.getMessageID(),
|
||||||
newChatRequestMessage.getSenderID(),
|
newChatRequestMessage.getSenderID(),
|
||||||
newChatRequestMessage.getSenderPeerAddress()
|
newChatRequestMessage.getSenderPeerAddress()
|
||||||
);
|
);*/
|
||||||
|
|
||||||
|
Log.i(LOG_TAG, "Chat " + newChatRequestMessage.getChatID() + " successfully accepted!");
|
||||||
|
|
||||||
peerDHT.remove(Number160.createHash(AppHelper.getPeerID() + "_pendingAcceptedChats"))
|
peerDHT.remove(Number160.createHash(AppHelper.getPeerID() + "_pendingAcceptedChats"))
|
||||||
.contentKey(Number160.createHash(newChatRequestMessage.getChatID()))
|
.contentKey(Number160.createHash(newChatRequestMessage.getChatID()))
|
||||||
.start()
|
.start()
|
||||||
.awaitUninterruptibly();
|
.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())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,4 +8,18 @@ public class ObservableUtils {
|
|||||||
jsonObject.addProperty("action", action);
|
jsonObject.addProperty("action", action);
|
||||||
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import com.google.gson.Gson;
|
|||||||
import net.tomp2p.dht.FutureGet;
|
import net.tomp2p.dht.FutureGet;
|
||||||
import net.tomp2p.dht.FuturePut;
|
import net.tomp2p.dht.FuturePut;
|
||||||
import net.tomp2p.dht.PeerDHT;
|
import net.tomp2p.dht.PeerDHT;
|
||||||
|
import net.tomp2p.futures.FutureDirect;
|
||||||
import net.tomp2p.futures.FuturePing;
|
import net.tomp2p.futures.FuturePing;
|
||||||
import net.tomp2p.peers.Number160;
|
import net.tomp2p.peers.Number160;
|
||||||
import net.tomp2p.peers.Number640;
|
import net.tomp2p.peers.Number640;
|
||||||
@ -59,4 +60,14 @@ public class P2PUtils {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean send(PeerAddress address, String data) {
|
||||||
|
FutureDirect futureDirect = peerDHT
|
||||||
|
.peer()
|
||||||
|
.sendDirect(address)
|
||||||
|
.object(data)
|
||||||
|
.start()
|
||||||
|
.awaitUninterruptibly();
|
||||||
|
return futureDirect.isSuccess();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,4 +10,5 @@ public class UIActions {
|
|||||||
public static final int NEW_CHAT = 0x6;
|
public static final int NEW_CHAT = 0x6;
|
||||||
public static final int PEER_NOT_EXIST = 0x7;
|
public static final int PEER_NOT_EXIST = 0x7;
|
||||||
public static final int SUCCESSFUL_CREATE_CHAT = 0x8;
|
public static final int SUCCESSFUL_CREATE_CHAT = 0x8;
|
||||||
|
public static final int MESSAGE_RECEIVED = 0x9;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,6 @@ import android.util.Log;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import net.tomp2p.dht.FuturePut;
|
|
||||||
import net.tomp2p.dht.PeerBuilderDHT;
|
import net.tomp2p.dht.PeerBuilderDHT;
|
||||||
import net.tomp2p.dht.PeerDHT;
|
import net.tomp2p.dht.PeerDHT;
|
||||||
import net.tomp2p.futures.FutureBootstrap;
|
import net.tomp2p.futures.FutureBootstrap;
|
||||||
@ -33,7 +32,7 @@ import java.security.spec.DSAPublicKeySpec;
|
|||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.util.UUID;
|
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.AppHelper;
|
||||||
import io.github.chronosx88.influence.helpers.DSAKey;
|
import io.github.chronosx88.influence.helpers.DSAKey;
|
||||||
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -10,10 +10,10 @@ import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
|
|||||||
@Dao
|
@Dao
|
||||||
public interface MessageDao {
|
public interface MessageDao {
|
||||||
@Insert
|
@Insert
|
||||||
void insertMessage(MessageEntity chatModel);
|
long insertMessage(MessageEntity chatModel);
|
||||||
|
|
||||||
@Query("DELETE FROM messages WHERE id = :msgID")
|
@Query("DELETE FROM messages WHERE id = :msgID")
|
||||||
void deleteMessage(String msgID);
|
void deleteMessage(long msgID);
|
||||||
|
|
||||||
@Query("DELETE FROM messages WHERE chatID = :chatID")
|
@Query("DELETE FROM messages WHERE chatID = :chatID")
|
||||||
void deleteMessagesByChatID(String chatID);
|
void deleteMessagesByChatID(String chatID);
|
||||||
@ -22,5 +22,11 @@ public interface MessageDao {
|
|||||||
List<MessageEntity> getMessagesByChatID(String chatID);
|
List<MessageEntity> getMessagesByChatID(String chatID);
|
||||||
|
|
||||||
@Query("SELECT * FROM messages WHERE id = :id")
|
@Query("SELECT * FROM messages WHERE id = :id")
|
||||||
List<MessageEntity> getMessageByID(String id);
|
List<MessageEntity> 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);
|
||||||
}
|
}
|
||||||
|
@ -7,41 +7,23 @@ import androidx.room.PrimaryKey;
|
|||||||
|
|
||||||
@Entity(tableName = "messages")
|
@Entity(tableName = "messages")
|
||||||
public class MessageEntity {
|
public class MessageEntity {
|
||||||
@PrimaryKey(autoGenerate = true) public int id;
|
@PrimaryKey(autoGenerate = true) public long id;
|
||||||
@ColumnInfo public int type;
|
@ColumnInfo public int type;
|
||||||
@ColumnInfo public String chatID;
|
@ColumnInfo public String chatID;
|
||||||
@ColumnInfo public String sender;
|
@ColumnInfo public String sender;
|
||||||
@ColumnInfo public long timestamp;
|
@ColumnInfo public long timestamp;
|
||||||
@ColumnInfo public String text;
|
@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.type = type;
|
||||||
this.chatID = chatID;
|
this.chatID = chatID;
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
this.isSent = isSent;
|
||||||
|
this.isRead = isRead;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.chronosx88.influence.presenters;
|
package io.github.chronosx88.influence.presenters;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import net.tomp2p.dht.FutureRemove;
|
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.contracts.chatlist.ChatListViewContract;
|
||||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||||
import io.github.chronosx88.influence.helpers.ChatListAdapter;
|
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.logic.ChatListLogic;
|
||||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||||
|
import io.github.chronosx88.influence.views.ChatActivity;
|
||||||
|
|
||||||
public class ChatListPresenter implements ChatListPresenterContract {
|
public class ChatListPresenter implements ChatListPresenterContract {
|
||||||
private ChatListViewContract view;
|
private ChatListViewContract view;
|
||||||
@ -20,7 +23,9 @@ public class ChatListPresenter implements ChatListPresenterContract {
|
|||||||
|
|
||||||
public ChatListPresenter(ChatListViewContract view) {
|
public ChatListPresenter(ChatListViewContract view) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
chatListAdapter = new ChatListAdapter();
|
chatListAdapter = new ChatListAdapter((v, p)-> {
|
||||||
|
openChat(chatListAdapter.getChatEntity(p).chatID);
|
||||||
|
});
|
||||||
this.logic = new ChatListLogic();
|
this.logic = new ChatListLogic();
|
||||||
this.view.setRecycleAdapter(chatListAdapter);
|
this.view.setRecycleAdapter(chatListAdapter);
|
||||||
}
|
}
|
||||||
@ -32,7 +37,10 @@ public class ChatListPresenter implements ChatListPresenterContract {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void openChat(String chatID) {
|
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
|
@Override
|
||||||
@ -43,6 +51,7 @@ public class ChatListPresenter implements ChatListPresenterContract {
|
|||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
ChatEntity chat = chatListAdapter.getItem(chatListAdapter.onClickPosition);
|
ChatEntity chat = chatListAdapter.getItem(chatListAdapter.onClickPosition);
|
||||||
AppHelper.getChatDB().chatDao().deleteChat(chat.chatID);
|
AppHelper.getChatDB().chatDao().deleteChat(chat.chatID);
|
||||||
|
AppHelper.getChatDB().messageDao().deleteMessagesByChatID(chat.chatID);
|
||||||
view.updateChatList(chatListAdapter, logic.loadAllChats());
|
view.updateChatList(chatListAdapter, logic.loadAllChats());
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
@ -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<MessageEntity> entities = LocalDBWrapper.getMessagesByChatID(chatID);
|
||||||
|
view.updateMessageList(entities == null ? new ArrayList<>() : entities);
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package io.github.chronosx88.influence.presenters;
|
package io.github.chronosx88.influence.presenters;
|
||||||
|
|
||||||
import io.github.chronosx88.influence.contracts.main.MainLogicContract;
|
import io.github.chronosx88.influence.contracts.mainactivity.MainLogicContract;
|
||||||
import io.github.chronosx88.influence.contracts.main.MainPresenterContract;
|
import io.github.chronosx88.influence.contracts.mainactivity.MainPresenterContract;
|
||||||
import io.github.chronosx88.influence.contracts.main.MainViewContract;
|
import io.github.chronosx88.influence.contracts.mainactivity.MainViewContract;
|
||||||
import io.github.chronosx88.influence.logic.MainLogic;
|
import io.github.chronosx88.influence.logic.MainLogic;
|
||||||
|
|
||||||
public class MainPresenter implements MainPresenterContract {
|
public class MainPresenter implements MainPresenterContract {
|
||||||
|
@ -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<MessageEntity> messages) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
chatAdapter.addMessages(messages);
|
||||||
|
chatAdapter.notifyDataSetChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,8 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
import io.github.chronosx88.influence.R;
|
import io.github.chronosx88.influence.R;
|
||||||
import io.github.chronosx88.influence.contracts.main.MainPresenterContract;
|
import io.github.chronosx88.influence.contracts.mainactivity.MainPresenterContract;
|
||||||
import io.github.chronosx88.influence.contracts.main.MainViewContract;
|
import io.github.chronosx88.influence.contracts.mainactivity.MainViewContract;
|
||||||
import io.github.chronosx88.influence.contracts.observer.Observer;
|
import io.github.chronosx88.influence.contracts.observer.Observer;
|
||||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||||
|
@ -68,8 +68,10 @@ public class ChatListFragment extends Fragment implements ChatListViewContract,
|
|||||||
@Override
|
@Override
|
||||||
public void handleEvent(JsonObject object) {
|
public void handleEvent(JsonObject object) {
|
||||||
switch (object.get("action").getAsInt()) {
|
switch (object.get("action").getAsInt()) {
|
||||||
|
case UIActions.SUCCESSFUL_CREATE_CHAT:
|
||||||
case UIActions.NEW_CHAT: {
|
case UIActions.NEW_CHAT: {
|
||||||
presenter.updateChatList();
|
presenter.updateChatList();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
app/src/main/res/drawable/ic_send_green_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_send_green_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#008577"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
|
||||||
|
</vector>
|
75
app/src/main/res/layout/activity_chat.xml
Normal file
75
app/src/main/res/layout/activity_chat.xml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:background="#e6e6e6">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/appbar_chat_activity"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar_chat_activity"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:theme="@style/Base.ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
|
app:popupTheme="@style/MenuStyle">
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
android:id="@+id/profile_image_chat_activity"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/appbar_username"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:layout_marginLeft="25dp"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginStart="25dp" />
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/message_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_below="@id/appbar_chat_activity"
|
||||||
|
android:layout_above="@+id/chat_activity_bottom_container"/>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/chat_activity_bottom_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="#FFFFFF"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="5dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/message_input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toLeftOf="@+id/send_button"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:hint="Type a message..." />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/send_button"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:background="@drawable/ic_send_green_24dp" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -11,27 +11,27 @@
|
|||||||
<de.hdodenhof.circleimageview.CircleImageView
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:id="@+id/contact_profile_image"
|
android:id="@+id/profile_image"
|
||||||
android:src="@mipmap/ic_launcher"/>
|
android:src="@mipmap/ic_launcher"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/message_item_left_background"
|
android:background="@drawable/message_item_left_background"
|
||||||
android:layout_toRightOf="@id/contact_profile_image"
|
android:layout_toRightOf="@id/profile_image"
|
||||||
android:text="Null"
|
android:text="Null"
|
||||||
android:paddingEnd="50dp"
|
android:paddingEnd="50dp"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_marginTop="7dp"
|
android:layout_marginTop="7dp"
|
||||||
android:id="@+id/message_text_left"
|
android:id="@+id/message_text"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:padding="8dp"/>
|
android:padding="8dp"/>
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/message_time_left"
|
android:id="@+id/message_time"
|
||||||
android:layout_alignBottom="@+id/message_text_left"
|
android:layout_alignBottom="@+id/message_text"
|
||||||
android:layout_alignRight="@+id/message_text_left"
|
android:layout_alignRight="@+id/message_text"
|
||||||
android:paddingBottom="3dp"
|
android:paddingBottom="3dp"
|
||||||
android:paddingRight="4dp"
|
android:paddingRight="4dp"
|
||||||
android:text="12:00"/>
|
android:text="12:00"/>
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
android:layout_toLeftOf="@id/profile_image"
|
android:layout_toLeftOf="@id/profile_image"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:layout_marginTop="7dp"
|
android:layout_marginTop="7dp"
|
||||||
android:id="@+id/message_text_right"
|
android:id="@+id/message_text"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:paddingEnd="50dp"
|
android:paddingEnd="50dp"
|
||||||
android:textColor="#ffffff"
|
android:textColor="#ffffff"
|
||||||
@ -33,9 +33,9 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/message_time_right"
|
android:id="@+id/message_time"
|
||||||
android:layout_alignBottom="@+id/message_text_right"
|
android:layout_alignBottom="@+id/message_text"
|
||||||
android:layout_alignRight="@+id/message_text_right"
|
android:layout_alignRight="@+id/message_text"
|
||||||
android:paddingBottom="3dp"
|
android:paddingBottom="3dp"
|
||||||
android:textColor="#ffffff"
|
android:textColor="#ffffff"
|
||||||
android:paddingRight="4dp"
|
android:paddingRight="4dp"
|
||||||
|
@ -32,4 +32,12 @@
|
|||||||
<item name="android:topDark">@android:color/transparent</item>
|
<item name="android:topDark">@android:color/transparent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="MenuStyle" parent="Theme.AppCompat.Light">
|
||||||
|
<item name="android:background">@android:color/white</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="NoWindowActionBar" parent="AppTheme">
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user