Skip to content
This repository was archived by the owner on Jul 25, 2024. It is now read-only.

Commit 06f0604

Browse files
committed
Sorted people list in people drawer.
Sort people list in order of active, recent private messages and then offline.
1 parent b596202 commit 06f0604

File tree

20 files changed

+764
-198
lines changed

20 files changed

+764
-198
lines changed

app/src/main/java/com/zulip/android/ZulipApp.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.zulip.android.models.Person;
3434
import com.zulip.android.models.Presence;
3535
import com.zulip.android.models.Stream;
36+
import com.zulip.android.models.PeopleDrawerList;
3637
import com.zulip.android.networking.AsyncUnreadMessagesUpdate;
3738
import com.zulip.android.networking.ZulipInterceptor;
3839
import com.zulip.android.networking.response.UserConfigurationResponse;
@@ -89,6 +90,11 @@ public class ZulipApp extends Application {
8990
* every couple of seconds
9091
*/
9192
public final Queue<Integer> unreadMessageQueue = new ConcurrentLinkedQueue<>();
93+
/**
94+
* Map of recent PM person with their email
95+
* Updated when new private message is arrived
96+
*/
97+
public final Map<String,PeopleDrawerList> recentPMPersons = new ConcurrentHashMap<>();
9298
// This object's intrinsic lock is used to prevent multiple threads from
9399
// making conflicting updates to ranges
94100
public Object updateRangeLock = new Object();
@@ -408,7 +414,7 @@ public void logOut() {
408414
ed.apply();
409415
this.api_key = null;
410416
setEventQueueId(null);
411-
417+
recentPMPersons.clear();
412418
new GoogleAuthHelper().logOutGoogleAuth();
413419
}
414420

app/src/main/java/com/zulip/android/activities/MessageListFragment.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.zulip.android.filters.NarrowFilterStream;
3636
import com.zulip.android.filters.NarrowListener;
3737
import com.zulip.android.models.Message;
38+
import com.zulip.android.models.MessageType;
3839
import com.zulip.android.models.Person;
3940
import com.zulip.android.models.Stream;
4041
import com.zulip.android.networking.AsyncGetOldMessages;
@@ -647,6 +648,7 @@ public void onMessages(Message[] messages, LoadPosition pos,
647648
return;
648649
}
649650

651+
boolean isNewPM = false;
650652
for (int i = 0; i < messages.length; i++) {
651653
Message message = messages[i];
652654

@@ -688,6 +690,14 @@ public void onMessages(Message[] messages, LoadPosition pos,
688690
if (message.getID() < firstMessageId || firstMessageId == -1) {
689691
firstMessageId = message.getID();
690692
}
693+
694+
if (!isNewPM && message.getType() == MessageType.PRIVATE_MESSAGE) {
695+
isNewPM = true;
696+
}
697+
}
698+
699+
if (isNewPM) {
700+
app.getZulipActivity().updateRecentPMHashMap();
691701
}
692702

693703
if (pos == LoadPosition.ABOVE) {
Lines changed: 144 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,163 @@
11
package com.zulip.android.activities;
22

33
import android.content.Context;
4-
import android.database.Cursor;
5-
import android.database.MatrixCursor;
6-
import android.support.v4.widget.SimpleCursorAdapter;
4+
import android.support.v7.widget.RecyclerView;
5+
import android.view.LayoutInflater;
6+
import android.view.View;
7+
import android.view.ViewGroup;
8+
import android.widget.TextView;
79

8-
import com.zulip.android.networking.AsyncCursorAdapterUpdater;
10+
import com.zulip.android.R;
11+
import com.zulip.android.ZulipApp;
12+
import com.zulip.android.models.PeopleDrawerList;
13+
import com.zulip.android.models.Presence;
14+
import com.zulip.android.models.PresenceType;
15+
import com.zulip.android.util.Constants;
16+
import com.zulip.android.viewholders.floatingRecyclerViewLables.FloatingHeaderAdapter;
17+
import com.zulip.android.viewholders.floatingRecyclerViewLables.FloatingHeaderDecoration;
918

10-
import java.util.concurrent.Callable;
19+
import java.util.List;
1120

1221
/**
1322
* An adapter that can be refreshed by any object that has a reference to it.
1423
* <p/>
1524
* This is useful when you don't want to have to encode knowledge of how to
1625
* refresh an adapter into any function that might want to do so.
1726
*/
18-
public class RefreshableCursorAdapter extends SimpleCursorAdapter {
27+
public abstract class RefreshableCursorAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
28+
implements FloatingHeaderAdapter<RefreshableCursorAdapter.HeaderHolder> {
1929

20-
private Callable<Cursor> cursorGenerator;
30+
private List<PeopleDrawerList> mList;
31+
private Context mContext;
32+
private ZulipApp mApp;
2133

22-
public RefreshableCursorAdapter(Context context, int layout,
23-
Cursor initialCursor, Callable<Cursor> cursorGenerator,
24-
String[] from, int[] to, int flags) {
25-
super(context, layout, initialCursor, from, to, flags);
26-
this.cursorGenerator = cursorGenerator;
34+
protected abstract void onPeopleSelect(int id);
35+
36+
RefreshableCursorAdapter(Context context, List<PeopleDrawerList> list, ZulipApp app) {
37+
this.mList = list;
38+
this.mContext = context;
39+
this.mApp = app;
40+
}
41+
42+
void filterList(List<PeopleDrawerList> list) {
43+
this.mList = list;
44+
notifyDataSetChanged();
45+
}
46+
47+
@Override
48+
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
49+
View view = LayoutInflater.from(mContext).inflate(R.layout.stream_tile, parent, false);
50+
return new TileHolder(view);
51+
}
52+
53+
@Override
54+
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
55+
if (holder instanceof TileHolder) {
56+
TileHolder tileHolder = (TileHolder) holder;
57+
if (position == 0) {
58+
//All Private message
59+
tileHolder.tvName.setText(R.string.all_private_messages);
60+
tileHolder.ivDot.setVisibility(View.VISIBLE);
61+
tileHolder.ivDot.setBackgroundResource(R.drawable.ic_email_black_24dp);
62+
holder.itemView.setOnClickListener(new View.OnClickListener() {
63+
@Override
64+
public void onClick(View v) {
65+
onPeopleSelect(Constants.ALL_PEOPLE_ID);
66+
}
67+
});
68+
return;
69+
}
70+
position = tileHolder.getLayoutPosition() - 1;
71+
tileHolder.tvName.setText(mList.get(position).getPerson().getName());
72+
//app is passed as parameter from ZulipActivity
73+
//presence of all persons are in ZulipApp
74+
//if ZulipApp==null then presence can't be accessed
75+
if (mApp == null || mList.get(position).getPerson().getEmail() == null) {
76+
tileHolder.ivDot.setVisibility(View.VISIBLE);
77+
tileHolder.ivDot.setBackgroundResource(R.drawable.presence_inactive);
78+
} else {
79+
Presence presence = mApp.presences.get(mList.get(position).getPerson().getEmail());
80+
if (presence == null) {
81+
tileHolder.ivDot.setVisibility(View.VISIBLE);
82+
tileHolder.ivDot.setBackgroundResource(R.drawable.presence_inactive);
83+
} else {
84+
PresenceType status = presence.getStatus();
85+
long age = presence.getAge();
86+
if (age > Constants.INACTIVE_TIME_OUT) {
87+
//person is inactive
88+
//show empty circle with stroke
89+
tileHolder.ivDot.setVisibility(View.VISIBLE);
90+
tileHolder.ivDot.setBackgroundResource(R.drawable.presence_inactive);
91+
} else if (PresenceType.ACTIVE == status) {
92+
//person is active
93+
//show green circle
94+
tileHolder.ivDot.setVisibility(View.VISIBLE);
95+
tileHolder.ivDot.setBackgroundResource(R.drawable.presence_active);
96+
} else if (PresenceType.IDLE == status) {
97+
//person is away
98+
//show orange circle
99+
tileHolder.ivDot.setVisibility(View.VISIBLE);
100+
tileHolder.ivDot.setBackgroundResource(R.drawable.presence_away);
101+
} else {
102+
//can't determine state of person
103+
//show as inactive
104+
tileHolder.ivDot.setVisibility(View.VISIBLE);
105+
tileHolder.ivDot.setBackgroundResource(R.drawable.presence_inactive);
106+
}
107+
}
108+
}
109+
final int finalPosition = position;
110+
holder.itemView.setOnClickListener(new View.OnClickListener() {
111+
@Override
112+
public void onClick(View v) {
113+
onPeopleSelect(mList.get(finalPosition).getPerson().getId());
114+
}
115+
});
116+
}
117+
}
118+
119+
@Override
120+
public int getItemCount() {
121+
return mList.size() + 1;
122+
}
123+
124+
@Override
125+
public long getHeaderId(int position) {
126+
if (position == 0)
127+
return FloatingHeaderDecoration.NO_HEADER_ID;
128+
return (long) mList.get(position - 1).getGroupId();
129+
}
130+
131+
@Override
132+
public HeaderHolder onCreateHeaderViewHolder(ViewGroup parent) {
133+
View view = LayoutInflater.from(mContext).inflate(R.layout.people_drawer_heading, parent, false);
134+
return new HeaderHolder(view);
135+
}
136+
137+
@Override
138+
public void onBindHeaderViewHolder(HeaderHolder headerHolder, int position) {
139+
headerHolder.tvHeading.setText(mList.get(position - 1).getGroupName());
27140
}
28141

29-
/**
30-
* Asynchronously updates the CursorAdapter
31-
* <p/>
32-
* Immediately on invocation, the CursorAdapter is blanked. It is updated
33-
* once the refresh completes.
34-
*/
35-
public void refresh() {
36-
this.changeCursor(new MatrixCursor(this.getCursor().getColumnNames()));
37-
this.notifyDataSetChanged();
38-
(new AsyncCursorAdapterUpdater()).execute(cursorGenerator, this);
142+
private static class TileHolder extends RecyclerView.ViewHolder {
143+
144+
private TextView tvName;
145+
private View ivDot;
146+
147+
TileHolder(View itemView) {
148+
super(itemView);
149+
tvName = (TextView) itemView.findViewById(R.id.name);
150+
ivDot = itemView.findViewById(R.id.stream_dot);
151+
}
152+
}
153+
154+
static class HeaderHolder extends RecyclerView.ViewHolder {
155+
156+
private TextView tvHeading;
39157

158+
HeaderHolder(View itemView) {
159+
super(itemView);
160+
tvHeading = (TextView) itemView.findViewById(R.id.tvHeading);
161+
}
40162
}
41163
}

0 commit comments

Comments
 (0)