From 6cc21659d249cdfce53a7f90901969f191e8fe0c Mon Sep 17 00:00:00 2001 From: ChronosX88 Date: Fri, 24 May 2019 14:33:06 +0400 Subject: [PATCH] Made showing last message ans changed default NTP server --- .../influence/helpers/AppHelper.java | 2 +- .../influence/helpers/LocalDBWrapper.java | 5 + .../influence/helpers/NetworkHandler.java | 3 + .../chronosx88/influence/logic/ChatLogic.java | 9 ++ .../influence/models/GenericMessage.java | 2 +- .../models/appEvents/LastMessageEvent.java | 29 ++++++ .../influence/models/daos/MessageDao.java | 3 + .../influence/presenters/ChatPresenter.kt | 5 +- .../presenters/DialogListPresenter.java | 96 +++++++++++++------ .../main/res/layout/item_dialog_custom.xml | 2 +- 10 files changed, 122 insertions(+), 34 deletions(-) create mode 100644 app/src/main/java/io/github/chronosx88/influence/models/appEvents/LastMessageEvent.java diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java b/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java index b85a489..668af74 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/AppHelper.java @@ -40,7 +40,7 @@ import io.github.chronosx88.influence.XMPPConnection; public class AppHelper extends MultiDexApplication { private static Application instance; public final static String APP_NAME = "Influence"; - public final static String DEFAULT_NTP_SERVER = "0.europe.pool.ntp.org"; + public final static String DEFAULT_NTP_SERVER = "time.apple.com"; private static String jid; private static RoomHelper chatDB; diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java b/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java index a9280e4..0e5255b 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/LocalDBWrapper.java @@ -79,4 +79,9 @@ public class LocalDBWrapper { dbInstance.messageDao().clearMessages(); dbInstance.chatDao().clearChats(); } + + public static MessageEntity getLastMessage(String chatID) { + long messageID = dbInstance.messageDao().getLastMessageByChatID(chatID); + return getMessageByID(messageID); + } } diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java b/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java index 15fe01a..7aae227 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java @@ -24,6 +24,8 @@ import org.jivesoftware.smack.chat2.IncomingChatMessageListener; import org.jivesoftware.smack.packet.Message; import org.jxmpp.jid.EntityBareJid; +import io.github.chronosx88.influence.models.GenericMessage; +import io.github.chronosx88.influence.models.appEvents.LastMessageEvent; import io.github.chronosx88.influence.models.appEvents.NewMessageEvent; public class NetworkHandler implements IncomingChatMessageListener { @@ -37,5 +39,6 @@ public class NetworkHandler implements IncomingChatMessageListener { long messageID = LocalDBWrapper.createMessageEntry(chat.getXmppAddressOfChatPartner().asUnescapedString(), from.asUnescapedString(), TrueTime.now().getTime(), message.getBody(), true, false); EventBus.getDefault().post(new NewMessageEvent(chat.getXmppAddressOfChatPartner().toString(), messageID)); + EventBus.getDefault().post(new LastMessageEvent(chat.getXmppAddressOfChatPartner().toString(), new GenericMessage(LocalDBWrapper.getMessageByID(messageID)))); } } \ No newline at end of file diff --git a/app/src/main/java/io/github/chronosx88/influence/logic/ChatLogic.java b/app/src/main/java/io/github/chronosx88/influence/logic/ChatLogic.java index 93e1e44..8035f00 100644 --- a/app/src/main/java/io/github/chronosx88/influence/logic/ChatLogic.java +++ b/app/src/main/java/io/github/chronosx88/influence/logic/ChatLogic.java @@ -22,6 +22,8 @@ import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; +import java.io.IOException; + import io.github.chronosx88.influence.contracts.CoreContracts; import io.github.chronosx88.influence.helpers.AppHelper; import io.github.chronosx88.influence.helpers.LocalDBWrapper; @@ -49,6 +51,13 @@ public class ChatLogic implements CoreContracts.IChatLogicContract { return null; } AppHelper.getXmppConnection().sendMessage(jid, text); + while (!TrueTime.isInitialized()) { + try { + TrueTime.build().initialize(); + } catch (IOException e) { + e.printStackTrace(); + } + } long messageID = LocalDBWrapper.createMessageEntry(chatID, AppHelper.getJid(), TrueTime.now().getTime(), text, false, false); return LocalDBWrapper.getMessageByID(messageID); } else { diff --git a/app/src/main/java/io/github/chronosx88/influence/models/GenericMessage.java b/app/src/main/java/io/github/chronosx88/influence/models/GenericMessage.java index aec2d54..22a08f0 100644 --- a/app/src/main/java/io/github/chronosx88/influence/models/GenericMessage.java +++ b/app/src/main/java/io/github/chronosx88/influence/models/GenericMessage.java @@ -31,7 +31,7 @@ public class GenericMessage implements IMessage { public GenericMessage(MessageEntity messageEntity) { this.messageID = messageEntity.messageID; - this.author = new GenericUser(messageEntity.senderJid, messageEntity.senderJid, ""); + this.author = new GenericUser(messageEntity.senderJid, messageEntity.senderJid, messageEntity.senderJid); this.timestamp = messageEntity.timestamp; this.text = messageEntity.text; } diff --git a/app/src/main/java/io/github/chronosx88/influence/models/appEvents/LastMessageEvent.java b/app/src/main/java/io/github/chronosx88/influence/models/appEvents/LastMessageEvent.java new file mode 100644 index 0000000..3813df8 --- /dev/null +++ b/app/src/main/java/io/github/chronosx88/influence/models/appEvents/LastMessageEvent.java @@ -0,0 +1,29 @@ +/* + * Copyright 2019 ChronosX88 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.github.chronosx88.influence.models.appEvents; + +import com.stfalcon.chatkit.commons.models.IMessage; + +public class LastMessageEvent { + public final String chatID; + public final IMessage message; + + public LastMessageEvent(String chatID, IMessage message) { + this.chatID = chatID; + this.message = message; + } +} diff --git a/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java b/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java index 12f1259..04978d7 100644 --- a/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java +++ b/app/src/main/java/io/github/chronosx88/influence/models/daos/MessageDao.java @@ -47,4 +47,7 @@ public interface MessageDao { @Query("DELETE FROM messages") void clearMessages(); + + @Query("SELECT messageID FROM messages WHERE jid = :chatID GROUP BY :chatID HAVING MAX(messageID)") + long getLastMessageByChatID(String chatID); } diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.kt b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.kt index a37331e..92d9a3f 100644 --- a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.kt +++ b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatPresenter.kt @@ -28,6 +28,7 @@ import io.github.chronosx88.influence.helpers.AppHelper import io.github.chronosx88.influence.helpers.LocalDBWrapper import io.github.chronosx88.influence.logic.ChatLogic import io.github.chronosx88.influence.models.GenericMessage +import io.github.chronosx88.influence.models.appEvents.LastMessageEvent import io.github.chronosx88.influence.models.appEvents.NewMessageEvent import io.github.chronosx88.influence.models.roomEntities.ChatEntity import io.github.chronosx88.influence.models.roomEntities.MessageEntity @@ -81,7 +82,9 @@ class ChatPresenter(private val view: CoreContracts.IChatViewContract, private v override fun sendMessage(text: String): Boolean { val message: MessageEntity? = logic.sendMessage(text) if(message != null) { - chatAdapter.addToStart(GenericMessage(message), true) + val message = GenericMessage(message) + chatAdapter.addToStart(message, true) + EventBus.getDefault().post(LastMessageEvent(chatEntity!!.jid, message)) return true } return false diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/DialogListPresenter.java b/app/src/main/java/io/github/chronosx88/influence/presenters/DialogListPresenter.java index fec1fbd..11907b4 100644 --- a/app/src/main/java/io/github/chronosx88/influence/presenters/DialogListPresenter.java +++ b/app/src/main/java/io/github/chronosx88/influence/presenters/DialogListPresenter.java @@ -28,12 +28,15 @@ import com.stfalcon.chatkit.dialogs.DialogsListAdapter; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.jivesoftware.smack.roster.RosterEntry; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.stringprep.XmppStringprepException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -43,9 +46,12 @@ import io.github.chronosx88.influence.helpers.AppHelper; import io.github.chronosx88.influence.helpers.LocalDBWrapper; import io.github.chronosx88.influence.logic.DialogListLogic; import io.github.chronosx88.influence.models.GenericDialog; +import io.github.chronosx88.influence.models.GenericMessage; import io.github.chronosx88.influence.models.appEvents.AuthenticationStatusEvent; +import io.github.chronosx88.influence.models.appEvents.LastMessageEvent; import io.github.chronosx88.influence.models.appEvents.NewChatEvent; import io.github.chronosx88.influence.models.appEvents.NewMessageEvent; +import io.github.chronosx88.influence.models.roomEntities.MessageEntity; import io.github.chronosx88.influence.views.ChatActivity; import java8.util.stream.StreamSupport; import java9.util.concurrent.CompletableFuture; @@ -55,33 +61,42 @@ public class DialogListPresenter implements CoreContracts.IDialogListPresenterCo private CoreContracts.IChatListViewContract view; private CoreContracts.IDialogListLogicContract logic; private DialogsListAdapter dialogListAdapter = new DialogsListAdapter<>(R.layout.item_dialog_custom, (imageView, url, payload) -> { - String firstLetter = Character.toString(Character.toUpperCase(url.charAt(0))); - imageView.setImageDrawable(TextDrawable.builder() - .beginConfig() - .width(64) - .height(64) - .endConfig() - .buildRound(firstLetter, ColorGenerator.MATERIAL.getColor(firstLetter))); - CompletableFuture.supplyAsync(() -> { - while (AppHelper.getXmppConnection() == null); - while (AppHelper.getXmppConnection().isConnectionAlive() != true); - EntityBareJid jid = null; - try { - jid = JidCreate.entityBareFrom(url); - } catch (XmppStringprepException e) { - e.printStackTrace(); + if(url.length() != 0) { + if(avatarsMap.containsKey(url)) { + byte[] avatarBytes = avatarsMap.get(url); + Bitmap avatar = BitmapFactory.decodeByteArray(avatarBytes, 0, avatarBytes.length); + imageView.setImageBitmap(avatar); + return; } - return AppHelper.getXmppConnection().getAvatar(jid); - }).thenAccept((avatarBytes) -> { - AppHelper.getMainUIThread().post(() -> { - if(avatarBytes != null) { - Bitmap avatar = BitmapFactory.decodeByteArray(avatarBytes, 0, avatarBytes.length); - imageView.setImageBitmap(avatar); - avatarsMap.put(url, avatarBytes); + String firstLetter = Character.toString(Character.toUpperCase(url.charAt(0))); + imageView.setImageDrawable(TextDrawable.builder() + .beginConfig() + .width(64) + .height(64) + .endConfig() + .buildRound(firstLetter, ColorGenerator.MATERIAL.getColor(firstLetter))); + CompletableFuture.supplyAsync(() -> { + while (AppHelper.getXmppConnection() == null); + while (AppHelper.getXmppConnection().isConnectionAlive() != true); + EntityBareJid jid = null; + try { + jid = JidCreate.entityBareFrom(url); + } catch (XmppStringprepException e) { + e.printStackTrace(); } + return AppHelper.getXmppConnection().getAvatar(jid); + }).thenAccept((avatarBytes) -> { + AppHelper.getMainUIThread().post(() -> { + if(avatarBytes != null) { + Bitmap avatar = BitmapFactory.decodeByteArray(avatarBytes, 0, avatarBytes.length); + imageView.setImageBitmap(avatar); + avatarsMap.put(url, avatarBytes); + } + }); }); - }); + } }); + private Comparator dialogComparator = (dialog1, dialog2) -> Long.compare(dialog2.getLastMessage().getCreatedAt().getTime(), dialog1.getLastMessage().getCreatedAt().getTime()); public DialogListPresenter(CoreContracts.IChatListViewContract view) { this.view = view; @@ -104,18 +119,27 @@ public class DialogListPresenter implements CoreContracts.IDialogListPresenterCo ArrayList dialogs = new ArrayList<>(); StreamSupport.stream(logic.loadLocalChats()) .forEach(chatEntity -> dialogs.add(new GenericDialog(chatEntity))); + StreamSupport.stream(dialogs) + .forEach(dialog -> { + MessageEntity messageEntity = LocalDBWrapper.getLastMessage(dialog.getId()); + if(messageEntity != null) { + dialog.setLastMessage(new GenericMessage(messageEntity)); + } + }); dialogListAdapter.setItems(dialogs); + dialogListAdapter.sort(dialogComparator); loadRemoteContactList(); - } - - @Override - public void onStart() { EventBus.getDefault().register(this); } + @Override + public void onStart() { + + } + @Override public void onStop() { - EventBus.getDefault().unregister(this); + } @Override @@ -154,11 +178,23 @@ public class DialogListPresenter implements CoreContracts.IDialogListPresenterCo AppHelper.getMainUIThread().post(() -> { if(contacts != null) { StreamSupport.stream(contacts).forEach(contact -> { - LocalDBWrapper.createChatEntry(contact.getJid().asUnescapedString(), contact.getName() == null ? contact.getJid().asUnescapedString().split("@")[0] : contact.getName()); - dialogListAdapter.upsertItem(new GenericDialog(LocalDBWrapper.getChatByChatID(contact.getJid().asUnescapedString()))); + String chatID = contact.getJid().asUnescapedString(); + LocalDBWrapper.createChatEntry(chatID, contact.getName() == null ? contact.getJid().asUnescapedString().split("@")[0] : contact.getName()); + GenericDialog dialog = new GenericDialog(LocalDBWrapper.getChatByChatID(chatID)); + MessageEntity messageEntity = LocalDBWrapper.getLastMessage(chatID); + if(messageEntity != null) { + dialog.setLastMessage(new GenericMessage(messageEntity)); + } + dialogListAdapter.upsertItem(dialog); }); } }); }); } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLastMessage(LastMessageEvent event) { + dialogListAdapter.updateDialogWithMessage(event.chatID, event.message); + dialogListAdapter.sort(dialogComparator); + } } diff --git a/app/src/main/res/layout/item_dialog_custom.xml b/app/src/main/res/layout/item_dialog_custom.xml index b1c9235..ec1cf61 100644 --- a/app/src/main/res/layout/item_dialog_custom.xml +++ b/app/src/main/res/layout/item_dialog_custom.xml @@ -73,7 +73,7 @@ android:layout_toRightOf="@id/dialogAvatar" android:layout_toStartOf="@+id/dialogUnreadBubble"> -