mirror of
https://github.com/ChronosX88/Influence.git
synced 2024-12-28 17:01:46 +00:00
Now basic chat functional are working! Fully replaced with XMPP.
This commit is contained in:
parent
a66a83c0fd
commit
be1b342e8a
@ -64,6 +64,9 @@ dependencies {
|
||||
implementation 'org.igniterealtime.smack:smack-android:4.3.3'
|
||||
implementation 'org.igniterealtime.smack:smack-extensions:4.3.3'
|
||||
|
||||
implementation 'com.github.stfalcon:chatkit:0.3.3'
|
||||
implementation 'net.sourceforge.streamsupport:streamsupport:1.7.0'
|
||||
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -2,39 +2,27 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "81501115d10a6dc46002667323359631",
|
||||
"identityHash": "2409c873b47ccd635ed7d10e4d8604f8",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "messages",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageID` TEXT NOT NULL, `type` INTEGER NOT NULL, `chatID` TEXT, `senderID` TEXT, `username` TEXT, `timestamp` INTEGER NOT NULL, `text` TEXT, `isSent` INTEGER NOT NULL, `isRead` INTEGER NOT NULL, PRIMARY KEY(`messageID`))",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageID` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `jid` TEXT, `senderJid` TEXT, `timestamp` INTEGER NOT NULL, `text` TEXT, `isSent` INTEGER NOT NULL, `isRead` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "messageID",
|
||||
"columnName": "messageID",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "chatID",
|
||||
"columnName": "chatID",
|
||||
"fieldPath": "jid",
|
||||
"columnName": "jid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "senderID",
|
||||
"columnName": "senderID",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "username",
|
||||
"columnName": "username",
|
||||
"fieldPath": "senderJid",
|
||||
"columnName": "senderJid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
@ -67,55 +55,43 @@
|
||||
"columnNames": [
|
||||
"messageID"
|
||||
],
|
||||
"autoGenerate": false
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "chats",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`chatID` TEXT NOT NULL, `name` TEXT, `metadataRef` TEXT, `membersRef` TEXT, `bannedUsers` TEXT, `chunkCursor` INTEGER NOT NULL, PRIMARY KEY(`chatID`))",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`jid` TEXT NOT NULL, `chatName` TEXT, `users` TEXT, `unreadMessagesCount` INTEGER NOT NULL, PRIMARY KEY(`jid`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "chatID",
|
||||
"columnName": "chatID",
|
||||
"fieldPath": "jid",
|
||||
"columnName": "jid",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"fieldPath": "chatName",
|
||||
"columnName": "chatName",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "metadataRef",
|
||||
"columnName": "metadataRef",
|
||||
"fieldPath": "users",
|
||||
"columnName": "users",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "membersRef",
|
||||
"columnName": "membersRef",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "bannedUsers",
|
||||
"columnName": "bannedUsers",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "chunkCursor",
|
||||
"columnName": "chunkCursor",
|
||||
"fieldPath": "unreadMessagesCount",
|
||||
"columnName": "unreadMessagesCount",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"chatID"
|
||||
"jid"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
@ -126,7 +102,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, \"81501115d10a6dc46002667323359631\")"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"2409c873b47ccd635ed7d10e4d8604f8\")"
|
||||
]
|
||||
}
|
||||
}
|
@ -56,9 +56,6 @@ public class XMPPConnection implements ConnectionListener {
|
||||
|
||||
public enum ConnectionState {
|
||||
CONNECTED,
|
||||
AUTHENTICATED,
|
||||
CONNECTING,
|
||||
DISCONNECTING,
|
||||
DISCONNECTED
|
||||
}
|
||||
|
||||
@ -68,6 +65,8 @@ public class XMPPConnection implements ConnectionListener {
|
||||
}
|
||||
|
||||
public XMPPConnection(Context context) {
|
||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
this.context = context;
|
||||
String jid = prefs.getString("jid", null);
|
||||
String password = prefs.getString("pass", null);
|
||||
if(jid != null && password != null) {
|
||||
@ -78,8 +77,6 @@ public class XMPPConnection implements ConnectionListener {
|
||||
credentials.password = password;
|
||||
}
|
||||
networkHandler = new NetworkHandler(context);
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void connect() throws XMPPException, SmackException, IOException {
|
||||
@ -97,6 +94,9 @@ public class XMPPConnection implements ConnectionListener {
|
||||
|
||||
connection = new XMPPTCPConnection(conf);
|
||||
connection.addConnectionListener(this);
|
||||
if(credentials.jabberHost.equals("") && credentials.password.equals("") && credentials.username.equals("")){
|
||||
throw new IOException();
|
||||
}
|
||||
try {
|
||||
connection.connect();
|
||||
connection.login(credentials.username, credentials.password);
|
||||
@ -121,26 +121,28 @@ public class XMPPConnection implements ConnectionListener {
|
||||
|
||||
@Override
|
||||
public void connected(org.jivesoftware.smack.XMPPConnection connection) {
|
||||
XMPPConnectionService.connectionState = ConnectionState.CONNECTED;
|
||||
XMPPConnectionService.CONNECTION_STATE = ConnectionState.CONNECTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticated(org.jivesoftware.smack.XMPPConnection connection, boolean resumed) {
|
||||
XMPPConnectionService.sessionState = SessionState.LOGGED_IN;
|
||||
XMPPConnectionService.SESSION_STATE = SessionState.LOGGED_IN;
|
||||
prefs.edit().putBoolean("logged_in", true).apply();
|
||||
context.sendBroadcast(new Intent(XMPPConnectionService.INTENT_AUTHENTICATED));
|
||||
AppHelper.setJid(credentials.username + "@" + credentials.jabberHost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
XMPPConnectionService.connectionState = ConnectionState.DISCONNECTED;
|
||||
XMPPConnectionService.sessionState = SessionState.LOGGED_OUT;
|
||||
XMPPConnectionService.CONNECTION_STATE = ConnectionState.DISCONNECTED;
|
||||
XMPPConnectionService.SESSION_STATE = SessionState.LOGGED_OUT;
|
||||
prefs.edit().putBoolean("logged_in", false).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosedOnError(Exception e) {
|
||||
XMPPConnectionService.connectionState = ConnectionState.DISCONNECTED;
|
||||
XMPPConnectionService.sessionState = SessionState.LOGGED_OUT;
|
||||
XMPPConnectionService.CONNECTION_STATE = ConnectionState.DISCONNECTED;
|
||||
XMPPConnectionService.SESSION_STATE = SessionState.LOGGED_OUT;
|
||||
prefs.edit().putBoolean("logged_in", false).apply();
|
||||
Log.e(LOG_TAG, "Connection closed, exception occurred");
|
||||
e.printStackTrace();
|
||||
|
@ -29,6 +29,8 @@ import org.jivesoftware.smack.XMPPException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
|
||||
public class XMPPConnectionService extends Service {
|
||||
public static final String INTENT_NEW_MESSAGE = "io.github.chronosx88.intents.new_message";
|
||||
public static final String INTENT_SEND_MESSAGE = "io.github.chronosx88.intents.send_message";
|
||||
@ -40,18 +42,16 @@ public class XMPPConnectionService extends Service {
|
||||
public static final String MESSAGE_BODY = "message_body";
|
||||
public static final String MESSAGE_RECIPIENT = "message_recipient";
|
||||
|
||||
public static XMPPConnection.ConnectionState connectionState = XMPPConnection.ConnectionState.DISCONNECTED;
|
||||
public static XMPPConnection.SessionState sessionState = XMPPConnection.SessionState.LOGGED_OUT;
|
||||
public static XMPPConnection.ConnectionState CONNECTION_STATE = XMPPConnection.ConnectionState.DISCONNECTED;
|
||||
public static XMPPConnection.SessionState SESSION_STATE = XMPPConnection.SessionState.LOGGED_OUT;
|
||||
|
||||
private Thread thread;
|
||||
private Handler threadHandler;
|
||||
private boolean isThreadAlive = false;
|
||||
private XMPPConnection connection;
|
||||
private Context context;
|
||||
private Context context = AppHelper.getContext();
|
||||
|
||||
public XMPPConnectionService(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
public XMPPConnectionService() { }
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) { return null; }
|
||||
@ -89,9 +89,8 @@ public class XMPPConnectionService extends Service {
|
||||
connection.connect();
|
||||
} catch (IOException | SmackException | XMPPException e) {
|
||||
Intent intent = new Intent(INTENT_AUTHENTICATION_FAILED);
|
||||
|
||||
context.sendBroadcast(intent);
|
||||
e.printStackTrace();
|
||||
//Stop the service all together.
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
package io.github.chronosx88.influence.contracts
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.MenuItem
|
||||
import com.stfalcon.chatkit.dialogs.DialogsListAdapter
|
||||
import com.stfalcon.chatkit.messages.MessagesListAdapter
|
||||
|
||||
import io.github.chronosx88.influence.helpers.ChatListAdapter
|
||||
import io.github.chronosx88.influence.models.GenericDialog
|
||||
import io.github.chronosx88.influence.models.GenericMessage
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity
|
||||
import io.github.chronosx88.influence.models.roomEntities.MessageEntity
|
||||
|
||||
@ -15,28 +18,23 @@ interface CoreContracts {
|
||||
|
||||
// -----ChatList-----
|
||||
|
||||
interface IChatListLogicContract {
|
||||
interface IDialogListLogicContract {
|
||||
fun loadAllChats(): List<ChatEntity>
|
||||
}
|
||||
|
||||
interface IChatListPresenterContract {
|
||||
fun updateChatList()
|
||||
interface IDialogListPresenterContract {
|
||||
fun openChat(chatID: String)
|
||||
fun onContextItemSelected(item: MenuItem)
|
||||
}
|
||||
|
||||
interface IChatListViewContract {
|
||||
fun setRecycleAdapter(adapter: ChatListAdapter)
|
||||
fun setDialogAdapter(adapter: DialogsListAdapter<GenericDialog>)
|
||||
fun startActivity(intent: Intent)
|
||||
fun updateChatList(adapter: ChatListAdapter, chats: List<ChatEntity>)
|
||||
fun getActivityContext(): Context?
|
||||
}
|
||||
|
||||
// -----MainActivity-----
|
||||
|
||||
interface IMainLogicContract {
|
||||
fun initPeer()
|
||||
fun sendStartChatMessage(username: String)
|
||||
fun shutdownPeer()
|
||||
}
|
||||
|
||||
interface IMainPresenterContract {
|
||||
@ -53,19 +51,17 @@ interface CoreContracts {
|
||||
// -----ChatActivity-----
|
||||
|
||||
interface IChatLogicContract {
|
||||
fun sendMessage(message: MessageEntity)
|
||||
fun stopTrackingForNewMsgs()
|
||||
fun sendMessage(text: String): MessageEntity
|
||||
}
|
||||
|
||||
interface IChatPresenterContract {
|
||||
fun sendMessage(text: String)
|
||||
fun updateAdapter()
|
||||
fun sendMessage(text: String): Boolean
|
||||
fun loadLocalMessages()
|
||||
fun onDestroy()
|
||||
}
|
||||
|
||||
interface IChatViewContract {
|
||||
fun updateMessageList(message: MessageEntity)
|
||||
fun updateMessageList(messages: List<MessageEntity>)
|
||||
fun setAdapter(adapter: MessagesListAdapter<GenericMessage>)
|
||||
}
|
||||
|
||||
// -----SettingsFragment-----
|
||||
|
@ -1,12 +1,9 @@
|
||||
package io.github.chronosx88.influence.contracts.observer;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public interface IObservable {
|
||||
void register(IObserver observer);
|
||||
void register(INetworkObserver networkObserver);
|
||||
void unregister(IObserver observer);
|
||||
void unregister(INetworkObserver networkObserver);
|
||||
void notifyUIObservers(JsonObject jsonObject);
|
||||
void notifyNetworkObservers(Object object);
|
||||
void notifyUIObservers(JSONObject jsonObject);
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package io.github.chronosx88.influence.contracts.observer;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public interface IObserver {
|
||||
void handleEvent(JsonObject object);
|
||||
void handleEvent(JSONObject object) throws JSONException;
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
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.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeSet;
|
||||
|
||||
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 Context context = AppHelper.getContext();
|
||||
private ArrayList<MessageEntity> messages = new ArrayList<>();
|
||||
private static Comparator<MessageEntity> comparator = ((o1, o2) -> Long.compare(o1.timestamp, o2.timestamp));
|
||||
|
||||
@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) {
|
||||
if(message != null) {
|
||||
for (MessageEntity messageEntity : messages) {
|
||||
if(messageEntity.messageID.equals(message.messageID)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
messages.add(message);
|
||||
Collections.sort(messages, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
public void addMessages(List<MessageEntity> messages) {
|
||||
this.messages.addAll(messages);
|
||||
Collections.sort(messages, comparator);
|
||||
}
|
||||
|
||||
@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)
|
||||
DateFormat dateFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String time = dateFormat.format(new Date(messages.get(position).timestamp));
|
||||
holder.messageTime.setText(time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return messages.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if(messages.get(position).senderID.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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package io.github.chronosx88.influence.helpers;
|
||||
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.IItemClickListener;
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||
|
||||
public class ChatListAdapter extends RecyclerView.Adapter<ChatListAdapter.ChatListViewHolder> {
|
||||
List<ChatEntity> chatList = new ArrayList<>();
|
||||
public int onClickPosition = -1;
|
||||
private IItemClickListener itemClickListener;
|
||||
|
||||
public ChatListAdapter(IItemClickListener itemClickListener) {
|
||||
this.itemClickListener = itemClickListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ChatListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.chat_item, parent, false);
|
||||
return new ChatListViewHolder(view);
|
||||
}
|
||||
|
||||
public void setChatList(List<ChatEntity> entities) {
|
||||
chatList.clear();
|
||||
chatList.addAll(entities);
|
||||
}
|
||||
|
||||
public ChatEntity getItem(int position) {
|
||||
return chatList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ChatListViewHolder holder, int position) {
|
||||
holder.chatName.setText(chatList.get(position).name);
|
||||
holder.onLongClick(position);
|
||||
}
|
||||
|
||||
public ChatEntity getChatEntity(int position) {
|
||||
return chatList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return chatList.size();
|
||||
}
|
||||
|
||||
class ChatListViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {
|
||||
TextView chatName;
|
||||
|
||||
public ChatListViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
chatName = itemView.findViewById(R.id.chat_name);
|
||||
itemView.setOnCreateContextMenuListener(this);
|
||||
itemView.setOnClickListener((v) -> {
|
||||
itemClickListener.onItemClick(v, getAdapterPosition());
|
||||
});
|
||||
}
|
||||
|
||||
public void onLongClick(int position) {
|
||||
itemView.setOnLongClickListener((v) -> {
|
||||
onClickPosition = position;
|
||||
itemView.showContextMenu();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
menu.add(0, 0, 0, "Remove chat");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2019 ChronosX88
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.chronosx88.influence.helpers;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
public class JavaSerializer<T> {
|
||||
public byte[] serialize(T object) {
|
||||
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
|
||||
try {
|
||||
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArray);
|
||||
objectOutputStream.writeObject(object);
|
||||
objectOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return byteArray.toByteArray();
|
||||
}
|
||||
|
||||
public T deserialize(byte[] serializedObject) {
|
||||
if(serializedObject == null)
|
||||
return null;
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(serializedObject);
|
||||
Object object = null;
|
||||
try {
|
||||
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
|
||||
object = objectInputStream.readObject();
|
||||
} catch (ClassNotFoundException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return (T) object;
|
||||
}
|
||||
}
|
@ -10,14 +10,14 @@ import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class KeyPairManager {
|
||||
private File keyPairDir;
|
||||
private Serializer<KeyPair> serializer;
|
||||
private JavaSerializer<KeyPair> serializer;
|
||||
|
||||
public KeyPairManager() {
|
||||
this.keyPairDir = new File(AppHelper.getContext().getFilesDir().getAbsoluteFile(), "keyPairs");
|
||||
if(!this.keyPairDir.exists()) {
|
||||
this.keyPairDir.mkdir();
|
||||
}
|
||||
this.serializer = new Serializer<>();
|
||||
this.serializer = new JavaSerializer<>();
|
||||
}
|
||||
|
||||
public KeyPair openMainKeyPair() {
|
||||
|
@ -13,7 +13,7 @@ public class LocalDBWrapper {
|
||||
private static RoomHelper dbInstance = AppHelper.getChatDB();
|
||||
|
||||
public static void createChatEntry(String jid, String chatName) {
|
||||
dbInstance.chatDao().addChat(new ChatEntity(jid, chatName));
|
||||
dbInstance.chatDao().addChat(new ChatEntity(jid, chatName, new ArrayList<>(), 0));
|
||||
}
|
||||
|
||||
public static long createMessageEntry(String jid, String senderJid, long timestamp, String text, boolean isSent, boolean isRead) {
|
||||
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2019 ChronosX88
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.chronosx88.influence.helpers;
|
||||
|
||||
public class ObservableActions {
|
||||
public static final int NEW_CHAT_CREATED = 0x0;
|
||||
}
|
@ -3,28 +3,48 @@ package io.github.chronosx88.influence.helpers;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class ObservableUtils {
|
||||
public static void notifyUI(int action) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", action);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
try {
|
||||
jsonObject.put("action", action);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
||||
}
|
||||
|
||||
public static void notifyUI(int action, String... additional) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", action);
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
for(String info : additional) {
|
||||
jsonArray.add(info);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
try {
|
||||
jsonObject.put("action", action);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
for(String info : additional) {
|
||||
jsonArray.put(info);
|
||||
}
|
||||
try {
|
||||
jsonObject.put("additional", jsonArray);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
jsonObject.add("additional", jsonArray);
|
||||
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
||||
}
|
||||
|
||||
public static void notifyUI(int action, int additional) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", action);
|
||||
jsonObject.addProperty("additional", additional);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
try {
|
||||
jsonObject.put("action", action);
|
||||
jsonObject.put("additional", additional);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,18 @@ import java.util.ArrayList;
|
||||
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import io.github.chronosx88.influence.models.GenericUser;
|
||||
|
||||
public class RoomTypeConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static ArrayList<String> fromString(String value) {
|
||||
public static ArrayList<GenericUser> fromString(String value) {
|
||||
Type listType = new TypeToken<ArrayList<String>>() {}.getType();
|
||||
return new Gson().fromJson(value, listType);
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static String fromArrayList(ArrayList<String> list) {
|
||||
public static <T> String fromArrayList(ArrayList<GenericUser> list) {
|
||||
Gson gson = new Gson();
|
||||
return gson.toJson(list);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import io.github.chronosx88.influence.contracts.CoreContracts;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||
|
||||
public class ChatListLogic implements CoreContracts.IChatListLogicContract {
|
||||
public class ChatListLogic implements CoreContracts.IDialogListLogicContract {
|
||||
|
||||
@Override
|
||||
public List<ChatEntity> loadAllChats() {
|
||||
|
@ -1,182 +1,39 @@
|
||||
package io.github.chronosx88.influence.logic;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import android.content.Intent;
|
||||
|
||||
import net.tomp2p.peers.Number640;
|
||||
import net.tomp2p.storage.Data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import com.instacart.library.truetime.TrueTime;
|
||||
|
||||
import io.github.chronosx88.influence.XMPPConnection;
|
||||
import io.github.chronosx88.influence.XMPPConnectionService;
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
||||
import io.github.chronosx88.influence.helpers.LocalDBWrapper;
|
||||
import io.github.chronosx88.influence.helpers.ObservableUtils;
|
||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||
import io.github.chronosx88.influence.models.JoinChatMessage;
|
||||
import io.github.chronosx88.influence.models.NextChunkReference;
|
||||
import io.github.chronosx88.influence.models.TextMessage;
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||
import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
|
||||
|
||||
public class ChatLogic implements CoreContracts.IChatLogicContract {
|
||||
private static Gson gson = new Gson();
|
||||
private String chatID;
|
||||
private volatile String newMessage = "";
|
||||
private ChatEntity chatEntity;
|
||||
private Thread checkNewMessagesThread = null;
|
||||
private KeyPairManager keyPairManager;
|
||||
private Timer timer;
|
||||
//private KeyPairManager keyPairManager;
|
||||
|
||||
public ChatLogic(ChatEntity chatEntity) {
|
||||
this.chatEntity = chatEntity;
|
||||
this.chatID = chatEntity.chatID;
|
||||
TimerTask timerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
checkForNewMessages();
|
||||
}
|
||||
};
|
||||
this.timer = new Timer();
|
||||
if(AppHelper.getPeerDHT() != null) {
|
||||
timer.schedule(timerTask, 1, 1000);
|
||||
}
|
||||
this.keyPairManager = new KeyPairManager();
|
||||
this.chatID = chatEntity.jid;
|
||||
//this.keyPairManager = new KeyPairManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(MessageEntity message) {
|
||||
if(AppHelper.getPeerDHT() == null) {
|
||||
ObservableUtils.notifyUI(UIActions.NODE_IS_OFFLINE);
|
||||
return;
|
||||
public MessageEntity sendMessage(String text) {
|
||||
if (XMPPConnectionService.CONNECTION_STATE.equals(XMPPConnection.ConnectionState.CONNECTED)) {
|
||||
Intent intent = new Intent(XMPPConnectionService.INTENT_SEND_MESSAGE);
|
||||
intent.putExtra(XMPPConnectionService.MESSAGE_BODY, text);
|
||||
intent.putExtra(XMPPConnectionService.MESSAGE_RECIPIENT, chatEntity.jid);
|
||||
AppHelper.getContext().sendBroadcast(intent);
|
||||
long messageID = LocalDBWrapper.createMessageEntry(chatID, AppHelper.getJid(), TrueTime.now().getTime(), text, false, false);
|
||||
return LocalDBWrapper.getMessageByID(messageID);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
new Thread(() -> {
|
||||
Data data = null;
|
||||
try {
|
||||
data = new Data(gson.toJson(new TextMessage(message.senderID, message.messageID, message.chatID, message.username, message.timestamp, message.text, false)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
data.protectEntry(keyPairManager.getKeyPair("mainKeyPair"));
|
||||
P2PUtils.put(chatID + "_messages" + chatEntity.chunkCursor, message.messageID, data);
|
||||
try {
|
||||
P2PUtils.put(chatID + "_newMessage", null, new Data(message.messageID));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void checkForNewMessages() {
|
||||
if(checkNewMessagesThread == null) {
|
||||
checkNewMessagesThread = new Thread(() -> {
|
||||
Map<Number640, Data> data = P2PUtils.get(chatID + "_newMessage");
|
||||
if(data != null) {
|
||||
for(Map.Entry<Number640, Data> entry : data.entrySet()) {
|
||||
String newMessage = null;
|
||||
try {
|
||||
newMessage = (String) entry.getValue().object();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if(!newMessage.equals(this.newMessage)) {
|
||||
handleNewMessages(chatEntity.chunkCursor);
|
||||
this.newMessage = newMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(!checkNewMessagesThread.isAlive()) {
|
||||
checkNewMessagesThread = new Thread(() -> {
|
||||
Map<Number640, Data> data = P2PUtils.get(chatID + "_newMessage");
|
||||
if(data != null) {
|
||||
for(Map.Entry<Number640, Data> entry : data.entrySet()) {
|
||||
String newMessage = null;
|
||||
try {
|
||||
newMessage = (String) entry.getValue().object();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if(!newMessage.equals(this.newMessage)) {
|
||||
handleNewMessages(chatEntity.chunkCursor);
|
||||
this.newMessage = newMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
checkNewMessagesThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNewMessages(int chunkID) {
|
||||
new Thread(() -> {
|
||||
Map<Number640, Data> messages = P2PUtils.get(chatEntity.chatID + "_messages" + chunkID);
|
||||
if (messages != null) {
|
||||
for (Map.Entry<Number640, Data> message : messages.entrySet()) {
|
||||
String json = null;
|
||||
try {
|
||||
json = (String) message.getValue().object();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
switch (getMessageAction(json)) {
|
||||
case NetworkActions.TEXT_MESSAGE: {
|
||||
TextMessage textMessage = gson.fromJson(json, TextMessage.class);
|
||||
LocalDBWrapper.createMessageEntry(NetworkActions.TEXT_MESSAGE, textMessage.getMessageID(), textMessage.getChatID(), textMessage.getUsername(), textMessage.getSenderID(), textMessage.getTimestamp(), textMessage.getText(), true, false);
|
||||
ObservableUtils.notifyUI(UIActions.MESSAGE_RECEIVED, chatID, textMessage.getMessageID());
|
||||
break;
|
||||
}
|
||||
case NetworkActions.JOIN_CHAT: {
|
||||
JoinChatMessage joinChatMessage = gson.fromJson(json, JoinChatMessage.class);
|
||||
LocalDBWrapper.createMessageEntry(NetworkActions.JOIN_CHAT, joinChatMessage.getMessageID(), joinChatMessage.getChatID(), joinChatMessage.getUsername(), joinChatMessage.getSenderID(), joinChatMessage.getTimestamp(), null, true, false);
|
||||
ObservableUtils.notifyUI(UIActions.MESSAGE_RECEIVED, chatID, joinChatMessage.getMessageID());
|
||||
break;
|
||||
}
|
||||
case NetworkActions.NEXT_CHUNK_REF: {
|
||||
NextChunkReference nextChunkReference = gson.fromJson(json, NextChunkReference.class);
|
||||
chatEntity.chunkCursor = nextChunkReference.getNextChunkID();
|
||||
LocalDBWrapper.updateChatEntity(chatEntity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(messages.size() > 10) {
|
||||
String messageID = UUID.randomUUID().toString();
|
||||
try {
|
||||
int nextChunkCursor = chatEntity.chunkCursor + 1;
|
||||
P2PUtils.put(chatEntity.chatID + "_messages" + chunkID, messageID, new Data(gson.toJson(new NextChunkReference(messageID, AppHelper.getPeerID(), AppHelper.getPeerID(), System.currentTimeMillis(), nextChunkCursor))));
|
||||
P2PUtils.put(chatEntity.chatID + "_newMessage", null, new Data(messageID));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private int getMessageAction(String json) {
|
||||
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
|
||||
return jsonObject.get("action").getAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopTrackingForNewMsgs() {
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
}
|
||||
}
|
||||
|
@ -1,83 +1,23 @@
|
||||
package io.github.chronosx88.influence.logic;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import net.tomp2p.connection.Bindings;
|
||||
import net.tomp2p.connection.ChannelClientConfiguration;
|
||||
import net.tomp2p.connection.ChannelServerConfiguration;
|
||||
import net.tomp2p.connection.Ports;
|
||||
import net.tomp2p.connection.RSASignatureFactory;
|
||||
import net.tomp2p.dht.PeerBuilderDHT;
|
||||
import net.tomp2p.dht.PeerDHT;
|
||||
import net.tomp2p.dht.Storage;
|
||||
import net.tomp2p.futures.FutureBootstrap;
|
||||
import net.tomp2p.futures.FutureDiscover;
|
||||
import net.tomp2p.nat.FutureRelayNAT;
|
||||
import net.tomp2p.nat.PeerBuilderNAT;
|
||||
import net.tomp2p.nat.PeerNAT;
|
||||
import net.tomp2p.p2p.PeerBuilder;
|
||||
import net.tomp2p.peers.Number160;
|
||||
import net.tomp2p.peers.Number640;
|
||||
import net.tomp2p.peers.PeerAddress;
|
||||
import net.tomp2p.relay.tcp.TCPRelayClientConfig;
|
||||
import net.tomp2p.replication.IndirectReplication;
|
||||
import net.tomp2p.storage.Data;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyPair;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
||||
import io.github.chronosx88.influence.helpers.LocalDBWrapper;
|
||||
import io.github.chronosx88.influence.helpers.NetworkHandler;
|
||||
import io.github.chronosx88.influence.helpers.ObservableUtils;
|
||||
import io.github.chronosx88.influence.helpers.StorageBerkeleyDB;
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||
import io.github.chronosx88.influence.models.ChatMetadata;
|
||||
import io.github.chronosx88.influence.models.NewChatRequestMessage;
|
||||
import io.github.chronosx88.influence.models.PublicUserProfile;
|
||||
|
||||
public class MainLogic implements CoreContracts.IMainLogicContract {
|
||||
private static final String LOG_TAG = MainLogic.class.getName();
|
||||
|
||||
private SharedPreferences preferences;
|
||||
private Number160 peerID;
|
||||
private PeerDHT peerDHT;
|
||||
private Context context;
|
||||
private InetAddress bootstrapAddress = null;
|
||||
private PeerAddress bootstrapPeerAddress = null;
|
||||
private Gson gson;
|
||||
private IndirectReplication replication;
|
||||
private KeyPairManager keyPairManager;
|
||||
private Thread checkNewChatsThread = null;
|
||||
private Storage storage;
|
||||
|
||||
public MainLogic() {
|
||||
this.context = AppHelper.getContext();
|
||||
this.preferences = context.getSharedPreferences("io.github.chronosx88.influence_preferences", context.MODE_PRIVATE);
|
||||
gson = new Gson();
|
||||
keyPairManager = new KeyPairManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
/*@Override
|
||||
public void initPeer() {
|
||||
org.apache.log4j.BasicConfigurator.configure();
|
||||
|
||||
@ -366,5 +306,5 @@ public class MainLogic implements CoreContracts.IMainLogicContract {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
@ -1,24 +1,18 @@
|
||||
package io.github.chronosx88.influence.logic
|
||||
|
||||
import android.util.Log
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts
|
||||
import io.github.chronosx88.influence.helpers.AppHelper
|
||||
import io.github.chronosx88.influence.helpers.KeyPairManager
|
||||
import io.github.chronosx88.influence.helpers.ObservableUtils
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions
|
||||
import net.tomp2p.peers.Number640
|
||||
import net.tomp2p.storage.Data
|
||||
import java.io.IOException
|
||||
|
||||
class SettingsLogic : CoreContracts.ISettingsLogic {
|
||||
|
||||
override fun checkUsernameExists(username: String) : Boolean {
|
||||
if (AppHelper.getPeerDHT() == null) {
|
||||
/*if (AppHelper.getPeerDHT() == null) {
|
||||
ObservableUtils.notifyUI(UIActions.NODE_IS_OFFLINE)
|
||||
return false
|
||||
}
|
||||
val usernameMap: MutableMap<Number640, Data>? = P2PUtils.get(username)
|
||||
usernameMap ?: return false
|
||||
return true*/
|
||||
return true
|
||||
}
|
||||
|
||||
@ -26,7 +20,7 @@ class SettingsLogic : CoreContracts.ISettingsLogic {
|
||||
private val LOG_TAG: String = "SettingsLogic"
|
||||
private val keyPairManager = KeyPairManager()
|
||||
|
||||
fun publishUsername(oldUsername: String?, username: String?) {
|
||||
/*fun publishUsername(oldUsername: String?, username: String?) {
|
||||
if (AppHelper.getPeerDHT() == null) {
|
||||
ObservableUtils.notifyUI(UIActions.NODE_IS_OFFLINE)
|
||||
return
|
||||
@ -53,6 +47,6 @@ class SettingsLogic : CoreContracts.ISettingsLogic {
|
||||
} ?: run {
|
||||
return
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2019 ChronosX88
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.chronosx88.influence.models;
|
||||
|
||||
import com.stfalcon.chatkit.commons.models.IDialog;
|
||||
import com.stfalcon.chatkit.commons.models.IMessage;
|
||||
import com.stfalcon.chatkit.commons.models.IUser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||
|
||||
public class GenericDialog implements IDialog {
|
||||
private String dialogID;
|
||||
private String dialogPhoto = "";
|
||||
private String dialogName;
|
||||
private List<GenericUser> users;
|
||||
private IMessage lastMessage;
|
||||
private int unreadMessagesCount;
|
||||
|
||||
public GenericDialog(ChatEntity chatEntity) {
|
||||
dialogID = chatEntity.jid;
|
||||
dialogName = chatEntity.chatName;
|
||||
users = new ArrayList<>();
|
||||
unreadMessagesCount = chatEntity.unreadMessagesCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return dialogID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDialogPhoto() {
|
||||
return dialogPhoto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDialogName() {
|
||||
return dialogName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IUser> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMessage getLastMessage() {
|
||||
return lastMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastMessage(IMessage message) {
|
||||
lastMessage = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnreadCount() {
|
||||
return unreadMessagesCount;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2019 ChronosX88
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.chronosx88.influence.models;
|
||||
|
||||
import com.stfalcon.chatkit.commons.models.IMessage;
|
||||
import com.stfalcon.chatkit.commons.models.IUser;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
|
||||
|
||||
public class GenericMessage implements IMessage {
|
||||
private long messageID;
|
||||
private IUser author;
|
||||
private long timestamp;
|
||||
private String text;
|
||||
|
||||
public GenericMessage(MessageEntity messageEntity) {
|
||||
this.messageID = messageEntity.messageID;
|
||||
this.author = new GenericUser(messageEntity.senderJid, messageEntity.senderJid, "");
|
||||
this.timestamp = messageEntity.timestamp;
|
||||
this.text = messageEntity.text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return String.valueOf(messageID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IUser getUser() {
|
||||
return author;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreatedAt() {
|
||||
return new Date(timestamp);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2019 ChronosX88
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.chronosx88.influence.models;
|
||||
|
||||
import com.stfalcon.chatkit.commons.models.IUser;
|
||||
|
||||
public class GenericUser implements IUser {
|
||||
private String jid;
|
||||
private String name;
|
||||
private String avatar;
|
||||
|
||||
public GenericUser(String jid, String name, String avatar) {
|
||||
this.jid = jid;
|
||||
this.name = name;
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return jid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
}
|
@ -5,13 +5,25 @@ import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.chronosx88.influence.models.GenericUser;
|
||||
|
||||
@Entity(tableName = "chats")
|
||||
public class ChatEntity {
|
||||
@PrimaryKey @NonNull public String jid;
|
||||
@ColumnInfo public String chatName;
|
||||
@ColumnInfo public ArrayList<GenericUser> users;
|
||||
@ColumnInfo public int unreadMessagesCount;
|
||||
|
||||
public ChatEntity(@NonNull String jid, String chatName) {
|
||||
public ChatEntity(@NonNull String jid, String chatName, ArrayList<GenericUser> users, int unreadMessagesCount) {
|
||||
this.jid = jid;
|
||||
this.chatName = chatName;
|
||||
this.users = users;
|
||||
this.unreadMessagesCount = unreadMessagesCount;
|
||||
}
|
||||
|
||||
public boolean isPrivateChat() {
|
||||
return users.size() == 1;
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,21 @@
|
||||
package io.github.chronosx88.influence.observable;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.chronosx88.influence.contracts.observer.INetworkObserver;
|
||||
import io.github.chronosx88.influence.contracts.observer.IObservable;
|
||||
import io.github.chronosx88.influence.contracts.observer.IObserver;
|
||||
|
||||
public class MainObservable implements IObservable {
|
||||
public static final int UI_ACTIONS_CHANNEL = 0;
|
||||
public static final int OTHER_ACTIONS_CHANNEL = 1;
|
||||
|
||||
private ArrayList<IObserver> uiObservers;
|
||||
private ArrayList<INetworkObserver> networkObservers;
|
||||
|
||||
public MainObservable() {
|
||||
this.uiObservers = new ArrayList<>();
|
||||
this.networkObservers = new ArrayList<>();
|
||||
}
|
||||
private ArrayList<IObserver> uiObservers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void register(IObserver observer) {
|
||||
uiObservers.add(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(INetworkObserver observer) {
|
||||
networkObservers.add(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(IObserver observer) {
|
||||
@ -36,21 +23,13 @@ public class MainObservable implements IObservable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(INetworkObserver observer) {
|
||||
networkObservers.remove(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyUIObservers(JsonObject jsonObject) {
|
||||
public void notifyUIObservers(JSONObject jsonObject) {
|
||||
for (IObserver observer : uiObservers) {
|
||||
observer.handleEvent(jsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNetworkObservers(Object object) {
|
||||
for (INetworkObserver observer : networkObservers) {
|
||||
observer.handleEvent(object);
|
||||
try {
|
||||
observer.handleEvent(jsonObject);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
package io.github.chronosx88.influence.presenters;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts;
|
||||
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 CoreContracts.IChatListPresenterContract {
|
||||
private CoreContracts.IChatListViewContract view;
|
||||
private CoreContracts.IChatListLogicContract logic;
|
||||
private ChatListAdapter chatListAdapter;
|
||||
|
||||
public ChatListPresenter(CoreContracts.IChatListViewContract view) {
|
||||
this.view = view;
|
||||
chatListAdapter = new ChatListAdapter((v, p)-> {
|
||||
openChat(chatListAdapter.getChatEntity(p).chatID);
|
||||
});
|
||||
this.logic = new ChatListLogic();
|
||||
this.view.setRecycleAdapter(chatListAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChatList() {
|
||||
view.updateChatList(chatListAdapter, logic.loadAllChats());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openChat(String chatID) {
|
||||
Intent intent = new Intent(AppHelper.getContext(), ChatActivity.class);
|
||||
intent.putExtra("chatID", chatID);
|
||||
intent.putExtra("contactUsername", LocalDBWrapper.getChatByChatID(chatID).name);
|
||||
view.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContextItemSelected(MenuItem item) {
|
||||
switch(item.getItemId()) {
|
||||
case 0: {
|
||||
if(chatListAdapter.onClickPosition != -1) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +1,76 @@
|
||||
package io.github.chronosx88.influence.presenters
|
||||
|
||||
import android.widget.Toast
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.instacart.library.truetime.TrueTime
|
||||
|
||||
import java.io.IOException
|
||||
import java.util.ArrayList
|
||||
import java.util.UUID
|
||||
|
||||
import com.stfalcon.chatkit.commons.ImageLoader
|
||||
import com.stfalcon.chatkit.messages.MessagesListAdapter
|
||||
import io.github.chronosx88.influence.R
|
||||
import io.github.chronosx88.influence.XMPPConnectionService
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts
|
||||
import io.github.chronosx88.influence.contracts.observer.IObserver
|
||||
import io.github.chronosx88.influence.helpers.AppHelper
|
||||
import io.github.chronosx88.influence.helpers.LocalDBWrapper
|
||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions
|
||||
import io.github.chronosx88.influence.logic.ChatLogic
|
||||
import io.github.chronosx88.influence.models.GenericDialog
|
||||
import io.github.chronosx88.influence.models.GenericMessage
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity
|
||||
import org.jetbrains.anko.doAsync
|
||||
import org.jetbrains.anko.doAsyncResult
|
||||
import io.github.chronosx88.influence.models.roomEntities.MessageEntity
|
||||
|
||||
class ChatPresenter(private val view: CoreContracts.IChatViewContract, private val chatID: String) : CoreContracts.IChatPresenterContract, IObserver {
|
||||
class ChatPresenter(private val view: CoreContracts.IChatViewContract, private val chatID: String) : CoreContracts.IChatPresenterContract {
|
||||
private val logic: CoreContracts.IChatLogicContract
|
||||
private val chatEntity: ChatEntity?
|
||||
private val gson: Gson
|
||||
private val chatAdapter: MessagesListAdapter<GenericMessage>
|
||||
private val newMessageReceiver: BroadcastReceiver
|
||||
|
||||
init {
|
||||
this.logic = ChatLogic(LocalDBWrapper.getChatByChatID(chatID)!!)
|
||||
this.chatEntity = LocalDBWrapper.getChatByChatID(chatID)
|
||||
|
||||
AppHelper.getObservable().register(this)
|
||||
gson = Gson()
|
||||
}
|
||||
chatAdapter = MessagesListAdapter(AppHelper.getJid(), ImageLoader { imageView, _, _ -> imageView.setImageResource(R.mipmap.ic_launcher) })
|
||||
view.setAdapter(chatAdapter)
|
||||
|
||||
override fun sendMessage(text: String) {
|
||||
doAsync {
|
||||
val message = LocalDBWrapper.createMessageEntry(NetworkActions.TEXT_MESSAGE, UUID.randomUUID().toString(), chatID, AppHelper.getPeerID(), AppHelper.getPeerID(), TrueTime.now().time, text, false, false)
|
||||
logic.sendMessage(message!!)
|
||||
view.updateMessageList(message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleEvent(obj: JsonObject) {
|
||||
when (obj.get("action").asInt) {
|
||||
UIActions.MESSAGE_RECEIVED -> {
|
||||
val jsonArray = obj.getAsJsonArray("additional")
|
||||
if (jsonArray.get(0).asString != chatID) {
|
||||
return
|
||||
newMessageReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if(intent.getStringExtra(XMPPConnectionService.MESSAGE_CHATID).equals(chatEntity.jid)) {
|
||||
val messageID = intent.getLongExtra(XMPPConnectionService.MESSAGE_ID, -1)
|
||||
chatAdapter.addToStart(GenericMessage(LocalDBWrapper.getMessageByID(messageID)), true)
|
||||
}
|
||||
val messageEntity = LocalDBWrapper.getMessageByID(jsonArray.get(1).asString)
|
||||
view.updateMessageList(messageEntity!!)
|
||||
}
|
||||
|
||||
UIActions.NODE_IS_OFFLINE -> {
|
||||
Toast.makeText(AppHelper.getContext(), "Нода не запущена!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(XMPPConnectionService.INTENT_NEW_MESSAGE)
|
||||
AppHelper.getContext().registerReceiver(newMessageReceiver, filter)
|
||||
}
|
||||
|
||||
override fun updateAdapter() {
|
||||
val entities = LocalDBWrapper.getMessagesByChatID(chatID)
|
||||
view.updateMessageList(entities ?: ArrayList())
|
||||
override fun sendMessage(text: String): Boolean {
|
||||
val message: MessageEntity? = logic.sendMessage(text)
|
||||
if(message != null) {
|
||||
chatAdapter.addToStart(GenericMessage(message), true)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun loadLocalMessages() {
|
||||
val entities: List<MessageEntity>? = LocalDBWrapper.getMessagesByChatID(chatID)
|
||||
val messages = ArrayList<GenericMessage>()
|
||||
if(entities != null) {
|
||||
entities.forEach {
|
||||
messages.add(GenericMessage(it))
|
||||
}
|
||||
}
|
||||
chatAdapter.addToEnd(messages, true)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
logic.stopTrackingForNewMsgs()
|
||||
//
|
||||
}
|
||||
|
||||
private fun setupIncomingMessagesReceiver() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
package io.github.chronosx88.influence.presenters;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.stfalcon.chatkit.dialogs.DialogsListAdapter;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.chronosx88.influence.R;
|
||||
import io.github.chronosx88.influence.XMPPConnectionService;
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts;
|
||||
import io.github.chronosx88.influence.contracts.observer.IObserver;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.LocalDBWrapper;
|
||||
import io.github.chronosx88.influence.helpers.ObservableActions;
|
||||
import io.github.chronosx88.influence.logic.ChatListLogic;
|
||||
import io.github.chronosx88.influence.models.GenericDialog;
|
||||
import io.github.chronosx88.influence.views.ChatActivity;
|
||||
import java8.util.stream.StreamSupport;
|
||||
|
||||
public class DialogListPresenter implements CoreContracts.IDialogListPresenterContract, IObserver {
|
||||
private CoreContracts.IChatListViewContract view;
|
||||
private CoreContracts.IDialogListLogicContract logic;
|
||||
private DialogsListAdapter<GenericDialog> dialogListAdapter = new DialogsListAdapter<>((imageView, url, payload) -> {
|
||||
imageView.setImageResource(R.mipmap.ic_launcher); // FIXME
|
||||
});
|
||||
private BroadcastReceiver incomingMessagesReceiver;
|
||||
|
||||
public DialogListPresenter(CoreContracts.IChatListViewContract view) {
|
||||
this.view = view;
|
||||
dialogListAdapter.setOnDialogClickListener(dialog -> openChat(dialog.getId()));
|
||||
dialogListAdapter.setOnDialogLongClickListener(dialog -> {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(view.getActivityContext());
|
||||
builder.setPositiveButton(R.string.ok, (dialog1, id) -> {
|
||||
dialogListAdapter.deleteById(dialog.getId());
|
||||
AppHelper.getChatDB().chatDao().deleteChat(dialog.getId());
|
||||
AppHelper.getChatDB().messageDao().deleteMessagesByChatID(dialog.getId());
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel, (dialog2, which) -> {
|
||||
//
|
||||
});
|
||||
builder.setMessage("Remove chat?");
|
||||
builder.create().show();
|
||||
});
|
||||
this.logic = new ChatListLogic();
|
||||
this.view.setDialogAdapter(dialogListAdapter);
|
||||
ArrayList<GenericDialog> dialogs = new ArrayList<>();
|
||||
StreamSupport.stream(logic.loadAllChats())
|
||||
.forEach(chatEntity -> dialogs.add(new GenericDialog(chatEntity)));
|
||||
dialogListAdapter.setItems(dialogs);
|
||||
setupIncomingMessagesReceiver();
|
||||
AppHelper.getObservable().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openChat(String chatID) {
|
||||
Intent intent = new Intent(AppHelper.getContext(), ChatActivity.class);
|
||||
intent.putExtra("chatID", chatID);
|
||||
intent.putExtra("chatName", LocalDBWrapper.getChatByChatID(chatID).chatName);
|
||||
view.startActivity(intent);
|
||||
}
|
||||
|
||||
private void setupIncomingMessagesReceiver() {
|
||||
incomingMessagesReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String chatID = intent.getStringExtra(XMPPConnectionService.MESSAGE_CHATID);
|
||||
GenericDialog dialog = dialogListAdapter.getItemById(chatID);
|
||||
if(dialog == null) {
|
||||
dialogListAdapter.addItem(new GenericDialog(LocalDBWrapper.getChatByChatID(chatID)));
|
||||
}
|
||||
}
|
||||
};
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(XMPPConnectionService.INTENT_NEW_MESSAGE);
|
||||
AppHelper.getContext().registerReceiver(incomingMessagesReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(JSONObject object) throws JSONException {
|
||||
switch (object.getInt("action")) {
|
||||
case ObservableActions.NEW_CHAT_CREATED: {
|
||||
dialogListAdapter.addItem(new GenericDialog(LocalDBWrapper.getChatByChatID(object.getJSONArray("additional").optString(0))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +1,68 @@
|
||||
package io.github.chronosx88.influence.presenters
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import android.app.ActivityManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import io.github.chronosx88.influence.R
|
||||
import io.github.chronosx88.influence.XMPPConnectionService
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts
|
||||
import io.github.chronosx88.influence.contracts.observer.IObserver
|
||||
import io.github.chronosx88.influence.helpers.AppHelper
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions
|
||||
import io.github.chronosx88.influence.helpers.LocalDBWrapper
|
||||
import io.github.chronosx88.influence.helpers.ObservableActions
|
||||
import io.github.chronosx88.influence.helpers.ObservableUtils
|
||||
import io.github.chronosx88.influence.logic.MainLogic
|
||||
import io.github.chronosx88.influence.views.LoginActivity
|
||||
import org.jetbrains.anko.doAsync
|
||||
|
||||
class MainPresenter(private val view: CoreContracts.IMainViewContract) : CoreContracts.IMainPresenterContract, IObserver {
|
||||
class MainPresenter(private val view: CoreContracts.IMainViewContract) : CoreContracts.IMainPresenterContract {
|
||||
private val logic: CoreContracts.IMainLogicContract = MainLogic()
|
||||
private var broadcastReceiver: BroadcastReceiver? = null
|
||||
|
||||
init {
|
||||
AppHelper.getObservable().register(this)
|
||||
}
|
||||
|
||||
override fun initPeer() {
|
||||
if (AppHelper.getPeerDHT() == null) {
|
||||
logic.initPeer()
|
||||
} else {
|
||||
view.showSnackbar(AppHelper.getContext().getString(R.string.node_already_running))
|
||||
view.showProgressBar(false)
|
||||
broadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action
|
||||
when (action) {
|
||||
XMPPConnectionService.INTENT_AUTHENTICATED -> {
|
||||
view.showProgressBar(false)
|
||||
}
|
||||
XMPPConnectionService.INTENT_AUTHENTICATION_FAILED -> {
|
||||
view.showProgressBar(false)
|
||||
val intent = Intent(AppHelper.getContext(), LoginActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
AppHelper.getContext().startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val filter = IntentFilter()
|
||||
filter.addAction(XMPPConnectionService.INTENT_AUTHENTICATED)
|
||||
filter.addAction(XMPPConnectionService.INTENT_AUTHENTICATION_FAILED)
|
||||
AppHelper.getContext().registerReceiver(broadcastReceiver, filter)
|
||||
|
||||
AppHelper.getContext().startService(Intent(AppHelper.getContext(), XMPPConnectionService::class.java))
|
||||
}
|
||||
|
||||
override fun startChatWithPeer(username: String) {
|
||||
doAsync {
|
||||
logic.sendStartChatMessage(username)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleEvent(obj: JsonObject) {
|
||||
when(obj.get("action").asInt) {
|
||||
UIActions.PEER_NOT_EXIST -> {
|
||||
view.showProgressBar(false)
|
||||
view.showSnackbar("Данный узел не существует!")
|
||||
}
|
||||
|
||||
UIActions.NEW_CHAT -> {
|
||||
view.showProgressBar(false)
|
||||
view.showSnackbar("Чат успешно создан!")
|
||||
}
|
||||
|
||||
UIActions.NODE_IS_OFFLINE -> {
|
||||
view.showProgressBar(false)
|
||||
view.showSnackbar("Нода не запущена!")
|
||||
}
|
||||
}
|
||||
LocalDBWrapper.createChatEntry(username, username)
|
||||
ObservableUtils.notifyUI(ObservableActions.NEW_CHAT_CREATED, username)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
logic.shutdownPeer()
|
||||
//
|
||||
}
|
||||
|
||||
// TODO
|
||||
private fun isServiceRunning(serviceClass: Class<*>): Boolean {
|
||||
val manager = AppHelper.getContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (serviceClass.name == service.service.className) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,17 @@
|
||||
package io.github.chronosx88.influence.presenters
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Handler
|
||||
import com.google.gson.JsonObject
|
||||
import io.github.chronosx88.influence.R
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts
|
||||
import io.github.chronosx88.influence.contracts.observer.IObserver
|
||||
import io.github.chronosx88.influence.helpers.AppHelper
|
||||
import io.github.chronosx88.influence.helpers.ObservableUtils
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions
|
||||
import io.github.chronosx88.influence.logic.SettingsLogic
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SettingsPresenter(private val view: CoreContracts.ISettingsView) : CoreContracts.ISettingsPresenter, IObserver {
|
||||
class SettingsPresenter(private val view: CoreContracts.ISettingsView) : CoreContracts.ISettingsPresenter {
|
||||
private val mainThreadHandler: Handler = Handler(AppHelper.getContext().mainLooper)
|
||||
private val logic: SettingsLogic = SettingsLogic()
|
||||
|
||||
init {
|
||||
AppHelper.getObservable().register(this)
|
||||
}
|
||||
|
||||
override fun updateUsername(username: String) {
|
||||
view.loadingScreen(true)
|
||||
/*view.loadingScreen(true)
|
||||
val editor: SharedPreferences.Editor = AppHelper.getPreferences().edit()
|
||||
|
||||
GlobalScope.launch {
|
||||
@ -52,23 +41,6 @@ class SettingsPresenter(private val view: CoreContracts.ISettingsView) : CoreCon
|
||||
} else {
|
||||
ObservableUtils.notifyUI(UIActions.USERNAME_ISNT_AVAILABLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleEvent(json: JsonObject) {
|
||||
val post = {
|
||||
when (json.get("action").asInt) {
|
||||
UIActions.USERNAME_AVAILABLE -> {
|
||||
view.loadingScreen(false)
|
||||
view.showMessage(AppHelper.getContext().getString(R.string.username_saved))
|
||||
view.refreshScreen()
|
||||
}
|
||||
UIActions.USERNAME_ISNT_AVAILABLE -> {
|
||||
view.loadingScreen(false)
|
||||
view.showMessage(AppHelper.getContext().getString(R.string.username_isnt_saved))
|
||||
}
|
||||
}
|
||||
}
|
||||
mainThreadHandler.post(post)
|
||||
}*/
|
||||
}
|
||||
}
|
@ -2,25 +2,25 @@ package io.github.chronosx88.influence.views
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.stfalcon.chatkit.commons.ImageLoader
|
||||
import com.stfalcon.chatkit.messages.MessageInput
|
||||
import com.stfalcon.chatkit.messages.MessagesList
|
||||
import com.stfalcon.chatkit.messages.MessagesListAdapter
|
||||
import io.github.chronosx88.influence.R
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts
|
||||
import io.github.chronosx88.influence.helpers.ChatAdapter
|
||||
import io.github.chronosx88.influence.helpers.AppHelper
|
||||
import io.github.chronosx88.influence.models.GenericMessage
|
||||
import io.github.chronosx88.influence.models.roomEntities.MessageEntity
|
||||
import io.github.chronosx88.influence.presenters.ChatPresenter
|
||||
|
||||
class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract {
|
||||
private var chatAdapter: ChatAdapter? = null
|
||||
private var messageList: RecyclerView? = null
|
||||
private var sendMessageButton: ImageButton? = null
|
||||
private var messageTextEdit: EditText? = null
|
||||
private var contactUsernameTextView: TextView? = null
|
||||
private var messageList: MessagesList? = null
|
||||
private var messageInput: MessageInput? = null
|
||||
private var chatNameTextView: TextView? = null
|
||||
private var presenter: ChatPresenter? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -29,45 +29,21 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract {
|
||||
|
||||
val intent = intent
|
||||
|
||||
presenter = ChatPresenter(this, intent.getStringExtra("chatID"))
|
||||
val toolbar = findViewById<Toolbar>(R.id.toolbar_chat_activity)
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar!!.setTitle("")
|
||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar!!.setHomeButtonEnabled(true)
|
||||
messageList = findViewById(R.id.message_list)
|
||||
chatAdapter = ChatAdapter()
|
||||
presenter!!.updateAdapter()
|
||||
messageList!!.adapter = chatAdapter
|
||||
messageList = findViewById(R.id.messages_list)
|
||||
messageList!!.layoutManager = LinearLayoutManager(this)
|
||||
contactUsernameTextView = findViewById(R.id.appbar_username)
|
||||
messageTextEdit = findViewById(R.id.message_input)
|
||||
sendMessageButton = findViewById(R.id.send_button)
|
||||
sendMessageButton!!.setOnClickListener sendMessageButton@{
|
||||
if (messageTextEdit!!.text.toString() == "") {
|
||||
return@sendMessageButton
|
||||
}
|
||||
presenter!!.sendMessage(messageTextEdit!!.text.toString())
|
||||
messageTextEdit!!.setText("")
|
||||
}
|
||||
contactUsernameTextView!!.text = intent.getStringExtra("contactUsername")
|
||||
messageList!!.scrollToPosition(chatAdapter!!.itemCount - 1)
|
||||
}
|
||||
|
||||
override fun updateMessageList(message: MessageEntity) {
|
||||
runOnUiThread {
|
||||
chatAdapter!!.addMessage(message)
|
||||
messageList!!.scrollToPosition(chatAdapter!!.itemCount - 1)
|
||||
chatAdapter!!.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateMessageList(messages: List<MessageEntity>) {
|
||||
runOnUiThread {
|
||||
chatAdapter!!.addMessages(messages)
|
||||
messageList!!.scrollToPosition(chatAdapter!!.itemCount - 1)
|
||||
chatAdapter!!.notifyDataSetChanged()
|
||||
chatNameTextView = findViewById(R.id.appbar_username)
|
||||
messageInput = findViewById(R.id.message_input)
|
||||
messageInput!!.setInputListener {
|
||||
presenter!!.sendMessage(it.toString())
|
||||
}
|
||||
chatNameTextView!!.text = intent.getStringExtra("chatName")
|
||||
presenter = ChatPresenter(this, intent.getStringExtra("chatID"))
|
||||
presenter!!.loadLocalMessages()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
@ -84,4 +60,8 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract {
|
||||
super.onDestroy()
|
||||
presenter!!.onDestroy()
|
||||
}
|
||||
|
||||
override fun setAdapter(adapter: MessagesListAdapter<GenericMessage>) {
|
||||
messageList!!.setAdapter(adapter)
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
@ -51,6 +50,8 @@ public class LoginActivity extends AppCompatActivity implements CoreContracts.IL
|
||||
passwordEditText = findViewById(R.id.login_password);
|
||||
signInButton = findViewById(R.id.sign_in_button);
|
||||
progressDialog = new ProgressDialog(LoginActivity.this);
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.setProgressStyle(android.R.style.Widget_ProgressBar_Small);
|
||||
signInButton.setOnClickListener((v) -> {
|
||||
if(checkLoginCredentials()) {
|
||||
saveLoginCredentials();
|
||||
@ -82,7 +83,7 @@ public class LoginActivity extends AppCompatActivity implements CoreContracts.IL
|
||||
}
|
||||
case XMPPConnectionService.INTENT_AUTHENTICATION_FAILED: {
|
||||
loadingScreen(false);
|
||||
passwordEditText.setError("Invalid JID/Password");
|
||||
jidEditText.setError("Invalid JID/Password/Server");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -7,59 +7,51 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import io.github.chronosx88.influence.R;
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts;
|
||||
import io.github.chronosx88.influence.contracts.observer.IObserver;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||
import io.github.chronosx88.influence.helpers.ObservableActions;
|
||||
import io.github.chronosx88.influence.presenters.MainPresenter;
|
||||
import io.github.chronosx88.influence.views.fragments.ChatListFragment;
|
||||
import io.github.chronosx88.influence.views.fragments.DialogListFragment;
|
||||
import io.github.chronosx88.influence.views.fragments.SettingsFragment;
|
||||
import kotlin.Pair;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements CoreContracts.IMainViewContract {
|
||||
public class MainActivity extends AppCompatActivity implements CoreContracts.IMainViewContract, IObserver {
|
||||
|
||||
private CoreContracts.IMainPresenterContract presenter;
|
||||
private ProgressDialog progressDialog;
|
||||
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
|
||||
= new BottomNavigationView.OnNavigationItemSelectedListener() {
|
||||
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = (item) -> {
|
||||
Fragment selectedFragment = null;
|
||||
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||
|
||||
Fragment selectedFragment = null;
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_chats:
|
||||
selectedFragment = new ChatListFragment();
|
||||
break;
|
||||
case R.id.action_settings:
|
||||
selectedFragment = new SettingsFragment();
|
||||
break;
|
||||
}
|
||||
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
transaction.replace(R.id.main_fragment_container, selectedFragment);
|
||||
transaction.commit();
|
||||
|
||||
return true;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_chats:
|
||||
selectedFragment = new DialogListFragment();
|
||||
break;
|
||||
case R.id.action_settings:
|
||||
selectedFragment = new SettingsFragment();
|
||||
break;
|
||||
}
|
||||
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
transaction.replace(R.id.main_fragment_container, selectedFragment);
|
||||
transaction.commit();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@Override
|
||||
@ -73,7 +65,7 @@ public class MainActivity extends AppCompatActivity implements CoreContracts.IMa
|
||||
fab.setOnClickListener((v) -> {
|
||||
Pair<AlertDialog.Builder, EditText> pair = ViewUtils.INSTANCE.setupEditTextDialog(MainActivity.this, getString(R.string.input_companion_username));
|
||||
pair.getFirst().setPositiveButton(getString(R.string.ok), (dialog, which) -> {
|
||||
progressDialog.show();
|
||||
showProgressBar(true);
|
||||
presenter.startChatWithPeer(pair.getSecond().getText().toString());
|
||||
});
|
||||
pair.getFirst().setNegativeButton(getString(R.string.cancel), (dialog, which) -> {
|
||||
@ -84,17 +76,17 @@ public class MainActivity extends AppCompatActivity implements CoreContracts.IMa
|
||||
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.main_fragment_container, new ChatListFragment())
|
||||
.replace(R.id.main_fragment_container, new DialogListFragment())
|
||||
.commit();
|
||||
|
||||
presenter = new MainPresenter(this);
|
||||
|
||||
|
||||
progressDialog = new ProgressDialog(MainActivity.this, R.style.AlertDialogTheme);
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.setProgressStyle(android.R.style.Widget_ProgressBar_Small);
|
||||
progressDialog.show();
|
||||
presenter.initPeer();
|
||||
AppHelper.getObservable().register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -120,10 +112,7 @@ public class MainActivity extends AppCompatActivity implements CoreContracts.IMa
|
||||
|
||||
@Override
|
||||
public void showSnackbar(@NotNull String message) {
|
||||
runOnUiThread(() -> {
|
||||
Snackbar.make(getRootView(), message, Snackbar.LENGTH_LONG)
|
||||
.show();
|
||||
});
|
||||
runOnUiThread(() -> Snackbar.make(getRootView(), message, Snackbar.LENGTH_LONG).show());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,4 +138,14 @@ public class MainActivity extends AppCompatActivity implements CoreContracts.IMa
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(JSONObject object) throws JSONException {
|
||||
switch (object.getInt("action")) {
|
||||
case ObservableActions.NEW_CHAT_CREATED: {
|
||||
showProgressBar(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
package io.github.chronosx88.influence.views.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.chronosx88.influence.R
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts
|
||||
import io.github.chronosx88.influence.contracts.observer.IObserver
|
||||
import io.github.chronosx88.influence.helpers.AppHelper
|
||||
import io.github.chronosx88.influence.helpers.ChatListAdapter
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity
|
||||
import io.github.chronosx88.influence.presenters.ChatListPresenter
|
||||
|
||||
class ChatListFragment : Fragment(), CoreContracts.IChatListViewContract, IObserver {
|
||||
private var presenter: CoreContracts.IChatListPresenterContract? = null
|
||||
private var chatList: RecyclerView? = null
|
||||
private var mainThreadHandler: Handler? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
AppHelper.getObservable().register(this)
|
||||
this.mainThreadHandler = Handler(context!!.mainLooper)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.chatlist_fragment, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
chatList = view.findViewById(R.id.chatlist_container)
|
||||
chatList!!.layoutManager = LinearLayoutManager(context)
|
||||
presenter = ChatListPresenter(this)
|
||||
presenter!!.updateChatList()
|
||||
registerForContextMenu(chatList!!)
|
||||
}
|
||||
|
||||
override fun setRecycleAdapter(adapter: ChatListAdapter) {
|
||||
chatList!!.adapter = adapter
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
presenter!!.updateChatList()
|
||||
}
|
||||
|
||||
override fun handleEvent(`object`: JsonObject) {
|
||||
when (`object`.get("action").asInt) {
|
||||
UIActions.SUCCESSFUL_CREATE_CHAT, UIActions.NEW_CHAT -> {
|
||||
presenter!!.updateChatList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateChatList(adapter: ChatListAdapter, chats: List<ChatEntity>) {
|
||||
mainThreadHandler!!.post {
|
||||
adapter.setChatList(chats)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onContextItemSelected(item: MenuItem): Boolean {
|
||||
presenter!!.onContextItemSelected(item)
|
||||
return super.onContextItemSelected(item)
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package io.github.chronosx88.influence.views.fragments
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.stfalcon.chatkit.dialogs.DialogsList
|
||||
import com.stfalcon.chatkit.dialogs.DialogsListAdapter
|
||||
import io.github.chronosx88.influence.R
|
||||
import io.github.chronosx88.influence.contracts.CoreContracts
|
||||
import io.github.chronosx88.influence.models.GenericDialog
|
||||
import io.github.chronosx88.influence.presenters.DialogListPresenter
|
||||
|
||||
|
||||
class DialogListFragment : Fragment(), CoreContracts.IChatListViewContract {
|
||||
private var presenter: CoreContracts.IDialogListPresenterContract? = null
|
||||
private var dialogList: DialogsList? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.chatlist_fragment, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
dialogList = view.findViewById(R.id.dialogsList)
|
||||
presenter = DialogListPresenter(this)
|
||||
}
|
||||
|
||||
override fun setDialogAdapter(adapter: DialogsListAdapter<GenericDialog>) {
|
||||
dialogList!!.setAdapter(adapter)
|
||||
}
|
||||
|
||||
override fun getActivityContext(): Context? {
|
||||
return context
|
||||
}
|
||||
}
|
@ -33,12 +33,12 @@ public class SettingsFragment extends PreferenceFragmentCompat implements CoreCo
|
||||
presenter = new SettingsPresenter(this);
|
||||
// Load the Preferences from the XML file
|
||||
addPreferencesFromResource(R.xml.main_settings);
|
||||
getPreferenceScreen().getPreference(0).setSummary(AppHelper.getPeerID());
|
||||
/*getPreferenceScreen().getPreference(0).setSummary(AppHelper.getPeerID());
|
||||
getPreferenceScreen().getPreference(0).setOnPreferenceClickListener((preference -> {
|
||||
ClipboardManager clipboard = (ClipboardManager) AppHelper.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipboardManager clipboard = (ClipboardManager) AppHelper.getActivityContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("", AppHelper.getPeerID());
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(AppHelper.getContext(), "Скопировано в буфер обмена!", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(AppHelper.getActivityContext(), "Скопировано в буфер обмена!", Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}));
|
||||
getPreferenceScreen().getPreference(1).setSummary(AppHelper.getUsername());
|
||||
@ -49,7 +49,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements CoreCo
|
||||
getPreferenceScreen().getPreference(1).setOnPreferenceChangeListener((p, nV) -> {
|
||||
getPreferenceScreen().getPreference(1).setSummary((String) nV);
|
||||
return true;
|
||||
});
|
||||
});*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -38,38 +38,26 @@
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/message_list"
|
||||
<com.stfalcon.chatkit.messages.MessagesList
|
||||
android:id="@+id/messages_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"/>
|
||||
android:layout_above="@+id/message_input"/>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/chat_activity_bottom_container"
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_above="@+id/message_input"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:background="@android:color/darker_gray"/>
|
||||
|
||||
<com.stfalcon.chatkit.messages.MessageInput
|
||||
android:id="@+id/message_input"
|
||||
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>
|
||||
app:inputHint="@string/hint_enter_a_message"
|
||||
app:showAttachmentButton="true"/>
|
||||
|
||||
</RelativeLayout>
|
@ -3,8 +3,8 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/chatlist_container"
|
||||
<com.stfalcon.chatkit.dialogs.DialogsList
|
||||
android:id="@+id/dialogsList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
@ -10,4 +10,5 @@
|
||||
<string name="reconnect_network">Переподключиться к сети</string>
|
||||
<string name="node_already_running">Узел уже запущен</string>
|
||||
<string name="input_companion_username">Введите имя пользователя собеседника</string>
|
||||
<string name="hint_enter_a_message">Введите сообщение...</string>
|
||||
</resources>
|
@ -9,4 +9,5 @@
|
||||
<string name="reconnect_network">Reconnect to the network</string>
|
||||
<string name="node_already_running">Node already running</string>
|
||||
<string name="input_companion_username">Input interlocutor\'s username</string>
|
||||
<string name="hint_enter_a_message">Enter message...</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user