Search page renewed

This commit is contained in:
CappielloAntonio 2021-04-20 11:53:51 +02:00
parent a4dc5f643d
commit a7fd7688ab
13 changed files with 358 additions and 174 deletions

View file

@ -17,6 +17,7 @@ import com.cappielloantonio.play.model.Album;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder> { public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder> {
private static final String TAG = "AlbumAdapter"; private static final String TAG = "AlbumAdapter";
@ -75,7 +76,16 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
public void onClick(View view) { public void onClick(View view) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable("album_object", albums.get(getBindingAdapterPosition())); bundle.putParcelable("album_object", albums.get(getBindingAdapterPosition()));
Navigation.findNavController(view).navigate(R.id.action_libraryFragment_to_albumPageFragment, bundle);
if (Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.searchFragment) {
Navigation.findNavController(view).navigate(R.id.action_searchFragment_to_albumPageFragment, bundle);
}
else if(Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.libraryFragment) {
Navigation.findNavController(view).navigate(R.id.action_libraryFragment_to_albumPageFragment, bundle);
}
else if(Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.albumCatalogueFragment) {
Navigation.findNavController(view).navigate(R.id.action_albumCatalogueFragment_to_albumPageFragment, bundle);
}
} }
@Override @Override

View file

@ -17,6 +17,7 @@ import com.cappielloantonio.play.model.Artist;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder> { public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder> {
private static final String TAG = "ArtistAdapter"; private static final String TAG = "ArtistAdapter";
@ -72,7 +73,16 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
public void onClick(View view) { public void onClick(View view) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable("artist_object", artists.get(getBindingAdapterPosition())); bundle.putParcelable("artist_object", artists.get(getBindingAdapterPosition()));
Navigation.findNavController(view).navigate(R.id.action_libraryFragment_to_artistPageFragment, bundle);
if (Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.searchFragment) {
Navigation.findNavController(view).navigate(R.id.action_searchFragment_to_artistPageFragment, bundle);
}
else if(Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.libraryFragment) {
Navigation.findNavController(view).navigate(R.id.action_libraryFragment_to_artistPageFragment, bundle);
}
else if(Objects.requireNonNull(Navigation.findNavController(view).getCurrentDestination()).getId() == R.id.artistCatalogueFragment) {
Navigation.findNavController(view).navigate(R.id.action_artistCatalogueFragment_to_artistPageFragment, bundle);
}
} }
@Override @Override

View file

@ -29,7 +29,7 @@ import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.model.SongArtistCross; import com.cappielloantonio.play.model.SongArtistCross;
import com.cappielloantonio.play.model.SongGenreCross; import com.cappielloantonio.play.model.SongGenreCross;
@Database(entities = {Album.class, Artist.class, Genre.class, Playlist.class, Song.class, RecentSearch.class, SongGenreCross.class, Queue.class, AlbumArtistCross.class, SongArtistCross.class, PlaylistSongCross.class}, version = 10, exportSchema = false) @Database(entities = {Album.class, Artist.class, Genre.class, Playlist.class, Song.class, RecentSearch.class, SongGenreCross.class, Queue.class, AlbumArtistCross.class, SongArtistCross.class, PlaylistSongCross.class}, version = 11, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase { public abstract class AppDatabase extends RoomDatabase {
private static final String TAG = "AppDatabase"; private static final String TAG = "AppDatabase";

View file

@ -7,6 +7,7 @@ import androidx.room.Insert;
import androidx.room.OnConflictStrategy; import androidx.room.OnConflictStrategy;
import androidx.room.Query; import androidx.room.Query;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Genre; import com.cappielloantonio.play.model.Genre;
import java.util.List; import java.util.List;
@ -27,4 +28,10 @@ public interface GenreDao {
@Query("DELETE FROM genre") @Query("DELETE FROM genre")
void deleteAll(); void deleteAll();
@Query("SELECT * FROM genre WHERE name LIKE '%' || :name || '%'")
LiveData<List<Genre>> searchGenre(String name);
@Query("SELECT name FROM genre WHERE name LIKE :query || '%' OR name like '% ' || :query || '%' GROUP BY name LIMIT :number")
List<String> searchSuggestions(String query, int number);
} }

View file

@ -13,12 +13,15 @@ import java.util.List;
@Dao @Dao
public interface RecentSearchDao { public interface RecentSearchDao {
@Query("SELECT * FROM recent_search GROUP BY search ORDER BY id DESC LIMIT :limit") @Query("SELECT * FROM recent_search GROUP BY search ORDER BY search DESC LIMIT :limit")
LiveData<List<RecentSearch>> getLast(int limit); List<String> getRecent(int limit);
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(RecentSearch search); void insert(RecentSearch search);
@Delete
void delete(RecentSearch search);
@Query("DELETE FROM recent_search") @Query("DELETE FROM recent_search")
void deleteAll(); void deleteAll();
} }

View file

@ -8,10 +8,7 @@ import androidx.room.PrimaryKey;
@Entity(tableName = "recent_search") @Entity(tableName = "recent_search")
public class RecentSearch { public class RecentSearch {
@NonNull @NonNull
@PrimaryKey(autoGenerate = true) @PrimaryKey
@ColumnInfo(name = "id")
private int id;
@ColumnInfo(name = "search") @ColumnInfo(name = "search")
private String search; private String search;
@ -20,14 +17,6 @@ public class RecentSearch {
} }
@NonNull @NonNull
public int getId() {
return id;
}
public void setId(@NonNull int id) {
this.id = id;
}
public String getSearch() { public String getSearch() {
return search; return search;
} }

View file

@ -5,8 +5,10 @@ import android.app.Application;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.database.AppDatabase; import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.ArtistDao;
import com.cappielloantonio.play.database.dao.GenreDao; import com.cappielloantonio.play.database.dao.GenreDao;
import com.cappielloantonio.play.database.dao.SongGenreCrossDao; import com.cappielloantonio.play.database.dao.SongGenreCrossDao;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Genre; import com.cappielloantonio.play.model.Genre;
import java.util.ArrayList; import java.util.ArrayList;
@ -17,6 +19,7 @@ public class GenreRepository {
private SongGenreCrossDao songGenreCrossDao; private SongGenreCrossDao songGenreCrossDao;
private LiveData<List<Genre>> listLiveGenres; private LiveData<List<Genre>> listLiveGenres;
private LiveData<List<Genre>> listLiveAlbumGenre; private LiveData<List<Genre>> listLiveAlbumGenre;
private LiveData<List<Genre>> searchListLiveGenre;
public GenreRepository(Application application) { public GenreRepository(Application application) {
AppDatabase database = AppDatabase.getInstance(application); AppDatabase database = AppDatabase.getInstance(application);
@ -110,4 +113,48 @@ public class GenreRepository {
genreDao.deleteAll(); genreDao.deleteAll();
} }
} }
public LiveData<List<Genre>> searchListLiveGenre(String name) {
searchListLiveGenre = genreDao.searchGenre(name);
return searchListLiveGenre;
}
public List<String> getSearchSuggestion(String query) {
List<String> suggestions = new ArrayList<>();
SearchSuggestionsThreadSafe suggestionsThread = new SearchSuggestionsThreadSafe(genreDao, query, 5);
Thread thread = new Thread(suggestionsThread);
thread.start();
try {
thread.join();
suggestions = suggestionsThread.getSuggestions();
} catch (InterruptedException e) {
e.printStackTrace();
}
return suggestions;
}
private static class SearchSuggestionsThreadSafe implements Runnable {
private GenreDao genreDao;
private String query;
private int number;
private List<String> suggestions = new ArrayList<>();
public SearchSuggestionsThreadSafe(GenreDao genreDao, String query, int number) {
this.genreDao = genreDao;
this.query = query;
this.number = number;
}
@Override
public void run() {
suggestions = genreDao.searchSuggestions(query, number);
}
public List<String> getSuggestions() {
return suggestions;
}
}
} }

View file

@ -8,20 +8,15 @@ import com.cappielloantonio.play.database.AppDatabase;
import com.cappielloantonio.play.database.dao.RecentSearchDao; import com.cappielloantonio.play.database.dao.RecentSearchDao;
import com.cappielloantonio.play.model.RecentSearch; import com.cappielloantonio.play.model.RecentSearch;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class RecentSearchRepository { public class RecentSearchRepository {
private RecentSearchDao recentSearchDao; private RecentSearchDao recentSearchDao;
private LiveData<List<RecentSearch>> listLiveRecentSearches;
public RecentSearchRepository(Application application) { public RecentSearchRepository(Application application) {
AppDatabase database = AppDatabase.getInstance(application); AppDatabase database = AppDatabase.getInstance(application);
recentSearchDao = database.recentSearchDao(); recentSearchDao = database.recentSearchDao();
listLiveRecentSearches = recentSearchDao.getLast(3);
}
public LiveData<List<RecentSearch>> getListLiveRecentSearches() {
return listLiveRecentSearches;
} }
public void insert(RecentSearch recentSearch) { public void insert(RecentSearch recentSearch) {
@ -30,6 +25,27 @@ public class RecentSearchRepository {
thread.start(); thread.start();
} }
public void delete(RecentSearch recentSearch) {
DeleteThreadSafe delete = new DeleteThreadSafe(recentSearchDao, recentSearch);
Thread thread = new Thread(delete);
thread.start();
}
private static class DeleteThreadSafe implements Runnable {
private RecentSearchDao recentSearchDao;
private RecentSearch recentSearch;
public DeleteThreadSafe(RecentSearchDao recentSearchDao, RecentSearch recentSearch) {
this.recentSearchDao = recentSearchDao;
this.recentSearch = recentSearch;
}
@Override
public void run() {
recentSearchDao.delete(recentSearch);
}
}
private static class InsertThreadSafe implements Runnable { private static class InsertThreadSafe implements Runnable {
private RecentSearchDao recentSearchDao; private RecentSearchDao recentSearchDao;
private RecentSearch recentSearch; private RecentSearch recentSearch;
@ -63,4 +79,41 @@ public class RecentSearchRepository {
recentSearchDao.deleteAll(); recentSearchDao.deleteAll();
} }
} }
public List<String> getRecentSearchSuggestion() {
List<String> recent = new ArrayList<>();
RecentThreadSafe suggestionsThread = new RecentThreadSafe(recentSearchDao,10);
Thread thread = new Thread(suggestionsThread);
thread.start();
try {
thread.join();
recent = suggestionsThread.getRecent();
} catch (InterruptedException e) {
e.printStackTrace();
}
return recent;
}
private static class RecentThreadSafe implements Runnable {
private RecentSearchDao recentSearchDao;
private int limit;
private List<String> recent = new ArrayList<>();
public RecentThreadSafe(RecentSearchDao recentSearchDao, int limit) {
this.recentSearchDao = recentSearchDao;
this.limit = limit;
}
@Override
public void run() {
recent = recentSearchDao.getRecent(limit);
}
public List<String> getRecent() {
return recent;
}
}
} }

View file

@ -13,13 +13,18 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.play.R;
import com.cappielloantonio.play.adapter.AlbumAdapter;
import com.cappielloantonio.play.adapter.AlbumCatalogueAdapter; import com.cappielloantonio.play.adapter.AlbumCatalogueAdapter;
import com.cappielloantonio.play.adapter.ArtistAdapter;
import com.cappielloantonio.play.adapter.ArtistCatalogueAdapter; import com.cappielloantonio.play.adapter.ArtistCatalogueAdapter;
import com.cappielloantonio.play.adapter.GenreCatalogueAdapter;
import com.cappielloantonio.play.adapter.RecentSearchAdapter; import com.cappielloantonio.play.adapter.RecentSearchAdapter;
import com.cappielloantonio.play.adapter.SongResultSearchAdapter; import com.cappielloantonio.play.adapter.SongResultSearchAdapter;
import com.cappielloantonio.play.databinding.FragmentSearchBinding; import com.cappielloantonio.play.databinding.FragmentSearchBinding;
import com.cappielloantonio.play.helper.recyclerview.GridItemDecoration; import com.cappielloantonio.play.helper.recyclerview.GridItemDecoration;
import com.cappielloantonio.play.model.RecentSearch; import com.cappielloantonio.play.model.RecentSearch;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.ui.activities.MainActivity; import com.cappielloantonio.play.ui.activities.MainActivity;
import com.cappielloantonio.play.viewmodel.SearchViewModel; import com.cappielloantonio.play.viewmodel.SearchViewModel;
import com.paulrybitskyi.persistentsearchview.adapters.model.SuggestionItem; import com.paulrybitskyi.persistentsearchview.adapters.model.SuggestionItem;
@ -35,10 +40,10 @@ public class SearchFragment extends Fragment {
private MainActivity activity; private MainActivity activity;
private SearchViewModel searchViewModel; private SearchViewModel searchViewModel;
private RecentSearchAdapter recentSearchAdapter;
private SongResultSearchAdapter songResultSearchAdapter; private SongResultSearchAdapter songResultSearchAdapter;
private AlbumCatalogueAdapter albumResultSearchAdapter; private AlbumAdapter albumAdapter;
private ArtistCatalogueAdapter artistResultSearchAdapter; private ArtistAdapter artistAdapter;
private GenreCatalogueAdapter genreCatalogueAdapter;
@Nullable @Nullable
@Override @Override
@ -49,8 +54,6 @@ public class SearchFragment extends Fragment {
View view = bind.getRoot(); View view = bind.getRoot();
searchViewModel = new ViewModelProvider(requireActivity()).get(SearchViewModel.class); searchViewModel = new ViewModelProvider(requireActivity()).get(SearchViewModel.class);
init();
initRecentSearchView();
initSearchResultView(); initSearchResultView();
initSearchView(); initSearchView();
@ -63,30 +66,18 @@ public class SearchFragment extends Fragment {
activity.setBottomNavigationBarVisibility(true); activity.setBottomNavigationBarVisibility(true);
} }
@Override
public void onResume() {
super.onResume();
inputFocus();
}
@Override @Override
public void onDestroyView() { public void onDestroyView() {
super.onDestroyView(); super.onDestroyView();
bind = null; bind = null;
} }
private void init() {
bind.clearAllSearchTextViewClickable.setOnClickListener(v -> searchViewModel.deleteAllRecentSearch());
}
private void initRecentSearchView() {
bind.recentlySearchedTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
bind.recentlySearchedTracksRecyclerView.setHasFixedSize(true);
recentSearchAdapter = new RecentSearchAdapter(requireContext());
recentSearchAdapter.setClickListener((view, position) -> {
RecentSearch search = recentSearchAdapter.getItem(position);
search(search.getSearch());
});
bind.recentlySearchedTracksRecyclerView.setAdapter(recentSearchAdapter);
searchViewModel.getSearchList().observe(requireActivity(), recentSearches -> recentSearchAdapter.setItems(recentSearches));
}
private void initSearchResultView() { private void initSearchResultView() {
// Songs // Songs
bind.searchResultTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); bind.searchResultTracksRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
@ -96,28 +87,47 @@ public class SearchFragment extends Fragment {
bind.searchResultTracksRecyclerView.setAdapter(songResultSearchAdapter); bind.searchResultTracksRecyclerView.setAdapter(songResultSearchAdapter);
// Albums // Albums
bind.searchResultAlbumRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2)); bind.searchResultAlbumRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.searchResultAlbumRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
bind.searchResultAlbumRecyclerView.setHasFixedSize(true); bind.searchResultAlbumRecyclerView.setHasFixedSize(true);
albumResultSearchAdapter = new AlbumCatalogueAdapter(requireContext()); albumAdapter = new AlbumAdapter(requireContext());
bind.searchResultAlbumRecyclerView.setAdapter(albumResultSearchAdapter); bind.searchResultAlbumRecyclerView.setAdapter(albumAdapter);
// Artist // Artists
bind.searchResultArtistRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2)); bind.searchResultArtistRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
bind.searchResultArtistRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
bind.searchResultArtistRecyclerView.setHasFixedSize(true); bind.searchResultArtistRecyclerView.setHasFixedSize(true);
artistResultSearchAdapter = new ArtistCatalogueAdapter(requireContext()); artistAdapter = new ArtistAdapter(requireContext());
bind.searchResultArtistRecyclerView.setAdapter(artistResultSearchAdapter); bind.searchResultArtistRecyclerView.setAdapter(artistAdapter);
// Genres
bind.searchResultGenreRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
bind.searchResultGenreRecyclerView.addItemDecoration(new GridItemDecoration(2, 16, false));
bind.searchResultGenreRecyclerView.setHasFixedSize(true);
genreCatalogueAdapter = new GenreCatalogueAdapter(requireContext());
genreCatalogueAdapter.setClickListener((view, position) -> {
Bundle bundle = new Bundle();
bundle.putString(Song.BY_GENRE, Song.BY_GENRE);
bundle.putParcelable("genre_object", genreCatalogueAdapter.getItem(position));
activity.navController.navigate(R.id.action_searchFragment_to_songListPageFragment, bundle);
});
bind.searchResultGenreRecyclerView.setAdapter(genreCatalogueAdapter);
} }
private void initSearchView() { private void initSearchView() {
if (isQueryValid(searchViewModel.getQuery())) {
search(searchViewModel.getQuery());
}
bind.persistentSearchView.setInputQuery(searchViewModel.getQuery());
setSuggestions();
bind.persistentSearchView.setOnSearchQueryChangeListener((searchView, oldQuery, newQuery) -> { bind.persistentSearchView.setOnSearchQueryChangeListener((searchView, oldQuery, newQuery) -> {
if (!newQuery.trim().equals("") && newQuery.trim().length() > 1) { if (!newQuery.trim().equals("") && newQuery.trim().length() > 1) {
searchView.setSuggestions(SuggestionCreationUtil.asRegularSearchSuggestions(searchViewModel.getSearchSuggestion(newQuery)), false); searchView.setSuggestions(SuggestionCreationUtil.asRegularSearchSuggestions(searchViewModel.getSearchSuggestion(newQuery)), false);
} else { } else {
searchView.setSuggestions(new ArrayList<>()); setSuggestions();
} }
}); });
@ -133,27 +143,69 @@ public class SearchFragment extends Fragment {
}); });
bind.persistentSearchView.setOnSearchConfirmedListener((searchView, query) -> { bind.persistentSearchView.setOnSearchConfirmedListener((searchView, query) -> {
search(query); if (isQueryValid(query)) {
searchView.collapse();
search(query);
}
else {
Toast.makeText(requireContext(), "Enter at least three characters", Toast.LENGTH_SHORT).show();
}
}); });
bind.persistentSearchView.setOnSuggestionChangeListener(new OnSuggestionChangeListener() {
@Override
public void onSuggestionPicked(SuggestionItem suggestion) {
search(suggestion.getItemModel().getText());
}
@Override
public void onSuggestionRemoved(SuggestionItem suggestion) {
searchViewModel.deleteRecentSearch(suggestion.getItemModel().getText());
}
});
bind.persistentSearchView.setOnClearInputBtnClickListener(v -> searchViewModel.setQuery(""));
}
private void setSuggestions() {
bind.persistentSearchView.setSuggestions(SuggestionCreationUtil.asRecentSearchSuggestions(searchViewModel.getRecentSearchSuggestion()), false);
} }
public void search(String query) { public void search(String query) {
if (!query.trim().equals("") && query.trim().length() > 2) { searchViewModel.setQuery(query);
searchViewModel.insertNewSearch(query);
bind.persistentSearchView.collapse();
bind.persistentSearchView.setInputQuery(query); bind.persistentSearchView.setInputQuery(query);
performSearch(query.trim()); performSearch(query);
} else {
Toast.makeText(requireContext(), "Enter at least three characters", Toast.LENGTH_SHORT).show();
}
} }
private void performSearch(String query) { private void performSearch(String query) {
searchViewModel.searchSong(query).observe(requireActivity(), songs -> songResultSearchAdapter.setItems(songs)); searchViewModel.searchSong(query).observe(requireActivity(), songs -> {
searchViewModel.searchAlbum(query).observe(requireActivity(), albums -> albumResultSearchAdapter.setItems(albums)); if(bind != null) bind.searchSongSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
searchViewModel.searchArtist(query).observe(requireActivity(), artists -> artistResultSearchAdapter.setItems(artists)); songResultSearchAdapter.setItems(songs);
});
searchViewModel.searchAlbum(query).observe(requireActivity(), albums -> {
if(bind != null) bind.searchAlbumSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
albumAdapter.setItems(albums);
});
searchViewModel.searchArtist(query).observe(requireActivity(), artists -> {
if(bind != null) bind.searchArtistSector.setVisibility(!artists.isEmpty() ? View.VISIBLE : View.GONE);
artistAdapter.setItems(artists);
});
searchViewModel.searchGenre(query).observe(requireActivity(), genres -> {
if(bind != null) bind.searchGenreSector.setVisibility(!genres.isEmpty() ? View.VISIBLE : View.GONE);
genreCatalogueAdapter.setItems(genres);
});
bind.searchResultLayout.setVisibility(View.VISIBLE); bind.searchResultLayout.setVisibility(View.VISIBLE);
} }
private boolean isQueryValid(String query) {
return !query.equals("") && query.trim().length() > 2;
}
private void inputFocus() {
if(!isQueryValid(searchViewModel.getQuery())) {
bind.persistentSearchView.expand();
}
}
} }

