Commit 500b0e78 authored by Yusuke Iwaki's avatar Yusuke Iwaki

add NotificationItem model.

parent 8e0983e2
......@@ -23,6 +23,8 @@ public class RoomSubscription extends RealmObject {
private boolean open;
private boolean alert;
private int unread;
private long _updatedAt;
private long ls; //last seen.
public String get_id() {
return _id;
......@@ -80,7 +82,35 @@ public class RoomSubscription extends RealmObject {
this.unread = unread;
}
public long get_updatedAt() {
return _updatedAt;
}
public void set_updatedAt(long _updatedAt) {
this._updatedAt = _updatedAt;
}
public long getLs() {
return ls;
}
public void setLs(long ls) {
this.ls = ls;
}
public static JSONObject customizeJson(JSONObject roomSubscriptionJson) throws JSONException {
if (!roomSubscriptionJson.isNull("ls")) {
long ls = roomSubscriptionJson.getJSONObject("ls").getLong("$date");
roomSubscriptionJson.remove("ls");
roomSubscriptionJson.put("ls", ls);
}
if (!roomSubscriptionJson.isNull("_updatedAt")) {
long updatedAt = roomSubscriptionJson.getJSONObject("_updatedAt").getLong("$date");
roomSubscriptionJson.remove("_updatedAt");
roomSubscriptionJson.put("_updatedAt", updatedAt);
}
return roomSubscriptionJson;
}
}
package chat.rocket.android.model.internal;
import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;
/**
* View model for notification.
*/
public class NotificationItem extends RealmObject {
@PrimaryKey private String roomId;
private String title;
private String description;
private int unreadCount;
private String senderName;
private long contentUpdatedAt; //subscription._updatedAt
private long lastSeenAt; //max(notification dismissed, subscription.ls)
public String getRoomId() {
return roomId;
}
public void setRoomId(String roomId) {
this.roomId = roomId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getUnreadCount() {
return unreadCount;
}
public void setUnreadCount(int unreadCount) {
this.unreadCount = unreadCount;
}
public String getSenderName() {
return senderName;
}
public void setSenderName(String senderName) {
this.senderName = senderName;
}
public long getContentUpdatedAt() {
return contentUpdatedAt;
}
public void setContentUpdatedAt(long contentUpdatedAt) {
this.contentUpdatedAt = contentUpdatedAt;
}
public long getLastSeenAt() {
return lastSeenAt;
}
public void setLastSeenAt(long lastSeenAt) {
this.lastSeenAt = lastSeenAt;
}
}
......@@ -22,7 +22,7 @@ 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.NewMessageObserver;
import chat.rocket.android.service.observer.ReactiveNotificationCancelManager;
import chat.rocket.android.service.observer.NotificationItemObserver;
import chat.rocket.android.service.observer.ReactiveNotificationManager;
import chat.rocket.android.service.observer.SessionObserver;
import chat.rocket.android.service.observer.TokenLoginObserver;
......@@ -49,7 +49,7 @@ public class RocketChatWebSocketThread extends HandlerThread {
NewMessageObserver.class,
CurrentUserObserver.class,
ReactiveNotificationManager.class,
ReactiveNotificationCancelManager.class
NotificationItemObserver.class
};
private final Context appContext;
private final String serverConfigId;
......
......@@ -5,6 +5,8 @@ import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android.model.ddp.RoomSubscription;
import chat.rocket.android.realm_helper.RealmHelper;
import io.realm.RealmObject;
import org.json.JSONException;
import org.json.JSONObject;
public class StreamNotifyUserSubscriptionsChanged extends AbstractStreamNotifyUserEventSubscriber {
public StreamNotifyUserSubscriptionsChanged(Context context, String hostname,
......@@ -20,6 +22,10 @@ public class StreamNotifyUserSubscriptionsChanged extends AbstractStreamNotifyUs
return RoomSubscription.class;
}
@Override protected JSONObject customizeFieldJson(JSONObject json) throws JSONException {
return RoomSubscription.customizeJson(super.customizeFieldJson(json));
}
@Override protected String getPrimaryKeyForModel() {
return "rid";
}
......
......@@ -3,6 +3,7 @@ package chat.rocket.android.service.observer;
import android.content.Context;
import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android.api.MethodCallHelper;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.model.ddp.User;
import chat.rocket.android.realm_helper.RealmHelper;
import chat.rocket.android.service.Registerable;
......@@ -65,7 +66,7 @@ public class CurrentUserObserver extends AbstractModelObserver<User> {
listeners.add(listener);
}
return null;
});
}).continueWith(new LogcatIfError());
}
@DebugLog
......
package chat.rocket.android.service.observer;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
import bolts.Task;
import chat.rocket.android.R;
import chat.rocket.android.activity.MainActivity;
import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android.helper.Avatar;
import chat.rocket.android.helper.TextUtils;
import chat.rocket.android.model.ServerConfig;
import chat.rocket.android.model.internal.NotificationItem;
import chat.rocket.android.realm_helper.RealmHelper;
import chat.rocket.android.realm_helper.RealmStore;
import io.realm.Realm;
import io.realm.RealmResults;
import java.util.List;
/**
* observes NotificationItem and notify/cancel notification.
*/
public class NotificationItemObserver extends AbstractModelObserver<NotificationItem> {
public NotificationItemObserver(Context context, String hostname, RealmHelper realmHelper,
DDPClientWraper ddpClient) {
super(context, hostname, realmHelper, ddpClient);
}
@Override public RealmResults<NotificationItem> queryItems(Realm realm) {
return realm.where(NotificationItem.class).findAll();
}
@Override public void onUpdateResults(List<NotificationItem> results) {
if (results.isEmpty()) {
return;
}
for (NotificationItem item : results) {
final String notificationId = item.getRoomId();
if (item.getUnreadCount() > 0
&& item.getContentUpdatedAt() > item.getLastSeenAt()) {
generateNotificationFor(item)
.onSuccess(task -> {
Notification notification = task.getResult();
if (notification != null) {
NotificationManagerCompat.from(context)
.notify(notificationId.hashCode(), notification);
}
return null;
});
} else {
NotificationManagerCompat.from(context).cancel(notificationId.hashCode());
}
}
}
private Task<Notification> generateNotificationFor(NotificationItem item) {
final String username = item.getSenderName();
final String roomId = item.getRoomId();
final String title = item.getTitle();
final String description = TextUtils.or(item.getDescription(), "").toString();
final int unreadCount = item.getUnreadCount();
if (TextUtils.isEmpty(username)) {
return Task.forResult(generateNotification(roomId, title, description, unreadCount, null));
}
int size = context.getResources().getDimensionPixelSize(R.dimen.notification_avatar_size);
return new Avatar(hostname, username).getBitmap(context, size)
.continueWithTask(task -> {
Bitmap icon = task.isFaulted() ? null : task.getResult();
final Notification notification =
generateNotification(roomId, title, description, unreadCount, icon);
return Task.forResult(notification);
});
}
private Notification generateNotification(String roomId, String title,
@NonNull String description, int unreadCount, @Nullable Bitmap icon) {
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP);
ServerConfig config = RealmStore.getDefault().executeTransactionForRead(realm ->
realm.where(ServerConfig.class).equalTo("hostname", hostname).findFirst());
if (config != null) {
intent.putExtra("serverConfigId", config.getServerConfigId());
intent.putExtra("roomId", roomId);
}
PendingIntent pendingIntent = PendingIntent.getActivity(context.getApplicationContext(),
(int) (System.currentTimeMillis() % Integer.MAX_VALUE),
intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentTitle(title)
.setContentText(description)
.setNumber(unreadCount)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setSmallIcon(R.drawable.rocket_chat_notification_24dp)
.setContentIntent(pendingIntent);
if (icon != null) {
builder.setLargeIcon(icon);
}
if (description.length() > 20) {
return new NotificationCompat.BigTextStyle(builder)
.bigText(description)
.build();
} else {
return builder.build();
}
}
}
package chat.rocket.android.service.observer;
import android.content.Context;
import android.support.v4.app.NotificationManagerCompat;
import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android.model.ddp.RoomSubscription;
import chat.rocket.android.realm_helper.RealmHelper;
import hugo.weaving.DebugLog;
import io.realm.Realm;
import io.realm.RealmResults;
import java.util.List;
/**
* observing room subscriptions with unread>0.
*/
public class ReactiveNotificationCancelManager extends AbstractModelObserver<RoomSubscription> {
public ReactiveNotificationCancelManager(Context context, String hostname,
RealmHelper realmHelper, DDPClientWraper ddpClient) {
super(context, hostname, realmHelper, ddpClient);
}
@Override public RealmResults<RoomSubscription> queryItems(Realm realm) {
return realm.where(RoomSubscription.class)
.equalTo("open", true)
.equalTo("unread", 0)
.findAll();
}
@DebugLog
@Override public void onUpdateResults(List<RoomSubscription> roomSubscriptions) {
// TODO implement!
for (RoomSubscription roomSubscription : roomSubscriptions) {
final String roomId = roomSubscription.getRid();
NotificationManagerCompat.from(context).cancel(roomId.hashCode());
}
}
}
package chat.rocket.android.service.observer;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
import chat.rocket.android.R;
import chat.rocket.android.activity.MainActivity;
import chat.rocket.android.api.DDPClientWraper;
import chat.rocket.android.model.ServerConfig;
import chat.rocket.android.helper.LogcatIfError;
import chat.rocket.android.log.RCLog;
import chat.rocket.android.model.ddp.RoomSubscription;
import chat.rocket.android.model.internal.NotificationItem;
import chat.rocket.android.realm_helper.RealmHelper;
import chat.rocket.android.realm_helper.RealmStore;
import hugo.weaving.DebugLog;
import io.realm.Realm;
import io.realm.RealmResults;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* observing room subscriptions with unread>0.
......@@ -31,7 +27,6 @@ public class ReactiveNotificationManager extends AbstractModelObserver<RoomSubsc
@Override public RealmResults<RoomSubscription> queryItems(Realm realm) {
return realm.where(RoomSubscription.class)
.equalTo("open", true)
.greaterThan("unread", 0)
.findAll();
}
......@@ -39,30 +34,37 @@ public class ReactiveNotificationManager extends AbstractModelObserver<RoomSubsc
@Override public void onUpdateResults(List<RoomSubscription> roomSubscriptions) {
// TODO implement!
JSONArray notifications = new JSONArray();
for (RoomSubscription roomSubscription : roomSubscriptions) {
final String roomId = roomSubscription.getRid();
NotificationItem item = realmHelper.executeTransactionForRead(realm ->
realm.where(NotificationItem.class).equalTo("roomId", roomId).findFirst());
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP);
ServerConfig config = RealmStore.getDefault().executeTransactionForRead(realm ->
realm.where(ServerConfig.class).equalTo("hostname", hostname).findFirst());
if (config != null) {
intent.putExtra("serverConfigId", config.getServerConfigId());
intent.putExtra("roomId", roomId);
}
PendingIntent pendingIntent = PendingIntent.getActivity(context.getApplicationContext(),
(int) (System.currentTimeMillis() % Integer.MAX_VALUE),
intent, PendingIntent.FLAG_ONE_SHOT);
long lastSeenAt = Math.max(item != null ? item.getLastSeenAt() : 0, roomSubscription.getLs());
try {
JSONObject notification = new JSONObject()
.put("roomId", roomSubscription.getRid())
.put("title", roomSubscription.getName())
.put("description", "new message")
.put("unreadCount", roomSubscription.getUnread())
.put("contentUpdatedAt", roomSubscription.get_updatedAt())
.put("lastSeenAt", lastSeenAt);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentTitle(roomSubscription.getName())
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setSmallIcon(R.drawable.rocket_chat_notification_24dp)
.setContentIntent(pendingIntent);
if (RoomSubscription.TYPE_DIRECT_MESSAGE.equals(roomSubscription.getT())) {
notification.put("senderName", roomSubscription.getName());
} else {
notification.put("senderName", JSONObject.NULL);
}
Notification notification = builder.build();
NotificationManagerCompat.from(context).notify(roomId.hashCode(), notification);
notifications.put(notification);
} catch (JSONException exception) {
RCLog.w(exception);
}
}
realmHelper.executeTransaction(realm -> {
realm.createOrUpdateAllFromJson(NotificationItem.class, notifications);
return null;
}).continueWith(new LogcatIfError());
}
}
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