Commit 4438355c authored by Tiago Cunha's avatar Tiago Cunha

That adapter...

parent 27d2d71b
...@@ -2,6 +2,8 @@ package chat.rocket.android.fragment.chatroom; ...@@ -2,6 +2,8 @@ package chat.rocket.android.fragment.chatroom;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import java.util.List;
import chat.rocket.core.models.Message;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
public interface RoomContract { public interface RoomContract {
...@@ -13,6 +15,10 @@ public interface RoomContract { ...@@ -13,6 +15,10 @@ public interface RoomContract {
void updateHistoryState(boolean hasNext, boolean isLoaded); void updateHistoryState(boolean hasNext, boolean isLoaded);
void onMessageSendSuccessfully(); void onMessageSendSuccessfully();
void showUnreadCount(int count);
void showMessages(List<Message> messages);
} }
interface Presenter { interface Presenter {
...@@ -29,5 +35,9 @@ public interface RoomContract { ...@@ -29,5 +35,9 @@ public interface RoomContract {
void resendMessage(String messageId); void resendMessage(String messageId);
void deleteMessage(String messageId); void deleteMessage(String messageId);
void onUnreadCount();
void onMarkAsRead();
} }
} }
...@@ -20,7 +20,6 @@ import android.support.v7.widget.LinearLayoutManager; ...@@ -20,7 +20,6 @@ import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
import com.jakewharton.rxbinding.support.v4.widget.RxDrawerLayout; import com.jakewharton.rxbinding.support.v4.widget.RxDrawerLayout;
import io.realm.Sort;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -31,7 +30,6 @@ import chat.rocket.android.fragment.chatroom.dialog.FileUploadProgressDialogFrag ...@@ -31,7 +30,6 @@ import chat.rocket.android.fragment.chatroom.dialog.FileUploadProgressDialogFrag
import chat.rocket.android.fragment.chatroom.dialog.UsersOfRoomDialogFragment; import chat.rocket.android.fragment.chatroom.dialog.UsersOfRoomDialogFragment;
import chat.rocket.android.helper.FileUploadHelper; import chat.rocket.android.helper.FileUploadHelper;
import chat.rocket.android.helper.LoadMoreScrollListener; import chat.rocket.android.helper.LoadMoreScrollListener;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.helper.OnBackPressListener; import chat.rocket.android.helper.OnBackPressListener;
import chat.rocket.android.helper.RecyclerViewAutoScrollManager; import chat.rocket.android.helper.RecyclerViewAutoScrollManager;
import chat.rocket.android.helper.RecyclerViewScrolledToBottomListener; import chat.rocket.android.helper.RecyclerViewScrolledToBottomListener;
...@@ -48,8 +46,8 @@ import chat.rocket.android.layouthelper.extra_action.upload.ImageUploadActionIte ...@@ -48,8 +46,8 @@ import chat.rocket.android.layouthelper.extra_action.upload.ImageUploadActionIte
import chat.rocket.android.layouthelper.extra_action.upload.VideoUploadActionItem; import chat.rocket.android.layouthelper.extra_action.upload.VideoUploadActionItem;
import chat.rocket.android.log.RCLog; import chat.rocket.android.log.RCLog;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
import chat.rocket.core.models.Message;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.persistence.realm.models.ddp.RealmMessage;
import chat.rocket.persistence.realm.models.ddp.RealmRoom; import chat.rocket.persistence.realm.models.ddp.RealmRoom;
import chat.rocket.persistence.realm.models.ddp.RealmUser; import chat.rocket.persistence.realm.models.ddp.RealmUser;
import chat.rocket.persistence.realm.models.internal.Session; import chat.rocket.persistence.realm.models.internal.Session;
...@@ -57,7 +55,7 @@ import chat.rocket.persistence.realm.repositories.RealmMessageRepository; ...@@ -57,7 +55,7 @@ import chat.rocket.persistence.realm.repositories.RealmMessageRepository;
import chat.rocket.persistence.realm.repositories.RealmRoomRepository; import chat.rocket.persistence.realm.repositories.RealmRoomRepository;
import chat.rocket.persistence.realm.repositories.RealmUserRepository; import chat.rocket.persistence.realm.repositories.RealmUserRepository;
import chat.rocket.persistence.realm.RealmHelper; import chat.rocket.persistence.realm.RealmHelper;
import chat.rocket.persistence.realm.RealmModelListAdapter; import chat.rocket.android.layouthelper.chatroom.ModelListAdapter;
import chat.rocket.persistence.realm.RealmStore; import chat.rocket.persistence.realm.RealmStore;
import chat.rocket.android.service.ConnectivityManager; import chat.rocket.android.service.ConnectivityManager;
import chat.rocket.android.widget.internal.ExtraActionPickerDialogFragment; import chat.rocket.android.widget.internal.ExtraActionPickerDialogFragment;
...@@ -71,7 +69,7 @@ import permissions.dispatcher.RuntimePermissions; ...@@ -71,7 +69,7 @@ import permissions.dispatcher.RuntimePermissions;
@RuntimePermissions @RuntimePermissions
public class RoomFragment extends AbstractChatRoomFragment public class RoomFragment extends AbstractChatRoomFragment
implements OnBackPressListener, ExtraActionPickerDialogFragment.Callback, implements OnBackPressListener, ExtraActionPickerDialogFragment.Callback,
RealmModelListAdapter.OnItemClickListener<PairedMessage>, RoomContract.View { ModelListAdapter.OnItemClickListener<PairedMessage>, RoomContract.View {
private static final int DIALOG_ID = 1; private static final int DIALOG_ID = 1;
private static final String HOSTNAME = "hostname"; private static final String HOSTNAME = "hostname";
...@@ -88,6 +86,7 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -88,6 +86,7 @@ public class RoomFragment extends AbstractChatRoomFragment
private AbstractNewMessageIndicatorManager newMessageIndicatorManager; private AbstractNewMessageIndicatorManager newMessageIndicatorManager;
private Snackbar unreadIndicator; private Snackbar unreadIndicator;
private boolean previousUnreadMessageExists; private boolean previousUnreadMessageExists;
private MessageListAdapter adapter;
private List<AbstractExtraActionItem> extraActionItems; private List<AbstractExtraActionItem> extraActionItems;
...@@ -131,6 +130,7 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -131,6 +130,7 @@ public class RoomFragment extends AbstractChatRoomFragment
new RealmUserRepository(hostname), new RealmUserRepository(hostname),
new RealmRoomRepository(hostname), new RealmRoomRepository(hostname),
new RealmMessageRepository(hostname), new RealmMessageRepository(hostname),
new MethodCallHelper(getContext(), hostname),
ConnectivityManager.getInstance(getContext().getApplicationContext()) ConnectivityManager.getInstance(getContext().getApplicationContext())
); );
...@@ -155,12 +155,7 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -155,12 +155,7 @@ public class RoomFragment extends AbstractChatRoomFragment
@Override @Override
protected void onSetupView() { protected void onSetupView() {
RecyclerView listView = (RecyclerView) rootView.findViewById(R.id.recyclerview); RecyclerView listView = (RecyclerView) rootView.findViewById(R.id.recyclerview);
MessageListAdapter adapter = (MessageListAdapter) realmHelper.createListAdapter(getContext(), adapter = new MessageListAdapter(getContext(), hostname, userId, token);
realm -> realm.where(RealmMessage.class)
.equalTo(RealmMessage.ROOM_ID, roomId)
.findAllSorted(RealmMessage.TIMESTAMP, Sort.DESCENDING),
context -> new MessageListAdapter(context, hostname, userId, token)
);
listView.setAdapter(adapter); listView.setAdapter(adapter);
adapter.setOnItemClickListener(this); adapter.setOnItemClickListener(this);
...@@ -171,7 +166,7 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -171,7 +166,7 @@ public class RoomFragment extends AbstractChatRoomFragment
@Override @Override
protected void onAutoScrollMissed() { protected void onAutoScrollMissed() {
if (newMessageIndicatorManager != null) { if (newMessageIndicatorManager != null) {
newMessageIndicatorManager.updateNewMessageCount(getUnreadMessageCount()); presenter.onUnreadCount();
} }
} }
}; };
...@@ -233,21 +228,6 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -233,21 +228,6 @@ public class RoomFragment extends AbstractChatRoomFragment
.setAction(R.string.dialog_view_latest_message_action, view -> scrollToLatestMessage()); .setAction(R.string.dialog_view_latest_message_action, view -> scrollToLatestMessage());
} }
private int getUnreadMessageCount() {
RealmRoom room = realmHelper.executeTransactionForRead(realm ->
realm.where(RealmRoom.class).equalTo(RealmRoom.ROOM_ID, roomId).findFirst());
if (room != null) {
return realmHelper.executeTransactionForReadResults(realm ->
realm.where(RealmMessage.class)
.equalTo(RealmMessage.ROOM_ID, roomId)
.greaterThanOrEqualTo(RealmMessage.TIMESTAMP, room.getLastSeen())
.notEqualTo(RealmMessage.USER_ID, userId)
.findAll()).size();
} else {
return 0;
}
}
@Override @Override
public void onDestroyView() { public void onDestroyView() {
RecyclerView listView = (RecyclerView) rootView.findViewById(R.id.recyclerview); RecyclerView listView = (RecyclerView) rootView.findViewById(R.id.recyclerview);
...@@ -277,7 +257,7 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -277,7 +257,7 @@ public class RoomFragment extends AbstractChatRoomFragment
View sideMenu = rootView.findViewById(R.id.room_side_menu); View sideMenu = rootView.findViewById(R.id.room_side_menu);
sideMenu.findViewById(R.id.btn_users).setOnClickListener(view -> { sideMenu.findViewById(R.id.btn_users).setOnClickListener(view -> {
UsersOfRoomDialogFragment.create(roomId, hostname) UsersOfRoomDialogFragment.create(roomId, hostname)
.show(getFragmentManager(), UsersOfRoomDialogFragment.class.getSimpleName()); .show(getFragmentManager(), "UsersOfRoomDialogFragment");
closeSideMenuIfNeeded(); closeSideMenuIfNeeded();
}); });
...@@ -370,12 +350,7 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -370,12 +350,7 @@ public class RoomFragment extends AbstractChatRoomFragment
} }
private void markAsReadIfNeeded() { private void markAsReadIfNeeded() {
RealmRoom room = realmHelper.executeTransactionForRead(realm -> presenter.onMarkAsRead();
realm.where(RealmRoom.class).equalTo(RealmRoom.ROOM_ID, roomId).findFirst());
if (room != null && room.isAlert()) {
new MethodCallHelper(getContext(), hostname).readMessages(roomId)
.continueWith(new LogcatIfError());
}
} }
@Override @Override
...@@ -492,4 +467,14 @@ public class RoomFragment extends AbstractChatRoomFragment ...@@ -492,4 +467,14 @@ public class RoomFragment extends AbstractChatRoomFragment
scrollToLatestMessage(); scrollToLatestMessage();
messageFormManager.onMessageSend(); messageFormManager.onMessageSend();
} }
@Override
public void showUnreadCount(int count) {
newMessageIndicatorManager.updateNewMessageCount(count);
}
@Override
public void showMessages(List<Message> messages) {
adapter.updateData(messages);
}
} }
package chat.rocket.android.fragment.chatroom; package chat.rocket.android.fragment.chatroom;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.util.Pair;
import java.util.UUID; import java.util.UUID;
import chat.rocket.android.BackgroundLooper; import chat.rocket.android.BackgroundLooper;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
import chat.rocket.core.models.Message; import chat.rocket.core.models.Message;
import chat.rocket.core.models.RoomHistoryState; import chat.rocket.core.models.RoomHistoryState;
...@@ -11,6 +14,7 @@ import chat.rocket.core.repositories.MessageRepository; ...@@ -11,6 +14,7 @@ import chat.rocket.core.repositories.MessageRepository;
import chat.rocket.core.repositories.RoomRepository; import chat.rocket.core.repositories.RoomRepository;
import chat.rocket.core.repositories.UserRepository; import chat.rocket.core.repositories.UserRepository;
import chat.rocket.android.service.ConnectivityManagerApi; import chat.rocket.android.service.ConnectivityManagerApi;
import rx.Single;
import rx.Subscription; import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.subscriptions.CompositeSubscription; import rx.subscriptions.CompositeSubscription;
...@@ -21,6 +25,7 @@ public class RoomPresenter implements RoomContract.Presenter { ...@@ -21,6 +25,7 @@ public class RoomPresenter implements RoomContract.Presenter {
private final UserRepository userRepository; private final UserRepository userRepository;
private final RoomRepository roomRepository; private final RoomRepository roomRepository;
private final MessageRepository messageRepository; private final MessageRepository messageRepository;
private final MethodCallHelper methodCallHelper;
private final ConnectivityManagerApi connectivityManagerApi; private final ConnectivityManagerApi connectivityManagerApi;
private CompositeSubscription compositeSubscription = new CompositeSubscription(); private CompositeSubscription compositeSubscription = new CompositeSubscription();
...@@ -29,11 +34,13 @@ public class RoomPresenter implements RoomContract.Presenter { ...@@ -29,11 +34,13 @@ public class RoomPresenter implements RoomContract.Presenter {
public RoomPresenter(String roomId, UserRepository userRepository, public RoomPresenter(String roomId, UserRepository userRepository,
RoomRepository roomRepository, RoomRepository roomRepository,
MessageRepository messageRepository, MessageRepository messageRepository,
MethodCallHelper methodCallHelper,
ConnectivityManagerApi connectivityManagerApi) { ConnectivityManagerApi connectivityManagerApi) {
this.roomId = roomId; this.roomId = roomId;
this.userRepository = userRepository; this.userRepository = userRepository;
this.roomRepository = roomRepository; this.roomRepository = roomRepository;
this.messageRepository = messageRepository; this.messageRepository = messageRepository;
this.methodCallHelper = methodCallHelper;
this.connectivityManagerApi = connectivityManagerApi; this.connectivityManagerApi = connectivityManagerApi;
} }
...@@ -43,6 +50,7 @@ public class RoomPresenter implements RoomContract.Presenter { ...@@ -43,6 +50,7 @@ public class RoomPresenter implements RoomContract.Presenter {
getRoomInfo(); getRoomInfo();
getRoomHistoryStateInfo(); getRoomHistoryStateInfo();
getMessages();
} }
@Override @Override
...@@ -151,6 +159,44 @@ public class RoomPresenter implements RoomContract.Presenter { ...@@ -151,6 +159,44 @@ public class RoomPresenter implements RoomContract.Presenter {
compositeSubscription.add(subscription); compositeSubscription.add(subscription);
} }
@Override
public void onUnreadCount() {
final Subscription subscription = Single.zip(
userRepository.getCurrentUser()
.filter(user -> user != null)
.first()
.toSingle(),
roomRepository.getById(roomId)
.first()
.toSingle(),
(user, room) -> new Pair<>(room, user)
)
.flatMap(roomUserPair -> messageRepository
.unreadCountFor(roomUserPair.first, roomUserPair.second))
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
count -> view.showUnreadCount(count)
);
compositeSubscription.add(subscription);
}
@Override
public void onMarkAsRead() {
final Subscription subscription = roomRepository.getById(roomId)
.first()
.filter(room -> room != null && room.isAlert())
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
room -> methodCallHelper.readMessages(room.getRoomId())
.continueWith(new LogcatIfError())
);
compositeSubscription.add(subscription);
}
private void getRoomInfo() { private void getRoomInfo() {
final Subscription subscription = roomRepository.getById(roomId) final Subscription subscription = roomRepository.getById(roomId)
.distinctUntilChanged() .distinctUntilChanged()
...@@ -180,4 +226,15 @@ public class RoomPresenter implements RoomContract.Presenter { ...@@ -180,4 +226,15 @@ public class RoomPresenter implements RoomContract.Presenter {
compositeSubscription.add(subscription); compositeSubscription.add(subscription);
} }
private void getMessages() {
final Subscription subscription = roomRepository.getById(roomId)
.first()
.flatMap(messageRepository::getAllFrom)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(messages -> view.showMessages(messages));
compositeSubscription.add(subscription);
}
} }
...@@ -3,21 +3,20 @@ package chat.rocket.android.layouthelper; ...@@ -3,21 +3,20 @@ package chat.rocket.android.layouthelper;
import android.content.Context; import android.content.Context;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import android.support.v7.util.ListUpdateCallback; import android.support.v7.util.ListUpdateCallback;
import io.realm.RealmObject;
import chat.rocket.persistence.realm.RealmModelListAdapter; import chat.rocket.android.layouthelper.chatroom.ModelListAdapter;
import chat.rocket.persistence.realm.RealmModelViewHolder; import chat.rocket.android.layouthelper.chatroom.ModelViewHolder;
@SuppressWarnings({"PMD.AbstractNaming", "PMD.GenericsNaming"}) @SuppressWarnings({"PMD.AbstractNaming", "PMD.GenericsNaming"})
/** /**
* RealmModelListAdapter with header and footer. * ModelListAdapter with header and footer.
*/ */
public abstract class ExtRealmModelListAdapter<T extends RealmObject, VM, public abstract class ExtModelListAdapter<T, VM,
VH extends RealmModelViewHolder<VM>> extends RealmModelListAdapter<T, VM, VH> { VH extends ModelViewHolder<VM>> extends ModelListAdapter<T, VM, VH> {
protected static final int VIEW_TYPE_HEADER = -1; protected static final int VIEW_TYPE_HEADER = -1;
protected static final int VIEW_TYPE_FOOTER = -2; protected static final int VIEW_TYPE_FOOTER = -2;
protected ExtRealmModelListAdapter(Context context) { protected ExtModelListAdapter(Context context) {
super(context); super(context);
} }
......
...@@ -8,10 +8,9 @@ import chat.rocket.android.R; ...@@ -8,10 +8,9 @@ import chat.rocket.android.R;
import chat.rocket.android.helper.DateTime; import chat.rocket.android.helper.DateTime;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
import chat.rocket.persistence.realm.RealmModelViewHolder;
import chat.rocket.android.widget.RocketChatAvatar; import chat.rocket.android.widget.RocketChatAvatar;
public abstract class AbstractMessageViewHolder extends RealmModelViewHolder<PairedMessage> { public abstract class AbstractMessageViewHolder extends ModelViewHolder<PairedMessage> {
protected final RocketChatAvatar avatar; protected final RocketChatAvatar avatar;
protected final TextView username; protected final TextView username;
protected final TextView subUsername; protected final TextView subUsername;
......
...@@ -9,14 +9,14 @@ import java.util.Collections; ...@@ -9,14 +9,14 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.layouthelper.ExtRealmModelListAdapter; import chat.rocket.android.layouthelper.ExtModelListAdapter;
import chat.rocket.persistence.realm.models.ddp.RealmMessage; import chat.rocket.core.models.Message;
/** /**
* target list adapter for chat room. * target list adapter for chat room.
*/ */
public class MessageListAdapter public class MessageListAdapter
extends ExtRealmModelListAdapter<RealmMessage, PairedMessage, AbstractMessageViewHolder> { extends ExtModelListAdapter<Message, PairedMessage, AbstractMessageViewHolder> {
private static final int VIEW_TYPE_UNKNOWN = 0; private static final int VIEW_TYPE_UNKNOWN = 0;
private static final int VIEW_TYPE_NORMAL_MESSAGE = 1; private static final int VIEW_TYPE_NORMAL_MESSAGE = 1;
...@@ -99,7 +99,7 @@ public class MessageListAdapter ...@@ -99,7 +99,7 @@ public class MessageListAdapter
} }
@Override @Override
protected List<PairedMessage> mapResultsToViewModel(List<RealmMessage> results) { protected List<PairedMessage> mapResultsToViewModel(List<Message> results) {
if (results.isEmpty()) { if (results.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
......
...@@ -3,7 +3,7 @@ package chat.rocket.android.layouthelper.chatroom; ...@@ -3,7 +3,7 @@ package chat.rocket.android.layouthelper.chatroom;
import android.content.Context; import android.content.Context;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.persistence.realm.models.ddp.RealmMessage; import chat.rocket.core.models.Message;
/** /**
* message type. * message type.
...@@ -11,46 +11,46 @@ import chat.rocket.persistence.realm.models.ddp.RealmMessage; ...@@ -11,46 +11,46 @@ import chat.rocket.persistence.realm.models.ddp.RealmMessage;
public enum MessageType { public enum MessageType {
ROOM_NAME_CHANGED("r") { ROOM_NAME_CHANGED("r") {
@Override @Override
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return context.getString(R.string.message_room_name_changed, return context.getString(R.string.message_room_name_changed,
message.getMessage(), getUsername(message)); message.getMessage(), getUsername(message));
} }
}, },
USER_ADDED("au") { USER_ADDED("au") {
@Override @Override
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return context.getString(R.string.message_user_added_by, return context.getString(R.string.message_user_added_by,
message.getMessage(), getUsername(message)); message.getMessage(), getUsername(message));
} }
}, },
USER_REMOVED("ru") { USER_REMOVED("ru") {
@Override @Override
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return context.getString(R.string.message_user_removed_by, return context.getString(R.string.message_user_removed_by,
message.getMessage(), getUsername(message)); message.getMessage(), getUsername(message));
} }
}, },
USER_JOINED("uj") { USER_JOINED("uj") {
@Override @Override
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return context.getString(R.string.message_user_joined_channel); return context.getString(R.string.message_user_joined_channel);
} }
}, },
USER_LEFT("ul") { USER_LEFT("ul") {
@Override @Override
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return context.getString(R.string.message_user_left); return context.getString(R.string.message_user_left);
} }
}, },
WELCOME("wm") { WELCOME("wm") {
@Override @Override
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return context.getString(R.string.message_welcome, getUsername(message)); return context.getString(R.string.message_welcome, getUsername(message));
} }
}, },
MESSAGE_REMOVED("rm") { MESSAGE_REMOVED("rm") {
@Override @Override
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return context.getString(R.string.message_removed); return context.getString(R.string.message_removed);
} }
}, },
...@@ -69,16 +69,18 @@ public enum MessageType { ...@@ -69,16 +69,18 @@ public enum MessageType {
public static MessageType parse(String value) { public static MessageType parse(String value) {
for (MessageType type : MessageType.values()) { for (MessageType type : MessageType.values()) {
if (type.value.equals(value)) return type; if (type.value.equals(value)) {
return type;
}
} }
return UNSPECIFIED; return UNSPECIFIED;
} }
public String getString(Context context, RealmMessage message) { public String getString(Context context, Message message) {
return ""; return "";
} }
private static String getUsername(RealmMessage message) { private static String getUsername(Message message) {
if (message != null && message.getUser() != null) { if (message != null && message.getUser() != null) {
return message.getUser().getUsername(); return message.getUser().getUsername();
} else { } else {
......
package chat.rocket.persistence.realm; package chat.rocket.android.layouthelper.chatroom;
import android.content.Context; import android.content.Context;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
...@@ -8,41 +8,20 @@ import android.support.v7.widget.RecyclerView; ...@@ -8,41 +8,20 @@ import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import io.realm.RealmObject;
import java.util.List; import java.util.List;
public abstract class RealmModelListAdapter<T extends RealmObject, VM, public abstract class ModelListAdapter<T, VM, VH extends ModelViewHolder<VM>>
VH extends RealmModelViewHolder<VM>> extends RecyclerView.Adapter<VH> { extends RecyclerView.Adapter<VH> {
protected final LayoutInflater inflater; protected final LayoutInflater inflater;
private RealmListObserver<T> realmListObserver;
private List<VM> adapterData; private List<VM> adapterData;
private OnItemClickListener<VM> onItemClickListener; private OnItemClickListener<VM> onItemClickListener;
protected RealmModelListAdapter(Context context) { protected ModelListAdapter(Context context) {
this.inflater = LayoutInflater.from(context); this.inflater = LayoutInflater.from(context);
} }
/*package*/ RealmModelListAdapter<T, VM, VH> initializeWith(final RealmHelper realmHelper,
RealmListObserver.Query<T> query) {
realmListObserver = new RealmListObserver<>(realmHelper, query)
.setOnUpdateListener(results -> updateData(realmHelper.copyFromRealm(results)));
return this;
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
realmListObserver.sub();
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
realmListObserver.unsub();
super.onDetachedFromRecyclerView(recyclerView);
}
protected abstract int getRealmModelViewType(VM model); protected abstract int getRealmModelViewType(VM model);
protected abstract protected abstract
...@@ -86,7 +65,7 @@ public abstract class RealmModelListAdapter<T extends RealmObject, VM, ...@@ -86,7 +65,7 @@ public abstract class RealmModelListAdapter<T extends RealmObject, VM,
return adapterData.get(position); return adapterData.get(position);
} }
private void updateData(List<T> newData) { public void updateData(List<T> newData) {
if (adapterData == null) { if (adapterData == null) {
adapterData = mapResultsToViewModel(newData); adapterData = mapResultsToViewModel(newData);
notifyDataSetChanged(); notifyDataSetChanged();
...@@ -133,8 +112,8 @@ public abstract class RealmModelListAdapter<T extends RealmObject, VM, ...@@ -133,8 +112,8 @@ public abstract class RealmModelListAdapter<T extends RealmObject, VM,
this.onItemClickListener = onItemClickListener; this.onItemClickListener = onItemClickListener;
} }
public interface Constructor<T extends RealmObject, VM, VH extends RealmModelViewHolder<VM>> { public interface Constructor<T, VM, VH extends ModelViewHolder<VM>> {
RealmModelListAdapter<T, VM, VH> getNewInstance(Context context); ModelListAdapter<T, VM, VH> getNewInstance(Context context);
} }
public interface OnItemClickListener<VM> { public interface OnItemClickListener<VM> {
......
package chat.rocket.persistence.realm; package chat.rocket.android.layouthelper.chatroom;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
public abstract class RealmModelViewHolder<T> extends RecyclerView.ViewHolder { public abstract class ModelViewHolder<T> extends RecyclerView.ViewHolder {
public RealmModelViewHolder(View itemView) { public ModelViewHolder(View itemView) {
super(itemView); super(itemView);
} }
......
package chat.rocket.android.layouthelper.chatroom; package chat.rocket.android.layouthelper.chatroom;
import chat.rocket.android.helper.DateTime; import chat.rocket.android.helper.DateTime;
import chat.rocket.persistence.realm.models.ddp.RealmMessage; import chat.rocket.core.models.Message;
/** /**
* ViewData Model for messages in chatroom. * ViewData Model for messages in chatroom.
*/ */
public class PairedMessage { public class PairedMessage {
public final RealmMessage target; public final Message target;
final RealmMessage nextSibling; final Message nextSibling;
public PairedMessage(RealmMessage target, RealmMessage nextSibling) { public PairedMessage(Message target, Message nextSibling) {
this.target = target; this.target = target;
this.nextSibling = nextSibling; this.nextSibling = nextSibling;
} }
......
...@@ -5,29 +5,31 @@ import android.support.graphics.drawable.VectorDrawableCompat; ...@@ -5,29 +5,31 @@ import android.support.graphics.drawable.VectorDrawableCompat;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import java.util.List;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.helper.Avatar; import chat.rocket.android.helper.Avatar;
import chat.rocket.android.helper.DateTime; import chat.rocket.android.helper.DateTime;
import chat.rocket.android.helper.TextUtils; import chat.rocket.android.helper.TextUtils;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
import chat.rocket.persistence.realm.models.ddp.RealmMessage; import chat.rocket.core.models.Attachment;
import chat.rocket.persistence.realm.models.ddp.RealmUser; import chat.rocket.core.models.Message;
import chat.rocket.android.widget.RocketChatAvatar; import chat.rocket.android.widget.RocketChatAvatar;
import chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout; import chat.rocket.android.widget.message.RocketChatMessageAttachmentsLayout;
import chat.rocket.android.widget.message.RocketChatMessageLayout; import chat.rocket.android.widget.message.RocketChatMessageLayout;
import chat.rocket.android.widget.message.RocketChatMessageUrlsLayout; import chat.rocket.android.widget.message.RocketChatMessageUrlsLayout;
import chat.rocket.core.models.User;
import chat.rocket.core.models.WebContent;
/** /**
* Renderer for RealmMessage model. * Renderer for RealmMessage model.
*/ */
public class MessageRenderer extends AbstractRenderer<RealmMessage> { public class MessageRenderer extends AbstractRenderer<Message> {
private final UserRenderer userRenderer; private final UserRenderer userRenderer;
public MessageRenderer(Context context, RealmMessage message) { public MessageRenderer(Context context, Message message) {
super(context, message); super(context, message);
RealmUser realmUser = message.getUser(); userRenderer = new UserRenderer(context, message.getUser());
userRenderer = new UserRenderer(context, realmUser == null ? null : realmUser.asUser());
} }
/** /**
...@@ -40,7 +42,7 @@ public class MessageRenderer extends AbstractRenderer<RealmMessage> { ...@@ -40,7 +42,7 @@ public class MessageRenderer extends AbstractRenderer<RealmMessage> {
} else if (TextUtils.isEmpty(object.getAvatar())) { } else if (TextUtils.isEmpty(object.getAvatar())) {
userRenderer.avatarInto(rocketChatAvatar, hostname); userRenderer.avatarInto(rocketChatAvatar, hostname);
} else { } else {
final RealmUser user = object.getUser(); final User user = object.getUser();
setAvatarInto(object.getAvatar(), hostname, user == null ? null : user.getUsername(), setAvatarInto(object.getAvatar(), hostname, user == null ? null : user.getUsername(),
rocketChatAvatar); rocketChatAvatar);
} }
...@@ -104,12 +106,12 @@ public class MessageRenderer extends AbstractRenderer<RealmMessage> { ...@@ -104,12 +106,12 @@ public class MessageRenderer extends AbstractRenderer<RealmMessage> {
return this; return this;
} }
String urls = object.getUrls(); List<WebContent> webContents = object.getWebContents();
if (TextUtils.isEmpty(urls)) { if (webContents == null || webContents.size() == 0) {
urlsLayout.setVisibility(View.GONE); urlsLayout.setVisibility(View.GONE);
} else { } else {
urlsLayout.setVisibility(View.VISIBLE); urlsLayout.setVisibility(View.VISIBLE);
urlsLayout.setUrls(urls); urlsLayout.setUrls(webContents);
} }
return this; return this;
...@@ -124,8 +126,8 @@ public class MessageRenderer extends AbstractRenderer<RealmMessage> { ...@@ -124,8 +126,8 @@ public class MessageRenderer extends AbstractRenderer<RealmMessage> {
return this; return this;
} }
String attachments = object.getAttachments(); List<Attachment> attachments = object.getAttachments();
if (TextUtils.isEmpty(attachments)) { if (attachments == null || attachments.size() == 0) {
attachmentsLayout.setVisibility(View.GONE); attachmentsLayout.setVisibility(View.GONE);
} else { } else {
attachmentsLayout.setVisibility(View.VISIBLE); attachmentsLayout.setVisibility(View.VISIBLE);
......
...@@ -3,7 +3,6 @@ package chat.rocket.persistence.realm; ...@@ -3,7 +3,6 @@ package chat.rocket.persistence.realm;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.os.Looper; import android.os.Looper;
import android.support.v7.widget.RecyclerView;
import io.realm.Realm; import io.realm.Realm;
import io.realm.RealmConfiguration; import io.realm.RealmConfiguration;
import io.realm.RealmObject; import io.realm.RealmObject;
...@@ -158,12 +157,6 @@ public class RealmHelper { ...@@ -158,12 +157,6 @@ public class RealmHelper {
return new RealmObjectObserver<T>(this, query); return new RealmObjectObserver<T>(this, query);
} }
public <T extends RealmObject, VM, VH extends RealmModelViewHolder<VM>>
RecyclerView.Adapter<VH> createListAdapter(Context context, RealmListObserver.Query<T> query,
RealmModelListAdapter.Constructor<T, VM, VH> constructor) {
return constructor.getNewInstance(context).initializeWith(this, query);
}
public <T extends RealmObject> RealmAutoCompleteAdapter<T> createAutoCompleteAdapter( public <T extends RealmObject> RealmAutoCompleteAdapter<T> createAutoCompleteAdapter(
Context context, Context context,
RealmAutoCompleteAdapter.RealmFilter<T> filter, RealmAutoCompleteAdapter.RealmFilter<T> filter,
......
...@@ -7,7 +7,9 @@ import org.json.JSONException; ...@@ -7,7 +7,9 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import chat.rocket.core.JsonConstants; import chat.rocket.core.JsonConstants;
import chat.rocket.core.SyncState; import chat.rocket.core.SyncState;
import chat.rocket.core.models.Attachment; import chat.rocket.core.models.Attachment;
...@@ -16,6 +18,9 @@ import chat.rocket.core.models.AttachmentField; ...@@ -16,6 +18,9 @@ import chat.rocket.core.models.AttachmentField;
import chat.rocket.core.models.AttachmentTitle; import chat.rocket.core.models.AttachmentTitle;
import chat.rocket.core.models.Message; import chat.rocket.core.models.Message;
import chat.rocket.core.models.WebContent; import chat.rocket.core.models.WebContent;
import chat.rocket.core.models.WebContentHeaders;
import chat.rocket.core.models.WebContentMeta;
import chat.rocket.core.models.WebContentParsedUrl;
/** /**
* RealmMessage. * RealmMessage.
...@@ -287,8 +292,80 @@ public class RealmMessage extends RealmObject { ...@@ -287,8 +292,80 @@ public class RealmMessage extends RealmObject {
private WebContent getWebContent(JSONObject jsonWebContent) { private WebContent getWebContent(JSONObject jsonWebContent) {
return WebContent.builder() return WebContent.builder()
.setUrl(jsonWebContent.optString("url")) .setUrl(jsonWebContent.optString("url"))
.setMeta(jsonWebContent.optString("meta", null)) .setMetaMap(getWebContentMetaMap(jsonWebContent.optJSONObject("meta")))
.setHeaders(jsonWebContent.optString("headers", null)) .setHeaders(getWebContentHeaders(jsonWebContent.optJSONObject("headers")))
.setParsedUrl(getWebContentParsedUrl(jsonWebContent.optJSONObject("parsedUrl")))
.build();
}
private Map<WebContentMeta.Type, WebContentMeta> getWebContentMetaMap(
JSONObject jsonWebContentMeta) {
if (jsonWebContentMeta == null) {
return null;
}
Map<WebContentMeta.Type, WebContentMeta> metaMap = new HashMap<>(3);
if (!jsonWebContentMeta.isNull("ogTitle")
|| !jsonWebContentMeta.isNull("ogDescription")
|| !jsonWebContentMeta.isNull("ogImage")) {
metaMap.put(
WebContentMeta.Type.OPEN_GRAPH,
WebContentMeta.builder()
.setType(WebContentMeta.Type.OPEN_GRAPH)
.setTitle(jsonWebContentMeta.optString("ogTitle", null))
.setDescription(jsonWebContentMeta.optString("ogDescription", null))
.setImage(jsonWebContentMeta.optString("ogImage", null))
.build()
);
}
if (!jsonWebContentMeta.isNull("twitterTitle")
|| !jsonWebContentMeta.isNull("twitterDescription")
|| !jsonWebContentMeta.isNull("twitterImage")) {
metaMap.put(
WebContentMeta.Type.TWITTER,
WebContentMeta.builder()
.setType(WebContentMeta.Type.TWITTER)
.setTitle(jsonWebContentMeta.optString("twitterTitle", null))
.setDescription(jsonWebContentMeta.optString("twitterDescription", null))
.setImage(jsonWebContentMeta.optString("twitterImage", null))
.build()
);
}
if (!jsonWebContentMeta.isNull("pageTitle")
|| !jsonWebContentMeta.isNull("description")) {
metaMap.put(
WebContentMeta.Type.OTHER,
WebContentMeta.builder()
.setType(WebContentMeta.Type.OTHER)
.setTitle(jsonWebContentMeta.optString("pageTitle", null))
.setDescription(jsonWebContentMeta.optString("description", null))
.build()
);
}
return metaMap;
}
private WebContentHeaders getWebContentHeaders(JSONObject jsonWebContentHeaders) {
if (jsonWebContentHeaders == null || jsonWebContentHeaders.isNull("contentType")) {
return null;
}
return WebContentHeaders.builder()
.setContentType(jsonWebContentHeaders.optString("contentType"))
.build();
}
private WebContentParsedUrl getWebContentParsedUrl(JSONObject jsonWebContentParsedUrl) {
if (jsonWebContentParsedUrl == null || jsonWebContentParsedUrl.isNull("host")) {
return null;
}
return WebContentParsedUrl.builder()
.setHost(jsonWebContentParsedUrl.optString("host"))
.build(); .build();
} }
......
...@@ -3,11 +3,15 @@ package chat.rocket.persistence.realm.repositories; ...@@ -3,11 +3,15 @@ package chat.rocket.persistence.realm.repositories;
import android.os.Looper; import android.os.Looper;
import io.realm.Realm; import io.realm.Realm;
import io.realm.RealmResults; import io.realm.RealmResults;
import io.realm.Sort;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import chat.rocket.core.models.Message; import chat.rocket.core.models.Message;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.User;
import chat.rocket.core.repositories.MessageRepository; import chat.rocket.core.repositories.MessageRepository;
import chat.rocket.persistence.realm.RealmStore; import chat.rocket.persistence.realm.RealmStore;
import chat.rocket.persistence.realm.models.ddp.RealmMessage; import chat.rocket.persistence.realm.models.ddp.RealmMessage;
...@@ -51,7 +55,7 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe ...@@ -51,7 +55,7 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe
&& it.isValid()) && it.isValid())
.first() .first()
.toSingle() .toSingle()
.map(it -> it.asMessage()); .map(RealmMessage::asMessage);
}); });
} }
...@@ -151,12 +155,59 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe ...@@ -151,12 +155,59 @@ public class RealmMessageRepository extends RealmRepository implements MessageRe
} }
@Override @Override
public Observable<Message> getAllFrom(Room room) { public Observable<List<Message>> getAllFrom(Room room) {
return null; return Observable.defer(() -> {
final Realm realm = RealmStore.getRealm(hostname);
final Looper looper = Looper.myLooper();
if (realm == null) {
return Observable.just(null);
}
return realm.where(RealmMessage.class)
.equalTo(RealmMessage.ROOM_ID, room.getRoomId())
.findAllSorted(RealmMessage.TIMESTAMP, Sort.DESCENDING)
.asObservable()
.unsubscribeOn(AndroidSchedulers.from(looper))
.doOnUnsubscribe(() -> close(realm, looper))
.filter(it -> it != null
&& it.isLoaded() && it.isValid())
.map(this::toList);
});
} }
@Override @Override
public Single<Integer> unreadCountFrom(Room room) { public Single<Integer> unreadCountFor(Room room, User user) {
return null; return Single.defer(() -> {
final Realm realm = RealmStore.getRealm(hostname);
final Looper looper = Looper.myLooper();
if (realm == null) {
return Single.just(0);
}
return realm.where(RealmMessage.class)
.equalTo(RealmMessage.ROOM_ID, room.getId())
.greaterThanOrEqualTo(RealmMessage.TIMESTAMP, room.getLastSeen())
.notEqualTo(RealmMessage.USER_ID, user.getId())
.findAll()
.asObservable()
.unsubscribeOn(AndroidSchedulers.from(looper))
.doOnUnsubscribe(() -> close(realm, looper))
.map(RealmResults::size)
.first()
.toSingle();
});
}
private List<Message> toList(RealmResults<RealmMessage> realmMessages) {
final int total = realmMessages.size();
final List<Message> messages = new ArrayList<>(total);
for (int i = 0; i < total; i++) {
messages.add(realmMessages.get(i).asMessage());
}
return messages;
} }
} }
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
buildscript { buildscript {
repositories { repositories {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath rootProject.ext.androidPlugin classpath rootProject.ext.androidPlugin
} }
} }
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig { defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.compileSdkVersion targetSdkVersion rootProject.ext.compileSdkVersion
versionCode 1 versionCode 1
versionName "1" versionName "1"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
} }
}
} }
dependencies { dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile rootProject.ext.supportAnnotations compile rootProject.ext.supportAnnotations
compile rootProject.ext.supportAppCompat compile rootProject.ext.supportAppCompat
compile rootProject.ext.supportV13 compile rootProject.ext.supportV13
compile rootProject.ext.supportDesign compile rootProject.ext.supportDesign
compile 'org.nibor.autolink:autolink:0.5.0'
compile rootProject.ext.textDrawable compile project(':rocket-chat-core')
compile rootProject.ext.okhttp3
compile rootProject.ext.boltsTask compile 'org.nibor.autolink:autolink:0.5.0'
compile rootProject.ext.frescoBase compile rootProject.ext.textDrawable
compile rootProject.ext.frescoAnimatedGif compile rootProject.ext.okhttp3
compile rootProject.ext.frescoAnimatedWebp compile rootProject.ext.boltsTask
compile rootProject.ext.frescoWebp
compile rootProject.ext.frescoImagePipelineOkHttp3 compile rootProject.ext.frescoBase
compile 'com.caverock:androidsvg:1.2.1' compile rootProject.ext.frescoAnimatedGif
compile rootProject.ext.frescoAnimatedWebp
compile rootProject.ext.frescoWebp
compile rootProject.ext.frescoImagePipelineOkHttp3
compile 'com.caverock:androidsvg:1.2.1'
} }
...@@ -19,18 +19,20 @@ import com.facebook.drawee.backends.pipeline.Fresco; ...@@ -19,18 +19,20 @@ import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.generic.GenericDraweeHierarchy; import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.interfaces.DraweeController; import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.drawee.view.SimpleDraweeView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import chat.rocket.android.widget.R; import chat.rocket.android.widget.R;
import chat.rocket.core.models.Attachment;
import chat.rocket.core.models.AttachmentAuthor;
import chat.rocket.core.models.AttachmentField;
import chat.rocket.core.models.AttachmentTitle;
/** /**
*/ */
public class RocketChatMessageAttachmentsLayout extends LinearLayout { public class RocketChatMessageAttachmentsLayout extends LinearLayout {
private LayoutInflater inflater; private LayoutInflater inflater;
private String hostname; private String hostname;
private String attachmentsString; private List<Attachment> attachments;
public RocketChatMessageAttachmentsLayout(Context context) { public RocketChatMessageAttachmentsLayout(Context context) {
super(context); super(context);
...@@ -63,48 +65,41 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -63,48 +65,41 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
this.hostname = hostname; this.hostname = hostname;
} }
public void setAttachments(String attachmentsString) { public void setAttachments(List<Attachment> attachments) {
if (this.attachmentsString != null && this.attachmentsString.equals(attachmentsString)) { if (this.attachments != null && this.attachments.equals(attachments)) {
return; return;
} }
this.attachmentsString = attachmentsString; this.attachments = attachments;
removeAllViews(); removeAllViews();
try { for (int i = 0, size = attachments.size(); i < size; i++) {
JSONArray attachments = new JSONArray(attachmentsString); appendAttachmentView(attachments.get(i));
for (int i = 0; i < attachments.length(); i++) {
JSONObject attachment = attachments.getJSONObject(i);
appendAttachmentView(attachment);
}
} catch (JSONException exception) {
return;
} }
} }
private void appendAttachmentView(JSONObject attachmentObj) throws JSONException { private void appendAttachmentView(Attachment attachment) {
if (attachmentObj == null) { if (attachment == null) {
return; return;
} }
View attachmentView = inflater.inflate(R.layout.message_inline_attachment, this, false); View attachmentView = inflater.inflate(R.layout.message_inline_attachment, this, false);
colorizeAttachmentBar(attachmentObj, attachmentView); colorizeAttachmentBar(attachment, attachmentView);
showAuthorAttachment(attachmentObj, attachmentView); showAuthorAttachment(attachment, attachmentView);
showTitleAttachment(attachmentObj, attachmentView); showTitleAttachment(attachment, attachmentView);
showReferenceAttachment(attachmentObj, attachmentView); showReferenceAttachment(attachment, attachmentView);
showImageAttachment(attachmentObj, attachmentView); showImageAttachment(attachment, attachmentView);
// audio // audio
// video // video
showFieldsAttachment(attachmentObj, attachmentView); showFieldsAttachment(attachment, attachmentView);
addView(attachmentView); addView(attachmentView);
} }
private void colorizeAttachmentBar(JSONObject attachmentObj, View attachmentView) private void colorizeAttachmentBar(Attachment attachment, View attachmentView) {
throws JSONException {
final View attachmentStrip = attachmentView.findViewById(R.id.attachment_strip); final View attachmentStrip = attachmentView.findViewById(R.id.attachment_strip);
final String colorString = attachmentObj.optString("color"); final String colorString = attachment.getColor();
if (TextUtils.isEmpty(colorString)) { if (TextUtils.isEmpty(colorString)) {
attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line); attachmentStrip.setBackgroundResource(R.color.inline_attachment_quote_line);
return; return;
...@@ -117,24 +112,23 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -117,24 +112,23 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
} }
} }
private void showAuthorAttachment(JSONObject attachmentObj, View attachmentView) private void showAuthorAttachment(Attachment attachment, View attachmentView) {
throws JSONException {
final View authorBox = attachmentView.findViewById(R.id.author_box); final View authorBox = attachmentView.findViewById(R.id.author_box);
if (attachmentObj.isNull("author_name") || attachmentObj.isNull("author_link") AttachmentAuthor author = attachment.getAttachmentAuthor();
|| attachmentObj.isNull("author_icon")) { if (author == null) {
authorBox.setVisibility(GONE); authorBox.setVisibility(GONE);
return; return;
} }
authorBox.setVisibility(VISIBLE); authorBox.setVisibility(VISIBLE);
loadImage(attachmentObj.getString("author_icon"), loadImage(author.getIconUrl(),
(SimpleDraweeView) attachmentView.findViewById(R.id.author_icon)); (SimpleDraweeView) attachmentView.findViewById(R.id.author_icon));
final TextView authorName = (TextView) attachmentView.findViewById(R.id.author_name); final TextView authorName = (TextView) attachmentView.findViewById(R.id.author_name);
authorName.setText(attachmentObj.getString("author_name")); authorName.setText(author.getName());
final String link = absolutize(attachmentObj.getString("author_link")); final String link = absolutize(author.getLink());
authorName.setOnClickListener(new OnClickListener() { authorName.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
...@@ -147,22 +141,22 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -147,22 +141,22 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
// timestamp and link - need to format time // timestamp and link - need to format time
} }
private void showTitleAttachment(JSONObject attachmentObj, View attachmentView) private void showTitleAttachment(Attachment attachment, View attachmentView) {
throws JSONException {
TextView titleView = (TextView) attachmentView.findViewById(R.id.title); TextView titleView = (TextView) attachmentView.findViewById(R.id.title);
if (attachmentObj.isNull("title")) { AttachmentTitle title = attachment.getAttachmentTitle();
if (title == null || title.getTitle() == null) {
titleView.setVisibility(View.GONE); titleView.setVisibility(View.GONE);
return; return;
} }
titleView.setVisibility(View.VISIBLE); titleView.setVisibility(View.VISIBLE);
titleView.setText(attachmentObj.getString("title")); titleView.setText(title.getTitle());
if (attachmentObj.isNull("title_link")) { if (title.getLink() == null) {
titleView.setOnClickListener(null); titleView.setOnClickListener(null);
titleView.setClickable(false); titleView.setClickable(false);
} else { } else {
final String link = absolutize(attachmentObj.getString("title_link")); final String link = absolutize(title.getLink());
titleView.setOnClickListener(new OnClickListener() { titleView.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
...@@ -176,10 +170,9 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -176,10 +170,9 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
} }
} }
private void showReferenceAttachment(JSONObject attachmentObj, View attachmentView) private void showReferenceAttachment(Attachment attachment, View attachmentView) {
throws JSONException {
final View refBox = attachmentView.findViewById(R.id.ref_box); final View refBox = attachmentView.findViewById(R.id.ref_box);
if (attachmentObj.isNull("thumb_url") && attachmentObj.isNull("text")) { if (attachment.getThumbUrl() == null && attachment.getText() == null) {
refBox.setVisibility(GONE); refBox.setVisibility(GONE);
return; return;
} }
...@@ -188,7 +181,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -188,7 +181,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
final SimpleDraweeView thumbImage = (SimpleDraweeView) refBox.findViewById(R.id.thumb); final SimpleDraweeView thumbImage = (SimpleDraweeView) refBox.findViewById(R.id.thumb);
final String thumbUrl = attachmentObj.optString("thumb_url"); final String thumbUrl = attachment.getThumbUrl();
if (TextUtils.isEmpty(thumbUrl)) { if (TextUtils.isEmpty(thumbUrl)) {
thumbImage.setVisibility(GONE); thumbImage.setVisibility(GONE);
} else { } else {
...@@ -198,7 +191,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -198,7 +191,7 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
final TextView refText = (TextView) refBox.findViewById(R.id.text); final TextView refText = (TextView) refBox.findViewById(R.id.text);
final String refString = attachmentObj.optString("text"); final String refString = attachment.getText();
if (TextUtils.isEmpty(refString)) { if (TextUtils.isEmpty(refString)) {
refText.setVisibility(GONE); refText.setVisibility(GONE);
} else { } else {
...@@ -207,38 +200,37 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout { ...@@ -207,38 +200,37 @@ public class RocketChatMessageAttachmentsLayout extends LinearLayout {
} }
} }
private void showImageAttachment(JSONObject attachmentObj, View attachmentView) private void showImageAttachment(Attachment attachment, View attachmentView) {
throws JSONException {
final SimpleDraweeView attachedImage = final SimpleDraweeView attachedImage =
(SimpleDraweeView) attachmentView.findViewById(R.id.image); (SimpleDraweeView) attachmentView.findViewById(R.id.image);
if (attachmentObj.isNull("image_url")) { if (attachment.getImageUrl() == null) {
attachedImage.setVisibility(GONE); attachedImage.setVisibility(GONE);
return; return;
} }
attachedImage.setVisibility(VISIBLE); attachedImage.setVisibility(VISIBLE);
loadImage(attachmentObj.getString("image_url"), attachedImage); loadImage(attachment.getImageUrl(), attachedImage);
} }
private void showFieldsAttachment(JSONObject attachmentObj, View attachmentView) private void showFieldsAttachment(Attachment attachment, View attachmentView) {
throws JSONException { List<AttachmentField> fields = attachment.getAttachmentFields();
if (attachmentObj.isNull("fields")) { if (fields == null || fields.size() == 0) {
return; return;
} }
final ViewGroup attachmentContent = final ViewGroup attachmentContent =
(ViewGroup) attachmentView.findViewById(R.id.attachment_content); (ViewGroup) attachmentView.findViewById(R.id.attachment_content);
final JSONArray fields = attachmentObj.getJSONArray("fields"); for (int i = 0, size = fields.size(); i < size; i++) {
for (int i = 0, size = fields.length(); i < size; i++) { final AttachmentField attachmentField = fields.get(i);
final JSONObject fieldObject = fields.getJSONObject(i); if (attachmentField.getTitle() == null
if (fieldObject.isNull("title") || fieldObject.isNull("value")) { || attachmentField.getText() == null) {
return; return;
} }
MessageAttachmentFieldLayout fieldLayout = new MessageAttachmentFieldLayout(getContext()); MessageAttachmentFieldLayout fieldLayout = new MessageAttachmentFieldLayout(getContext());
fieldLayout.setTitle(fieldObject.getString("title")); fieldLayout.setTitle(attachmentField.getTitle());
fieldLayout.setValue(fieldObject.getString("value")); fieldLayout.setValue(attachmentField.getText());
attachmentContent.addView(fieldLayout); attachmentContent.addView(fieldLayout);
} }
......
...@@ -16,18 +16,21 @@ import com.facebook.drawee.backends.pipeline.Fresco; ...@@ -16,18 +16,21 @@ import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.generic.GenericDraweeHierarchy; import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.interfaces.DraweeController; import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView; import com.facebook.drawee.view.SimpleDraweeView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import java.util.Map;
import chat.rocket.android.widget.R; import chat.rocket.android.widget.R;
import chat.rocket.android.widget.helper.ImageFormat; import chat.rocket.android.widget.helper.ImageFormat;
import chat.rocket.core.models.WebContent;
import chat.rocket.core.models.WebContentHeaders;
import chat.rocket.core.models.WebContentMeta;
import chat.rocket.core.models.WebContentParsedUrl;
/** /**
*/ */
public class RocketChatMessageUrlsLayout extends LinearLayout { public class RocketChatMessageUrlsLayout extends LinearLayout {
private LayoutInflater inflater; private LayoutInflater inflater;
private String urlsString; private List<WebContent> webContents;
public RocketChatMessageUrlsLayout(Context context) { public RocketChatMessageUrlsLayout(Context context) {
super(context); super(context);
...@@ -56,99 +59,78 @@ public class RocketChatMessageUrlsLayout extends LinearLayout { ...@@ -56,99 +59,78 @@ public class RocketChatMessageUrlsLayout extends LinearLayout {
setOrientation(VERTICAL); setOrientation(VERTICAL);
} }
public void setUrls(String urlsString) { public void setUrls(List<WebContent> webContents) {
if (this.urlsString != null && this.urlsString.equals(urlsString)) { if (this.webContents != null && this.webContents.equals(webContents)) {
return; return;
} }
this.urlsString = urlsString;
this.webContents = webContents;
removeAllViews(); removeAllViews();
try { for (int i = 0, size = webContents.size(); i < size; i++) {
JSONArray urls = new JSONArray(urlsString); appendUrlView(webContents.get(i));
for (int i = 0; i < urls.length(); i++) {
JSONObject url = urls.getJSONObject(i);
appendUrlView(url);
}
} catch (JSONException exception) {
return;
} }
} }
private void appendUrlView(JSONObject urlObj) throws JSONException { private void appendUrlView(WebContent webContent) {
final String url = urlObj.getString("url"); final String url = webContent.getUrl();
String contentType = urlObj.getJSONObject("headers").getString("contentType"); final WebContentHeaders webContentHeaders = webContent.getHeaders();
String contentType = webContentHeaders != null ? webContentHeaders.getContentType() : "";
if (contentType.startsWith("image/") && ImageFormat.SUPPORTED_LIST.contains(contentType)) { if (contentType != null && contentType.startsWith("image/")
&& ImageFormat.SUPPORTED_LIST.contains(contentType)) {
View inlineImage = inflater.inflate(R.layout.message_inline_image, this, false); View inlineImage = inflater.inflate(R.layout.message_inline_image, this, false);
loadImage(url, (SimpleDraweeView) inlineImage.findViewById(R.id.message_inline_image)); loadImage(url, (SimpleDraweeView) inlineImage.findViewById(R.id.message_inline_image));
addView(inlineImage); addView(inlineImage);
} }
// see Rocket.Chat:packages/rocketchat-oembed/client/oembedUrlWidget.coffee // see Rocket.Chat:packages/rocketchat-oembed/client/oembedUrlWidget.coffee
if (!urlObj.isNull("meta")) { final Map<WebContentMeta.Type, WebContentMeta> webContentMetaMap = webContent.getMetaMap();
JSONObject meta = urlObj.getJSONObject("meta"); if (webContentMetaMap == null || webContentMetaMap.size() == 0) {
return;
String title = null; }
if (!meta.isNull("ogTitle")) {
title = meta.getString("ogTitle");
} else if (!meta.isNull("twitterTitle")) {
title = meta.getString("twitterTitle");
} else if (!meta.isNull("pageTitle")) {
title = meta.getString("pageTitle");
}
String description = null; String title = webContent.getMetaTitle();
if (!meta.isNull("ogDescription")) {
description = meta.getString("ogDescription");
} else if (!meta.isNull("twitterDescription")) {
description = meta.getString("twitterDescription");
} else if (!meta.isNull("description")) {
description = meta.getString("description");
}
if (description != null) { String description = webContent.getMetaDescription();
if (description.startsWith("\"")) { if (description != null) {
description = description.substring(1); if (description.startsWith("\"")) {
} description = description.substring(1);
if (description.endsWith("\"")) {
description = description.substring(0, description.length() - 1);
}
} }
if (description.endsWith("\"")) {
String imageURL = null; description = description.substring(0, description.length() - 1);
if (!meta.isNull("ogImage")) {
imageURL = meta.getString("ogImage");
} else if (!meta.isNull("twitterImage")) {
imageURL = meta.getString("twitterImage");
} }
}
String host = urlObj.getJSONObject("parsedUrl").getString("host"); String imageURL = webContent.getMetaImage();
View embedUrl = inflater.inflate(R.layout.message_inline_embed_url, this, false);
((TextView) embedUrl.findViewById(R.id.hostname)).setText(host); WebContentParsedUrl parsedUrl = webContent.getParsedUrl();
((TextView) embedUrl.findViewById(R.id.title)).setText(title); String host = parsedUrl != null ? parsedUrl.getHost() : null;
((TextView) embedUrl.findViewById(R.id.description)).setText(description);
final SimpleDraweeView image = (SimpleDraweeView) embedUrl.findViewById(R.id.image); View embedUrl = inflater.inflate(R.layout.message_inline_embed_url, this, false);
if (TextUtils.isEmpty(imageURL)) {
image.setVisibility(View.GONE);
} else {
loadImage(imageURL, image);
image.setVisibility(View.VISIBLE);
}
embedUrl.setOnClickListener(new View.OnClickListener() { ((TextView) embedUrl.findViewById(R.id.hostname)).setText(host);
@Override ((TextView) embedUrl.findViewById(R.id.title)).setText(title);
public void onClick(View v) { ((TextView) embedUrl.findViewById(R.id.description)).setText(description);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
});
addView(embedUrl); final SimpleDraweeView image = (SimpleDraweeView) embedUrl.findViewById(R.id.image);
if (TextUtils.isEmpty(imageURL)) {
image.setVisibility(View.GONE);
} else {
loadImage(imageURL, image);
image.setVisibility(View.VISIBLE);
} }
embedUrl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
});
addView(embedUrl);
} }
private void loadImage(String imageUrl, SimpleDraweeView draweeView) { private void loadImage(String imageUrl, SimpleDraweeView draweeView) {
......
...@@ -2,6 +2,7 @@ package chat.rocket.core.models; ...@@ -2,6 +2,7 @@ package chat.rocket.core.models;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@AutoValue @AutoValue
...@@ -10,10 +11,13 @@ public abstract class WebContent { ...@@ -10,10 +11,13 @@ public abstract class WebContent {
public abstract String getUrl(); public abstract String getUrl();
@Nullable @Nullable
public abstract String getMeta(); public abstract Map<WebContentMeta.Type, WebContentMeta> getMetaMap();
@Nullable @Nullable
public abstract String getHeaders(); public abstract WebContentHeaders getHeaders();
@Nullable
public abstract WebContentParsedUrl getParsedUrl();
public static Builder builder() { public static Builder builder() {
return new AutoValue_WebContent.Builder(); return new AutoValue_WebContent.Builder();
...@@ -24,11 +28,79 @@ public abstract class WebContent { ...@@ -24,11 +28,79 @@ public abstract class WebContent {
public abstract Builder setUrl(String url); public abstract Builder setUrl(String url);
public abstract Builder setMeta(String meta); public abstract Builder setMetaMap(Map<WebContentMeta.Type, WebContentMeta> webContentMetaMap);
public abstract Builder setHeaders(WebContentHeaders webContentHeaders);
public abstract Builder setHeaders(String headers); public abstract Builder setParsedUrl(WebContentParsedUrl webContentParsedUrl);
public abstract WebContent build(); public abstract WebContent build();
} }
public String getMetaTitle() {
final Map<WebContentMeta.Type, WebContentMeta> webContentMetaMap = getMetaMap();
if (webContentMetaMap == null) {
return null;
}
WebContentMeta webContentMeta = webContentMetaMap.get(WebContentMeta.Type.OPEN_GRAPH);
if (webContentMeta != null && webContentMeta.getTitle() != null) {
return webContentMeta.getTitle();
}
webContentMeta = webContentMetaMap.get(WebContentMeta.Type.TWITTER);
if (webContentMeta != null && webContentMeta.getTitle() != null) {
return webContentMeta.getTitle();
}
webContentMeta = webContentMetaMap.get(WebContentMeta.Type.OTHER);
if (webContentMeta != null && webContentMeta.getTitle() != null) {
return webContentMeta.getTitle();
}
return null;
}
public String getMetaDescription() {
final Map<WebContentMeta.Type, WebContentMeta> webContentMetaMap = getMetaMap();
if (webContentMetaMap == null) {
return null;
}
WebContentMeta webContentMeta = webContentMetaMap.get(WebContentMeta.Type.OPEN_GRAPH);
if (webContentMeta != null && webContentMeta.getDescription() != null) {
return webContentMeta.getDescription();
}
webContentMeta = webContentMetaMap.get(WebContentMeta.Type.TWITTER);
if (webContentMeta != null && webContentMeta.getDescription() != null) {
return webContentMeta.getDescription();
}
webContentMeta = webContentMetaMap.get(WebContentMeta.Type.OTHER);
if (webContentMeta != null && webContentMeta.getDescription() != null) {
return webContentMeta.getDescription();
}
return null;
}
public String getMetaImage() {
final Map<WebContentMeta.Type, WebContentMeta> webContentMetaMap = getMetaMap();
if (webContentMetaMap == null) {
return null;
}
WebContentMeta webContentMeta = webContentMetaMap.get(WebContentMeta.Type.OPEN_GRAPH);
if (webContentMeta != null && webContentMeta.getImage() != null) {
return webContentMeta.getImage();
}
webContentMeta = webContentMetaMap.get(WebContentMeta.Type.TWITTER);
if (webContentMeta != null && webContentMeta.getImage() != null) {
return webContentMeta.getImage();
}
return null;
}
} }
package chat.rocket.core.models;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;
@AutoValue
public abstract class WebContentHeaders {
@Nullable
public abstract String getContentType();
public static Builder builder() {
return new AutoValue_WebContentHeaders.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setContentType(String contentType);
public abstract WebContentHeaders build();
}
}
package chat.rocket.core.models;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;
@AutoValue
public abstract class WebContentMeta {
public enum Type {
OPEN_GRAPH, TWITTER, OTHER
}
public abstract Type getType();
@Nullable
public abstract String getTitle();
@Nullable
public abstract String getDescription();
@Nullable
public abstract String getImage();
public static Builder builder() {
return new AutoValue_WebContentMeta.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setType(Type type);
public abstract Builder setTitle(String title);
public abstract Builder setDescription(String description);
public abstract Builder setImage(String image);
public abstract WebContentMeta build();
}
}
package chat.rocket.core.models;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;
@AutoValue
public abstract class WebContentParsedUrl {
@Nullable
public abstract String getHost();
public static Builder builder() {
return new AutoValue_WebContentParsedUrl.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder setHost(String host);
public abstract WebContentParsedUrl build();
}
}
package chat.rocket.core.repositories; package chat.rocket.core.repositories;
import java.util.List;
import chat.rocket.core.models.Message; import chat.rocket.core.models.Message;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.User;
import rx.Observable; import rx.Observable;
import rx.Single; import rx.Single;
...@@ -15,7 +17,7 @@ public interface MessageRepository { ...@@ -15,7 +17,7 @@ public interface MessageRepository {
Single<Boolean> delete(Message message); Single<Boolean> delete(Message message);
Observable<Message> getAllFrom(Room room); Observable<List<Message>> getAllFrom(Room room);
Single<Integer> unreadCountFrom(Room room); Single<Integer> unreadCountFor(Room room, User user);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment