ApolloTkog / Sporify

2 stars 0 forks source link

ISSUE#24 Ο χρήστης να έχει τη δυνατότητα να επιλέγει ένα τραγούδι και να βλέπει πληροφορίες για αυτό. #28

Closed AceTsak closed 2 years ago

AceTsak commented 2 years ago

Ο χρήστης να έχει τη δυνατότητα να επιλέγει ένα τραγούδι και να βλέπει πληροφορίες για αυτό.

AceTsak commented 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);
}

}`

AceTsak commented 2 years ago

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;
}

} `

AceTsak commented 2 years ago

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();
    }
}

} `