package it.niedermann.nextcloud.deck.ui.main.search; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.R; import it.niedermann.nextcloud.deck.databinding.ItemSearchCardBinding; import it.niedermann.nextcloud.deck.databinding.ItemSearchStackBinding; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.Stack; import it.niedermann.nextcloud.deck.model.full.FullBoard; import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.model.interfaces.IRemoteEntity; import it.niedermann.nextcloud.deck.ui.card.CardActionListener; import it.niedermann.nextcloud.deck.ui.card.CardOptionsItemSelectedListener; public class SearchAdapter extends RecyclerView.Adapter implements CardOptionsItemSelectedListener { private static final int TYPE_STACK = 0; private static final int TYPE_CARD = 1; @NonNull private CardActionListener cardActionListener; @Nullable private Account account; @Nullable private FullBoard fullBoard; private final List items = new ArrayList<>(); @NonNull private String term = ""; public SearchAdapter(@NonNull CardActionListener cardActionListener) { this.cardActionListener = cardActionListener; } @NonNull @Override public SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { final var context = parent.getContext(); switch (viewType) { case TYPE_STACK: { return new SearchStackViewHolder(ItemSearchStackBinding.inflate(LayoutInflater.from(context), parent, false)); } case TYPE_CARD: { return new SearchCardViewHolder(ItemSearchCardBinding.inflate(LayoutInflater.from(context), parent, false)); } default: { throw new UnsupportedOperationException("Unknown view type: " + viewType); } } } @Override public void onBindViewHolder(@NonNull SearchViewHolder holder, int position) { switch (getItemViewType(position)) { case TYPE_STACK: { final var localId = -getItemId(position); items.stream() .filter(item -> item.getClass() == Stack.class) .filter(item -> item.getLocalId() == localId) .findAny() .map(item -> (Stack) item) .ifPresent(stack -> { final var searchStackViewHolder = (SearchStackViewHolder) holder; searchStackViewHolder.bind(stack); if (fullBoard == null) { DeckLog.logError(new IllegalStateException("board is null")); return; } searchStackViewHolder.applyTheme(fullBoard.getBoard().getColor()); }); break; } case TYPE_CARD: { if (account == null || fullBoard == null) { DeckLog.logError(new IllegalStateException("account or board is null")); break; } final var localId = getItemId(position); items.stream() .filter(item -> item.getClass() == FullCard.class) .filter(item -> item.getLocalId() == localId) .findAny() .map(item -> (FullCard) item) .ifPresent(fullCard -> { final var searchCardViewHolder = (SearchCardViewHolder) holder; searchCardViewHolder.bind(account, fullBoard.getLocalId(), fullCard, fullBoard.getId(), R.menu.card_menu, this); searchCardViewHolder.applyTheme(fullBoard.getBoard().getColor(), term); }); break; } default: { throw new UnsupportedOperationException("Unknown view type for position " + position); } } } @Override public int getItemViewType(int position) { return getItemId(position) > 0 ? TYPE_CARD : TYPE_STACK; } /** * @return {@link FullCard#getLocalId()} or negated {@link Stack#getLocalId()} */ @Override public long getItemId(int position) { final var item = items.get(position); final var clazz = item.getClass(); if (clazz == Stack.class) { return -item.getLocalId(); } else if (clazz == FullCard.class) { return item.getLocalId(); } throw new UnsupportedOperationException("Expected item list to only contain " + Stack.class.getSimpleName() + " or " + FullCard.class.getSimpleName() + " but found " + clazz.getSimpleName()); } @Override public int getItemCount() { return items.size(); } public void setItems(@NonNull SearchResults results) { this.account = results.account; this.fullBoard = results.fullBoard; this.term = results.term; this.items.clear(); results.result.entrySet() .stream() .sorted(Comparator.comparingLong(o -> o.getKey().getOrder())) .forEach(entry -> { this.items.add(entry.getKey()); this.items.addAll(entry.getValue()); }); notifyDataSetChanged(); } @Override public boolean onCardOptionsItemSelected(@NonNull MenuItem menuItem, @NonNull FullCard fullCard) { final int itemId = menuItem.getItemId(); if (itemId == R.id.share_link) { if (fullBoard == null) { DeckLog.warn("Can not share link to card", fullCard.getCard().getTitle(), "because fullBoard is null"); return false; } cardActionListener.onShareLink(fullBoard, fullCard); return true; } else if (itemId == R.id.share_content) { cardActionListener.onShareContent(fullCard); } else if (itemId == R.id.action_card_assign) { cardActionListener.onAssignCurrentUser(fullCard); return true; } else if (itemId == R.id.action_card_unassign) { cardActionListener.onUnassignCurrentUser(fullCard); return true; } else if (itemId == R.id.action_card_move) { if (fullBoard == null) { DeckLog.warn("Can not move card", fullCard.getCard().getTitle(), "because fullBoard is null"); return false; } cardActionListener.onMove(fullBoard, fullCard); return true; } else if (itemId == R.id.action_card_archive) { cardActionListener.onArchive(fullCard); return true; } else if (itemId == R.id.action_card_delete) { cardActionListener.onDelete(fullCard); return true; } return true; } }