Closed AceTsak closed 2 years ago
Class Track Details
`package com.example.sporify.activities.track;
import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider;
import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Html; import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast;
import com.bumptech.glide.Glide; import com.example.sporify.R; import com.example.sporify.adapters.LibraryAdapter; import com.example.sporify.fragments.library.LibraryViewModel; import com.example.sporify.models.Playlist; import com.example.sporify.models.Searchable; import com.example.sporify.models.Track; import com.example.sporify.utils.Type;
import java.util.ArrayList; import java.util.List;
public class TrackDetails extends AppCompatActivity {
TextView trackName, artistName, trackContent, trackSummary;
ImageView trackImage, artistImage;
private TrackDetailsViewModel trackDetailsViewModel;
private FavoriteTrackViewModel favoriteTrackViewModel;
private LibraryViewModel libraryViewModel;
private Track trackInfo;
private ImageButton addFavorite, playlistBtn;
private Searchable searchable;
private String token;
private List<Playlist> playlists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_track_details);
trackDetailsViewModel = new ViewModelProvider(this).get(TrackDetailsViewModel.class);
favoriteTrackViewModel = new ViewModelProvider(this).get(FavoriteTrackViewModel.class);
libraryViewModel = new ViewModelProvider(this).get(LibraryViewModel.class);
// Getting user token from shared prefs
SharedPreferences sharedPref = this.getSharedPreferences("user", Context.MODE_PRIVATE);
token = sharedPref.getString("token", "token");
trackName = findViewById(R.id.track_name);
artistName = findViewById(R.id.track_artist);
trackImage = findViewById(R.id.track_image);
artistImage = findViewById(R.id.artist_image);
trackContent = findViewById(R.id.track_content);
trackSummary = findViewById(R.id.track_summary);
addFavorite = findViewById(R.id.add_favorite);
playlistBtn = findViewById(R.id.playlist_button);
Intent intent = getIntent();
searchable = new Searchable();
playlists = new ArrayList<>();
if(intent.getSerializableExtra("item") != null){
searchable = (Searchable) intent.getSerializableExtra("item");
Log.d("SEARCHABLE", searchable.getMbid());
}
// show track details
showTrackInfo();
// favorite button listener
addFavorite();
// fetch playlists
getPlaylists();
// manage playlist dialog
playlistBtn.setOnClickListener(view -> {
PlaylistDialog playlistDialog = new PlaylistDialog(searchable.getMbid(), token, trackInfo,playlists);
if(!playlistDialog.isAdded()){
playlistDialog.show(getSupportFragmentManager(), PlaylistDialog.TAG);
}
});
}
private void addFavorite(){
// listener when add favorite is tapped
addFavorite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Observer<String> observer1 = new Observer<String>() {
@Override
public void onChanged(String response) {
if(response == null)
return;
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_SHORT).show();
favoriteTrackViewModel.getFavoriteTracksResponse().removeObservers(TrackDetails.this);
}
};
favoriteTrackViewModel.init(searchable.getMbid(), token, trackInfo);
favoriteTrackViewModel.getFavoriteTracksResponse().observe(TrackDetails.this, observer1);
}
});
}
private void showTrackInfo(){
trackInfo = new Track();
Observer<Track> observer = track -> {
if(track != null){
trackInfo = track;
trackName.setText(track.getName());
artistName.setText(track.getArtistName());
trackSummary.setMovementMethod(LinkMovementMethod.getInstance());
trackSummary.setText(Html.fromHtml(track.getSummary()));
trackContent.setMovementMethod(LinkMovementMethod.getInstance());
trackContent.setText(Html.fromHtml(track.getContent()));
// trackContent.setText(track.getContent());
Glide.with(getApplicationContext())
.load(track.getImageURL().isEmpty() ? R.drawable.artist_placeholder : track.getImageURL())
.fitCenter()
.into(trackImage);
Glide.with(getApplicationContext())
.load(track.getArtistImageURL().isEmpty() ? R.drawable.artist_placeholder : track.getArtistImageURL())
.fitCenter()
.into(artistImage);
}
// trackDetailsViewModel.getTrack().removeObservers(TrackDetails.this);
};
trackDetailsViewModel.getTrackInfo(searchable.getMbid()).observe(this, observer);
}
private void getPlaylists(){
libraryViewModel.init(token);
Observer<List<Playlist>> playlistObserver = new Observer<List<Playlist>>() {
@Override
public void onChanged(List<Playlist> playlistsData) {
if(playlistsData.size() <= 0){
Toast.makeText(getApplicationContext(), "Empty", Toast.LENGTH_SHORT).show();
}
playlists = new ArrayList<>(playlistsData);
}
};
libraryViewModel.getPlaylists().observe(this, playlistObserver);
}
}`
Class TrackDetailsViewModel
`package com.example.sporify.activities.track;
import android.app.Application; import android.util.Log; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel;
import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.JsonObjectRequest; import com.example.sporify.interfaces.VolleyCallBackAlt; import com.example.sporify.mappers.ArtistMapper; import com.example.sporify.mappers.TrackMapper; import com.example.sporify.models.Album; import com.example.sporify.models.Track; import com.example.sporify.models.Track; import com.example.sporify.utils.MyApplication; import com.example.sporify.utils.VolleySingleton;
import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject;
import java.util.ArrayList; import java.util.List;
public class TrackDetailsViewModel extends ViewModel {
private MutableLiveData<Track> trackLiveData;
private Track track;
private RequestQueue requestQueue;
public TrackDetailsViewModel() {
track = new Track();
requestQueue = VolleySingleton.getmInstance(MyApplication.getAppContext()).getRequestQueue();
}
public LiveData<Track> getTrack() {
return trackLiveData;
}
public LiveData<Track> getTrackInfo(String mbid){
track = new Track();
if (trackLiveData == null) {
trackLiveData = new MutableLiveData<>();
getTrackInfo(mbid, new VolleyCallBackAlt() {
@Override
public void onSuccess(String id) {
getArtistImage(id);
}
});
}
return trackLiveData;
}
private LiveData<Track> getTrackInfo(String mbid, final VolleyCallBackAlt callBack){
final MutableLiveData<Track> TrackData = new MutableLiveData<>();
String url =
"http://ws.audioscrobbler.com/2.0/?method=track.getinfo&mbid=" + mbid+ "&api_key=8fc89f699e4ff45a21b968623a93ed52&format=json";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, response -> {
try {
track = TrackMapper.getTrackFromJson(response);
callBack.onSuccess(track.getArtistMbid());
trackLiveData.setValue(track);
trackLiveData.postValue(track);
} catch (JSONException e) {
Log.d("Parsing error: ", e.getMessage());
try {
reFetchTrackInfo(response, callBack);
} catch (JSONException jsonException) {
jsonException.printStackTrace();
}
}
finally {
trackLiveData.setValue(track);
trackLiveData.postValue(track);
}
}, error -> {
trackLiveData.setValue(null);
trackLiveData.postValue(null);
});
requestQueue.add(jsonObjectRequest).addMarker("a");
return TrackData;
}
private void reFetchTrackInfo(JSONObject jsonObject, VolleyCallBackAlt callBack) throws JSONException {
JSONObject trackObject = jsonObject.getJSONObject("track");
String name = trackObject.getString("name");
String image = trackObject.getJSONObject("album").getJSONArray("image").getJSONObject(3).getString("#text");
String artistName = trackObject.getJSONObject("artist").getString("name");
String artistMbid = trackObject.getJSONObject("artist").getString("mbid");
track = new Track(name, image, artistName, artistMbid, "No summary for this track", "No more content for this track");
callBack.onSuccess(artistMbid);
}
private LiveData<Track> getArtistImage(String mbid){
final MutableLiveData<Track> trackData = new MutableLiveData<>();
String url =
"http://webservice.fanart.tv/v3/music/"+ mbid +"?api_key=1e325be5bfa7db0c79aa464a0a924a46";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, response -> {
try {
String imageURL = ArtistMapper.getArtistImage(response);
if(!imageURL.isEmpty()){
track.setArtistImageURL(imageURL);
}
trackLiveData.setValue(track);
trackLiveData.postValue(track);
} catch (JSONException e) {
Log.d("Parsing error: ", e.getMessage());
// Toast.makeText(getApplication(), e.getMessage(), Toast.LENGTH_SHORT).show(); } }, error -> { // Toast.makeText(getApplication(), error.getMessage(), Toast.LENGTH_SHORT).show(); Log.d("Request error: ", "Error getting artist's image"); });
requestQueue.add(jsonObjectRequest);
return trackData;
}
} `
Test TrackDetailsTest
`package com.example.sporify.details;
import androidx.arch.core.executor.testing.InstantTaskExecutorRule; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.example.sporify.LiveDataTestUtil; import com.example.sporify.MockDataReader; import com.example.sporify.activities.track.TrackDetailsViewModel; import com.example.sporify.mappers.TrackMapper; import com.example.sporify.models.Track;
import org.json.JSONException; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.Spy;
import java.util.List;
@RunWith(AndroidJUnit4.class) public class TrackDetailsTest {
private TrackDetailsViewModel trackDetailsViewModel;
private List<Track> trackList;
public Track trackInfo;
@Rule
public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
@Before
public void setUp(){
trackDetailsViewModel = new TrackDetailsViewModel();
}
@Test
public void should_get_album_info() throws InterruptedException {
// query that is expected to be found
String trackToBeFound = "ecfa6746-7bc4-4088-ace6-d209477bd63f";
trackInfo = LiveDataTestUtil.getOrAwaitValue(trackDetailsViewModel.getTrackInfo(trackToBeFound));
Assert.assertNotEquals(null, trackInfo);
}
@Test
public void should_fail_get_album_info() throws InterruptedException {
// query that is expected to be found
String trackToBeNotFound = "";
trackInfo = LiveDataTestUtil.getOrAwaitValue(trackDetailsViewModel.getTrackInfo(trackToBeNotFound));
Assert.assertNull(trackInfo.getMbid());
Assert.assertEquals("No info" ,trackInfo.getName());
Assert.assertNull(trackInfo.getArtistName());
}
@Spy
Track trackMock;
@Test
public void mock_should_get_album_info() throws Exception {
Track albumInfo = Mockito.spy(TrackMapper.getTrackFromJson(MockDataReader.getNetworkResponse("tracks/trackPassTest.json")));
trackMock = Mockito.spy(Track.class);
trackMock.setName("D.D.");
Mockito.verify(trackMock).setName("D.D.");
trackMock.setArtistName("The Weeknd");
Mockito.verify(trackMock).setArtistName("The Weeknd");
Assert.assertEquals(trackMock.getArtistName(), albumInfo.getArtistName());
Assert.assertEquals(trackMock.getName(), albumInfo.getName());
}
@Test
public void mock_should_fail_get_album_info() {
try{
trackInfo = Mockito.spy(TrackMapper.getTrackFromJson(MockDataReader.getNetworkResponse("tracks/trackFailTest.json")));
trackMock = Mockito.spy(Track.class);
Assert.fail("Should have thrown JSON parse exception");
}
catch (JSONException e){
// success
Assert.assertEquals("No value for track", e.getMessage());
Assert.assertNull(trackInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
} `
Ο χρήστης να έχει τη δυνατότητα να επιλέγει ένα τραγούδι και να βλέπει πληροφορίες για αυτό.