MTU-Dining/app/src/main/java/com/thebrokenrail/mtudining/activity/task/TaskAdapter.java
2024-02-16 22:04:50 -05:00

164 lines
4.4 KiB
Java

package com.thebrokenrail.mtudining.activity.task;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.thebrokenrail.mtudining.widget.LoaderView;
/**
* RecyclerView adapter for a given {@link Task}.
*/
public abstract class TaskAdapter<E, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Task.Listener<E> {
public static final int LOADER_TYPE = 1;
public static final int DATA_TYPE = 0;
/**
* The task.
*/
private final Task<E> task;
/**
* Current task status.
*/
private Task.Status currentStatus;
/**
* Task result (or null if none).
*/
private E result;
/**
* Get task result.
* @return Task result
*/
protected E getResult() {
return result;
}
/**
* Create adapter.
* @param task The task
*/
public TaskAdapter(Task<E> task) {
// Setup Event Handling
this.task = task;
task.addListener(this);
}
/**
* Call when activity is destroyed.
*/
public void onDestroy() {
// Stop Handling Events
task.removeListener(this);
}
/**
* Create view holder for item in task's result.
* @param parent The view parent
* @return The new view holder
*/
protected abstract VH createItemViewHolder(@NonNull ViewGroup parent);
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == LOADER_TYPE) {
// Loader
LoaderView loader = new LoaderView(parent.getContext(), null);
RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT);
loader.setLayoutParams(layoutParams);
return new RecyclerView.ViewHolder(loader) {};
} else if (viewType == DATA_TYPE) {
// Data
return createItemViewHolder(parent);
} else {
// Unknown
throw new RuntimeException();
}
}
/**
* Bind view holder for item in task's result.
* @param holder The view holder
* @param position The item's position
*/
protected abstract void bindDataViewHolder(@NonNull VH holder, int position);
@SuppressWarnings({"unchecked"})
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
int type = getItemViewType(position);
if (type == LOADER_TYPE) {
// Loader
((LoaderView) holder.itemView).setup(currentStatus == Task.Status.ERROR, task::start);
} else if (type == DATA_TYPE) {
// Data
bindDataViewHolder((VH) holder, position);
}
}
/**
* Get size of task's dataset.
* @return The size of the dataset
*/
protected abstract int getDataSize();
@Override
public int getItemCount() {
if (currentStatus != Task.Status.DONE) {
// Only Loader
return 1;
} else {
// Data Size
return getDataSize();
}
}
@Override
public int getItemViewType(int position) {
if (currentStatus != Task.Status.DONE && position == 0) {
// Loader
return LOADER_TYPE;
} else {
// Data
return DATA_TYPE;
}
}
@Override
public void update(Task.Status status, E result) {
int oldItemCount = getItemCount();
// Store
this.currentStatus = status;
this.result = result;
// Change UI
if (status == Task.Status.IN_PROGRESS || status == Task.Status.NOT_STARTED) {
// Show Progress Circle
reloadUI(oldItemCount);
// Start Task If Needed
if (status == Task.Status.NOT_STARTED) {
task.start();
}
} else if (status == Task.Status.ERROR) {
// Show Error
reloadUI(oldItemCount);
} else {
// Done
reloadUI(oldItemCount);
}
}
/**
* Reload UI.
*/
private void reloadUI(int oldItemCount) {
// Remove Existing Items
notifyItemRangeRemoved(0, oldItemCount);
// Add Items
notifyItemRangeInserted(0, getItemCount());
}
}