217 lines
5.8 KiB
Java
217 lines
5.8 KiB
Java
package com.thebrokenrail.mtudining.activity.task;
|
|
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
import com.thebrokenrail.mtudining.R;
|
|
import com.thebrokenrail.mtudining.widget.LoaderView;
|
|
|
|
/**
|
|
* RecyclerView adapter for a given {@link Task}.
|
|
*/
|
|
public abstract class TaskAdapter<E> extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Task.Listener<E> {
|
|
public static final int LOADER_TYPE = 1;
|
|
public static final int ITEM_TYPE = 0;
|
|
public static final int HEADER_TYPE = 2;
|
|
|
|
/**
|
|
* 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 for item in task's result.
|
|
* @param parent The view parent
|
|
* @return The new view
|
|
*/
|
|
protected abstract View createItemView(@NonNull ViewGroup parent);
|
|
|
|
/**
|
|
* Create view for header.
|
|
* @param parent The view parent
|
|
* @return The new view
|
|
*/
|
|
protected View createHeader(@NonNull ViewGroup parent) {
|
|
// Just Create Margin
|
|
View view = new View(parent.getContext());
|
|
int margin = parent.getResources().getDimensionPixelSize(R.dimen.margin);
|
|
RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, margin);
|
|
view.setLayoutParams(layoutParams);
|
|
return view;
|
|
}
|
|
|
|
@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 == ITEM_TYPE) {
|
|
// Data
|
|
return new RecyclerView.ViewHolder(createItemView(parent)) {};
|
|
} else if (viewType == HEADER_TYPE) {
|
|
// Header
|
|
return new RecyclerView.ViewHolder(createHeader(parent)) {};
|
|
} else {
|
|
// Unknown
|
|
throw new RuntimeException();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind view for item in task's result.
|
|
* @param view The view
|
|
* @param position The item's position
|
|
*/
|
|
protected abstract void bindItemView(View view, int position);
|
|
|
|
/**
|
|
* Bind view for header.
|
|
* @param view The view
|
|
*/
|
|
protected void bindHeader(View view) {
|
|
}
|
|
|
|
@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 == ITEM_TYPE) {
|
|
// Data
|
|
bindItemView(holder.itemView, position);
|
|
} else if (type == HEADER_TYPE) {
|
|
// Header
|
|
bindHeader(holder.itemView);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get size of task's dataset.
|
|
* @return The size of the dataset
|
|
*/
|
|
protected abstract int getDataSize();
|
|
|
|
@Override
|
|
public int getItemCount() {
|
|
int size;
|
|
if (currentStatus != Task.Status.DONE) {
|
|
// Only Loader
|
|
size = 1;
|
|
} else {
|
|
// Data Size
|
|
size = getDataSize();
|
|
}
|
|
// Header
|
|
size++;
|
|
// Return
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* Get position of first non-header element.
|
|
* @return Element position
|
|
*/
|
|
public int getFirstElementPosition() {
|
|
return 1;
|
|
}
|
|
|
|
@Override
|
|
public int getItemViewType(int position) {
|
|
if (currentStatus != Task.Status.DONE && position == getFirstElementPosition()) {
|
|
// Loader
|
|
return LOADER_TYPE;
|
|
} else if (position == 0) {
|
|
// Header
|
|
return HEADER_TYPE;
|
|
} else {
|
|
// Item
|
|
return ITEM_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());
|
|
}
|
|
|
|
/**
|
|
* Get task.
|
|
* @return The task
|
|
*/
|
|
public Task<E> getTask() {
|
|
return task;
|
|
}
|
|
}
|