Revert saving notifications to Realm through User, use PopupNotificationsManager instead

Combine Notification & GlobalNotification models since they model the same thing
This commit is contained in:
Carl Vuorinen 2019-04-28 22:07:25 +03:00
parent a4583c479a
commit a78897cda7
20 changed files with 145 additions and 257 deletions

View file

@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.habitrpg.android.habitica.models.ContentResult;
import com.habitrpg.android.habitica.models.FAQArticle;
import com.habitrpg.android.habitica.models.Notification;
import com.habitrpg.android.habitica.models.Skill;
import com.habitrpg.android.habitica.models.Tag;
import com.habitrpg.android.habitica.models.TutorialStep;
@ -17,7 +18,6 @@ import com.habitrpg.android.habitica.models.inventory.Quest;
import com.habitrpg.android.habitica.models.inventory.QuestCollect;
import com.habitrpg.android.habitica.models.inventory.QuestDropItem;
import com.habitrpg.android.habitica.models.members.Member;
import com.habitrpg.android.habitica.models.notifications.GlobalNotification;
import com.habitrpg.android.habitica.models.responses.FeedResponse;
import com.habitrpg.android.habitica.models.social.Challenge;
import com.habitrpg.android.habitica.models.social.ChatMessage;
@ -119,7 +119,7 @@ public class GSonFactoryCreator {
.registerTypeAdapter(Member.class, new MemberSerialization())
.registerTypeAdapter(WorldState.class, new WorldStateSerialization())
.registerTypeAdapter(FindUsernameResult.class, new FindUsernameResultDeserializer())
.registerTypeAdapter(GlobalNotification.class, new NotificationDeserializer())
.registerTypeAdapter(Notification.class, new NotificationDeserializer())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.create();
return GsonConverterFactory.create(gson);

View file

@ -73,11 +73,11 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener;
observable
.filter { it.data != null }
.map { habitResponse ->
if (habitResponse.notifications != null) {
popupNotificationsManager.showNotificationDialog(habitResponse.notifications)
}
habitResponse.data
}
if (habitResponse.notifications != null) {
popupNotificationsManager.setNotifications(habitResponse.notifications)
}
habitResponse.data
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(this)

View file

@ -2,12 +2,16 @@ package com.habitrpg.android.habitica.helpers;
import android.content.Context;
import androidx.annotation.Nullable;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.subjects.BehaviorSubject;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.data.ApiClient;
import com.habitrpg.android.habitica.events.ShowCheckinDialog;
import com.habitrpg.android.habitica.events.ShowSnackbarEvent;
import com.habitrpg.android.habitica.models.Notification;
import com.habitrpg.android.habitica.models.notifications.LoginIncentiveData;
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar;
import org.greenrobot.eventbus.EventBus;
@ -26,11 +30,24 @@ public class PopupNotificationsManager {
private ApiClient apiClient;
private Context context;
private BehaviorSubject<List<Notification>> notifications;
// @TODO: A queue for displaying alert dialogues
public PopupNotificationsManager(Context context) {
this.seenNotifications = new HashMap<>();
this.context = context;
this.notifications = BehaviorSubject.create();
}
public void setNotifications(List<Notification> current) {
this.notifications.onNext(current);
this.showNotificationDialog(current);
}
public Flowable<List<Notification>> getNotifications() {
return this.notifications.toFlowable(BackpressureStrategy.LATEST);
}
public void setApiClient(@Nullable ApiClient apiClient) {
@ -38,15 +55,16 @@ public class PopupNotificationsManager {
}
Boolean displayNotification(Notification notification) {
String nextUnlockText = context.getString(R.string.nextPrizeUnlocks, notification.data.nextRewardAt);
if (notification.data.rewardKey != null) {
LoginIncentiveData notificationData = (LoginIncentiveData)notification.getData();
String nextUnlockText = context.getString(R.string.nextPrizeUnlocks, notificationData.getNextRewardAt());
if (notificationData.getRewardKey() != null) {
ShowCheckinDialog event = new ShowCheckinDialog();
event.notification = notification;
event.nextUnlockText = nextUnlockText;
EventBus.getDefault().post(event);
} else {
ShowSnackbarEvent event = new ShowSnackbarEvent();
event.title = notification.data.message;
event.title = notificationData.getMessage();
event.text = nextUnlockText;
event.type = HabiticaSnackbar.SnackbarDisplayType.BLUE;
EventBus.getDefault().post(event);

View file

@ -1,88 +0,0 @@
package com.habitrpg.android.habitica.models;
/**
* Created by krh12 on 11/28/2016.
*/
import com.habitrpg.android.habitica.models.notifications.NotificationData;
import java.util.HashMap;
import java.util.Map;
public class Notification {
public NotificationData data;
private String type;
private String createdAt;
private String id;
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
/**
* @return The type
*/
public String getType() {
return type;
}
/**
* @param type The type
*/
public void setType(String type) {
this.type = type;
}
/**
* @return The createdAt
*/
public String getCreatedAt() {
return createdAt;
}
/**
* @param createdAt The createdAt
*/
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
/**
*
* @return
* The data
*/
// public T getData() {
// return data;
// }
/**
*
* @param data
* The data
*/
// public void setData(T data) {
// this.data = data;
// }
/**
* @return The id
*/
public String getId() {
return id;
}
/**
* @param id The id
*/
public void setId(String id) {
this.id = id;
}
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}

View file

@ -0,0 +1,30 @@
package com.habitrpg.android.habitica.models
import com.habitrpg.android.habitica.models.notifications.*
class Notification {
enum class Type(val type: String) {
LOGIN_INCENTIVE("LOGIN_INCENTIVE"),
NEW_STUFF("NEW_STUFF"),
NEW_CHAT_MESSAGE("NEW_CHAT_MESSAGE"),
NEW_MYSTERY_ITEMS("NEW_MYSTERY_ITEMS"),
UNALLOCATED_STATS_POINTS("UNALLOCATED_STATS_POINTS");
}
var id: String = ""
var type: String? = null
var seen: Boolean? = null
var data: NotificationData? = null
fun getDataType(): java.lang.reflect.Type? {
return when (type) {
Type.LOGIN_INCENTIVE.type -> LoginIncentiveData::class.java
Type.NEW_STUFF.type -> NewStuffData::class.java
Type.NEW_CHAT_MESSAGE.type -> NewChatMessageData::class.java
Type.UNALLOCATED_STATS_POINTS.type -> UnallocatedPointsData::class.java
else -> null
}
}
}

View file

@ -1,65 +0,0 @@
package com.habitrpg.android.habitica.models.notifications
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import java.lang.reflect.Type
enum class NotificationType(val type: String) {
NEW_STUFF("NEW_STUFF"),
NEW_CHAT_MESSAGE("NEW_CHAT_MESSAGE"),
NEW_MYSTERY_ITEMS("NEW_MYSTERY_ITEMS"),
UNALLOCATED_STATS_POINTS("UNALLOCATED_STATS_POINTS");
companion object {
fun contains(type: String?): Boolean {
return NotificationType.values().map { it.type }.contains(type)
}
}
}
/**
* Represents Habitica "Global notifications", i.e. the notifications about chat messages
* (in Guilds and Party), Party & Quest invitations, unallocated stat points etc.
*
* These are different from other kind of notifications, such as Push notifications and
* Popup notifications.
*/
open class GlobalNotification : RealmObject() {
@PrimaryKey
var id: String = ""
var type: String? = null
var seen: Boolean? = null
var newStuffData: NewStuffData? = null
var newChatMessageData: NewChatMessageData? = null
var unallocatedPointsData: UnallocatedPointsData? = null
// Workaround for Realms lack of polymorphism
fun getData(): GlobalNotificationData? {
return when (type) {
NotificationType.NEW_STUFF.type -> newStuffData
NotificationType.NEW_CHAT_MESSAGE.type -> newChatMessageData
NotificationType.UNALLOCATED_STATS_POINTS.type -> unallocatedPointsData
else -> null
}
}
fun setData(data: GlobalNotificationData?) {
when (type) {
NotificationType.NEW_STUFF.type -> newStuffData = data as NewStuffData?
NotificationType.NEW_CHAT_MESSAGE.type -> newChatMessageData = data as NewChatMessageData?
NotificationType.UNALLOCATED_STATS_POINTS.type -> unallocatedPointsData = data as UnallocatedPointsData?
}
}
fun getDataType(): Type? {
return when (type) {
NotificationType.NEW_STUFF.type -> NewStuffData::class.java
NotificationType.NEW_CHAT_MESSAGE.type -> NewChatMessageData::class.java
NotificationType.UNALLOCATED_STATS_POINTS.type -> UnallocatedPointsData::class.java
else -> null
}
}
}

View file

@ -1,5 +0,0 @@
package com.habitrpg.android.habitica.models.notifications
import io.realm.RealmModel
interface GlobalNotificationData : RealmModel

View file

@ -0,0 +1,11 @@
package com.habitrpg.android.habitica.models.notifications
open class LoginIncentiveData : NotificationData {
var message: String? = null
var nextRewardAt: Int? = null
var rewardText: String? = null
var rewardKey: List<String>? = null
var reward: List<Reward>? = null
}

View file

@ -1,7 +1,5 @@
package com.habitrpg.android.habitica.models.notifications
import io.realm.RealmObject
open class NewChatMessageData : RealmObject(), GlobalNotificationData {
open class NewChatMessageData : NotificationData {
var group: NotificationGroup? = null
}

View file

@ -1,7 +1,5 @@
package com.habitrpg.android.habitica.models.notifications
import io.realm.RealmObject
open class NewStuffData : RealmObject(), GlobalNotificationData {
open class NewStuffData : NotificationData {
var title: String? = null
}

View file

@ -1,18 +0,0 @@
package com.habitrpg.android.habitica.models.notifications;
import java.util.List;
/**
* Created by krh12 on 11/30/2016.
*/
public class NotificationData {
public String groupId;
public String message;
public Integer nextRewardAt;
public String rewardText;
public List<String> rewardKey;
public List<Reward> reward;
}

View file

@ -0,0 +1,3 @@
package com.habitrpg.android.habitica.models.notifications
interface NotificationData

View file

@ -1,8 +1,6 @@
package com.habitrpg.android.habitica.models.notifications
import io.realm.RealmObject
open class NotificationGroup : RealmObject() {
open class NotificationGroup {
var id: String = ""
var name: String? = null

View file

@ -1,7 +1,5 @@
package com.habitrpg.android.habitica.models.notifications
import io.realm.RealmObject
open class UnallocatedPointsData : RealmObject(), GlobalNotificationData {
open class UnallocatedPointsData : NotificationData {
var points: Int? = null
}

View file

@ -5,7 +5,6 @@ import com.habitrpg.android.habitica.models.Avatar
import com.habitrpg.android.habitica.models.PushDevice
import com.habitrpg.android.habitica.models.Tag
import com.habitrpg.android.habitica.models.invitations.Invitations
import com.habitrpg.android.habitica.models.notifications.GlobalNotification
import com.habitrpg.android.habitica.models.social.ChallengeMembership
import com.habitrpg.android.habitica.models.social.UserParty
import com.habitrpg.android.habitica.models.tasks.TaskList
@ -123,8 +122,6 @@ open class User : RealmObject(), Avatar {
@Ignore
var pushDevices: List<PushDevice>? = null
var notifications = RealmList<GlobalNotification>()
var purchased: Purchases? = null
set(purchased) {
field = purchased

View file

@ -46,6 +46,7 @@ import com.habitrpg.android.habitica.helpers.*
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager
import com.habitrpg.android.habitica.interactors.*
import com.habitrpg.android.habitica.models.TutorialStep
import com.habitrpg.android.habitica.models.notifications.LoginIncentiveData
import com.habitrpg.android.habitica.models.responses.MaintenanceResponse
import com.habitrpg.android.habitica.models.responses.TaskScoringResult
import com.habitrpg.android.habitica.models.tasks.Task
@ -827,19 +828,20 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
@Subscribe
fun showCheckinDialog(event: ShowCheckinDialog) {
val title = event.notification.data.message
val notificationData = event.notification.data as LoginIncentiveData
val title = notificationData.message
val factory = LayoutInflater.from(this)
val view = factory.inflate(R.layout.dialog_login_incentive, null)
val imageView = view.findViewById<View>(R.id.imageView) as? SimpleDraweeView
var imageKey = event.notification.data.rewardKey[0]
var imageKey = notificationData.rewardKey!!.get(0)
if (imageKey.contains("armor")) {
imageKey = "slim_$imageKey"
}
DataBindingUtils.loadImage(imageView, imageKey)
val youEarnedMessage = this.getString(R.string.checkInRewardEarned, event.notification.data.rewardText)
val youEarnedMessage = this.getString(R.string.checkInRewardEarned, notificationData.rewardText)
val titleTextView = TextView(this)
titleTextView.setBackgroundResource(R.color.blue_100)

View file

@ -12,6 +12,7 @@ import androidx.lifecycle.ViewModelProviders
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.Notification
import com.habitrpg.android.habitica.models.notifications.*
import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel
import io.reactivex.functions.Consumer
@ -25,7 +26,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
override fun getLayoutResId(): Int = R.layout.activity_notifications
private var notifications: List<GlobalNotification> = emptyList()
private var notifications: List<Notification> = emptyList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -65,7 +66,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
}, RxErrorHandler.handleEmptyError()))
}
private fun setNotifications(notifications: List<GlobalNotification>) {
private fun setNotifications(notifications: List<Notification>) {
this.notifications = notifications
if (notification_items == null) {
@ -86,17 +87,17 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
)
}
private fun displayNotificationsListView(notifications: List<GlobalNotification>) {
private fun displayNotificationsListView(notifications: List<Notification>) {
notification_items.addView(
createNotificationsHeaderView(notifications.count())
)
notifications.map {
val item: View? = when (it.type) {
NotificationType.NEW_CHAT_MESSAGE.type -> createNewChatMessageNotification(it)
NotificationType.NEW_STUFF.type -> createNewStuffNotification(it)
NotificationType.UNALLOCATED_STATS_POINTS.type -> createUnallocatedStatsNotification(it)
NotificationType.NEW_MYSTERY_ITEMS.type -> createMysteryItemsNotification(it)
Notification.Type.NEW_CHAT_MESSAGE.type -> createNewChatMessageNotification(it)
Notification.Type.NEW_STUFF.type -> createNewStuffNotification(it)
Notification.Type.UNALLOCATED_STATS_POINTS.type -> createUnallocatedStatsNotification(it)
Notification.Type.NEW_MYSTERY_ITEMS.type -> createMysteryItemsNotification(it)
//TODO rest of the notification types
else -> null
}
@ -117,8 +118,8 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
return header
}
private fun createNewChatMessageNotification(notification: GlobalNotification): View? {
val data = notification.getData() as? NewChatMessageData
private fun createNewChatMessageNotification(notification: Notification): View? {
val data = notification.data as? NewChatMessageData
val stringId = if (viewModel.isPartyMessage(data)) R.string.new_msg_party else R.string.new_msg_guild
return createNotificationItem(
@ -127,8 +128,8 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
)
}
private fun createNewStuffNotification(notification: GlobalNotification): View? {
val data = notification.getData() as? NewStuffData
private fun createNewStuffNotification(notification: Notification): View? {
val data = notification.data as? NewStuffData
val text = fromHtml("<b>" + getString(R.string.new_bailey_update) + "</b><br>" + data?.title)
return createNotificationItem(
@ -138,8 +139,8 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
)
}
private fun createUnallocatedStatsNotification(notification: GlobalNotification): View? {
val data = notification.getData() as? UnallocatedPointsData
private fun createUnallocatedStatsNotification(notification: Notification): View? {
val data = notification.data as? UnallocatedPointsData
return createNotificationItem(
notification,
@ -148,7 +149,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
)
}
private fun createMysteryItemsNotification(notification: GlobalNotification): View? {
private fun createMysteryItemsNotification(notification: Notification): View? {
return createNotificationItem(
notification,
fromHtml(getString(R.string.new_subscriber_item)),
@ -156,7 +157,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
)
}
private fun createNotificationItem(notification: GlobalNotification, messageText: CharSequence, imageResourceId: Int? = null): View? {
private fun createNotificationItem(notification: Notification, messageText: CharSequence, imageResourceId: Int? = null): View? {
val item = inflater.inflate(R.layout.notification_item, notification_items, false)
val dismissButton = item?.findViewById(R.id.dismiss_button) as? ImageView

View file

@ -1,28 +1,53 @@
package com.habitrpg.android.habitica.ui.viewmodels
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.helpers.PopupNotificationsManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.notifications.GlobalNotification
import com.habitrpg.android.habitica.models.Notification
import com.habitrpg.android.habitica.models.notifications.NewChatMessageData
import com.habitrpg.android.habitica.models.notifications.NotificationType
import com.habitrpg.android.habitica.models.social.UserParty
import io.reactivex.Flowable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
import io.realm.RealmList
import java.util.HashMap
import javax.inject.Inject
open class NotificationsViewModel : BaseViewModel() {
var party: UserParty? = null
@Inject
lateinit var notificationsManager: PopupNotificationsManager
/**
* A list of notification types handled by this component.
* NOTE: Those not listed here won't be shown in the notification panel
*/
private val supportedNotificationTypes = listOf(
Notification.Type.NEW_STUFF.type,
Notification.Type.NEW_CHAT_MESSAGE.type,
Notification.Type.NEW_MYSTERY_ITEMS.type,
Notification.Type.UNALLOCATED_STATS_POINTS.type
)
/**
* Keep track of users party so we can determine which chat notifications are party chat
* instead of guild chat notifications.
*/
private var party: UserParty? = null
override fun inject(component: AppComponent) {
component.inject(this)
}
fun getNotifications(): Flowable<List<GlobalNotification>> {
return userRepository.getUser()
.doOnEach { party = it.value?.party }
.map { filterSupportedTypes(it.notifications) }
init {
disposable.add(userRepository.getUser()
.subscribe(Consumer {
party = it.party
}, RxErrorHandler.handleEmptyError()))
}
fun getNotifications(): Flowable<List<Notification>> {
return notificationsManager.notifications
.map { filterSupportedTypes(it) }
.observeOn(AndroidSchedulers.mainThread())
}
@ -38,12 +63,12 @@ open class NotificationsViewModel : BaseViewModel() {
.distinctUntilChanged()
}
fun refreshNotifications(): Flowable<RealmList<GlobalNotification>> {
return userRepository.retrieveUser(withTasks = false, forced = true).map { it.notifications }
fun refreshNotifications(): Flowable<*> {
return userRepository.retrieveUser(withTasks = false, forced = true)
}
private fun filterSupportedTypes(notifications: List<GlobalNotification>): List<GlobalNotification> {
return notifications.filter { NotificationType.contains(it.type) }
private fun filterSupportedTypes(notifications: List<Notification>): List<Notification> {
return notifications.filter { supportedNotificationTypes.contains(it.type) }
}
fun isPartyMessage(data: NewChatMessageData?): Boolean {
@ -54,15 +79,12 @@ open class NotificationsViewModel : BaseViewModel() {
return party?.id == data.group?.id
}
fun dismissNotification(notification: GlobalNotification) {
fun dismissNotification(notification: Notification) {
disposable.add(userRepository.readNotification(notification.id)
.subscribe(Consumer {
// TODO better way to handle updates than reload whole user ??
refreshNotifications()
}, RxErrorHandler.handleEmptyError()))
.subscribe(Consumer {}, RxErrorHandler.handleEmptyError()))
}
fun dismissAllNotifications(notifications: List<GlobalNotification>) {
fun dismissAllNotifications(notifications: List<Notification>) {
if (notifications.isEmpty()) {
return
}
@ -71,12 +93,10 @@ open class NotificationsViewModel : BaseViewModel() {
notificationIds["notificationIds"] = notifications.map { notification -> notification.id }
disposable.add(userRepository.readNotifications(notificationIds)
.subscribe(Consumer {
refreshNotifications()
}, RxErrorHandler.handleEmptyError()))
.subscribe(Consumer {}, RxErrorHandler.handleEmptyError()))
}
fun markNotificationsAsSeen(notifications: List<GlobalNotification>) {
fun markNotificationsAsSeen(notifications: List<Notification>) {
val unseenIds = notifications.filter { notification -> notification.seen != true }
.map { notification -> notification.id }
@ -88,9 +108,7 @@ open class NotificationsViewModel : BaseViewModel() {
notificationIds["notificationIds"] = unseenIds
disposable.add(userRepository.seeNotifications(notificationIds)
.subscribe(Consumer {
refreshNotifications()
}, RxErrorHandler.handleEmptyError()))
.subscribe(Consumer {}, RxErrorHandler.handleEmptyError()))
}
}

View file

@ -4,13 +4,13 @@ import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonParseException
import com.habitrpg.android.habitica.models.notifications.*
import com.habitrpg.android.habitica.models.Notification
import java.lang.reflect.Type
class NotificationDeserializer : JsonDeserializer<GlobalNotification> {
class NotificationDeserializer : JsonDeserializer<Notification> {
@Throws(JsonParseException::class)
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): GlobalNotification {
val notification = GlobalNotification()
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Notification {
val notification = Notification()
val obj = json.asJsonObject
if (obj.has("id")) {
@ -27,9 +27,7 @@ class NotificationDeserializer : JsonDeserializer<GlobalNotification> {
val dataType = notification.getDataType()
if (obj.has("data") && dataType != null) {
notification.setData(
context.deserialize(obj.getAsJsonObject("data"), dataType)
)
notification.data = context.deserialize(obj.getAsJsonObject("data"), dataType)
}
return notification

View file

@ -11,7 +11,6 @@ import com.habitrpg.android.habitica.models.PushDevice
import com.habitrpg.android.habitica.models.Tag
import com.habitrpg.android.habitica.models.inventory.Quest
import com.habitrpg.android.habitica.models.invitations.Invitations
import com.habitrpg.android.habitica.models.notifications.GlobalNotification
import com.habitrpg.android.habitica.models.social.ChallengeMembership
import com.habitrpg.android.habitica.models.social.UserParty
import com.habitrpg.android.habitica.models.tasks.TasksOrder
@ -110,11 +109,6 @@ class UserDeserializer : JsonDeserializer<User> {
.forEach { (user.pushDevices as? ArrayList<PushDevice>)?.add(it) }
}
if (obj.has("notifications")) {
user.notifications = context.deserialize(obj.get("notifications"), object: TypeToken<RealmList<GlobalNotification>>() {
}.type)
}
if (obj.has("lastCron")) {
user.lastCron = context.deserialize(obj.get("lastCron"), Date::class.java)
}