package com.marverenic.music.data.store; import android.content.Context; import android.net.Uri; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializer; import com.marverenic.music.model.Album; import com.marverenic.music.model.Artist; import com.marverenic.music.model.Genre; import com.marverenic.music.model.Song; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import rx.Observable; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import rx.subjects.BehaviorSubject; public class DemoMusicStore implements MusicStore { private static final String SONGS_FILENAME = "library-songs.json"; private static final String ARTISTS_FILENAME = "library-artists.json"; private static final String ALBUMS_FILENAME = "library-albums.json"; private static final String GENRES_FILENAME = "library-genres.json"; private Context mContext; private Observable<List<Song>> mSongs; private Observable<List<Album>> mAlbums; private Observable<List<Artist>> mArtists; private Observable<List<Genre>> mGenres; public DemoMusicStore(Context context) { mContext = context; } @Override public void loadAll() { // Do nothing. Performance isn't important in the demo app, so just load lazily. } @Override public Observable<Boolean> refresh() { return Observable.just(true); } @Override public Observable<Boolean> isLoading() { return Observable.just(false); } @Override public Observable<List<Song>> getSongs() { if (mSongs == null) { BehaviorSubject<List<Song>> subject = BehaviorSubject.create(); Observable.fromCallable(() -> this.<Song>parseJson(SONGS_FILENAME, Song[].class)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subject::onNext, subject::onError); mSongs = subject.asObservable(); } return mSongs; } @Override public Observable<List<Album>> getAlbums() { if (mAlbums == null) { BehaviorSubject<List<Album>> subject = BehaviorSubject.create(); Observable.fromCallable(() -> this.<Album>parseJson(ALBUMS_FILENAME, Album[].class)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subject::onNext, subject::onError); mAlbums = subject.asObservable(); } return mAlbums; } @Override public Observable<List<Artist>> getArtists() { if (mArtists == null) { BehaviorSubject<List<Artist>> subject = BehaviorSubject.create(); Observable.fromCallable(() -> this.<Artist>parseJson(ARTISTS_FILENAME, Artist[].class)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subject::onNext, subject::onError); mArtists = subject.asObservable(); } return mArtists; } @Override public Observable<List<Genre>> getGenres() { if (mGenres == null) { BehaviorSubject<List<Genre>> subject = BehaviorSubject.create(); Observable.fromCallable(() -> this.<Genre>parseJson(GENRES_FILENAME, Genre[].class)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subject::onNext, subject::onError); mGenres = subject.asObservable(); } return mGenres; } @SuppressWarnings("ThrowFromFinallyBlock") private <T extends Comparable<? super T>> List<T> parseJson( String filename, Class<? extends T[]> type) throws IOException { InputStream stream = null; InputStreamReader reader = null; try { File json = new File(mContext.getExternalFilesDir(null), filename); stream = new FileInputStream(json); reader = new InputStreamReader(stream); Gson gson = new GsonBuilder() .registerTypeAdapter(Uri.class, (JsonDeserializer) (src, srcType, c) -> Uri.parse(src.getAsString())) .create(); T[] values = gson.fromJson(reader, type); ArrayList<T> list = new ArrayList<>(Arrays.asList(values)); Collections.sort(list); return list; } finally { if (stream != null) stream.close(); if (reader != null) reader.close(); } } @Override public Observable<List<Song>> getSongs(Artist artist) { return getSongs().map( library -> { List<Song> filtered = new ArrayList<>(); for (Song song : library) { if (song.getArtistId() == artist.getArtistId()) { filtered.add(song); } } return filtered; }); } @Override public Observable<List<Song>> getSongs(Album album) { return getSongs().map( library -> { List<Song> filtered = new ArrayList<>(); for (Song song : library) { if (song.getAlbumId() == album.getAlbumId()) { filtered.add(song); } } return filtered; }); } @Override public Observable<List<Song>> getSongs(Genre genre) { throw new UnsupportedOperationException("Genre contents are not supported in demo library"); } @Override public Observable<List<Album>> getAlbums(Artist artist) { return getAlbums().map( library -> { List<Album> filtered = new ArrayList<>(); for (Album album : library) { if (album.getArtistId() == artist.getArtistId()) { filtered.add(album); } } return filtered; }); } @Override public Observable<Artist> findArtistById(long artistId) { return getArtists().flatMap( library -> { for (Artist artist : library) { if (artist.getArtistId() == artistId) { return Observable.just(artist); } } return Observable.just(null); }); } @Override public Observable<Album> findAlbumById(long albumId) { return getAlbums().flatMap( library -> { for (Album album : library) { if (album.getAlbumId() == albumId) { return Observable.just(album); } } return Observable.just(null); }); } @Override public Observable<Artist> findArtistByName(String artistName) { return getArtists().flatMap( library -> { for (Artist artist : library) { if (artist.getArtistName().equals(artistName)) { return Observable.just(artist); } } return Observable.just(null); }); } @Override public Observable<List<Song>> searchForSongs(String query) { return getSongs().map( library -> { List<Song> filtered = new ArrayList<>(); for (Song song : library) { if (song.getSongName().contains(query)) { filtered.add(song); } } return filtered; }); } @Override public Observable<List<Artist>> searchForArtists(String query) { return getArtists().map( library -> { List<Artist> filtered = new ArrayList<>(); for (Artist artist : library) { if (artist.getArtistName().contains(query)) { filtered.add(artist); } } return filtered; }); } @Override public Observable<List<Album>> searchForAlbums(String query) { return getAlbums().map( library -> { List<Album> filtered = new ArrayList<>(); for (Album album : library) { if (album.getArtistName().contains(query)) { filtered.add(album); } } return filtered; }); } @Override public Observable<List<Genre>> searchForGenres(String query) { return getGenres().map( library -> { List<Genre> filtered = new ArrayList<>(); for (Genre genre : library) { if (genre.getGenreName().contains(query)) { filtered.add(genre); } } return filtered; }); } }