View file

@ -8,10 +8,12 @@ import androidx.lifecycle.LiveData;
import com.cappielloantonio.play.model.Album; import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist; import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Genre;
import com.cappielloantonio.play.model.RecentSearch; import com.cappielloantonio.play.model.RecentSearch;
import com.cappielloantonio.play.model.Song; import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.AlbumRepository; import com.cappielloantonio.play.repository.AlbumRepository;
import com.cappielloantonio.play.repository.ArtistRepository; import com.cappielloantonio.play.repository.ArtistRepository;
import com.cappielloantonio.play.repository.GenreRepository;
import com.cappielloantonio.play.repository.RecentSearchRepository; import com.cappielloantonio.play.repository.RecentSearchRepository;
import com.cappielloantonio.play.repository.SongRepository; import com.cappielloantonio.play.repository.SongRepository;
@ -22,15 +24,18 @@ import java.util.List;
public class SearchViewModel extends AndroidViewModel { public class SearchViewModel extends AndroidViewModel {
private static final String TAG = "SearchViewModel"; private static final String TAG = "SearchViewModel";
private String query = "";
private SongRepository songRepository; private SongRepository songRepository;
private AlbumRepository albumRepository; private AlbumRepository albumRepository;
private ArtistRepository artistRepository; private ArtistRepository artistRepository;
private GenreRepository genreRepository;
private RecentSearchRepository recentSearchRepository; private RecentSearchRepository recentSearchRepository;
private LiveData<List<Song>> searchSong; private LiveData<List<Song>> searchSong;
private LiveData<List<Album>> searchAlbum; private LiveData<List<Album>> searchAlbum;
private LiveData<List<Artist>> searchArtist; private LiveData<List<Artist>> searchArtist;
private LiveData<List<RecentSearch>> recentSearches; private LiveData<List<Genre>> searchGenre;
public SearchViewModel(@NonNull Application application) { public SearchViewModel(@NonNull Application application) {
super(application); super(application);
@ -38,9 +43,22 @@ public class SearchViewModel extends AndroidViewModel {
songRepository = new SongRepository(application); songRepository = new SongRepository(application);
albumRepository = new AlbumRepository(application); albumRepository = new AlbumRepository(application);
artistRepository = new ArtistRepository(application); artistRepository = new ArtistRepository(application);
genreRepository = new GenreRepository(application);
recentSearchRepository = new RecentSearchRepository(application); recentSearchRepository = new RecentSearchRepository(application);
} }
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
if(!query.isEmpty()) {
insertNewSearch(query);
}
}
public LiveData<List<Song>> searchSong(String title) { public LiveData<List<Song>> searchSong(String title) {
searchSong = songRepository.searchListLiveSong(title); searchSong = songRepository.searchListLiveSong(title);
return searchSong; return searchSong;
@ -56,17 +74,17 @@ public class SearchViewModel extends AndroidViewModel {
return searchArtist; return searchArtist;
} }
public LiveData<List<RecentSearch>> getSearchList() { public LiveData<List<Genre>> searchGenre(String name) {
recentSearches = recentSearchRepository.getListLiveRecentSearches(); searchGenre = genreRepository.searchListLiveGenre(name);
return recentSearches; return searchGenre;
} }
public void insertNewSearch(String search) { public void insertNewSearch(String search) {
recentSearchRepository.insert(new RecentSearch(search)); recentSearchRepository.insert(new RecentSearch(search));
} }
public void deleteAllRecentSearch() { public void deleteRecentSearch(String search) {
recentSearchRepository.deleteAll(); recentSearchRepository.delete(new RecentSearch(search));
} }
public List<String> getSearchSuggestion(String query) { public List<String> getSearchSuggestion(String query) {
@ -74,10 +92,18 @@ public class SearchViewModel extends AndroidViewModel {
suggestions.addAll(songRepository.getSearchSuggestion(query)); suggestions.addAll(songRepository.getSearchSuggestion(query));
suggestions.addAll(albumRepository.getSearchSuggestion(query)); suggestions.addAll(albumRepository.getSearchSuggestion(query));
suggestions.addAll(artistRepository.getSearchSuggestion(query)); suggestions.addAll(artistRepository.getSearchSuggestion(query));
suggestions.addAll(genreRepository.getSearchSuggestion(query));
LinkedHashSet<String> hashSet = new LinkedHashSet<>(suggestions); LinkedHashSet<String> hashSet = new LinkedHashSet<>(suggestions);
ArrayList<String> suggestionsWithoutDuplicates = new ArrayList<>(hashSet); ArrayList<String> suggestionsWithoutDuplicates = new ArrayList<>(hashSet);
return suggestionsWithoutDuplicates; return suggestionsWithoutDuplicates;
} }
public List<String> getRecentSearchSuggestion() {
ArrayList<String> suggestions = new ArrayList<>();
suggestions.addAll(recentSearchRepository.getRecentSearchSuggestion());
return suggestions;
}
} }

View file

@ -42,159 +42,143 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/persistentSearchView" > android:layout_below="@id/persistentSearchView" >
<!-- Search result -->
<LinearLayout <LinearLayout
android:id="@+id/search_result_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical"
android:paddingBottom="@dimen/global_padding_bottom"
android:visibility="gone">
<!-- Recent searched --> <!-- Songs -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:id="@+id/search_song_sector"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Label and button -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingTop="8dp"
android:paddingEnd="8dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingBottom="8dp"
android:paddingEnd="8dp"
android:text="Recent Searches"
android:textColor="@color/titleTextColor"
android:textSize="22sp"
android:textStyle="bold" />
<TextView
android:id="@+id/clear_all_search_text_view_clickable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="8dp"
android:paddingTop="12dp"
android:paddingEnd="8dp"
android:text="Clear all"
android:textColor="@color/subtitleTextColor"
android:textSize="14sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recently_searched_tracks_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="4dp"
android:clipToPadding="false"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:nestedScrollingEnabled="false"/>
</LinearLayout>
<!-- Search result -->
<LinearLayout
android:id="@+id/search_result_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:paddingBottom="@dimen/global_padding_bottom" android:paddingBottom="8dp">
android:visibility="gone">
<!-- Label -->
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family" android:fontFamily="@font/open_sans_font_family"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="20dp"
android:paddingEnd="8dp" android:paddingEnd="16dp"
android:text="Search results"
android:textColor="@color/titleTextColor"
android:textSize="22sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="8dp"
android:text="Songs" android:text="Songs"
android:textColor="@color/titleTextColor" android:textColor="@color/titleTextColor"
android:textSize="18sp" android:textSize="22sp"
android:textStyle="bold" /> android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_result_tracks_recycler_view" android:id="@+id/search_result_tracks_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginTop="4dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false" android:clipToPadding="false"
android:overScrollMode="never"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingBottom="24dp" android:paddingBottom="8dp" />
android:nestedScrollingEnabled="false"/> </LinearLayout>
<!-- Album -->
<LinearLayout
android:id="@+id/search_album_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family" android:fontFamily="@font/open_sans_font_family"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="20dp"
android:paddingEnd="8dp" android:paddingEnd="16dp"
android:text="Albums" android:text="Albums"
android:textColor="@color/titleTextColor" android:textColor="@color/titleTextColor"
android:textSize="18sp" android:textSize="22sp"
android:textStyle="bold" /> android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_result_album_recycler_view" android:id="@+id/search_result_album_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginTop="4dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false" android:clipToPadding="false"
android:overScrollMode="never"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:paddingBottom="16dp" android:paddingBottom="8dp" />
android:nestedScrollingEnabled="false"/> </LinearLayout>
<!-- Artist -->
<LinearLayout
android:id="@+id/search_artist_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family" android:fontFamily="@font/open_sans_font_family"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="8dp" android:paddingTop="20dp"
android:paddingTop="8dp" android:paddingEnd="16dp"
android:text="Artists" android:text="Artists"
android:textColor="@color/titleTextColor" android:textColor="@color/titleTextColor"
android:textSize="18sp" android:textSize="22sp"
android:textStyle="bold" /> android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_result_artist_recycler_view" android:id="@+id/search_result_artist_recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginTop="4dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false" android:clipToPadding="false"
android:overScrollMode="never"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="8dp" android:paddingTop="8dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:paddingBottom="56dp" android:paddingBottom="8dp" />
android:nestedScrollingEnabled="false"/> </LinearLayout>
<!-- Genre -->
<LinearLayout
android:id="@+id/search_genre_sector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/open_sans_font_family"
android:paddingStart="16dp"
android:paddingTop="20dp"
android:paddingEnd="16dp"
android:text="Genres"
android:textColor="@color/titleTextColor"
android:textSize="22sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_result_genre_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View file

@ -32,7 +32,7 @@
android:id="@+id/genre_label" android:id="@+id/genre_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:gravity="center_vertical"
android:fontFamily="@font/open_sans_font_family" android:fontFamily="@font/open_sans_font_family"
android:paddingStart="8dp" android:paddingStart="8dp"
android:text="@string/label_placeholder" android:text="@string/label_placeholder"

View file

@ -129,6 +129,9 @@
<action <action
android:id="@+id/action_searchFragment_to_albumPageFragment" android:id="@+id/action_searchFragment_to_albumPageFragment"
app:destination="@id/albumPageFragment" /> app:destination="@id/albumPageFragment" />
<action
android:id="@+id/action_searchFragment_to_songListPageFragment"
app:destination="@id/songListPageFragment" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/filterFragment" android:id="@+id/filterFragment"