Commit b7a175d8 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Merge branch 'develop' into feature/multi-server

parents 3dfd5163 0103fdb6
# Rocket.Chat Android native application
[![CircleCI](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop.svg?style=shield)](https://circleci.com/gh/RocketChat/Rocket.Chat.Android/tree/develop) [![Build Status](https://travis-ci.org/RocketChat/Rocket.Chat.Android.svg?branch=develop)](https://travis-ci.org/RocketChat/Rocket.Chat.Android) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a81156a8682e4649994270d3670c3c83)](https://www.codacy.com/app/matheusjardimb/Rocket.Chat.Android)
# Rocket.Chat.Android
Rocket.Chat Native Android Application.
# Get it from Google Play
[![Rocket.Chat on Google Play](https://user-images.githubusercontent.com/551004/29770692-a20975c6-8bc6-11e7-8ab0-1cde275496e0.png)](https://play.google.com/store/apps/details?id=chat.rocket.android)
## How to build
......
......@@ -45,8 +45,8 @@ android {
applicationId "chat.rocket.android"
minSdkVersion 16
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 31
versionName "1.0.17"
versionCode 34
versionName "1.0.18"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
......
......@@ -483,7 +483,11 @@ public class MethodCallHelper {
final JSONObject result = task.getResult();
JSONArray roomJsonArray = (JSONArray) result.get("rooms");
if (roomJsonArray.length() > 0) {
int roomTotal = roomJsonArray.length();
if (roomTotal > 0) {
for (int i = 0; i < roomTotal; ++i) {
RealmSpotlight.Companion.customizeRoomJSONObject(roomJsonArray.getJSONObject(i));
}
jsonString = roomJsonArray.toString();
}
......
......@@ -47,9 +47,6 @@ abstract class AbstractChatRoomFragment extends AbstractFragment {
case User.STATUS_AWAY:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_AWAY);
break;
case User.STATUS_OFFLINE:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_OFFLINE);
break;
default:
roomToolbar.showUserStatusIcon(RoomToolbar.STATUS_OFFLINE);
break;
......
......@@ -2,10 +2,10 @@ package chat.rocket.android.fragment.sidebar;
import android.support.annotation.NonNull;
import chat.rocket.core.models.RoomSidebar;
import io.reactivex.Flowable;
import java.util.List;
import chat.rocket.android.shared.BaseContract;
import chat.rocket.core.models.Room;
import chat.rocket.core.models.Spotlight;
import chat.rocket.core.models.User;
......@@ -17,14 +17,14 @@ public interface SidebarMainContract {
void showEmptyScreen();
void showRoomList(@NonNull List<Room> roomList);
void showRoomSidebarList(@NonNull List<RoomSidebar> roomSidebarList);
void show(User user);
}
interface Presenter extends BaseContract.Presenter<View> {
void onRoomSelected(Room room);
void onRoomSelected(RoomSidebar roomSidebar);
void onSpotlightSelected(Spotlight spotlight);
......
......@@ -11,6 +11,7 @@ import android.support.v7.widget.SearchView;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.TextView;
import chat.rocket.android.BuildConfig;
import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache;
......@@ -29,7 +30,7 @@ import chat.rocket.android.layouthelper.chatroom.roomlist.UnreadRoomListHeader;
import chat.rocket.android.renderer.UserRenderer;
import chat.rocket.core.interactors.RoomInteractor;
import chat.rocket.core.interactors.SessionInteractor;
import chat.rocket.core.models.Room;
import chat.rocket.core.models.RoomSidebar;
import chat.rocket.core.models.Spotlight;
import chat.rocket.core.models.User;
import chat.rocket.persistence.realm.repositories.RealmRoomRepository;
......@@ -123,9 +124,9 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
adapter = new RoomListAdapter();
adapter.setOnItemClickListener(new RoomListAdapter.OnItemClickListener() {
@Override
public void onItemClick(Room room) {
public void onItemClick(RoomSidebar roomSidebar) {
searchView.clearFocus();
presenter.onRoomSelected(room);
presenter.onRoomSelected(roomSidebar);
}
@Override
......@@ -142,7 +143,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
RxSearchView.queryTextChanges(searchView)
.compose(bindToLifecycle())
.debounce(300, TimeUnit.MILLISECONDS)
.debounce(100, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.switchMap(charSequence -> {
if (charSequence.length() == 0) {
......@@ -187,8 +188,8 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
}
@Override
public void showRoomList(@NonNull List<Room> roomList) {
adapter.setRooms(roomList);
public void showRoomSidebarList(@NonNull List<RoomSidebar> roomSidebarList) {
adapter.setRoomSidebarList(roomSidebarList);
}
@Override
......@@ -228,12 +229,9 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
private void updateRoomListMode(User user) {
final List<RoomListHeader> roomListHeaders = new ArrayList<>();
if (user != null && user.getSettings() != null && user.getSettings().getPreferences() != null
&& user.getSettings().getPreferences().isUnreadRoomsMode()) {
roomListHeaders.add(new UnreadRoomListHeader(
getString(R.string.fragment_sidebar_main_unread_rooms_title)
));
}
roomListHeaders.add(new FavoriteRoomListHeader(
getString(R.string.fragment_sidebar_main_favorite_title)
......
......@@ -3,11 +3,8 @@ package chat.rocket.android.fragment.sidebar;
import android.support.annotation.NonNull;
import android.support.v4.util.Pair;
import chat.rocket.core.models.Spotlight;
import chat.rocket.persistence.realm.repositories.RealmSpotlightRepository;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import java.util.ArrayList;
import java.util.List;
import chat.rocket.android.BackgroundLooper;
import chat.rocket.android.RocketChatCache;
......@@ -19,19 +16,25 @@ import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.shared.BasePresenter;
import chat.rocket.core.interactors.RoomInteractor;
import chat.rocket.core.models.Room;
import chat.rocket.core.models.RoomSidebar;
import chat.rocket.core.models.Spotlight;
import chat.rocket.core.models.User;
import chat.rocket.core.repositories.SpotlightRepository;
import chat.rocket.core.repositories.UserRepository;
import java.util.List;
import chat.rocket.persistence.realm.repositories.RealmSpotlightRepository;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View> implements SidebarMainContract.Presenter {
private final String hostname;
private String userId;
private final RoomInteractor roomInteractor;
private final UserRepository userRepository;
private final RocketChatCache rocketChatCache;
private final AbsoluteUrlHelper absoluteUrlHelper;
private final MethodCallHelper methodCallHelper;
private RealmSpotlightRepository realmSpotlightRepository;
private SpotlightRepository realmSpotlightRepository;
private List<RoomSidebar> roomSidebarList;
public SidebarMainPresenter(String hostname,
RoomInteractor roomInteractor,
......@@ -69,20 +72,14 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
)
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
pair -> {
userId = pair.first.orNull().getId();
view.show(pair.first.orNull());
},
Logger::report
);
.subscribe(pair -> view.show(pair.first.orNull()), Logger::report);
addSubscription(subscription);
}
@Override
public void onRoomSelected(Room room) {
rocketChatCache.setSelectedRoomId(room.getRoomId());
public void onRoomSelected(RoomSidebar roomSidebar) {
rocketChatCache.setSelectedRoomId(roomSidebar.getRoomId());
}
@Override
......@@ -143,14 +140,65 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
.distinctUntilChanged()
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
rooms -> view.showRoomList(rooms),
Logger::report
);
.subscribe(this::processRooms, Logger::report);
addSubscription(subscription);
}
private void processRooms(List<Room> roomList) {
roomSidebarList = new ArrayList<>();
List<String> userToObserverList = new ArrayList<>();
for (Room room : roomList) {
String roomName = room.getName();
String roomType = room.getType();
RoomSidebar roomSidebar = new RoomSidebar();
roomSidebar.setId(room.getId());
roomSidebar.setRoomId(room.getRoomId());
roomSidebar.setRoomName(roomName);
roomSidebar.setType(roomType);
roomSidebar.setAlert(room.isAlert());
roomSidebar.setFavorite(room.isFavorite());
roomSidebar.setUnread(room.getUnread());
roomSidebar.setUpdateAt(room.getUpdatedAt());
roomSidebar.setLastSeen(room.getLastSeen());
if (roomType.equals(Room.TYPE_DIRECT_MESSAGE)) {
userToObserverList.add(roomName);
}
roomSidebarList.add(roomSidebar);
}
if (userToObserverList.isEmpty()) {
view.showRoomSidebarList(roomSidebarList);
} else {
getUsersStatus();
}
}
private void getUsersStatus() {
// TODO Filter when Android Studion uses the java8 features (removeIf).
// .filter(userList -> userList.removeIf(user -> !userToObserverList.contains(user.getUsername())))
final Disposable subscription = userRepository.getAll()
.distinctUntilChanged()
.subscribeOn(AndroidSchedulers.from(BackgroundLooper.get()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::processUsers, Logger::report);
addSubscription(subscription);
}
private void processUsers(List<User> userList) {
for (User user: userList) {
for(RoomSidebar roomSidebar: roomSidebarList) {
if (roomSidebar.getRoomName().equals(user.getUsername())) {
roomSidebar.setUserStatus(user.getStatus());
}
}
}
view.showRoomSidebarList(roomSidebarList);
}
private void updateCurrentUserStatus(String status) {
methodCallHelper.setUserStatus(status).continueWith(new LogIfError());
}
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import android.support.annotation.NonNull;
import chat.rocket.core.models.RoomSidebar;
import java.util.List;
import chat.rocket.core.models.Room;
......@@ -21,12 +22,12 @@ public class ChannelRoomListHeader implements RoomListHeader {
}
@Override
public boolean owns(Room room) {
return room.isChannel() || room.isPrivate();
public boolean owns(RoomSidebar roomSidebar) {
return roomSidebar.getType().equals(Room.TYPE_CHANNEL) || roomSidebar.getType().equals(Room.TYPE_PRIVATE);
}
@Override
public boolean shouldShow(@NonNull List<Room> roomList) {
public boolean shouldShow(@NonNull List<RoomSidebar> roomSidebarList) {
return true;
}
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import android.support.annotation.NonNull;
import chat.rocket.core.models.RoomSidebar;
import java.util.List;
import chat.rocket.core.models.Room;
......@@ -21,12 +22,12 @@ public class DirectMessageRoomListHeader implements RoomListHeader {
}
@Override
public boolean owns(Room room) {
return room.isDirectMessage();
public boolean owns(RoomSidebar roomSidebar) {
return roomSidebar.getType().equals(Room.TYPE_DIRECT_MESSAGE);
}
@Override
public boolean shouldShow(@NonNull List<Room> roomList) {
public boolean shouldShow(@NonNull List<RoomSidebar> roomSidebarList) {
return true;
}
......
......@@ -2,8 +2,8 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import android.support.annotation.NonNull;
import chat.rocket.core.models.RoomSidebar;
import java.util.List;
import chat.rocket.core.models.Room;
public class FavoriteRoomListHeader implements RoomListHeader {
......@@ -19,18 +19,17 @@ public class FavoriteRoomListHeader implements RoomListHeader {
}
@Override
public boolean owns(Room room) {
return room.isFavorite();
public boolean owns(RoomSidebar roomSidebar) {
return roomSidebar.isFavorite();
}
@Override
public boolean shouldShow(@NonNull List<Room> roomList) {
for (int i = 0, size = roomList.size(); i < size; i++) {
if (roomList.get(i).isFavorite()) {
public boolean shouldShow(@NonNull List<RoomSidebar> roomSidebarList) {
for (RoomSidebar roomSidebar: roomSidebarList) {
if (roomSidebar.isFavorite()) {
return true;
}
}
return false;
}
......
......@@ -5,6 +5,7 @@ import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import chat.rocket.core.models.RoomSidebar;
import chat.rocket.core.models.Spotlight;
import java.util.Collections;
import java.util.HashMap;
......@@ -12,7 +13,6 @@ import java.util.List;
import java.util.Map;
import chat.rocket.android.R;
import chat.rocket.android.widget.internal.RoomListItemView;
import chat.rocket.core.models.Room;
public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
......@@ -22,7 +22,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private static final int VIEW_TYPE_HEADER = 0;
private static final int VIEW_TYPE_ROOM = 1;
private List<Room> roomList = Collections.emptyList();
private List<RoomSidebar> roomSidebarList = Collections.emptyList();
private List<Spotlight> spotlightList = Collections.emptyList();
private List<RoomListHeader> roomListHeaders = Collections.emptyList();
private Map<Integer, RoomListHeader> headersPosition = new HashMap<>();
......@@ -32,9 +32,9 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private OnItemClickListener externalListener;
private OnItemClickListener listener = new OnItemClickListener() {
@Override
public void onItemClick(Room room) {
public void onItemClick(RoomSidebar roomSidebar) {
if (externalListener != null) {
externalListener.onItemClick(room);
externalListener.onItemClick(roomSidebar);
}
}
......@@ -48,17 +48,17 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
public void setRoomListHeaders(@NonNull List<RoomListHeader> roomListHeaders) {
this.roomListHeaders = roomListHeaders;
updateRoomList();
updateRoomSidebarList();
}
public void setRooms(@NonNull List<Room> roomList) {
this.roomList = roomList;
updateRoomList();
public void setRoomSidebarList(@NonNull List<RoomSidebar> roomSidebarList) {
this.roomSidebarList = roomSidebarList;
updateRoomSidebarList();
}
public void setSpotlightList(@NonNull List<Spotlight> spotlightList) {
this.spotlightList = spotlightList;
updateRoomList();
updateRoomSidebarList();
}
public void setMode(int mode) {
......@@ -77,8 +77,8 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_HEADER) {
return new RoomListHeaderViewHolder(
LayoutInflater.from(parent.getContext())
return new RoomListHeaderViewHolder(LayoutInflater
.from(parent.getContext())
.inflate(R.layout.room_list_header, parent, false)
);
}
......@@ -89,13 +89,12 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (mode == MODE_ROOM) {
if (getItemViewType(position) == VIEW_TYPE_HEADER) {
((RoomListHeaderViewHolder) holder)
.bind(headersPosition.get(position));
((RoomListHeaderViewHolder) holder).bind(headersPosition.get(position));
return;
}
((RoomListItemViewHolder) holder)
.bind(roomList.get(position - getTotalHeadersBeforePosition(position)));
RoomSidebar roomSidebar = roomSidebarList.get(position - getTotalHeadersBeforePosition(position));
((RoomListItemViewHolder) holder).bind(roomSidebar);
} else if (mode == MODE_SPOTLIGHT) {
((RoomListItemViewHolder) holder).bind(spotlightList.get(position));
}
......@@ -106,7 +105,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
if (mode == MODE_SPOTLIGHT) {
return spotlightList.size();
}
return roomList.size() + headersPosition.size();
return roomSidebarList.size() + headersPosition.size();
}
@Override
......@@ -121,7 +120,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
return VIEW_TYPE_ROOM;
}
private void updateRoomList() {
private void updateRoomSidebarList() {
if (mode == MODE_ROOM) {
sortRoomList();
calculateHeadersPosition();
......@@ -132,18 +131,18 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private void sortRoomList() {
int totalHeaders = roomListHeaders.size();
Collections.sort(roomList, (room, anotherRoom) -> {
Collections.sort(roomSidebarList, (roomSidebar, anotherRoom) -> {
for (int i = 0; i < totalHeaders; i++) {
final RoomListHeader header = roomListHeaders.get(i);
if (header.owns(room) && !header.owns(anotherRoom)) {
if (header.owns(roomSidebar) && !header.owns(anotherRoom)) {
return -1;
} else if (!header.owns(room) && header.owns(anotherRoom)) {
} else if (!header.owns(roomSidebar) && header.owns(anotherRoom)) {
return 1;
}
}
return room.getName().compareTo(anotherRoom.getName());
return roomSidebar.getRoomName().compareTo(anotherRoom.getRoomName());
});
}
......@@ -151,19 +150,19 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
headersPosition.clear();
int roomIdx = 0;
int totalRooms = roomList.size();
int totalRooms = roomSidebarList.size();
int totalHeaders = roomListHeaders.size();
for (int i = 0; i < totalHeaders; i++) {
final RoomListHeader header = roomListHeaders.get(i);
if (!header.shouldShow(roomList)) {
if (!header.shouldShow(roomSidebarList)) {
continue;
}
headersPosition.put(roomIdx + headersPosition.size(), header);
for (; roomIdx < totalRooms; roomIdx++) {
final Room room = roomList.get(roomIdx);
if (!header.owns(room)) {
final RoomSidebar roomSidebar = roomSidebarList.get(roomIdx);
if (!header.owns(roomSidebar)) {
break;
}
}
......@@ -185,7 +184,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
public interface OnItemClickListener {
void onItemClick(Room room);
void onItemClick(RoomSidebar roomSidebar);
void onItemClick(Spotlight spotlight);
}
......
......@@ -2,16 +2,16 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import android.support.annotation.NonNull;
import chat.rocket.core.models.RoomSidebar;
import java.util.List;
import chat.rocket.core.models.Room;
public interface RoomListHeader {
String getTitle();
boolean owns(Room room);
boolean owns(RoomSidebar roomSidebar);
boolean shouldShow(@NonNull List<Room> roomList);
boolean shouldShow(@NonNull List<RoomSidebar> roomSidebarList);
ClickListener getClickListener();
......
......@@ -14,8 +14,8 @@ public class RoomListHeaderViewHolder extends RecyclerView.ViewHolder {
public RoomListHeaderViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
button = (Button) itemView.findViewById(R.id.btn_add);
title = itemView.findViewById(R.id.title);
button = itemView.findViewById(R.id.btn_add);
}
public void bind(RoomListHeader roomListHeader) {
......
......@@ -4,43 +4,99 @@ import android.support.v7.widget.RecyclerView;
import chat.rocket.android.widget.internal.RoomListItemView;
import chat.rocket.core.models.Room;
import chat.rocket.core.models.RoomSidebar;
import chat.rocket.core.models.Spotlight;
import chat.rocket.core.models.User;
public class RoomListItemViewHolder extends RecyclerView.ViewHolder {
public RoomListItemViewHolder(RoomListItemView itemView,
RoomListAdapter.OnItemClickListener listener) {
private RoomListItemView itemView;
public RoomListItemViewHolder(RoomListItemView itemView, RoomListAdapter.OnItemClickListener listener) {
super(itemView);
itemView.setOnClickListener(view -> {
if (listener != null) {
Object tag = view.getTag();
this.itemView = itemView;
if (tag instanceof Room) {
listener.onItemClick((Room) view.getTag());
} else if (tag instanceof Spotlight) {
listener.onItemClick((Spotlight) view.getTag());
}
itemView.setOnClickListener(view -> {
Object object = view.getTag();
if (object instanceof RoomSidebar) {
listener.onItemClick((RoomSidebar)object);
} else if (object instanceof Spotlight) {
listener.onItemClick((Spotlight)object);
}
});
}
public void bind(Room room) {
((RoomListItemView) itemView)
.setRoomId(room.getRoomId())
.setRoomName(room.getName())
.setRoomType(room.getType())
.setAlert(room.isAlert())
.setUnreadCount(room.getUnread())
.setTag(room);
public void bind(RoomSidebar roomSidebar) {
itemView.setRoomId(roomSidebar.getRoomId());
itemView.setRoomName(roomSidebar.getRoomName());
itemView.setAlert(roomSidebar.isAlert());
itemView.setUnreadCount(roomSidebar.getUnread());
itemView.setTag(roomSidebar);
String roomType = roomSidebar.getType();
if (roomType.equals(Room.TYPE_DIRECT_MESSAGE)) {
showUserStatusIcon(roomSidebar.getUserStatus());
} else {
showRoomIcon(roomType);
}
}
public void bind(Spotlight spotlight) {
((RoomListItemView) itemView)
.setRoomId(spotlight.getId())
.setRoomName(spotlight.getName())
.setRoomType(spotlight.getType())
.setAlert(false)
.setUnreadCount(0)
.setTag(spotlight);
itemView.setRoomId(spotlight.getId());
itemView.setRoomName(spotlight.getName());
itemView.setAlert(false);
itemView.setUnreadCount(0);
itemView.setTag(spotlight);
String roomType = spotlight.getType();
if (roomType.equals(Room.TYPE_DIRECT_MESSAGE)) {
showUserStatusIcon(spotlight.getStatus());
} else {
showRoomIcon(roomType);
}
}
/**
* Shows the user status icon.
* @param userStatus The user status to show the correspondent icon.
* @see User
*/
private void showUserStatusIcon(String userStatus) {
if (userStatus == null) {
itemView.showOfflineUserStatusIcon();
} else {
switch (userStatus) {
case User.STATUS_ONLINE:
itemView.showOnlineUserStatusIcon();
break;
case User.STATUS_BUSY:
itemView.showBusyUserStatusIcon();
break;
case User.STATUS_AWAY:
itemView.showAwayUserStatusIcon();
break;
default:
itemView.showOfflineUserStatusIcon();
break;
}
}
}
/**
* Only shows the room icon if it is a PRIVATE CHANNEL or PUBLIC CHANNEL, otherwise you should use {@link #showUserStatusIcon(String)} to show the icon.
* @param roomType The type of Room.
* @see Room
*/
private void showRoomIcon(String roomType) {
switch (roomType) {
case Room.TYPE_CHANNEL:
itemView.showPublicChannelIcon();
break;
case Room.TYPE_PRIVATE:
itemView.showPrivateChannelIcon();
break;
default:
throw new AssertionError("Room type doesn't satisfies the method documentation. Room type is:" + roomType);
}
}
}
\ No newline at end of file
......@@ -2,8 +2,8 @@ package chat.rocket.android.layouthelper.chatroom.roomlist;
import android.support.annotation.NonNull;
import chat.rocket.core.models.RoomSidebar;
import java.util.List;
import chat.rocket.core.models.Room;
public class UnreadRoomListHeader implements RoomListHeader {
......@@ -19,18 +19,17 @@ public class UnreadRoomListHeader implements RoomListHeader {
}
@Override
public boolean owns(Room room) {
return room.isAlert();
public boolean owns(RoomSidebar roomSidebar) {
return roomSidebar.isAlert();
}
@Override
public boolean shouldShow(@NonNull List<Room> roomList) {
for (int i = 0, size = roomList.size(); i < size; i++) {
if (roomList.get(i).isAlert()) {
public boolean shouldShow(@NonNull List<RoomSidebar> roomSidebarList) {
for (RoomSidebar roomSidebar: roomSidebarList) {
if (roomSidebar.isAlert()) {
return true;
}
}
return false;
}
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M16.5,6v11.5c0,2.21 -1.79,4 -4,4s-4,-1.79 -4,-4V5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5v10.5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6H10v9.5c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5V5c0,-2.21 -1.79,-4 -4,-4S7,2.79 7,5v12.5c0,3.04 2.46,5.5 5.5,5.5s5.5,-2.46 5.5,-5.5V6h-1.5z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:alpha="0.78"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0"
android:width="24dp">
<path
android:fillColor="#FF000000"
android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
</vector>
......@@ -4,7 +4,7 @@
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:theme="@style/Theme.AppCompat.Light">
android:background="@android:color/white">
<TextView
android:layout_width="match_parent"
......
......@@ -10,21 +10,26 @@ open class RealmSpotlight : RealmObject() {
@PrimaryKey var _id: String? = null
var name: String? = null
var t: String? = null
var status: String? = null
fun asSpotlight(): Spotlight {
return Spotlight.builder()
.setId(_id)
.setName(name)
.setType(t)
.setStatus(status)
.build()
}
companion object {
fun customizeRoomJSONObject(roomJsonObject: JSONObject) {
roomJsonObject.put(Columns.STATUS, "")
}
fun customizeUserJSONObject(userJsonObject: JSONObject) {
userJsonObject.put(Columns.NAME, userJsonObject.get("username"))
userJsonObject.put(Columns.TYPE, "d")
userJsonObject.remove("username")
userJsonObject.remove("status")
}
}
......@@ -33,6 +38,7 @@ open class RealmSpotlight : RealmObject() {
const val ID = "_id"
const val NAME = "name"
const val TYPE = "t"
const val STATUS = "status"
}
}
}
\ No newline at end of file
......@@ -107,7 +107,6 @@ public class RealmRoomRepository extends RealmRepository implements RoomReposito
if (optional.isPresent()) {
return Optional.of(optional.get().asRoomHistoryState());
}
return Optional.absent();
}));
}
......
......@@ -27,6 +27,21 @@ public class RealmUserRepository extends RealmRepository implements UserReposito
this.hostname = hostname;
}
@Override
public Flowable<List<User>> getAll() {
return Flowable.defer(() -> Flowable.using(
() -> new Pair<>(RealmStore.getRealm(hostname), Looper.myLooper()),
pair -> RxJavaInterop.toV2Flowable(
pair.first.where(RealmUser.class)
.findAll()
.asObservable()),
pair -> close(pair.first, pair.second))
.unsubscribeOn(AndroidSchedulers.from(Looper.myLooper()))
.filter(roomSubscriptions -> roomSubscriptions != null && roomSubscriptions.isLoaded()
&& roomSubscriptions.isValid())
.map(this::toList));
}
@Override
public Flowable<Optional<User>> getCurrent() {
return Flowable.defer(() ->
......
......@@ -7,7 +7,6 @@ import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.graphics.drawable.DrawerArrowDrawable;
import android.support.v7.widget.AppCompatImageView;
import android.support.v7.widget.Toolbar;
......@@ -17,6 +16,7 @@ import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import chat.rocket.android.widget.helper.DrawableHelper;
import com.amulyakhare.textdrawable.TextDrawable;
import java.lang.reflect.Field;
......@@ -103,23 +103,24 @@ public class RoomToolbar extends Toolbar {
}
public void showUserStatusIcon(int status) {
wrapDrawable(userStatusDrawable);
DrawableHelper.INSTANCE.wrapDrawable(userStatusDrawable);
Context context = getContext();
switch (status) {
case STATUS_ONLINE:
tintDrawable(userStatusDrawable, R.color.color_user_status_online);
DrawableHelper.INSTANCE.tintDrawable(userStatusDrawable, context, R.color.color_user_status_online);
break;
case STATUS_BUSY:
tintDrawable(userStatusDrawable, R.color.color_user_status_busy);
DrawableHelper.INSTANCE.tintDrawable(userStatusDrawable, context, R.color.color_user_status_busy);
break;
case STATUS_AWAY:
tintDrawable(userStatusDrawable, R.color.color_user_status_away);
DrawableHelper.INSTANCE.tintDrawable(userStatusDrawable, context, R.color.color_user_status_away);
break;
case STATUS_OFFLINE:
tintDrawable(userStatusDrawable, R.color.color_user_status_offline);
DrawableHelper.INSTANCE.tintDrawable(userStatusDrawable, context, R.color.color_user_status_offline);
break;
default:
tintDrawable(userStatusDrawable, R.color.color_user_status_offline);
DrawableHelper.INSTANCE.tintDrawable(userStatusDrawable, context, R.color.color_user_status_offline);
break;
}
......@@ -128,25 +129,6 @@ public class RoomToolbar extends Toolbar {
userStatusImage.setVisibility(VISIBLE);
}
/**
* Wraps a drawable to be used for example for tinting.
* @param drawable The drawable to wrap.
* @see #tintDrawable(Drawable, int)
*/
private void wrapDrawable(Drawable drawable) {
DrawableCompat.wrap(drawable);
}
/**
* REMARK: You MUST always wrap the drawable before tint it.
* @param drawable The drawable to tint.
* @param color The color to tint the drawable.
* @see #wrapDrawable(Drawable)
*/
private void tintDrawable(Drawable drawable, int color) {
DrawableCompat.setTint(drawable, ContextCompat.getColor(getContext(), color));
}
public void setUnreadBudge(int numUnreadChannels, int numMentionsSum) {
if (getNavigationIcon() == null) {
return;
......@@ -166,7 +148,7 @@ public class RoomToolbar extends Toolbar {
badgeImageView.setImageDrawable(getBadgeDrawable(numMentionsSum));
} else {
badgeImageView.setScaleType(ImageView.ScaleType.CENTER);
badgeImageView.setImageResource(R.drawable.badge_without_number);
badgeImageView.setImageResource(R.drawable.ic_badge_without_number_red_10dp);
}
badgeImageView.setVisibility(View.VISIBLE);
} else {
......@@ -180,7 +162,7 @@ public class RoomToolbar extends Toolbar {
.beginConfig()
.useFont(Typeface.SANS_SERIF)
.endConfig()
.buildRound(icon, ContextCompat.getColor(getContext(), R.color.color_user_status_busy));
.buildRound(icon, ContextCompat.getColor(getContext(), R.color.color_alert));
}
@Override
......
package chat.rocket.android.widget.helper
import android.content.Context
import android.graphics.drawable.Drawable
import android.support.v4.content.ContextCompat
import android.support.v4.graphics.drawable.DrawableCompat
object DrawableHelper {
/**
* Wraps a drawable to be used for example for tinting.
*
* @param drawable The drawable to wrap.
* @see tintDrawable
*/
fun wrapDrawable(drawable: Drawable) {
DrawableCompat.wrap(drawable)
}
/**
* REMARK: You MUST always wrap the drawable before tint it.
*
* @param drawable The drawable to tint.
* @param context The context.
* @param resId The resource id color to tint the drawable.
* @see wrapDrawable
*/
fun tintDrawable(drawable: Drawable, context: Context, resId: Int) {
DrawableCompat.setTint(drawable, ContextCompat.getColor(context, resId))
}
}
\ No newline at end of file
package chat.rocket.android.widget.internal;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.HashMap;
import chat.rocket.android.widget.R;
/**
* Room list-item view used in sidebar.
*/
public class RoomListItemView extends FrameLayout {
private static HashMap<String, Integer> ICON_TABLE = new HashMap<String, Integer>() {
{
put("c", R.string.fa_hashtag);
put("p", R.string.fa_lock);
put("d", R.string.fa_at);
}
};
private String roomId;
private String roomName;
public RoomListItemView(Context context) {
super(context);
initialize(context);
}
public RoomListItemView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context);
}
public RoomListItemView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public RoomListItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize(context);
}
private void initialize(Context context) {
setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
TypedArray array2 = context.getTheme().obtainStyledAttributes(new int[]{
R.attr.selectableItemBackground
});
setBackground(array2.getDrawable(0));
array2.recycle();
View.inflate(context, R.layout.room_list_item, this);
}
public String getRoomId() {
return roomId;
}
public RoomListItemView setRoomId(String roomId) {
this.roomId = roomId;
return this;
}
public RoomListItemView setRoomType(String type) {
if (ICON_TABLE.containsKey(type)) {
TextView icon = (TextView) findViewById(R.id.icon);
icon.setText(ICON_TABLE.get(type));
}
return this;
}
public RoomListItemView setUnreadCount(int count) {
View alertCountContainer = findViewById(R.id.alert_count_container);
TextView alertCount = (TextView) findViewById(R.id.alert_count);
if (count > 0) {
alertCount.setText(Integer.toString(count));
alertCountContainer.setVisibility(View.VISIBLE);
} else {
alertCountContainer.setVisibility(View.GONE);
}
return this;
}
public RoomListItemView setAlert(boolean alert) {
setAlpha(alert ? 1.0f : 0.62f);
return this;
}
public String getRoomName() {
return roomName;
}
public RoomListItemView setRoomName(String roomName) {
this.roomName = roomName;
TextView text = (TextView) findViewById(R.id.text);
text.setText(roomName);
return this;
}
}
package chat.rocket.android.widget.internal
import android.annotation.TargetApi
import android.content.Context
import android.content.res.TypedArray
import android.graphics.drawable.Drawable
import android.os.Build
import android.support.annotation.ColorRes
import android.support.annotation.StringRes
import android.support.graphics.drawable.VectorDrawableCompat
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import chat.rocket.android.widget.R
import chat.rocket.android.widget.helper.DrawableHelper
/**
* Room list-item view used in sidebar.
*/
class RoomListItemView : FrameLayout {
lateinit private var roomId: String
lateinit private var roomTypeImage: ImageView
lateinit private var userStatusImage: ImageView
lateinit private var roomNameText: TextView
lateinit private var alertCountText: TextView
lateinit private var privateChannelDrawable: Drawable
lateinit private var publicChannelDrawable: Drawable
lateinit private var userStatusDrawable: Drawable
constructor(context: Context) : super(context) {
initialize(context)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initialize(context)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initialize(context)
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
initialize(context)
}
private fun initialize(context: Context) {
layoutParams = LinearLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)
val array = context
.theme
.obtainStyledAttributes(intArrayOf(R.attr.selectableItemBackground))
background = array.getDrawable(0)
array.recycle()
View.inflate(context, R.layout.room_list_item, this)
roomTypeImage = findViewById(R.id.image_room_type)
userStatusImage = findViewById(R.id.image_user_status)
roomNameText = findViewById(R.id.text_room_name)
alertCountText = findViewById(R.id.text_alert_count)
privateChannelDrawable = VectorDrawableCompat.create(resources, R.drawable.ic_lock_white_24dp, null)!!
publicChannelDrawable = VectorDrawableCompat.create(resources, R.drawable.ic_hashtag_white_24dp, null)!!
userStatusDrawable = VectorDrawableCompat.create(resources, R.drawable.ic_user_status_black_24dp, null)!!
}
fun setRoomId(roomId: String) {
this.roomId = roomId
}
fun setUnreadCount(count: Int) {
if (count > 0) {
alertCountText.text = count.toString()
alertCountText.visibility = View.VISIBLE
} else {
alertCountText.visibility = View.GONE
}
}
fun setAlert(alert: Boolean) {
alpha = if (alert) 1.0f else 0.62f
}
fun setRoomName(roomName: String) {
roomNameText.text = roomName
}
fun showPrivateChannelIcon() {
roomTypeImage.setImageDrawable(privateChannelDrawable)
userStatusImage.visibility = View.GONE
roomTypeImage.visibility = View.VISIBLE
}
fun showPublicChannelIcon() {
roomTypeImage.setImageDrawable(publicChannelDrawable)
userStatusImage.visibility = View.GONE
roomTypeImage.visibility = View.VISIBLE
}
fun showOnlineUserStatusIcon() {
prepareDrawableAndShow(R.color.color_user_status_online)
}
fun showBusyUserStatusIcon() {
prepareDrawableAndShow(R.color.color_user_status_busy)
}
fun showAwayUserStatusIcon() {
prepareDrawableAndShow(R.color.color_user_status_away)
}
fun showOfflineUserStatusIcon() {
prepareDrawableAndShow(R.color.color_user_status_offline)
}
private fun prepareDrawableAndShow(@ColorRes resId: Int) {
DrawableHelper.wrapDrawable(userStatusDrawable)
DrawableHelper.tintDrawable(userStatusDrawable, context, resId)
userStatusImage.setImageDrawable(userStatusDrawable)
roomTypeImage.visibility = View.GONE
userStatusImage.visibility = View.VISIBLE
}
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="10dp"
android:height="10dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFF44336"
android:pathData="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/badge_color" />
<size android:width="@dimen/badge_size" android:height="@dimen/badge_size"/>
android:shape="rectangle">
<solid
android:color="@color/color_alert" />
<corners
android:radius="4dp" />
</shape>
\ No newline at end of file
......@@ -2,50 +2,49 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingStart="?attr/listPreferredItemPaddingLeft"
android:paddingEnd="?attr/listPreferredItemPaddingRight"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:paddingEnd="?attr/listPreferredItemPaddingRight">
android:paddingBottom="10dp">
<FrameLayout
android:layout_width="32dp"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp">
<ImageView
android:id="@+id/image_room_type"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:visibility="gone" />
<io.github.yusukeiwaki.android.widget.FontAwesomeTextView
android:id="@+id/icon"
android:layout_width="wrap_content"
<ImageView
android:id="@+id/image_user_status"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:layout_width="10dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
</FrameLayout>
android:visibility="gone" />
<TextView
android:id="@+id/text"
android:id="@+id/text_room_name"
android:layout_width="0dp"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_weight="0.9"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" />
<FrameLayout
android:id="@+id/alert_count_container"
android:layout_width="wrap_content"
android:minWidth="20dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:padding="3dp"
android:layout_gravity="center_vertical"
android:background="@drawable/unread_count_background"
android:layout_marginLeft="8dp">
<TextView
android:id="@+id/alert_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dp"
android:layout_gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
</FrameLayout>
android:id="@+id/text_alert_count"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.1"
android:gravity="center"
android:textSize="14sp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:background="@drawable/style_alert_count"
android:visibility="gone" />
</LinearLayout>
\ No newline at end of file
......@@ -13,7 +13,7 @@
android:layout_height="10dp"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:visibility="gone"/>
android:visibility="gone" />
<ImageView
android:id="@+id/image_room_type"
......@@ -21,7 +21,7 @@
android:layout_height="24dp"
android:layout_marginRight="10dp"
android:layout_marginEnd="10dp"
android:visibility="gone"/>
android:visibility="gone" />
<TextView
android:id="@+id/text_toolbar"
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="badge_color">#FFFFFFFF</color>
<dimen name="badge_size">10dp</dimen>
</resources>
\ No newline at end of file
......@@ -7,6 +7,8 @@
<color name="color_timestamp">#FFA8A8A8</color>
<color name="color_embed_hostname">@color/color_timestamp</color>
<color name="color_alert">#FFF44336</color> <!-- Red 500-->
<!-- User status colors-->
<color name="color_user_status_online">#FF4CAF50</color> <!-- Green 500 -->
<color name="color_user_status_busy">#FFF44336</color> <!-- Red 500-->
......
package chat.rocket.core.models
class RoomSidebar {
lateinit var id: String
lateinit var roomId: String
lateinit var roomName: String
lateinit var type: String
var userStatus: String? = null
var isAlert: Boolean = false
var isFavorite: Boolean = false
var unread: Int = 0
var updateAt: Long = 0
var lastSeen: Long = 0
}
\ No newline at end of file
......@@ -11,6 +11,8 @@ public abstract class Spotlight {
public abstract String getType();
public abstract String getStatus();
public static Spotlight.Builder builder() {
return new AutoValue_Spotlight.Builder();
}
......@@ -24,6 +26,8 @@ public abstract class Spotlight {
public abstract Builder setType(String type);
public abstract Builder setStatus(String status);
public abstract Spotlight build();
}
}
\ No newline at end of file
......@@ -6,6 +6,8 @@ import chat.rocket.core.models.User
interface UserRepository {
fun getAll(): Flowable<List<User>>
fun getCurrent(): Flowable<Optional<User>>
fun getByUsername(username: String): Flowable<Optional<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