diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/data/MonsterRepository.java b/Android/app/src/main/java/com/majinnaibu/monstercards/data/MonsterRepository.java index 5aba6b2..09d95cb 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/data/MonsterRepository.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/data/MonsterRepository.java @@ -8,6 +8,7 @@ import com.majinnaibu.monstercards.models.Collection; import com.majinnaibu.monstercards.models.CollectionMonster; import com.majinnaibu.monstercards.models.CollectionWithCount; import com.majinnaibu.monstercards.models.Monster; +import com.majinnaibu.monstercards.models.SearchResultItem; import java.util.ArrayList; import java.util.List; @@ -50,6 +51,43 @@ public class MonsterRepository { .observeOn(AndroidSchedulers.mainThread()); } + public Flowable> searchAll(String searchText) { + Flowable> monstersFlowable = m_db.monsterDAO() + .getAll() + .map(monsters -> { + ArrayList filteredMonsters = new ArrayList<>(); + for (Monster monster : monsters) { + if (Helpers.monsterMatchesSearch(monster, searchText)) { + filteredMonsters.add(monster); + } + } + return (List) filteredMonsters; + }); + + Flowable> collectionsFlowable = m_db.collectionDAO() + .getAll() + .map(collections -> { + ArrayList filteredCollections = new ArrayList<>(); + for (Collection collection : collections) { + if (StringHelper.isNullOrEmpty(searchText) || StringHelper.containsCaseInsensitive(collection.name, searchText)) { + filteredCollections.add(collection); + } + } + return (List) filteredCollections; + }); + + return Flowable.combineLatest(monstersFlowable, collectionsFlowable, (monsters, collections) -> { + ArrayList results = new ArrayList<>(); + for (Monster monster : monsters) { + results.add(new SearchResultItem(monster)); + } + for (Collection collection : collections) { + results.add(new SearchResultItem(collection)); + } + return (List) results; + }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); + } + public Flowable getMonster(@NonNull UUID monsterId) { return m_db.monsterDAO() .loadAllByIds(new String[]{monsterId.toString()}) diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/models/SearchResultItem.java b/Android/app/src/main/java/com/majinnaibu/monstercards/models/SearchResultItem.java new file mode 100644 index 0000000..1d02b29 --- /dev/null +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/models/SearchResultItem.java @@ -0,0 +1,32 @@ +package com.majinnaibu.monstercards.models; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class SearchResultItem { + public enum Type { + MONSTER, + COLLECTION + } + + @NonNull + public final Type type; + + @Nullable + public final Monster monster; + + @Nullable + public final Collection collection; + + public SearchResultItem(@NonNull Monster monster) { + this.type = Type.MONSTER; + this.monster = monster; + this.collection = null; + } + + public SearchResultItem(@NonNull Collection collection) { + this.type = Type.COLLECTION; + this.monster = null; + this.collection = collection; + } +} diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java index 12ab602..ad0095b 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java @@ -9,11 +9,14 @@ import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.navigation.NavDirections; +import androidx.navigation.Navigation; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.data.MonsterRepository; +import com.majinnaibu.monstercards.models.SearchResultItem; import com.majinnaibu.monstercards.ui.shared.MCFragment; public class SearchFragment extends MCFragment { @@ -22,7 +25,17 @@ public class SearchFragment extends MCFragment { ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_search, container, false); MonsterRepository repository = this.getMonsterRepository(); - SearchResultsRecyclerViewAdapter adapter = new SearchResultsRecyclerViewAdapter(repository, null); + SearchResultsRecyclerViewAdapter adapter = new SearchResultsRecyclerViewAdapter(repository, item -> { + if (item != null) { + if (item.type == SearchResultItem.Type.MONSTER && item.monster != null) { + NavDirections action = SearchFragmentDirections.actionNavigationSearchToNavigationMonster(item.monster.id.toString()); + Navigation.findNavController(requireView()).navigate(action); + } else if (item.type == SearchResultItem.Type.COLLECTION && item.collection != null) { + NavDirections action = SearchFragmentDirections.actionNavigationSearchToCollectionDetailFragment(item.collection.id.toString()); + Navigation.findNavController(requireView()).navigate(action); + } + } + }); final RecyclerView recyclerView = root.findViewById(R.id.monster_list); assert recyclerView != null; setupRecyclerView(recyclerView, adapter); diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java index 93c546a..3a010a9 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java @@ -3,6 +3,7 @@ package com.majinnaibu.monstercards.ui.search; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; @@ -10,7 +11,10 @@ import androidx.recyclerview.widget.RecyclerView; import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.data.MonsterRepository; +import com.majinnaibu.monstercards.helpers.StringHelper; +import com.majinnaibu.monstercards.models.Collection; import com.majinnaibu.monstercards.models.Monster; +import com.majinnaibu.monstercards.models.SearchResultItem; import com.majinnaibu.monstercards.utils.Logger; import java.util.ArrayList; @@ -23,7 +27,7 @@ public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter mValues; + private List mValues; private Disposable mSubscriptionHandler; public SearchResultsRecyclerViewAdapter(MonsterRepository repository, @@ -42,9 +46,9 @@ public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter> foundMonsters = mRepository.searchMonsters(mSearchText); - mSubscriptionHandler = foundMonsters.subscribe(monsters -> { - mValues = monsters; + Flowable> resultsFlowable = mRepository.searchAll(mSearchText); + mSubscriptionHandler = resultsFlowable.subscribe(results -> { + mValues = results; notifyDataSetChanged(); }, throwable -> Logger.logError("Error performing search", throwable)); @@ -54,18 +58,52 @@ public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter 0) { + sb.append(", "); + } + sb.append("CR ").append(cr); + } + if (sb.length() > 0) { + holder.mSubtitleView.setText(sb.toString()); + holder.mSubtitleView.setVisibility(View.VISIBLE); + } else { + holder.mSubtitleView.setVisibility(View.GONE); + } + holder.mIconView.setVisibility(View.GONE); + } else if (item.type == SearchResultItem.Type.COLLECTION && item.collection != null) { + Collection collection = item.collection; + holder.mTitleView.setText(collection.name); + + if (!StringHelper.isNullOrEmpty(collection.description)) { + holder.mSubtitleView.setText(collection.description); + holder.mSubtitleView.setVisibility(View.VISIBLE); + } else { + holder.mSubtitleView.setVisibility(View.GONE); + } + holder.mIconView.setVisibility(View.VISIBLE); + } + + holder.itemView.setTag(item); holder.itemView.setOnClickListener(view -> { if (mOnClickHandler != null) { - mOnClickHandler.onItem(monster); + mOnClickHandler.onItem(item); } }); } @@ -76,15 +114,19 @@ public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter + + + + + + + + + + + diff --git a/Android/app/src/main/res/navigation/mobile_navigation.xml b/Android/app/src/main/res/navigation/mobile_navigation.xml index 7d8193e..23d9422 100644 --- a/Android/app/src/main/res/navigation/mobile_navigation.xml +++ b/Android/app/src/main/res/navigation/mobile_navigation.xml @@ -13,6 +13,9 @@ +