Skip to content

Commit

Permalink
Loading and error page on detail fragment implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
ShashankSinha98 committed Apr 5, 2022
1 parent 869c424 commit 4be65ae
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 23 deletions.
1 change: 1 addition & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ public interface MovieDao {
void insertMovieDetail(MovieDetail movieDetail);

@Query("SELECT * FROM movie_detail WHERE id=:movieId")
Flowable<MovieDetail> getMovieDetailForMovieId(Long movieId);
Flowable<List<MovieDetail>> getMovieDetailForMovieId(Long movieId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public void onComplete() {

@Override
public void fetchMovieDetail(Long movieId, ResourceCallback resourceCallback) {

Log.d(TAG, "xlr8: fetchMovieDetail: movieId: "+movieId);
if(movieId==null || movieId<=0L) {
resourceCallback.onResponse(Resource.error(INVALID_MOVIE_ID_ERROR_MSG,null));
return;
Expand All @@ -139,12 +139,12 @@ public void fetchMovieDetail(Long movieId, ResourceCallback resourceCallback) {
.subscribe(new Observer<MovieDetail>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG,"fetchMovieDetail - onSubscribe");
Log.d(TAG,"xlr8: fetchMovieDetail - onSubscribe");
}

@Override
public void onNext(@NonNull MovieDetail movieDetail) {
Log.d(TAG,"fetchMovieDetail - onNext: movieDetail: "+movieDetail);
Log.d(TAG,"xlr8: fetchMovieDetail - onNext: movieDetail: "+movieDetail);
try {
processMovieDetailResponse(movieDetail, resourceCallback);
} catch (Exception e) {
Expand All @@ -154,13 +154,13 @@ public void onNext(@NonNull MovieDetail movieDetail) {

@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG, "fetchMovieDetail - onError: e: "+e.getMessage());
Log.d(TAG, "xlr8: fetchMovieDetail - onError: e: "+e.getMessage());
checkMovieDetailDataInDatabase(movieId, resourceCallback);
}

@Override
public void onComplete() {
Log.d(TAG, "fetchMovieDetail - onComplete");
Log.d(TAG, "xlr8: fetchMovieDetail - onComplete");
}
});
}
Expand Down Expand Up @@ -262,6 +262,7 @@ public void accept(List<FavouriteMovieIdsEntity> favouriteMovieIdsEntities) thro

@Override
public void checkMovieDataInDatabaseForIds(List<Long> movieIds, ResourceCallback<List<MovieResult>> callback) {
Log.d(TAG, "xlr8: checkMovieDataInDatabaseForIds, movieIds: "+movieIds);
// Fetch movies data from DB
movieDao.getMovieResultsForMovieIds(movieIds).subscribeOn(Schedulers.io())
.subscribe(new Consumer<List<MovieResult>>() {
Expand Down Expand Up @@ -405,7 +406,7 @@ public void accept(List<NowPlayingMovieIdsEntity> nowPlayingMovieIdsEntities) th
}

private void processMovieDetailResponse(MovieDetail movieDetail, ResourceCallback callback) throws Exception {
Log.d(TAG, "xlr8:processMovieDetailResponse called: movieDetail: "+movieDetail);
Log.d(TAG, "xlr8: processMovieDetailResponse called: movieDetail: "+movieDetail);

if(movieDetail==null) {
callback.onResponse(Resource.error("Null Movie Detail response", null));
Expand Down Expand Up @@ -446,12 +447,13 @@ public void onError(@NonNull Throwable e) {
private void checkMovieDetailDataInDatabase(Long movieId, ResourceCallback callback) {
Log.d(TAG, "xlr8: checkMovieDetailDataInDatabase called, movieId: "+movieId);
movieDao.getMovieDetailForMovieId(movieId)
.subscribeOn(Schedulers.computation())
.subscribe(new Consumer<MovieDetail>() {
.subscribeOn(Schedulers.io())
.subscribe(new Consumer<List<MovieDetail>>() {
@Override
public void accept(MovieDetail movieDetail) throws Exception {
if(movieDetail!=null) {
callback.onResponse(Resource.success(movieDetail));
public void accept(List<MovieDetail> movieDetails) throws Exception {
Log.d(TAG, "xlr8: checkMovieDetailDataInDatabase accept: movieDetail: "+movieDetails);
if(movieDetails!=null && movieDetails.size()!=0) {
callback.onResponse(Resource.success(movieDetails.get(0)));
} else {
callback.onResponse(Resource.error("Null Movie Detail Query Response", null));
}
Expand Down
123 changes: 116 additions & 7 deletions app/src/main/java/com/shashank/moviedb/ui/detail/DetailFragment.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
package com.shashank.moviedb.ui.detail;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.widget.NestedScrollView;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.RequestManager;
import com.google.android.material.snackbar.Snackbar;
import com.shashank.moviedb.R;
import com.shashank.moviedb.common.ViewModelProviderFactory;
import com.shashank.moviedb.data.Resource;
import com.shashank.moviedb.model.Genre;
import com.shashank.moviedb.model.MovieDetail;
import com.shashank.moviedb.model.MovieResult;
import com.shashank.moviedb.ui.detail.adapter.CastRecyclerAdapter;
import com.shashank.moviedb.ui.trending.TrendingViewModel;
import com.shashank.moviedb.util.Constants;

import java.util.List;
Expand All @@ -36,10 +39,13 @@
public class DetailFragment extends DaggerFragment implements View.OnClickListener {

private static final String TAG = "DetailFragment";
private AppCompatImageView ivBackdrop, ivPoster, ivFavorite;
private TextView tvMovieTitle, tvVoteAverage, tvDuration, tvGenre, tvDescription, tvQuote;
private AppCompatImageView ivBackdrop, ivPoster, ivFavorite, noInternetIcon;
private ProgressBar progressBar;
private TextView tvMovieTitle, tvVoteAverage, tvDuration, tvGenre, tvDescription, tvQuote, tvDescriptionTitle, tvCastTitle, tvTaglineTitle;
private RecyclerView castRecyclerView;
private ConstraintLayout detailLayout;
private NestedScrollView nestedScrollView;
private Snackbar snackbar;

@Inject public ViewModelProviderFactory providerFactory;
@Inject public RequestManager requestManager;
Expand Down Expand Up @@ -73,8 +79,14 @@ private void initObservers() {
public void onChanged(Resource<MovieDetail> movieDetailResource) {
switch (movieDetailResource.getStatus()) {
case SUCCESS:
showProgressBar(false);
MovieDetail movieDetail = ((MovieDetail)movieDetailResource.getData());
updateLayoutWithMovieData(movieDetail);
updateLayoutForMovieResult(View.VISIBLE);
updateLayoutWithMovieDetailData(movieDetail);
break;

case LOADING:
showProgressBar(true);
break;
}
}
Expand All @@ -91,10 +103,66 @@ public void onChanged(Resource<Boolean> booleanResource) {
}
}
});

detailViewModel.getMovieResultLiveData().observe(getViewLifecycleOwner(), new Observer<Resource<List<MovieResult>>>() {
@Override
public void onChanged(Resource<List<MovieResult>> listResource) {
switch (listResource.getStatus()) {
case SUCCESS:
Log.d(TAG, "xlr8: getMovieResultLiveData SUCCESS");
showProgressBar(false);
MovieResult movieResult = listResource.getData().get(0);
updateLayoutForMovieResult(View.INVISIBLE);
updateLayoutWithMovieResultData(movieResult);
showSnackBar();
break;

case ERROR:
Log.d(TAG, "xlr8: getMovieResultLiveData ERROR: e: "+listResource.getMessage());
break;
}
}
});

}

private void showSnackBar() {
snackbar =Snackbar.make(nestedScrollView, "No Connection", Snackbar.LENGTH_INDEFINITE);
snackbar.setAction("Retry", new View.OnClickListener() {
@Override
public void onClick(View view) {
snackbar.dismiss();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
detailViewModel.getMovieDetail(movieId);
}
}, 250);
}
});

snackbar.show();
}

private void updateLayoutWithMovieData(MovieDetail movieDetail) {
Log.d(TAG,"xlr8: movieDetail: "+movieDetail);
private void updateLayoutWithMovieResultData(MovieResult movieResult) {
Log.d(TAG,"xlr8: updateLayoutWithMovieResultData movieResult: "+movieResult);
detailLayout.setVisibility(View.VISIBLE);
tvMovieTitle.setText(movieResult.getTitle());
tvMovieTitle.setSelected(true);
tvVoteAverage.setText(movieResult.getVoteAverage().toString());

requestManager.load(Constants.BASE_IMAGE_URL_API+movieResult.getPosterPath())
.into(ivPoster);

requestManager.load(Constants.BASE_IMAGE_URL_w500_API+movieResult.getBackdropPath())
.into(ivBackdrop);

}



private void updateLayoutWithMovieDetailData(MovieDetail movieDetail) {
Log.d(TAG,"xlr8: updateLayoutWithMovieDetailData movieDetail: "+movieDetail);
detailLayout.setVisibility(View.VISIBLE);
tvMovieTitle.setText(movieDetail.getTitle());
tvMovieTitle.setSelected(true);
Expand Down Expand Up @@ -145,7 +213,15 @@ private void initViews(View view) {
tvQuote = view.findViewById(R.id.tvQuoteValue);
castRecyclerView = view.findViewById(R.id.rvCast);
detailLayout = view.findViewById(R.id.clDetail);
tvDescriptionTitle = view.findViewById(R.id.tvDescriptionTitle);
ivFavorite = view.findViewById(R.id.ivFavorite);
tvCastTitle = view.findViewById(R.id.tvCastTitle);
tvTaglineTitle = view.findViewById(R.id.tvTaglineTitle);
progressBar = view.findViewById(R.id.progress_bar);
noInternetIcon = view.findViewById(R.id.no_internet_cloud_icon);
nestedScrollView = view.findViewById(R.id.nestedDetail);



ivFavorite.setOnClickListener(this);
}
Expand All @@ -161,4 +237,37 @@ public void onClick(View view) {
detailViewModel.updateFavourite(movieId);
}
}

private void updateLayoutForMovieResult(int visible) {
Log.d(TAG ,"xlr8: updateLayoutForMovieResult called, visible: "+(visible==View.VISIBLE));
tvGenre.setVisibility(visible);
tvDuration.setVisibility(visible);
tvDescriptionTitle.setVisibility(visible);
tvDescription.setVisibility(visible);
tvCastTitle.setVisibility(visible);
castRecyclerView.setVisibility(visible);
tvTaglineTitle.setVisibility(visible);
tvQuote.setVisibility(visible);

if(visible==View.INVISIBLE) {
noInternetIcon.setVisibility(View.VISIBLE);
} else {
noInternetIcon.setVisibility(View.INVISIBLE);
}
}

private void showProgressBar(boolean show) {
if(show)
progressBar.setVisibility(View.VISIBLE);
else
progressBar.setVisibility(View.GONE);
}

@Override
public void onDestroyView() {
super.onDestroyView();
if(snackbar!=null) {
snackbar.dismiss();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
package com.shashank.moviedb.ui.detail;

import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.shashank.moviedb.data.Resource;
import com.shashank.moviedb.data.ResourceCallback;
import com.shashank.moviedb.data.Status;
import com.shashank.moviedb.data.remote.MovieRepository;
import com.shashank.moviedb.model.MovieDetail;
import com.shashank.moviedb.model.MovieResult;

import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

public class DetailViewModel extends ViewModel {

private static final String TAG = "DetailViewModel";

private MovieRepository movieRepository;
private MutableLiveData<Resource<MovieDetail>> _movieDetailResponse = new MutableLiveData<>();
private MutableLiveData<Resource<List<MovieResult>>> _movieResultResponse = new MutableLiveData<>();
private MutableLiveData<Resource<Boolean>> _favouriteIconStatus = new MutableLiveData<>();


Expand All @@ -27,13 +37,29 @@ public void getMovieDetail(Long movieId) {
movieRepository.fetchMovieDetail(movieId, new ResourceCallback() {
@Override
public void onResponse(Resource resource) {
_movieDetailResponse.postValue(resource);
if(resource.getStatus()== Status.SUCCESS)
_movieDetailResponse.postValue(resource);
else
checkMovieDataInMovieTable(movieId);
}
});

validateFavouriteIcon(movieId);
}

private void checkMovieDataInMovieTable(Long movieId) {
Log.d(TAG, "xlr8: checkMovieDataInMovieTable called, movieId: "+movieId);
List<Long> movieIds = new ArrayList<>();
movieIds.add(movieId);

movieRepository.checkMovieDataInDatabaseForIds(movieIds, new ResourceCallback<List<MovieResult>>() {
@Override
public void onResponse(Resource<List<MovieResult>> resource) {
_movieResultResponse.postValue(resource);
}
});
}

private void validateFavouriteIcon(Long movieId) {
movieRepository.isFavourite(movieId, new ResourceCallback<Boolean>() {
@Override
Expand All @@ -51,6 +77,10 @@ public LiveData<Resource<Boolean>> getFavouriteIconStatus() {
return _favouriteIconStatus;
}

public LiveData<Resource<List<MovieResult>>> getMovieResultLiveData() {
return _movieResultResponse;
}


private void addMovieIdToFavourite(Long movieId) {
movieRepository.addFavourite(movieId, new ResourceCallback<Boolean>() {
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_cloud_off_black_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/Black_20"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4c-1.48,0 -2.85,0.43 -4.01,1.17l1.46,1.46C10.21,6.23 11.08,6 12,6c3.04,0 5.5,2.46 5.5,5.5v0.5H19c1.66,0 3,1.34 3,3 0,1.13 -0.64,2.11 -1.56,2.62l1.45,1.45C23.16,18.16 24,16.68 24,15c0,-2.64 -2.05,-4.78 -4.65,-4.96zM3,5.27l2.75,2.74C2.56,8.15 0,10.77 0,14c0,3.31 2.69,6 6,6h11.73l2,2L21,20.73 4.27,4 3,5.27zM7.73,10l8,8H6c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4h1.73z"/>
</vector>
Loading

0 comments on commit 4be65ae

Please sign in to comment.