Add EventHub, add fav, reblog events, improve timelines (#562)
* Add AppStore, add fav, reblog events * Add events, add handling to Timeline * Add event handling to Notifications * Mostly finish events * Fix unsubscribing * Cleanup timeline * Fix newStatusEvent in thread, fix deleteEvent * Insert new toots only in specific timelines * Add missing else * Rename AppStore to EventHub * Fix tests * Use DiffUtils for timeline * Fix empty timeline bug. Improve loading placeholder * Fix AsyncListDiff, loading indicator, "load more" * Timeline fixes & improvements. Fix infinite loading. Remove spinner correctly. Don't refresh timeline without need.
This commit is contained in:
parent
3a8d96346b
commit
3756a1fd20
31 changed files with 1064 additions and 542 deletions
|
|
@ -18,30 +18,35 @@ package com.keylesspalace.tusky.adapter;
|
|||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
|
||||
public class PlaceholderViewHolder extends RecyclerView.ViewHolder {
|
||||
public final class PlaceholderViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private Button loadMoreButton;
|
||||
|
||||
private ProgressBar progressBar;
|
||||
|
||||
PlaceholderViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
loadMoreButton = itemView.findViewById(R.id.button_load_more);
|
||||
|
||||
progressBar = itemView.findViewById(R.id.progress_bar);
|
||||
}
|
||||
|
||||
public void setup(boolean enabled, final StatusActionListener listener){
|
||||
public void setup(boolean enabled, final StatusActionListener listener) {
|
||||
this.setup(enabled, listener, false);
|
||||
}
|
||||
|
||||
public void setup(boolean enabled, final StatusActionListener listener, boolean progress) {
|
||||
loadMoreButton.setVisibility(progress ? View.GONE : View.VISIBLE);
|
||||
progressBar.setVisibility(progress ? View.VISIBLE : View.GONE);
|
||||
|
||||
loadMoreButton.setEnabled(enabled);
|
||||
if(enabled) {
|
||||
loadMoreButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
loadMoreButton.setEnabled(false);
|
||||
listener.onLoadMore(getAdapterPosition());
|
||||
}
|
||||
if (enabled) {
|
||||
loadMoreButton.setOnClickListener(v -> {
|
||||
loadMoreButton.setEnabled(false);
|
||||
listener.onLoadMore(getAdapterPosition());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,11 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
notifyItemRangeInserted(end, statuses.size());
|
||||
}
|
||||
|
||||
public void removeItem(int position) {
|
||||
statuses.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
statuses.clear();
|
||||
detailedStatusPosition = RecyclerView.NO_POSITION;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
@ -25,29 +25,32 @@ import com.keylesspalace.tusky.R;
|
|||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
public final class TimelineAdapter extends RecyclerView.Adapter {
|
||||
|
||||
public interface AdapterDataSource<T> {
|
||||
int getItemCount();
|
||||
|
||||
T getItemAt(int pos);
|
||||
}
|
||||
|
||||
public class TimelineAdapter extends RecyclerView.Adapter {
|
||||
private static final int VIEW_TYPE_STATUS = 0;
|
||||
private static final int VIEW_TYPE_FOOTER = 1;
|
||||
private static final int VIEW_TYPE_PLACEHOLDER = 2;
|
||||
|
||||
private List<StatusViewData> statuses;
|
||||
private StatusActionListener statusListener;
|
||||
private FooterViewHolder.State footerState;
|
||||
private final AdapterDataSource<StatusViewData> dataSource;
|
||||
private final StatusActionListener statusListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
|
||||
public TimelineAdapter(StatusActionListener statusListener) {
|
||||
public TimelineAdapter(AdapterDataSource<StatusViewData> dataSource,
|
||||
StatusActionListener statusListener) {
|
||||
super();
|
||||
statuses = new ArrayList<>();
|
||||
this.dataSource = dataSource;
|
||||
this.statusListener = statusListener;
|
||||
footerState = FooterViewHolder.State.END;
|
||||
mediaPreviewEnabled = true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
|
||||
switch (viewType) {
|
||||
default:
|
||||
case VIEW_TYPE_STATUS: {
|
||||
|
|
@ -55,11 +58,6 @@ public class TimelineAdapter extends RecyclerView.Adapter {
|
|||
.inflate(R.layout.item_status, viewGroup, false);
|
||||
return new StatusViewHolder(view);
|
||||
}
|
||||
case VIEW_TYPE_FOOTER: {
|
||||
View view = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.item_footer, viewGroup, false);
|
||||
return new FooterViewHolder(view);
|
||||
}
|
||||
case VIEW_TYPE_PLACEHOLDER: {
|
||||
View view = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.item_status_placeholder, viewGroup, false);
|
||||
|
|
@ -69,76 +67,39 @@ public class TimelineAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
||||
if (position < statuses.size()) {
|
||||
StatusViewData status = statuses.get(position);
|
||||
if (status instanceof StatusViewData.Placeholder) {
|
||||
PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder;
|
||||
holder.setup(!((StatusViewData.Placeholder) status).isLoading(), statusListener);
|
||||
} else {
|
||||
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||
statusListener, mediaPreviewEnabled);
|
||||
}
|
||||
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
StatusViewData status = dataSource.getItemAt(position);
|
||||
if (status instanceof StatusViewData.Placeholder) {
|
||||
PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder;
|
||||
holder.setup(!((StatusViewData.Placeholder) status).isLoading(),
|
||||
statusListener, ((StatusViewData.Placeholder) status).isLoading());
|
||||
} else {
|
||||
FooterViewHolder holder = (FooterViewHolder) viewHolder;
|
||||
holder.setState(footerState);
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||
statusListener, mediaPreviewEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return statuses.size() + 1;
|
||||
return dataSource.getItemCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (position == statuses.size()) {
|
||||
return VIEW_TYPE_FOOTER;
|
||||
if (dataSource.getItemAt(position) instanceof StatusViewData.Placeholder) {
|
||||
return VIEW_TYPE_PLACEHOLDER;
|
||||
} else {
|
||||
if (statuses.get(position) instanceof StatusViewData.Placeholder) {
|
||||
return VIEW_TYPE_PLACEHOLDER;
|
||||
} else {
|
||||
return VIEW_TYPE_STATUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void update(@Nullable List<StatusViewData> newStatuses) {
|
||||
if (newStatuses == null || newStatuses.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
statuses.clear();
|
||||
statuses.addAll(newStatuses);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addItems(List<StatusViewData> newStatuses) {
|
||||
statuses.addAll(newStatuses);
|
||||
notifyItemRangeInserted(statuses.size(), newStatuses.size());
|
||||
}
|
||||
|
||||
public void changeItem(int position, StatusViewData newData, boolean notifyAdapter) {
|
||||
statuses.set(position, newData);
|
||||
if (notifyAdapter) notifyItemChanged(position);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
statuses.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setFooterState(FooterViewHolder.State newFooterState) {
|
||||
FooterViewHolder.State oldValue = footerState;
|
||||
footerState = newFooterState;
|
||||
if (footerState != oldValue) {
|
||||
notifyItemChanged(statuses.size());
|
||||
return VIEW_TYPE_STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean enabled) {
|
||||
mediaPreviewEnabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return dataSource.getItemAt(position).getViewDataId();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue