Commit 8cb36a6f authored by Tiago Cunha's avatar Tiago Cunha Committed by GitHub

Merge pull request #273 from RocketChat/feature/search-channel

TDC emergency search channel
parents 13837af2 43cbdabe
...@@ -109,6 +109,7 @@ dependencies { ...@@ -109,6 +109,7 @@ dependencies {
compile "com.jakewharton.rxbinding2:rxbinding:$rxbindingVersion" compile "com.jakewharton.rxbinding2:rxbinding:$rxbindingVersion"
compile "com.jakewharton.rxbinding2:rxbinding-support-v4:$rxbindingVersion" compile "com.jakewharton.rxbinding2:rxbinding-support-v4:$rxbindingVersion"
compile "com.jakewharton.rxbinding2:rxbinding-appcompat-v7:$rxbindingVersion"
compile "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion" compile "com.trello.rxlifecycle2:rxlifecycle:$rxlifecycleVersion"
compile "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion" compile "com.trello.rxlifecycle2:rxlifecycle-android:$rxlifecycleVersion"
......
...@@ -154,6 +154,11 @@ public class MethodCallHelper { ...@@ -154,6 +154,11 @@ public class MethodCallHelper {
.onSuccessTask(task -> Task.forResult(null)); .onSuccessTask(task -> Task.forResult(null));
} }
public Task<Void> joinRoom(String roomId) {
return call("joinRoom", TIMEOUT_MS, () -> new JSONArray().put(roomId))
.onSuccessTask(task -> Task.forResult(null));
}
/** /**
* Login with username/email and password. * Login with username/email and password.
*/ */
......
...@@ -6,6 +6,7 @@ import java.util.List; ...@@ -6,6 +6,7 @@ import java.util.List;
import chat.rocket.android.fragment.chatroom.RocketChatAbsoluteUrl; import chat.rocket.android.fragment.chatroom.RocketChatAbsoluteUrl;
import chat.rocket.android.shared.BaseContract; import chat.rocket.android.shared.BaseContract;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.SpotlightRoom;
import chat.rocket.core.models.User; import chat.rocket.core.models.User;
public interface SidebarMainContract { public interface SidebarMainContract {
...@@ -25,6 +26,8 @@ public interface SidebarMainContract { ...@@ -25,6 +26,8 @@ public interface SidebarMainContract {
void onRoomSelected(Room room); void onRoomSelected(Room room);
void onSpotlightRoomSelected(SpotlightRoom spotlightRoom);
void onUserOnline(); void onUserOnline();
void onUserAway(); void onUserAway();
......
...@@ -7,15 +7,22 @@ import android.support.annotation.Nullable; ...@@ -7,15 +7,22 @@ import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.view.View; import android.view.View;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.jakewharton.rxbinding2.support.v7.widget.RxSearchView;
import com.jakewharton.rxbinding2.widget.RxCompoundButton; import com.jakewharton.rxbinding2.widget.RxCompoundButton;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import chat.rocket.android.BuildConfig; import chat.rocket.android.BuildConfig;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.RocketChatCache; import chat.rocket.android.RocketChatCache;
...@@ -33,14 +40,17 @@ import chat.rocket.android.layouthelper.chatroom.roomlist.FavoriteRoomListHeader ...@@ -33,14 +40,17 @@ import chat.rocket.android.layouthelper.chatroom.roomlist.FavoriteRoomListHeader
import chat.rocket.android.layouthelper.chatroom.roomlist.RoomListAdapter; import chat.rocket.android.layouthelper.chatroom.roomlist.RoomListAdapter;
import chat.rocket.android.layouthelper.chatroom.roomlist.RoomListHeader; import chat.rocket.android.layouthelper.chatroom.roomlist.RoomListHeader;
import chat.rocket.android.layouthelper.chatroom.roomlist.UnreadRoomListHeader; import chat.rocket.android.layouthelper.chatroom.roomlist.UnreadRoomListHeader;
import chat.rocket.core.SortDirection;
import chat.rocket.core.interactors.RoomInteractor; import chat.rocket.core.interactors.RoomInteractor;
import chat.rocket.core.interactors.SessionInteractor; import chat.rocket.core.interactors.SessionInteractor;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.SpotlightRoom;
import chat.rocket.core.models.User; import chat.rocket.core.models.User;
import chat.rocket.android.renderer.UserRenderer; import chat.rocket.android.renderer.UserRenderer;
import chat.rocket.persistence.realm.repositories.RealmRoomRepository; import chat.rocket.persistence.realm.repositories.RealmRoomRepository;
import chat.rocket.persistence.realm.repositories.RealmServerInfoRepository; import chat.rocket.persistence.realm.repositories.RealmServerInfoRepository;
import chat.rocket.persistence.realm.repositories.RealmSessionRepository; import chat.rocket.persistence.realm.repositories.RealmSessionRepository;
import chat.rocket.persistence.realm.repositories.RealmSpotlightRoomRepository;
import chat.rocket.persistence.realm.repositories.RealmUserRepository; import chat.rocket.persistence.realm.repositories.RealmUserRepository;
import chat.rocket.android.widget.RocketChatAvatar; import chat.rocket.android.widget.RocketChatAvatar;
...@@ -54,6 +64,10 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -54,6 +64,10 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
private String hostname; private String hostname;
private MethodCallHelper methodCallHelper;
private RealmSpotlightRoomRepository realmSpotlightRoomRepository;
private SearchView searchView;
public SidebarMainFragment() { public SidebarMainFragment() {
} }
...@@ -77,6 +91,9 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -77,6 +91,9 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
Bundle args = getArguments(); Bundle args = getArguments();
hostname = args == null ? null : args.getString(HOSTNAME); hostname = args == null ? null : args.getString(HOSTNAME);
methodCallHelper = new MethodCallHelper(getContext(), hostname);
realmSpotlightRoomRepository = new RealmSpotlightRoomRepository(hostname);
RealmUserRepository userRepository = new RealmUserRepository(hostname); RealmUserRepository userRepository = new RealmUserRepository(hostname);
AbsoluteUrlHelper absoluteUrlHelper = new AbsoluteUrlHelper( AbsoluteUrlHelper absoluteUrlHelper = new AbsoluteUrlHelper(
...@@ -113,6 +130,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -113,6 +130,7 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
return R.layout.fragment_sidebar_main; return R.layout.fragment_sidebar_main;
} }
@SuppressLint("RxLeakedSubscription")
@Override @Override
protected void onSetupView() { protected void onSetupView() {
setupUserActionToggle(); setupUserActionToggle();
...@@ -121,12 +139,55 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -121,12 +139,55 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
setupVersionInfo(); setupVersionInfo();
adapter = new RoomListAdapter(); adapter = new RoomListAdapter();
adapter.setOnItemClickListener(room -> presenter.onRoomSelected(room)); adapter.setOnItemClickListener(new RoomListAdapter.OnItemClickListener() {
@Override
public void onItemClick(Room room) {
searchView.clearFocus();
presenter.onRoomSelected(room);
}
@Override
public void onItemClick(SpotlightRoom spotlightRoom) {
searchView.setQuery(null, false);
searchView.clearFocus();
methodCallHelper.joinRoom(spotlightRoom.getId())
.onSuccessTask(task -> {
presenter.onSpotlightRoomSelected(spotlightRoom);
return null;
});
}
});
RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.room_list_container); RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.room_list_container);
recyclerView.setLayoutManager( recyclerView.setLayoutManager(
new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
searchView = (SearchView) rootView.findViewById(R.id.search);
RxSearchView.queryTextChanges(searchView)
.compose(bindToLifecycle())
.debounce(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.switchMap(it -> {
if (it.length() == 0) {
adapter.setMode(RoomListAdapter.MODE_ROOM);
return Observable.just(Collections.<SpotlightRoom>emptyList());
}
adapter.setMode(RoomListAdapter.MODE_SPOTLIGHT_ROOM);
final String queryString = it.toString();
methodCallHelper.searchSpotlightRooms(queryString);
return realmSpotlightRoomRepository.getSuggestionsFor(queryString, SortDirection.DESC, 10)
.toObservable();
})
.subscribe(
this::showSearchSuggestions,
Logger::report
);
} }
@SuppressLint("RxLeakedSubscription") @SuppressLint("RxLeakedSubscription")
...@@ -246,4 +307,8 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain ...@@ -246,4 +307,8 @@ public class SidebarMainFragment extends AbstractFragment implements SidebarMain
onRenderCurrentUser(user, absoluteUrl); onRenderCurrentUser(user, absoluteUrl);
updateRoomListMode(user); updateRoomListMode(user);
} }
private void showSearchSuggestions(List<SpotlightRoom> spotlightRooms) {
adapter.setSpotlightRoomList(spotlightRooms);
}
} }
...@@ -17,6 +17,7 @@ import chat.rocket.android.helper.TextUtils; ...@@ -17,6 +17,7 @@ import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.shared.BasePresenter; import chat.rocket.android.shared.BasePresenter;
import chat.rocket.core.interactors.RoomInteractor; import chat.rocket.core.interactors.RoomInteractor;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.SpotlightRoom;
import chat.rocket.core.models.User; import chat.rocket.core.models.User;
import chat.rocket.core.repositories.UserRepository; import chat.rocket.core.repositories.UserRepository;
...@@ -76,6 +77,11 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View ...@@ -76,6 +77,11 @@ public class SidebarMainPresenter extends BasePresenter<SidebarMainContract.View
rocketChatCache.setSelectedRoomId(room.getRoomId()); rocketChatCache.setSelectedRoomId(room.getRoomId());
} }
@Override
public void onSpotlightRoomSelected(SpotlightRoom spotlightRoom) {
rocketChatCache.setSelectedRoomId(spotlightRoom.getId());
}
@Override @Override
public void onUserOnline() { public void onUserOnline() {
updateCurrentUserStatus(User.STATUS_ONLINE); updateCurrentUserStatus(User.STATUS_ONLINE);
......
...@@ -12,21 +12,38 @@ import java.util.Map; ...@@ -12,21 +12,38 @@ import java.util.Map;
import chat.rocket.android.R; import chat.rocket.android.R;
import chat.rocket.android.widget.internal.RoomListItemView; import chat.rocket.android.widget.internal.RoomListItemView;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.SpotlightRoom;
public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int MODE_ROOM = 0;
public static final int MODE_SPOTLIGHT_ROOM = 1;
private static final int VIEW_TYPE_HEADER = 0; private static final int VIEW_TYPE_HEADER = 0;
private static final int VIEW_TYPE_ROOM = 1; private static final int VIEW_TYPE_ROOM = 1;
private List<Room> roomList = Collections.emptyList(); private List<Room> roomList = Collections.emptyList();
private List<SpotlightRoom> spotlightRoomList = Collections.emptyList();
private List<RoomListHeader> roomListHeaders = Collections.emptyList(); private List<RoomListHeader> roomListHeaders = Collections.emptyList();
private Map<Integer, RoomListHeader> headersPosition = new HashMap<>(); private Map<Integer, RoomListHeader> headersPosition = new HashMap<>();
private int mode = MODE_ROOM;
private OnItemClickListener externalListener; private OnItemClickListener externalListener;
private OnItemClickListener listener = room -> { private OnItemClickListener listener = new OnItemClickListener() {
@Override
public void onItemClick(Room room) {
if (externalListener != null) { if (externalListener != null) {
externalListener.onItemClick(room); externalListener.onItemClick(room);
} }
}
@Override
public void onItemClick(SpotlightRoom spotlightRoom) {
if (externalListener != null) {
externalListener.onItemClick(spotlightRoom);
}
}
}; };
public void setRoomListHeaders(@NonNull List<RoomListHeader> roomListHeaders) { public void setRoomListHeaders(@NonNull List<RoomListHeader> roomListHeaders) {
...@@ -39,6 +56,20 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde ...@@ -39,6 +56,20 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
updateRoomList(); updateRoomList();
} }
public void setSpotlightRoomList(@NonNull List<SpotlightRoom> spotlightRoomList) {
this.spotlightRoomList = spotlightRoomList;
updateRoomList();
}
public void setMode(int mode) {
this.mode = mode;
if (mode == MODE_ROOM) {
// clean up
spotlightRoomList.clear();
}
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) { public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
externalListener = onItemClickListener; externalListener = onItemClickListener;
} }
...@@ -56,6 +87,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde ...@@ -56,6 +87,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
@Override @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (mode == MODE_ROOM) {
if (getItemViewType(position) == VIEW_TYPE_HEADER) { if (getItemViewType(position) == VIEW_TYPE_HEADER) {
((RoomListHeaderViewHolder) holder) ((RoomListHeaderViewHolder) holder)
.bind(headersPosition.get(position)); .bind(headersPosition.get(position));
...@@ -64,15 +96,26 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde ...@@ -64,15 +96,26 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
((RoomListItemViewHolder) holder) ((RoomListItemViewHolder) holder)
.bind(roomList.get(position - getTotalHeadersBeforePosition(position))); .bind(roomList.get(position - getTotalHeadersBeforePosition(position)));
} else if (mode == MODE_SPOTLIGHT_ROOM) {
((RoomListItemViewHolder) holder)
.bind(spotlightRoomList.get(position));
}
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
if (mode == MODE_SPOTLIGHT_ROOM) {
return spotlightRoomList.size();
}
return roomList.size() + headersPosition.size(); return roomList.size() + headersPosition.size();
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (mode == MODE_SPOTLIGHT_ROOM) {
return VIEW_TYPE_ROOM;
}
if (headersPosition.containsKey(position)) { if (headersPosition.containsKey(position)) {
return VIEW_TYPE_HEADER; return VIEW_TYPE_HEADER;
} }
...@@ -80,8 +123,10 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde ...@@ -80,8 +123,10 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
} }
private void updateRoomList() { private void updateRoomList() {
if (mode == MODE_ROOM) {
sortRoomList(); sortRoomList();
calculateHeadersPosition(); calculateHeadersPosition();
}
notifyDataSetChanged(); notifyDataSetChanged();
} }
...@@ -142,5 +187,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde ...@@ -142,5 +187,7 @@ public class RoomListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
public interface OnItemClickListener { public interface OnItemClickListener {
void onItemClick(Room room); void onItemClick(Room room);
void onItemClick(SpotlightRoom spotlightRoom);
} }
} }
...@@ -4,6 +4,7 @@ import android.support.v7.widget.RecyclerView; ...@@ -4,6 +4,7 @@ import android.support.v7.widget.RecyclerView;
import chat.rocket.android.widget.internal.RoomListItemView; import chat.rocket.android.widget.internal.RoomListItemView;
import chat.rocket.core.models.Room; import chat.rocket.core.models.Room;
import chat.rocket.core.models.SpotlightRoom;
public class RoomListItemViewHolder extends RecyclerView.ViewHolder { public class RoomListItemViewHolder extends RecyclerView.ViewHolder {
public RoomListItemViewHolder(RoomListItemView itemView, public RoomListItemViewHolder(RoomListItemView itemView,
...@@ -12,7 +13,13 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder { ...@@ -12,7 +13,13 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder {
itemView.setOnClickListener(view -> { itemView.setOnClickListener(view -> {
if (listener != null) { if (listener != null) {
Object tag = view.getTag();
if (tag instanceof Room) {
listener.onItemClick((Room) view.getTag()); listener.onItemClick((Room) view.getTag());
} else if (tag instanceof SpotlightRoom) {
listener.onItemClick((SpotlightRoom) view.getTag());
}
} }
}); });
} }
...@@ -26,4 +33,14 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder { ...@@ -26,4 +33,14 @@ public class RoomListItemViewHolder extends RecyclerView.ViewHolder {
.setUnreadCount(room.getUnread()) .setUnreadCount(room.getUnread())
.setTag(room); .setTag(room);
} }
public void bind(SpotlightRoom spotlightRoom) {
((RoomListItemView) itemView)
.setRoomId(spotlightRoom.getId())
.setRoomName(spotlightRoom.getName())
.setRoomType(spotlightRoom.getType())
.setAlert(false)
.setUnreadCount(0)
.setTag(spotlightRoom);
}
} }
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:theme="@style/AppTheme.Dark" android:theme="@style/AppTheme.Dark"
...@@ -55,11 +56,35 @@ ...@@ -55,11 +56,35 @@
</LinearLayout> </LinearLayout>
<FrameLayout
android:id="@+id/search_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/margin_8"
android:paddingTop="@dimen/margin_8"
android:elevation="2dp"
android:layout_below="@+id/user_info_container"
android:background="?attr/colorPrimaryDark">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:focusableInTouchMode="true"
android:focusable="true" />
<android.support.v7.widget.SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:queryHint="@string/navigation_search_rooms"
app:iconifiedByDefault="false" />
</FrameLayout>
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:id="@+id/room_list_container" android:id="@+id/room_list_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@+id/user_info_container" android:layout_below="@+id/search_box"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="?attr/colorPrimary" /> android:background="?attr/colorPrimary" />
......
...@@ -50,4 +50,5 @@ ...@@ -50,4 +50,5 @@
<string name="two_factor_authentication_title">Two-factor authentication</string> <string name="two_factor_authentication_title">Two-factor authentication</string>
<string name="open_your_authentication_app_and_enter_the_code">Open your authentication app and enter the code</string> <string name="open_your_authentication_app_and_enter_the_code">Open your authentication app and enter the code</string>
<string name="two_factor_code">Two-factor code</string> <string name="two_factor_code">Two-factor code</string>
<string name="navigation_search_rooms">Search Rooms</string>
</resources> </resources>
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