Refresh message timestamp every minute (#1113)
* Refresh message timestamp every minute * Refresh timeline adapter every minute via differ
This commit is contained in:
parent
d0f7f6f83c
commit
7680b1b529
5 changed files with 182 additions and 104 deletions
|
@ -44,7 +44,9 @@ import at.connyduck.sparkbutton.SparkEventListener;
|
|||
import kotlin.collections.CollectionsKt;
|
||||
|
||||
public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public static class Key{
|
||||
public static final String KEY_CREATED = "created";
|
||||
}
|
||||
private TextView displayName;
|
||||
private TextView username;
|
||||
private ImageButton replyButton;
|
||||
|
@ -538,6 +540,11 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled) {
|
||||
this.setupWithStatus(status,listener,mediaPreviewEnabled,null);
|
||||
}
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
||||
if (payloads == null) {
|
||||
setDisplayName(status.getUserFullName(), status.getAccountEmojis());
|
||||
setUsername(status.getNickname());
|
||||
setCreatedAt(status.getCreatedAt());
|
||||
|
@ -578,6 +585,16 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
// and let RecyclerView ask for a new delegate.
|
||||
itemView.setAccessibilityDelegate(null);
|
||||
}
|
||||
else{
|
||||
if (payloads instanceof List)
|
||||
for (Object item:(List)payloads) {
|
||||
if (Key.KEY_CREATED.equals(item)){
|
||||
setCreatedAt(status.getCreatedAt());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setContentDescription(@Nullable StatusViewData.Concrete status) {
|
||||
|
|
|
@ -125,9 +125,9 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
@Override
|
||||
protected void setupWithStatus(final StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled) {
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled);
|
||||
|
||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled,payloads);
|
||||
if (payloads==null) {
|
||||
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
||||
|
||||
setApplication(status.getApplication());
|
||||
|
@ -194,6 +194,7 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
setStatusVisibility(status.getVisibility());
|
||||
}
|
||||
}
|
||||
|
||||
private void setStatusVisibility(Status.Visibility visibility) {
|
||||
if (visibility == null || this.timestampInfo == null) {
|
||||
|
|
|
@ -75,13 +75,14 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
@Override
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled) {
|
||||
if(status == null) {
|
||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
||||
if (status == null || payloads==null) {
|
||||
if (status == null) {
|
||||
showContent(false);
|
||||
} else {
|
||||
showContent(true);
|
||||
setupCollapsedState(status, listener);
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled);
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, null);
|
||||
|
||||
String rebloggedByDisplayName = status.getRebloggedByUsername();
|
||||
if (rebloggedByDisplayName == null) {
|
||||
|
@ -90,7 +91,10 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
setRebloggedByDisplayName(rebloggedByDisplayName);
|
||||
}
|
||||
|
||||
rebloggedBar.setOnClickListener(v -> listener.onOpenReblog(getAdapterPosition()));
|
||||
rebloggedBar.setOnClickListener(v -> listener.onOpenReblog(getAdapterPosition()));}
|
||||
}
|
||||
else{
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, payloads);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
@ -70,17 +73,25 @@ public final class TimelineAdapter 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){
|
||||
StatusViewData status = dataSource.getItemAt(position);
|
||||
if (status instanceof StatusViewData.Placeholder) {
|
||||
PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder;
|
||||
holder.setup(statusListener, ((StatusViewData.Placeholder) status).isLoading());
|
||||
} else {
|
||||
} else if (status instanceof StatusViewData.Concrete) {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||
statusListener, mediaPreviewEnabled);
|
||||
holder.setupWithStatus((StatusViewData.Concrete)status,statusListener, mediaPreviewEnabled,payloads!=null&&!payloads.isEmpty()?payloads.get(0):null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return dataSource.getItemCount();
|
||||
|
|
|
@ -28,9 +28,11 @@ import android.widget.ProgressBar;
|
|||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import io.reactivex.Observable;
|
||||
import com.keylesspalace.tusky.AccountListActivity;
|
||||
import com.keylesspalace.tusky.BaseActivity;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.adapter.StatusBaseViewHolder;
|
||||
import com.keylesspalace.tusky.adapter.TimelineAdapter;
|
||||
import com.keylesspalace.tusky.appstore.BlockEvent;
|
||||
import com.keylesspalace.tusky.appstore.EventHub;
|
||||
|
@ -63,10 +65,12 @@ import com.keylesspalace.tusky.view.EndlessOnScrollListener;
|
|||
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.ListIterator;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -1266,7 +1270,48 @@ public class TimelineFragment extends SFragment implements
|
|||
|
||||
@Override
|
||||
public boolean areContentsTheSame(StatusViewData oldItem, @NonNull StatusViewData newItem) {
|
||||
return oldItem.deepEquals(newItem);
|
||||
return false; //Items are different always. It allows to refresh timestamp on every view holder update
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getChangePayload(@NonNull StatusViewData oldItem, @NonNull StatusViewData newItem) {
|
||||
if (oldItem.deepEquals(newItem)){
|
||||
//If items are equal - update timestamp only
|
||||
List<String> 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()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue