mirror of
https://github.com/ChronosX88/Influence.git
synced 2024-11-23 10:02:18 +00:00
Implemented showing user presence
This commit is contained in:
parent
501c2eb5bc
commit
dc66de02fb
@ -38,7 +38,9 @@ import org.jivesoftware.smack.tcp.XMPPTCPConnection;
|
||||
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
|
||||
import org.jivesoftware.smackx.mam.MamManager;
|
||||
import org.jivesoftware.smackx.vcardtemp.VCardManager;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
@ -117,6 +119,7 @@ public class XMPPConnection implements ConnectionListener {
|
||||
reconnectionManager.enableAutomaticReconnection();
|
||||
roster = roster.getInstanceFor(connection);
|
||||
roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
|
||||
roster.addPresenceEventListener(networkHandler);
|
||||
mamManager = MamManager.getInstanceFor(connection);
|
||||
try {
|
||||
if(mamManager.isSupported()) {
|
||||
@ -217,4 +220,8 @@ public class XMPPConnection implements ConnectionListener {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Presence getUserPresence(BareJid jid) {
|
||||
return roster.getPresence(jid);
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ interface CoreContracts {
|
||||
|
||||
interface IChatLogicContract {
|
||||
fun sendMessage(text: String): MessageEntity?
|
||||
fun getUserStatus(): Boolean
|
||||
}
|
||||
|
||||
interface IChatPresenterContract {
|
||||
@ -88,6 +89,7 @@ interface CoreContracts {
|
||||
|
||||
interface IChatViewContract {
|
||||
fun setAdapter(adapter: MessagesListAdapter<GenericMessage>)
|
||||
fun setUserStatus(status: String)
|
||||
}
|
||||
|
||||
// -----SettingsFragment-----
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.helpers;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class HashUtils {
|
||||
public static String sha1(final String text) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||
md.update(text.getBytes("UTF-8"), 0, text.length());
|
||||
byte[] sha1hash = md.digest();
|
||||
return hashToString(sha1hash);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String hashToString(final byte[] buf) {
|
||||
if (buf == null) return "";
|
||||
int l = buf.length;
|
||||
StringBuffer result = new StringBuffer(2 * l);
|
||||
for (int i = 0; i < buf.length; i++) {
|
||||
appendByte(result, buf[i]);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private final static String HEX_PACK = "0123456789ABCDEF";
|
||||
|
||||
private static void appendByte(final StringBuffer sb, final byte b) {
|
||||
sb
|
||||
.append(HEX_PACK.charAt((b >> 4) & 0x0f))
|
||||
.append(HEX_PACK.charAt(b & 0x0f));
|
||||
}
|
||||
}
|
@ -19,16 +19,23 @@ package io.github.chronosx88.influence.helpers;
|
||||
import com.instacart.library.truetime.TrueTime;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.jivesoftware.smack.PresenceListener;
|
||||
import org.jivesoftware.smack.chat2.Chat;
|
||||
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.roster.PresenceEventListener;
|
||||
import org.jxmpp.jid.BareJid;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.FullJid;
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
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.appEvents.UserPresenceChangedEvent;
|
||||
|
||||
public class NetworkHandler implements IncomingChatMessageListener {
|
||||
public class NetworkHandler implements IncomingChatMessageListener, PresenceEventListener {
|
||||
private final static String LOG_TAG = "NetworkHandler";
|
||||
|
||||
@Override
|
||||
@ -44,4 +51,29 @@ public class NetworkHandler implements IncomingChatMessageListener {
|
||||
EventBus.getDefault().post(new NewMessageEvent(chatID, messageID));
|
||||
EventBus.getDefault().post(new LastMessageEvent(chatID, new GenericMessage(LocalDBWrapper.getMessageByID(messageID))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void presenceAvailable(FullJid address, Presence availablePresence) {
|
||||
EventBus.getDefault().post(new UserPresenceChangedEvent(address.asBareJid().asUnescapedString(), availablePresence.isAvailable()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void presenceUnavailable(FullJid address, Presence presence) {
|
||||
EventBus.getDefault().post(new UserPresenceChangedEvent(address.asBareJid().asUnescapedString(), presence.isAvailable()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void presenceError(Jid address, Presence errorPresence) {
|
||||
EventBus.getDefault().post(new UserPresenceChangedEvent(address.asBareJid().asUnescapedString(), errorPresence.isAvailable()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void presenceSubscribed(BareJid address, Presence subscribedPresence) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void presenceUnsubscribed(BareJid address, Presence unsubscribedPresence) {
|
||||
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package io.github.chronosx88.influence.logic;
|
||||
|
||||
import com.instacart.library.truetime.TrueTime;
|
||||
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
import org.jxmpp.jid.impl.JidCreate;
|
||||
import org.jxmpp.stringprep.XmppStringprepException;
|
||||
@ -58,10 +59,26 @@ public class ChatLogic implements CoreContracts.IChatLogicContract {
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
long messageID = LocalDBWrapper.createMessageEntry(chatID, AppHelper.getJid(), TrueTime.now().getTime(), text, false, false);
|
||||
long messageID = LocalDBWrapper.createMessageEntry(chatID, AppHelper.getJid(), TrueTime.now().getTime(), text, true, false);
|
||||
return LocalDBWrapper.getMessageByID(messageID);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getUserStatus() {
|
||||
if(AppHelper.getXmppConnection() != null) {
|
||||
if(AppHelper.getXmppConnection().isConnectionAlive()) {
|
||||
Presence presence = null;
|
||||
try {
|
||||
presence = AppHelper.getXmppConnection().getUserPresence(JidCreate.bareFrom(chatID));
|
||||
} catch (XmppStringprepException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return presence.isAvailable();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class UserPresenceChangedEvent {
|
||||
public final String jid;
|
||||
public final boolean status;
|
||||
|
||||
public UserPresenceChangedEvent(String jid, boolean status) {
|
||||
this.jid = jid;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
@ -28,11 +28,16 @@ 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.appEvents.UserPresenceChangedEvent
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity
|
||||
import io.github.chronosx88.influence.models.roomEntities.MessageEntity
|
||||
import java9.util.concurrent.CompletableFuture
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.async
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import kotlin.math.log
|
||||
|
||||
class ChatPresenter(private val view: CoreContracts.IChatViewContract, private val chatID: String) : CoreContracts.IChatPresenterContract {
|
||||
private val logic: CoreContracts.IChatLogicContract
|
||||
@ -48,6 +53,7 @@ class ChatPresenter(private val view: CoreContracts.IChatViewContract, private v
|
||||
holdersConfig.setIncomingTextLayout(R.layout.item_incoming_text_message_custom)
|
||||
chatAdapter = MessagesListAdapter(AppHelper.getJid(), holdersConfig, AvatarImageLoader())
|
||||
view.setAdapter(chatAdapter)
|
||||
getUserStatus()
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
@ -85,4 +91,25 @@ class ChatPresenter(private val view: CoreContracts.IChatViewContract, private v
|
||||
LocalDBWrapper.updateChatUnreadMessagesCount(chatEntity.jid, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public fun onPresenceChanged(event: UserPresenceChangedEvent) {
|
||||
if(event.jid == (chatID)) {
|
||||
if(event.status) view.setUserStatus(AppHelper.getContext().getString(R.string.online)) else view.setUserStatus(AppHelper.getContext().getString(R.string.offline))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUserStatus() {
|
||||
CompletableFuture.supplyAsync {
|
||||
return@supplyAsync logic.getUserStatus()
|
||||
}.thenAccept { status ->
|
||||
AppHelper.getMainUIThread().post({
|
||||
if(status) {
|
||||
view.setUserStatus(AppHelper.getContext().getString(R.string.online))
|
||||
} else {
|
||||
view.setUserStatus(AppHelper.getContext().getString(R.string.offline))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,12 @@ public class DialogListPresenter implements CoreContracts.IDialogListPresenterCo
|
||||
private CoreContracts.IChatListViewContract view;
|
||||
private CoreContracts.IDialogListLogicContract logic;
|
||||
private DialogsListAdapter<GenericDialog> dialogListAdapter = new DialogsListAdapter<>(R.layout.item_dialog_custom, new AvatarImageLoader());
|
||||
private Comparator<GenericDialog> dialogComparator = (dialog1, dialog2) -> Long.compare(dialog2.getLastMessage().getCreatedAt().getTime(), dialog1.getLastMessage().getCreatedAt().getTime());
|
||||
private Comparator<GenericDialog> dialogComparator = (dialog1, dialog2) -> {
|
||||
if(dialog2.getLastMessage() != null && dialog1.getLastMessage() != null) {
|
||||
return Long.compare(dialog2.getLastMessage().getCreatedAt().getTime(), dialog1.getLastMessage().getCreatedAt().getTime());
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
public DialogListPresenter(CoreContracts.IChatListViewContract view) {
|
||||
this.view = view;
|
||||
|
@ -38,12 +38,14 @@ import io.github.chronosx88.influence.models.GenericMessage
|
||||
import io.github.chronosx88.influence.models.roomEntities.MessageEntity
|
||||
import io.github.chronosx88.influence.presenters.ChatPresenter
|
||||
import kotlinx.android.synthetic.main.activity_chat.view.*
|
||||
import org.jetbrains.anko.find
|
||||
|
||||
class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract {
|
||||
private var messageList: MessagesList? = null
|
||||
private var messageInput: MessageInput? = null
|
||||
private var chatNameTextView: TextView? = null
|
||||
private var chatAvatar: ImageView? = null
|
||||
private var userStatus: TextView? = null
|
||||
private var presenter: ChatPresenter? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -59,7 +61,8 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract {
|
||||
supportActionBar!!.setHomeButtonEnabled(true)
|
||||
messageList = findViewById(R.id.messages_list)
|
||||
messageList!!.layoutManager = LinearLayoutManager(this)
|
||||
chatNameTextView = findViewById(R.id.appbar_username)
|
||||
chatNameTextView = find(R.id.appbar_username)
|
||||
userStatus = find(R.id.user_status_text)
|
||||
chatAvatar = findViewById(R.id.profile_image_chat_activity)
|
||||
messageInput = findViewById(R.id.message_input)
|
||||
messageInput!!.setInputListener {
|
||||
@ -107,4 +110,8 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract {
|
||||
.buildRound(firstLetter, ColorGenerator.MATERIAL.getColor(firstLetter)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUserStatus(status: String) {
|
||||
userStatus!!.text = status
|
||||
}
|
||||
}
|
||||
|
@ -39,15 +39,27 @@
|
||||
android:layout_height="40dp"
|
||||
android:id="@+id/profile_image_chat_activity"/>
|
||||
|
||||
<TextView
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/appbar_username"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginLeft="25dp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginStart="25dp" />
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/appbar_username"
|
||||
android:textSize="18sp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textStyle="bold"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/user_status_text"
|
||||
android:textSize="18sp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:text="@string/offline"/>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
|
@ -24,4 +24,6 @@
|
||||
<string name="logout">Выйти из аккаунта</string>
|
||||
<string name="sign_in_button">Войти</string>
|
||||
<string name="invalid_jid_error">Неверный JabberID!</string>
|
||||
<string name="offline">Не в сети</string>
|
||||
<string name="online">В сети</string>
|
||||
</resources>
|
@ -23,4 +23,6 @@
|
||||
<string name="logout">Log out from account</string>
|
||||
<string name="sign_in_button">Sign In</string>
|
||||
<string name="invalid_jid_error">Invalid JabberID!</string>
|
||||
<string name="offline">Offline</string>
|
||||
<string name="online">Online</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user