Commit 0586deb6 authored by Yusuke Iwaki's avatar Yusuke Iwaki

FIX #60 implement getUsersOfRoom

parent 4a29236c
......@@ -273,4 +273,9 @@ public class MethodCallHelper {
.onSuccessTask(task -> Task.forResult(null));
}
public Task<JSONObject> getUsersOfRoom(final String roomId, final boolean showAll) {
return call("getUsersOfRoom", TIMEOUT_MS, () -> new JSONArray().put(roomId).put(showAll))
.onSuccessTask(CONVERT_TO_JSON_OBJECT);
}
}
......@@ -8,8 +8,8 @@ import android.support.v4.widget.SlidingPaneLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;
import chat.rocket.android.R;
import chat.rocket.android.fragment.chatroom.dialog.UsersOfRoomDialogFragment;
import chat.rocket.android.helper.LoadMoreScrollListener;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.helper.OnBackPressListener;
......@@ -34,6 +34,7 @@ import timber.log.Timber;
*/
public class RoomFragment extends AbstractChatRoomFragment implements OnBackPressListener {
private String serverConfigId;
private RealmHelper realmHelper;
private String roomId;
private RealmObjectObserver<RoomSubscription> roomObserver;
......@@ -60,7 +61,7 @@ public class RoomFragment extends AbstractChatRoomFragment implements OnBackPres
super.onCreate(savedInstanceState);
Bundle args = getArguments();
String serverConfigId = args.getString("serverConfigId");
serverConfigId = args.getString("serverConfigId");
realmHelper = RealmStore.get(serverConfigId);
roomId = args.getString("roomId");
hostname = RealmStore.getDefault().executeTransactionForRead(realm ->
......@@ -111,7 +112,8 @@ public class RoomFragment extends AbstractChatRoomFragment implements OnBackPres
private void setupSideMenu() {
View sidemenu = rootView.findViewById(R.id.room_side_menu);
sidemenu.findViewById(R.id.btn_users).setOnClickListener(view -> {
Toast.makeText(view.getContext(), "not implemented yet.", Toast.LENGTH_SHORT).show();
UsersOfRoomDialogFragment.create(serverConfigId, roomId, hostname)
.show(getFragmentManager(), UsersOfRoomDialogFragment.class.getSimpleName());
closeSideMenuIfNeeded();
});
......
package chat.rocket.android.fragment.chatroom.dialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetDialogFragment;
import chat.rocket.android.realm_helper.RealmHelper;
import chat.rocket.android.realm_helper.RealmStore;
abstract class AbstractChatroomDialogFragment extends BottomSheetDialogFragment {
protected RealmHelper realmHelper;
protected String roomId;
protected @LayoutRes abstract int getLayout();
protected abstract void onSetupDialog();
@Override public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
handleArgs(args);
}
}
protected void handleArgs(@NonNull Bundle args) {
String serverConfigId = args.getString("serverConfigId");
realmHelper = RealmStore.get(serverConfigId);
roomId = args.getString("roomId");
}
@Override public final void setupDialog(Dialog dialog, int style) {
super.setupDialog(dialog, style);
dialog.setContentView(getLayout());
onSetupDialog();
}
}
package chat.rocket.android.fragment.chatroom.dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import chat.rocket.android.R;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.layouthelper.chatroom.dialog.RoomUserAdapter;
import chat.rocket.android.model.SyncState;
import chat.rocket.android.model.internal.GetUsersOfRoomsProcedure;
import chat.rocket.android.realm_helper.RealmObjectObserver;
import chat.rocket.android.service.RocketChatService;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import timber.log.Timber;
/**
* Dialog to show members in a room.
*/
public class UsersOfRoomDialogFragment extends AbstractChatroomDialogFragment {
private String hostname;
private RealmObjectObserver<GetUsersOfRoomsProcedure> procedureObserver;
private int previousSyncState;
public UsersOfRoomDialogFragment() {}
/**
* create UsersOfRoomDialogFragment with required parameters.
*/
public static UsersOfRoomDialogFragment create(String serverConfigId,
String roomId, String hostname) {
Bundle args = new Bundle();
args.putString("serverConfigId", serverConfigId);
args.putString("roomId", roomId);
args.putString("hostname", hostname);
UsersOfRoomDialogFragment fragment = new UsersOfRoomDialogFragment();
fragment.setArguments(args);
return fragment;
}
@Override public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
procedureObserver = realmHelper
.createObjectObserver(realm ->
realm.where(GetUsersOfRoomsProcedure.class).equalTo("roomId", roomId))
.setOnUpdateListener(this::onUpdateGetUsersOfRoomProcedure);
previousSyncState = SyncState.NOT_SYNCED;
if (savedInstanceState == null) {
requestGetUsersOfRoom();
}
}
@Override protected void handleArgs(@NonNull Bundle args) {
super.handleArgs(args);
hostname = args.getString("hostname");
}
@Override protected int getLayout() {
return R.layout.dialog_users_of_room;
}
@Override protected void onSetupDialog() {
RecyclerView recyclerView = (RecyclerView) getDialog().findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
recyclerView.setAdapter(new RoomUserAdapter(getContext(), realmHelper, hostname));
}
private void requestGetUsersOfRoom() {
realmHelper.executeTransaction(realm -> {
realm.createOrUpdateObjectFromJson(GetUsersOfRoomsProcedure.class, new JSONObject()
.put("roomId", roomId)
.put("syncstate", SyncState.NOT_SYNCED)
.put("showAll", true));
return null;
}).onSuccessTask(task -> {
RocketChatService.keepalive(getContext());
return task;
}).continueWith(new LogcatIfError());
}
@Override public void onResume() {
super.onResume();
procedureObserver.sub();
}
@Override public void onPause() {
procedureObserver.unsub();
super.onPause();
}
private void onUpdateGetUsersOfRoomProcedure(GetUsersOfRoomsProcedure procedure) {
if (procedure == null) {
return;
}
int syncstate = procedure.getSyncstate();
if (previousSyncState != syncstate) {
onSyncStateUpdated(syncstate);
previousSyncState = syncstate;
}
if (syncstate == SyncState.SYNCED) {
onRenderTotalCount(procedure.getTotal());
try {
JSONArray array = new JSONArray(procedure.getRecords());
ArrayList<String> users = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
users.add(array.getString(i));
}
onRenderUsers(users);
} catch (JSONException exception) {
Timber.e(exception);
}
}
}
/**
* called only if prevSyncstate != newSyncstate.
*/
private void onSyncStateUpdated(int newSyncstate) {
boolean show = newSyncstate == SyncState.NOT_SYNCED || newSyncstate == SyncState.SYNCING;
getDialog().findViewById(R.id.waiting).setVisibility(show ? View.VISIBLE : View.GONE);
}
/**
* called only if syncstate = SYNCED.
*/
private void onRenderTotalCount(long total) {
TextView userCount = (TextView) getDialog().findViewById(R.id.room_user_count);
userCount.setText(getString(R.string.fmt_room_user_count, total));
}
/**
* called only if syncstate = SYNCED.
*/
private void onRenderUsers(List<String> usernames) {
RecyclerView recyclerView = (RecyclerView) getDialog().findViewById(R.id.recyclerview);
if (recyclerView != null && recyclerView.getAdapter() instanceof RoomUserAdapter) {
((RoomUserAdapter) recyclerView.getAdapter()).setUsernames(usernames);
}
}
}
package chat.rocket.android.layouthelper.chatroom.dialog;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import chat.rocket.android.R;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.model.ddp.User;
import chat.rocket.android.realm_helper.RealmHelper;
import chat.rocket.android.renderer.UserRenderer;
import java.util.List;
/**
*/
public class RoomUserAdapter extends RecyclerView.Adapter<RoomUserViewHolder> {
private final Context context;
private final LayoutInflater inflater;
private final RealmHelper realmHelper;
private final String hostname;
private List<String> usernames;
public RoomUserAdapter(Context context, RealmHelper realmHelper, String hostname) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.realmHelper = realmHelper;
this.hostname = hostname;
}
@Override public RoomUserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = inflater.inflate(R.layout.listitem_room_user, parent, false);
return new RoomUserViewHolder(itemView);
}
@Override public void onBindViewHolder(RoomUserViewHolder holder, int position) {
String username = usernames.get(position);
if (TextUtils.isEmpty(username)) {
return;
}
User user = realmHelper.executeTransactionForRead(realm ->
realm.where(User.class).equalTo("username", username).findFirst());
if (user == null) {
user = new User();
user.setUsername(username);
new UserRenderer(context, user)
.avatarInto(holder.avatar, hostname)
.usernameInto(holder.username);
} else {
new UserRenderer(context, user)
.statusColorInto(holder.status)
.avatarInto(holder.avatar, hostname)
.usernameInto(holder.username);
}
}
@Override public int getItemCount() {
return usernames != null ? usernames.size() : 0;
}
public void setUsernames(List<String> usernames) {
this.usernames = usernames;
notifyDataSetChanged();
}
}
package chat.rocket.android.layouthelper.chatroom.dialog;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import chat.rocket.android.R;
/**
* ViewHolder for UsersOfRoom.
*/
public class RoomUserViewHolder extends RecyclerView.ViewHolder {
ImageView status;
ImageView avatar;
TextView username;
public RoomUserViewHolder(View itemView) {
super(itemView);
status = (ImageView) itemView.findViewById(R.id.room_user_status);
avatar = (ImageView) itemView.findViewById(R.id.room_user_avatar);
username = (TextView) itemView.findViewById(R.id.room_user_name);
}
}
package chat.rocket.android.model.internal;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
/**
* Get users in a Room.
*/
public class GetUsersOfRoomsProcedure extends RealmObject {
@PrimaryKey private String roomId;
private int syncstate;
private boolean showAll;
private long total;
private String records;
public String getRoomId() {
return roomId;
}
public void setRoomId(String roomId) {
this.roomId = roomId;
}
public int getSyncstate() {
return syncstate;
}
public void setSyncstate(int syncstate) {
this.syncstate = syncstate;
}
public boolean isShowAll() {
return showAll;
}
public void setShowAll(boolean showAll) {
this.showAll = showAll;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public String getRecords() {
return records;
}
public void setRecords(String records) {
this.records = records;
}
}
......@@ -6,6 +6,7 @@ import android.os.HandlerThread;
import bolts.Continuation;
import bolts.Task;
import bolts.TaskCompletionSource;
import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.model.ServerConfig;
......@@ -14,11 +15,11 @@ import chat.rocket.android.realm_helper.RealmHelper;
import chat.rocket.android.realm_helper.RealmStore;
import chat.rocket.android.service.ddp.ActiveUsersSubscriber;
import chat.rocket.android.service.ddp.LoginServiceConfigurationSubscriber;
import chat.rocket.android.service.observer.GetUsersOfRoomsProcedureObserver;
import chat.rocket.android.service.observer.LoadMessageProcedureObserver;
import chat.rocket.android.service.observer.MethodCallObserver;
import chat.rocket.android.service.observer.SessionObserver;
import chat.rocket.android.service.observer.TokenLoginObserver;
import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android_ddp.DDPClientCallback;
import hugo.weaving.DebugLog;
import java.lang.reflect.Constructor;
......@@ -37,7 +38,8 @@ public class RocketChatWebSocketThread extends HandlerThread {
TokenLoginObserver.class,
MethodCallObserver.class,
SessionObserver.class,
LoadMessageProcedureObserver.class
LoadMessageProcedureObserver.class,
GetUsersOfRoomsProcedureObserver.class
};
private final Context appContext;
private final String serverConfigId;
......
package chat.rocket.android.service.observer;
import android.content.Context;
import bolts.Task;
import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.model.SyncState;
import chat.rocket.android.model.internal.GetUsersOfRoomsProcedure;
import chat.rocket.android.realm_helper.RealmHelper;
import io.realm.Realm;
import io.realm.RealmResults;
import java.util.List;
import org.json.JSONObject;
import timber.log.Timber;
/**
*/
public class GetUsersOfRoomsProcedureObserver extends AbstractModelObserver<GetUsersOfRoomsProcedure> {
private final MethodCallHelper methodCall;
public GetUsersOfRoomsProcedureObserver(Context context, RealmHelper realmHelper,
DDPClientWraper ddpClient) {
super(context, realmHelper, ddpClient);
methodCall = new MethodCallHelper(realmHelper, ddpClient);
}
@Override public RealmResults<GetUsersOfRoomsProcedure> queryItems(Realm realm) {
return realm.where(GetUsersOfRoomsProcedure.class)
.equalTo("syncstate", SyncState.NOT_SYNCED)
.findAll();
}
@Override public void onUpdateResults(List<GetUsersOfRoomsProcedure> results) {
if (results == null || results.isEmpty()) {
return;
}
GetUsersOfRoomsProcedure procedure = results.get(0);
final String roomId = procedure.getRoomId();
final boolean showAll = procedure.isShowAll();
realmHelper.executeTransaction(realm ->
realm.createOrUpdateObjectFromJson(GetUsersOfRoomsProcedure.class, new JSONObject()
.put("roomId", roomId)
.put("syncstate", SyncState.SYNCING))
).onSuccessTask(task ->
methodCall.getUsersOfRoom(roomId, showAll)
.onSuccessTask(_task -> {
JSONObject result = _task.getResult()
.put("roomId", roomId)
.put("syncstate", SyncState.SYNCED);
return realmHelper.executeTransaction(realm ->
realm.createOrUpdateObjectFromJson(GetUsersOfRoomsProcedure.class, result));
})
).continueWithTask(task -> {
if (task.isFaulted()) {
Timber.w(task.getError());
return realmHelper.executeTransaction(realm ->
realm.createOrUpdateObjectFromJson(GetUsersOfRoomsProcedure.class, new JSONObject()
.put("roomId", roomId)
.put("syncstate", SyncState.FAILED)));
} else {
return Task.forResult(null);
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<FrameLayout
android:id="@+id/room_user_titlebar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:paddingStart="@dimen/margin_16"
android:paddingRight="@dimen/margin_16"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/users_of_room_title"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:layout_gravity="start|center_vertical"/>
<TextView
android:id="@+id/room_user_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:layout_gravity="end|center_vertical"/>
</FrameLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<chat.rocket.android.widget.WaitingView
android:id="@+id/waiting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:gravity="center_vertical">
<ImageView
android:id="@+id/room_user_status"
android:layout_width="8dp"
android:layout_height="8dp"
android:layout_margin="@dimen/margin_8"/>
<ImageView
android:id="@+id/room_user_avatar"
android:layout_width="24dp"
android:layout_height="24dp" />
<TextView
android:id="@+id/room_user_name"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/margin_8"
android:layout_marginRight="@dimen/margin_8"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
\ No newline at end of file
......@@ -9,4 +9,6 @@
<string name="fragment_sidebar_main_logout_title">Logout</string>
<string name="start_of_conversation">Start of conversation</string>
<string name="users_of_room_title">Members List</string>
<string name="fmt_room_user_count">Total: %,d users</string>
</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