diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java index d5649f4c3..cce26b49b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java @@ -124,12 +124,24 @@ public class NotificationsAdapter extends RecyclerView.Adapter { @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + bindViewHolder(viewHolder,position,null); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position, @NonNull List payloads) { + bindViewHolder(viewHolder,position,payloads); + } + + private void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position, @Nullable List payloads){ + Object payloadForHolder = payloads!=null&&!payloads.isEmpty()?payloads.get(0):null; if (position < this.dataSource.getItemCount()) { NotificationViewData notification = dataSource.getItemAt(position); if (notification instanceof NotificationViewData.Placeholder) { - NotificationViewData.Placeholder placeholder = ((NotificationViewData.Placeholder) notification); - PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder; - holder.setup(statusListener, placeholder.isLoading()); + if (payloadForHolder==null) { + NotificationViewData.Placeholder placeholder = ((NotificationViewData.Placeholder) notification); + PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder; + holder.setup(statusListener, placeholder.isLoading()); + } return; } NotificationViewData.Concrete concreteNotificaton = @@ -141,43 +153,54 @@ public class NotificationsAdapter extends RecyclerView.Adapter { StatusViewHolder holder = (StatusViewHolder) viewHolder; StatusViewData.Concrete status = concreteNotificaton.getStatusViewData(); holder.setupWithStatus(status, - statusListener, mediaPreviewEnabled); + statusListener, mediaPreviewEnabled,payloadForHolder); break; } case FAVOURITE: case REBLOG: { StatusNotificationViewHolder holder = (StatusNotificationViewHolder) viewHolder; StatusViewData.Concrete statusViewData = concreteNotificaton.getStatusViewData(); + if (payloadForHolder==null) { + if (statusViewData == null) { + holder.showNotificationContent(false); + } else { + holder.showNotificationContent(true); - if (statusViewData == null) { - holder.showNotificationContent(false); - } else { - holder.showNotificationContent(true); + holder.setDisplayName(statusViewData.getUserFullName(), statusViewData.getAccountEmojis()); + holder.setUsername(statusViewData.getNickname()); + holder.setCreatedAt(statusViewData.getCreatedAt()); - holder.setDisplayName(statusViewData.getUserFullName(), statusViewData.getAccountEmojis()); - holder.setUsername(statusViewData.getNickname()); - holder.setCreatedAt(statusViewData.getCreatedAt()); + holder.setAvatars(concreteNotificaton.getStatusViewData().getAvatar(), + concreteNotificaton.getAccount().getAvatar()); + } - holder.setAvatars(concreteNotificaton.getStatusViewData().getAvatar(), - concreteNotificaton.getAccount().getAvatar()); + holder.setMessage(concreteNotificaton, statusListener, bidiFormatter); + holder.setupButtons(notificationActionListener, + concreteNotificaton.getAccount().getId(), + concreteNotificaton.getId()); + } + else{ + if (payloadForHolder instanceof List) + for (Object item:payloads) { + if (StatusBaseViewHolder.Key.KEY_CREATED.equals(item)){ + holder.setCreatedAt(statusViewData.getCreatedAt()); + } + } } - - holder.setMessage(concreteNotificaton, statusListener, bidiFormatter); - holder.setupButtons(notificationActionListener, - concreteNotificaton.getAccount().getId(), - concreteNotificaton.getId()); break; } case FOLLOW: { - FollowViewHolder holder = (FollowViewHolder) viewHolder; - holder.setMessage(concreteNotificaton.getAccount(), bidiFormatter); - holder.setupButtons(notificationActionListener, concreteNotificaton.getAccount().getId()); + if (payloadForHolder==null) { + FollowViewHolder holder = (FollowViewHolder) viewHolder; + holder.setMessage(concreteNotificaton.getAccount(), bidiFormatter); + holder.setupButtons(notificationActionListener, concreteNotificaton.getAccount().getId()); + } break; } } } - } + } @Override public int getItemCount() { return dataSource.getItemCount(); diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index 1f025e6b4..7a694a098 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -44,9 +44,10 @@ import at.connyduck.sparkbutton.SparkEventListener; import kotlin.collections.CollectionsKt; public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { - public static class Key{ + public static class Key { public static final String KEY_CREATED = "created"; } + private TextView displayName; private TextView username; private ImageButton replyButton; @@ -540,8 +541,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener, boolean mediaPreviewEnabled) { - this.setupWithStatus(status,listener,mediaPreviewEnabled,null); + this.setupWithStatus(status, listener, mediaPreviewEnabled, null); } + protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener, boolean mediaPreviewEnabled, @Nullable Object payloads) { if (payloads == null) { @@ -584,14 +586,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { // fetches another one from its delegate because it checks that it's set so we remove it // and let RecyclerView ask for a new delegate. itemView.setAccessibilityDelegate(null); - } - else{ + } else { if (payloads instanceof List) - for (Object item:(List)payloads) { - if (Key.KEY_CREATED.equals(item)){ - setCreatedAt(status.getCreatedAt()); + for (Object item : (List) payloads) { + if (Key.KEY_CREATED.equals(item)) { + setCreatedAt(status.getCreatedAt()); + } } - } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java index 43a6cc6e6..d893267df 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -31,6 +31,7 @@ import com.google.android.material.tabs.TabLayout; import com.keylesspalace.tusky.MainActivity; import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.adapter.NotificationsAdapter; +import com.keylesspalace.tusky.adapter.StatusBaseViewHolder; import com.keylesspalace.tusky.appstore.BlockEvent; import com.keylesspalace.tusky.appstore.EventHub; import com.keylesspalace.tusky.appstore.FavoriteEvent; @@ -57,9 +58,11 @@ import com.keylesspalace.tusky.viewdata.NotificationViewData; import com.keylesspalace.tusky.viewdata.StatusViewData; import java.io.IOException; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; @@ -78,6 +81,7 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import at.connyduck.sparkbutton.helpers.Utils; +import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import kotlin.Unit; import kotlin.collections.CollectionsKt; @@ -929,7 +933,45 @@ public class NotificationsFragment extends SFragment implements @Override public boolean areContentsTheSame(NotificationViewData oldItem, NotificationViewData newItem) { - return oldItem.deepEquals(newItem); + return false; + } + + @Nullable + @Override + public Object getChangePayload(@NonNull NotificationViewData oldItem, @NonNull NotificationViewData newItem) { + if (oldItem.deepEquals(newItem)) { + //If items are equal - update timestamp only + List payload = new ArrayList<>(); + payload.add(StatusBaseViewHolder.Key.KEY_CREATED); + return payload; + } else + // If items are different - update a whole view holder + return null; } }; + + @Override + public void onResume() { + super.onResume(); + startUpdateTimestamp(); + } + + /** + * Start to update adapter every minute to refresh timestamp + * If setting absoluteTimeView is false + * Auto dispose observable on pause + */ + private void startUpdateTimestamp() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false); + if (!useAbsoluteTime) { + Observable.interval(1, TimeUnit.MINUTES) + .observeOn(AndroidSchedulers.mainThread()) + .as(autoDisposable(from(this, Lifecycle.Event.ON_PAUSE))) + .subscribe( + interval -> updateAdapter() + ); + } + + } }