Added picture loading and adding user to userlist in chat entity

This commit is contained in:
ChronosX88 2019-05-26 18:00:27 +04:00
parent 6936c0127e
commit 5400aeea88
13 changed files with 111 additions and 47 deletions

View File

@ -84,6 +84,8 @@ dependencies {
implementation 'net.sourceforge.streamsupport:android-retrofuture:1.7.0'
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'org.igniterealtime.smack:smack-experimental:4.3.3'
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
}
repositories {
mavenCentral()

View File

@ -16,9 +16,11 @@
package io.github.chronosx88.influence.contracts
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.view.MenuItem
import androidx.fragment.app.Fragment
import com.stfalcon.chatkit.dialogs.DialogsListAdapter
import com.stfalcon.chatkit.messages.MessagesListAdapter
import io.github.chronosx88.influence.models.GenericDialog
@ -49,10 +51,11 @@ interface CoreContracts {
fun loadRemoteContactList()
}
interface IChatListViewContract {
interface IDialogListViewContract {
fun setDialogAdapter(adapter: DialogsListAdapter<GenericDialog>)
fun startActivity(intent: Intent)
fun getActivityContext(): Context?
fun getFragmentObject(): Fragment
}
// -----MainActivity-----
@ -99,6 +102,7 @@ interface CoreContracts {
interface IChatViewContract {
fun setAdapter(adapter: MessagesListAdapter<GenericMessage>)
fun setUserStatus(status: String)
fun getActivityObject(): Activity
}
// -----SettingsFragment-----

View File

@ -16,58 +16,85 @@
package io.github.chronosx88.influence.helpers;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.amulyakhare.textdrawable.TextDrawable;
import com.amulyakhare.textdrawable.util.ColorGenerator;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.stfalcon.chatkit.commons.ImageLoader;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import io.github.chronosx88.influence.R;
import java9.util.concurrent.CompletableFuture;
public class AvatarImageLoader implements ImageLoader {
private Fragment fragment = null;
private Activity activity = null;
public AvatarImageLoader(Fragment fragment) {
this.fragment = fragment;
}
public AvatarImageLoader(Activity activity) {
this.activity = activity;
}
@Override
public void loadImage(ImageView imageView, @Nullable String url, @Nullable Object payload) {
if(url.length() != 0) {
if(AppHelper.avatarsCache.containsKey(url)) {
byte[] avatarBytes = AppHelper.avatarsCache.get(url);
Bitmap avatar = BitmapFactory.decodeByteArray(avatarBytes, 0, avatarBytes.length);
imageView.setImageBitmap(avatar);
return;
}
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.contains("http")) {
if(AppHelper.avatarsCache.containsKey(url)) {
byte[] avatarBytes = AppHelper.avatarsCache.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);
AppHelper.avatarsCache.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);
AppHelper.avatarsCache.put(url, avatarBytes);
}
});
});
});
} else {
RequestOptions requestOptions = new RequestOptions()
.placeholder(R.drawable.no_image_picture)
.error(R.drawable.no_image_picture);
if(fragment != null) {
Glide.with(fragment).setDefaultRequestOptions(requestOptions).load(url).into(imageView);
} else if(activity != null) {
Glide.with(activity).setDefaultRequestOptions(requestOptions).load(url).into(imageView);
}
}
}
}
}

View File

@ -21,6 +21,7 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import io.github.chronosx88.influence.models.GenericUser;
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
@ -28,8 +29,8 @@ public class LocalDBWrapper {
private static final String LOG_TAG = "LocalDBWrapper";
private static RoomHelper dbInstance = AppHelper.getChatDB();
public static void createChatEntry(String jid, String chatName) {
dbInstance.chatDao().addChat(new ChatEntity(jid, chatName, new ArrayList<>(), 0, ""));
public static void createChatEntry(String jid, String chatName, ArrayList<GenericUser> users) {
dbInstance.chatDao().addChat(new ChatEntity(jid, chatName, users, 0, ""));
}
public static long createMessageEntry(String chatID, String messageUid, String senderJid, long timestamp, String text, boolean isSent, boolean isRead) {

View File

@ -45,11 +45,13 @@ import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import io.github.chronosx88.influence.R;
import io.github.chronosx88.influence.models.GenericMessage;
import io.github.chronosx88.influence.models.GenericUser;
import io.github.chronosx88.influence.models.appEvents.LastMessageEvent;
import io.github.chronosx88.influence.models.appEvents.NewMessageEvent;
import io.github.chronosx88.influence.models.appEvents.UserPresenceChangedEvent;
@ -69,7 +71,10 @@ public class NetworkHandler implements IncomingChatMessageListener, PresenceEven
public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
String chatID = chat.getXmppAddressOfChatPartner().asUnescapedString();
if(LocalDBWrapper.getChatByChatID(from.asEntityBareJidString()) == null) {
LocalDBWrapper.createChatEntry(chatID, chat.getXmppAddressOfChatPartner().asBareJid().asUnescapedString().split("@")[0]);
ArrayList<GenericUser> users = new ArrayList<>();
users.add(new GenericUser(AppHelper.getJid(), AppHelper.getJid().split("@")[0], AppHelper.getJid()));
users.add(new GenericUser(chat.getXmppAddressOfChatPartner().asBareJid().asUnescapedString(), chat.getXmppAddressOfChatPartner().asBareJid().asUnescapedString().split("@")[0], chat.getXmppAddressOfChatPartner().asBareJid().asUnescapedString()));
LocalDBWrapper.createChatEntry(chatID, chat.getXmppAddressOfChatPartner().asBareJid().asUnescapedString().split("@")[0], users);
}
long messageID = LocalDBWrapper.createMessageEntry(chatID, message.getStanzaId(), from.asUnescapedString(), TrueTime.now().getTime(), message.getBody(), true, false);
int newUnreadMessagesCount = LocalDBWrapper.getChatByChatID(chatID).unreadMessagesCount + 1;

View File

@ -30,7 +30,7 @@ public class RoomTypeConverter {
@TypeConverter
public static ArrayList<GenericUser> fromString(String value) {
Type listType = new TypeToken<ArrayList<String>>() {}.getType();
Type listType = new TypeToken<ArrayList<GenericUser>>() {}.getType();
return new Gson().fromJson(value, listType);
}

View File

@ -16,26 +16,31 @@
package io.github.chronosx88.influence.models;
import androidx.annotation.Nullable;
import com.stfalcon.chatkit.commons.models.IMessage;
import com.stfalcon.chatkit.commons.models.IUser;
import com.stfalcon.chatkit.commons.models.MessageContentType;
import java.util.Date;
import io.github.chronosx88.influence.models.roomEntities.MessageEntity;
public class GenericMessage implements IMessage {
public class GenericMessage implements IMessage, MessageContentType.Image {
private long messageID;
private String messageUid;
private IUser author;
private long timestamp;
private String text;
private String imageUrl;
public GenericMessage(MessageEntity messageEntity) {
this.messageID = messageEntity.messageID;
this.messageUid = messageEntity.messageUid;
this.author = new GenericUser(messageEntity.senderJid, messageEntity.senderJid, messageEntity.senderJid);
this.timestamp = messageEntity.timestamp;
this.text = messageEntity.text;
if(messageEntity.text.contains("http") && messageEntity.text.contains(".jpg")) {
imageUrl = messageEntity.text;
}
}
@Override
@ -58,7 +63,9 @@ public class GenericMessage implements IMessage {
return new Date(timestamp);
}
public String getMessageUid() {
return messageUid;
@Nullable
@Override
public String getImageUrl() {
return imageUrl;
}
}

View File

@ -55,7 +55,7 @@ class ChatPresenter(private val view: CoreContracts.IChatViewContract, private v
gson = Gson()
val holdersConfig = MessageHolders()
holdersConfig.setIncomingTextLayout(R.layout.item_incoming_text_message_custom)
chatAdapter = MessagesListAdapter(AppHelper.getJid(), holdersConfig, AvatarImageLoader())
chatAdapter = MessagesListAdapter(AppHelper.getJid(), holdersConfig, AvatarImageLoader(view.getActivityObject()))
chatAdapter.setLoadMoreListener { page, _ -> loadMoreMessages() }
view.setAdapter(chatAdapter)
getUserStatus()

View File

@ -38,6 +38,7 @@ 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.GenericUser;
import io.github.chronosx88.influence.models.appEvents.AuthenticationStatusEvent;
import io.github.chronosx88.influence.models.appEvents.LastMessageEvent;
import io.github.chronosx88.influence.models.appEvents.NewChatEvent;
@ -48,10 +49,9 @@ import java8.util.stream.StreamSupport;
import java9.util.concurrent.CompletableFuture;
public class DialogListPresenter implements CoreContracts.IDialogListPresenterContract {
private ConcurrentHashMap<String, byte[]> avatarsMap = new ConcurrentHashMap<>();
private CoreContracts.IChatListViewContract view;
private CoreContracts.IDialogListViewContract view;
private CoreContracts.IDialogListLogicContract logic;
private DialogsListAdapter<GenericDialog> dialogListAdapter = new DialogsListAdapter<>(R.layout.item_dialog_custom, new AvatarImageLoader());
private DialogsListAdapter<GenericDialog> dialogListAdapter;
private Comparator<GenericDialog> dialogComparator = (dialog1, dialog2) -> {
if(dialog2.getLastMessage() != null && dialog1.getLastMessage() != null) {
return Long.compare(dialog2.getLastMessage().getCreatedAt().getTime(), dialog1.getLastMessage().getCreatedAt().getTime());
@ -64,8 +64,9 @@ public class DialogListPresenter implements CoreContracts.IDialogListPresenterCo
return 0;
};
public DialogListPresenter(CoreContracts.IChatListViewContract view) {
public DialogListPresenter(CoreContracts.IDialogListViewContract view) {
this.view = view;
dialogListAdapter = new DialogsListAdapter<>(R.layout.item_dialog_custom, new AvatarImageLoader(view.getFragmentObject()));
dialogListAdapter.setOnDialogClickListener(dialog -> openChat(dialog.getId()));
dialogListAdapter.setOnDialogLongClickListener(dialog -> {
AlertDialog.Builder builder = new AlertDialog.Builder(view.getActivityContext());
@ -147,7 +148,10 @@ public class DialogListPresenter implements CoreContracts.IDialogListPresenterCo
if(contacts != null) {
StreamSupport.stream(contacts).forEach(contact -> {
String chatID = contact.getJid().asUnescapedString();
LocalDBWrapper.createChatEntry(chatID, contact.getName() == null ? contact.getJid().asUnescapedString().split("@")[0] : contact.getName());
ArrayList<GenericUser> users = new ArrayList<>();
users.add(new GenericUser(AppHelper.getJid(), AppHelper.getJid().split("@")[0], AppHelper.getJid()));
users.add(new GenericUser(chatID, contact.getName() == null ? contact.getJid().asUnescapedString().split("@")[0] : contact.getName(), chatID));
LocalDBWrapper.createChatEntry(chatID, contact.getName() == null ? contact.getJid().asUnescapedString().split("@")[0] : contact.getName(), users);
GenericDialog dialog = new GenericDialog(LocalDBWrapper.getChatByChatID(chatID));
MessageEntity messageEntity = LocalDBWrapper.getLastMessage(chatID);
if(messageEntity != null) {

View File

@ -23,6 +23,7 @@ import io.github.chronosx88.influence.contracts.CoreContracts
import io.github.chronosx88.influence.helpers.AppHelper
import io.github.chronosx88.influence.helpers.LocalDBWrapper
import io.github.chronosx88.influence.logic.MainLogic
import io.github.chronosx88.influence.models.GenericUser
import io.github.chronosx88.influence.models.appEvents.AuthenticationStatusEvent
import io.github.chronosx88.influence.models.appEvents.NewChatEvent
import io.github.chronosx88.influence.views.LoginActivity
@ -47,7 +48,10 @@ class MainPresenter(private val view: CoreContracts.IMainViewContract) : CoreCon
view.showSnackbar(AppHelper.getContext().getString(R.string.invalid_jid_error))
return
}
LocalDBWrapper.createChatEntry(username, username.split("@")[0])
val users = ArrayList<GenericUser>()
users.add(GenericUser(AppHelper.getJid(), AppHelper.getJid().split("@")[0], AppHelper.getJid()))
users.add(GenericUser(username, username.split("@")[0], AppHelper.getJid()))
LocalDBWrapper.createChatEntry(username, username.split("@")[0], users)
EventBus.getDefault().post(NewChatEvent(username))
}

View File

@ -16,6 +16,7 @@
package io.github.chronosx88.influence.views
import android.app.Activity
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Bundle
@ -122,4 +123,8 @@ class ChatActivity : AppCompatActivity(), CoreContracts.IChatViewContract {
super.onResume()
presenter!!.loadRecentPageMessages()
}
override fun getActivityObject(): Activity {
return this
}
}

View File

@ -16,6 +16,7 @@
package io.github.chronosx88.influence.views.fragments
import android.app.Activity
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
@ -30,7 +31,7 @@ import io.github.chronosx88.influence.models.GenericDialog
import io.github.chronosx88.influence.presenters.DialogListPresenter
class DialogListFragment : Fragment(), CoreContracts.IChatListViewContract {
class DialogListFragment : Fragment(), CoreContracts.IDialogListViewContract {
private lateinit var presenter: CoreContracts.IDialogListPresenterContract
private lateinit var dialogList: DialogsList
@ -62,4 +63,8 @@ class DialogListFragment : Fragment(), CoreContracts.IChatListViewContract {
presenter.onStop()
super.onStop()
}
override fun getFragmentObject(): Fragment {
return this
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B