package com.etiennelawlor.loop.fragments; import android.app.SearchManager; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Typeface; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.etiennelawlor.loop.EventMapKeys; import com.etiennelawlor.loop.EventNames; import com.etiennelawlor.loop.LoopApplication; import com.etiennelawlor.loop.R; import com.etiennelawlor.loop.activities.SearchableActivity; import com.etiennelawlor.loop.activities.VideoCommentsActivity; import com.etiennelawlor.loop.analytics.Event; import com.etiennelawlor.loop.analytics.EventLogger; import com.etiennelawlor.loop.bus.RxBus; import com.etiennelawlor.loop.bus.events.LikeVideoClickedEvent; import com.etiennelawlor.loop.bus.events.SearchPerformedEvent; import com.etiennelawlor.loop.bus.events.WatchLaterClickedEvent; import com.etiennelawlor.loop.models.AccessToken; import com.etiennelawlor.loop.network.ServiceGenerator; import com.etiennelawlor.loop.network.VimeoService; import com.etiennelawlor.loop.network.interceptors.AuthorizedNetworkInterceptor; import com.etiennelawlor.loop.network.models.response.User; import com.etiennelawlor.loop.network.models.response.Video; import com.etiennelawlor.loop.prefs.LoopPrefs; import com.etiennelawlor.loop.ui.AvatarView; import com.etiennelawlor.loop.utilities.FontCache; import com.etiennelawlor.loop.utilities.NetworkLogUtility; import com.etiennelawlor.loop.utilities.NetworkUtility; import com.etiennelawlor.loop.utilities.Transformers; import com.etiennelawlor.loop.utilities.TrestleUtility; import com.greenfrvr.hashtagview.HashtagView; import java.util.HashMap; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; import rx.subscriptions.CompositeSubscription; /** * Created by etiennelawlor on 1/3/17. */ public class VideoDetailsInfoFragment extends BaseFragment { // region Constants // endregion // region Views @BindView(R.id.title_tv) TextView titleTextView; @BindView(R.id.subtitle_tv) TextView subtitleTextView; @BindView(R.id.user_iv) AvatarView userImageView; @BindView(R.id.view_count_tv) TextView viewCountTextView; @BindView(R.id.upload_date_tv) TextView uploadDateTextView; @BindView(R.id.like_iv) ImageView likeImageView; @BindView(R.id.watch_later_iv) ImageView watchLaterImageView; @BindView(R.id.comments_iv) ImageView commentsImageView; @BindView(R.id.info_iv) ImageView infoImageView; @BindView(R.id.htv) HashtagView hashtagView; @BindView(R.id.description_tv) TextView descriptionTextView; @BindView(R.id.additional_info_ll) LinearLayout additionalInfoLinearLayout; // endregion // region Member Variables private Video video; private boolean isLikeOn = false; private boolean isWatchLaterOn = false; private boolean hasDescription = false; private boolean hasTags = false; private VimeoService vimeoService; private Unbinder unbinder; private Typeface font; private Typeface boldFont; private CompositeSubscription compositeSubscription; // endregion // region Listeners @OnClick(R.id.info_iv) public void onInfoImageViewClicked(final View v) { int visibility = additionalInfoLinearLayout.getVisibility(); if(visibility == View.VISIBLE){ additionalInfoLinearLayout.setVisibility(View.GONE); v.animate().rotation(0.0f).setDuration(300).start(); } else if(visibility == View.GONE){ additionalInfoLinearLayout.setVisibility(View.VISIBLE); v.animate().rotation(180.0f).setDuration(300).start(); } } @OnClick(R.id.comments_iv) public void onCommentsImageViewClicked(final View v) { Intent intent = new Intent(getActivity(), VideoCommentsActivity.class); Bundle bundle = new Bundle(); bundle.putParcelable(LikedVideosFragment.KEY_VIDEO, video); intent.putExtras(bundle); startActivity(intent); } @OnClick(R.id.watch_later_iv) public void onWatchLaterImageViewClicked(final View v) { if (isWatchLaterOn) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity(), R.style.DialogTheme); alertDialogBuilder.setMessage("Are you sure you want to remove this video from your Watch Later collection?"); alertDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { Call removeVideoFromWatchLaterCall = vimeoService.removeVideoFromWatchLater(String.valueOf(video.getId())); calls.add(removeVideoFromWatchLaterCall); removeVideoFromWatchLaterCall.enqueue(removeVideoFromWatchLaterCallback); } }); alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Canceled. } }); alertDialogBuilder.show(); } else { Call addVideoToWatchLaterCall = vimeoService.addVideoToWatchLater(String.valueOf(video.getId())); calls.add(addVideoToWatchLaterCall); addVideoToWatchLaterCall.enqueue(addVideoToWatchLaterCallback); } } @OnClick(R.id.like_iv) public void onLikeImageViewClicked(final View v) { if (isLikeOn) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity(), R.style.DialogTheme); alertDialogBuilder.setMessage("Are you sure you want to unlike this video?"); alertDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { Call unlikeVideoCall = vimeoService.unlikeVideo(String.valueOf(video.getId())); calls.add(unlikeVideoCall); unlikeVideoCall.enqueue(unlikeVideoCallback); } }); alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Canceled. } }); alertDialogBuilder.show(); } else { Call likeVideoCall = vimeoService.likeVideo(String.valueOf(video.getId())); calls.add(likeVideoCall); likeVideoCall.enqueue(likeVideoCallback); } } // endregion // region Callbacks private Callback<ResponseBody> addVideoToWatchLaterCallback = new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (!response.isSuccessful()) { int responseCode = response.code(); if(responseCode == 504) { // 504 Unsatisfiable Request (only-if-cached) // errorTextView.setText("Can't load data.\nCheck your network connection."); // errorLinearLayout.setVisibility(View.VISIBLE); } return; } okhttp3.Response rawResponse = response.raw(); if (rawResponse != null) { int code = rawResponse.code(); switch (code) { case 204: // No Content RxBus.getInstance().send(new WatchLaterClickedEvent()); isWatchLaterOn = true; watchLaterImageView.setImageResource(R.drawable.ic_watch_later_on); break; // case 400: // // If the video is owned by the authenticated user // break; // case 403: // // If the authenticated user is not allowed to like videos // break; } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { NetworkLogUtility.logFailure(call, t); if (!call.isCanceled()){ if(NetworkUtility.isKnownException(t)){ Snackbar.make(getActivity().findViewById(R.id.main_content), TrestleUtility.getFormattedText("Network connection is unavailable.", font, 16), Snackbar.LENGTH_LONG) .show(); } } } }; private Callback<ResponseBody> removeVideoFromWatchLaterCallback = new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (!response.isSuccessful()) { int responseCode = response.code(); if(responseCode == 504) { // 504 Unsatisfiable Request (only-if-cached) // errorTextView.setText("Can't load data.\nCheck your network connection."); // errorLinearLayout.setVisibility(View.VISIBLE); } return; } okhttp3.Response rawResponse = response.raw(); if (rawResponse != null) { int code = rawResponse.code(); switch (code) { case 204: // No Content RxBus.getInstance().send(new WatchLaterClickedEvent()); isWatchLaterOn = false; watchLaterImageView.setImageResource(R.drawable.ic_watch_later_off); break; // case 403: // // If the authenticated user is not allowed to like videos // break; } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { NetworkLogUtility.logFailure(call, t); if (!call.isCanceled()){ if(NetworkUtility.isKnownException(t)){ Snackbar.make(getActivity().findViewById(R.id.main_content), TrestleUtility.getFormattedText("Network connection is unavailable.", font, 16), Snackbar.LENGTH_LONG) .show(); } } } }; private Callback<ResponseBody> likeVideoCallback = new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (!response.isSuccessful()) { int responseCode = response.code(); if(responseCode == 504) { // 504 Unsatisfiable Request (only-if-cached) // errorTextView.setText("Can't load data.\nCheck your network connection."); // errorLinearLayout.setVisibility(View.VISIBLE); } return; } okhttp3.Response rawResponse = response.raw(); if (rawResponse != null) { int code = rawResponse.code(); switch (code) { case 204: // No Content RxBus.getInstance().send(new LikeVideoClickedEvent()); HashMap<String, Object> map = new HashMap<>(); map.put(EventMapKeys.NAME, video.getName()); map.put(EventMapKeys.DURATION, video.getDuration()); map.put(EventMapKeys.VIDEO_ID, video.getId()); Event event = new Event(EventNames.VIDEO_LIKED, map); EventLogger.logEvent(event); isLikeOn = true; likeImageView.setImageResource(R.drawable.ic_likes_on); break; case 400: // If the video is owned by the authenticated user break; case 403: // If the authenticated user is not allowed to like videos break; } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { NetworkLogUtility.logFailure(call, t); if (!call.isCanceled()){ if(NetworkUtility.isKnownException(t)){ Snackbar.make(getActivity().findViewById(R.id.main_content), TrestleUtility.getFormattedText("Network connection is unavailable.", font, 16), Snackbar.LENGTH_LONG) .show(); } } } }; private Callback<ResponseBody> unlikeVideoCallback = new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (!response.isSuccessful()) { int responseCode = response.code(); if(responseCode == 504) { // 504 Unsatisfiable Request (only-if-cached) // errorTextView.setText("Can't load data.\nCheck your network connection."); // errorLinearLayout.setVisibility(View.VISIBLE); } return; } okhttp3.Response rawResponse = response.raw(); if (rawResponse != null) { int code = rawResponse.code(); switch (code) { case 204: // No Content RxBus.getInstance().send(new LikeVideoClickedEvent()); HashMap<String, Object> map = new HashMap<>(); map.put(EventMapKeys.NAME, video.getName()); map.put(EventMapKeys.DURATION, video.getDuration()); map.put(EventMapKeys.VIDEO_ID, video.getId()); Event event = new Event(EventNames.VIDEO_DISLIKED, map); EventLogger.logEvent(event); isLikeOn = false; likeImageView.setImageResource(R.drawable.ic_likes_off); break; case 403: // If the authenticated user is not allowed to like videos break; } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { NetworkLogUtility.logFailure(call, t); if (!call.isCanceled()){ if(NetworkUtility.isKnownException(t)){ Snackbar.make(getActivity().findViewById(R.id.main_content), TrestleUtility.getFormattedText("Network connection is unavailable.", font, 16), Snackbar.LENGTH_LONG) .show(); } } } }; // endregion // region Constructors public VideoDetailsInfoFragment() { } // endregion // region Factory Methods public static VideoDetailsInfoFragment newInstance(Bundle extras) { VideoDetailsInfoFragment fragment = new VideoDetailsInfoFragment(); fragment.setArguments(extras); return fragment; } public static VideoDetailsInfoFragment newInstance() { VideoDetailsInfoFragment fragment = new VideoDetailsInfoFragment(); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } // endregion // region Lifecycle Methods @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { video = (Video) getArguments().get(LikedVideosFragment.KEY_VIDEO); } AccessToken token = LoopPrefs.getAccessToken(getActivity()); vimeoService = ServiceGenerator.createService( VimeoService.class, VimeoService.BASE_URL, new AuthorizedNetworkInterceptor(token)); boldFont = FontCache.getTypeface("Ubuntu-Bold.ttf", LoopApplication.getInstance().getApplicationContext()); font = FontCache.getTypeface("Ubuntu-Medium.ttf", getContext()); compositeSubscription = new CompositeSubscription(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_video_details_info, container, false); unbinder = ButterKnife.bind(this, rootView); return rootView; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setUpRxBusSubscription(); if(video != null){ setUpTitle(titleTextView, video); setUpSubtitle(subtitleTextView, video); setUpViewCount(viewCountTextView, video); setUpLike(likeImageView, video); setUpWatchLater(watchLaterImageView, video); setUpUserImage(userImageView, video); setUpUploadedDate(uploadDateTextView, video); setUpDescription(descriptionTextView, video); setUpTags(hashtagView, video); setUpInfoImage(infoImageView); } } @Override public void onDestroyView() { super.onDestroyView(); removeListeners(); unbinder.unbind(); } @Override public void onDestroy() { super.onDestroy(); compositeSubscription.unsubscribe(); } // endregion // region Helper Methods private void setUpTitle(TextView tv, Video video) { String name = video.getName(); if (!TextUtils.isEmpty(name)) { tv.setText(name); } } private void setUpSubtitle(TextView tv, Video video) { User user = video.getUser(); if (user != null) { String userName = user.getName(); if (!TextUtils.isEmpty(userName)) { tv.setText(userName); } } } private void setUpLike(ImageView iv, Video video){ boolean isLiked = video.isLiked(); if (isLiked) { isLikeOn = true; iv.setImageResource(R.drawable.ic_likes_on); } } private void setUpWatchLater(ImageView iv, Video video){ boolean isAddedToWatchLater = video.isAddedToWatchLater(); if (isAddedToWatchLater) { isWatchLaterOn = true; iv.setImageResource(R.drawable.ic_watch_later_on); } } private void setUpUserImage(AvatarView av, Video video) { User user = video.getUser(); if(user != null){ av.bind(user); } else { av.nullify(); } } private void setUpViewCount(TextView tv, Video video) { String formattedViewCount = video.getFormattedViewCount(); if(!TextUtils.isEmpty(formattedViewCount)){ tv.setText(formattedViewCount); tv.setVisibility(View.VISIBLE); } else { tv.setVisibility(View.GONE); } } private void setUpUploadedDate(TextView tv, Video video) { String formattedCreatedTime = video.getFormattedCreatedTime(); if (!TextUtils.isEmpty(formattedCreatedTime)) { tv.setText(formattedCreatedTime); tv.setVisibility(View.VISIBLE); } else { tv.setVisibility(View.GONE); } } private void setUpTags(final HashtagView htv, Video video) { List<String> canonicalTags = video.getCanonicalTags(); if(canonicalTags.size() > 0){ hasTags = true; htv.setData(canonicalTags, Transformers.HASH); htv.setTypeface(boldFont); htv.addOnTagClickListener(new HashtagView.TagsClickListener() { @Override public void onItemClicked(Object item) { String tag = (String) item; // TODO this triggers two events somehow RxBus.getInstance().send(new SearchPerformedEvent(tag)); } }); htv.setVisibility(View.VISIBLE); } else { htv.setVisibility(View.GONE); } } private void setUpDescription(TextView tv, Video video) { String formattedDescription = video.getFormattedDescription(); if (!TextUtils.isEmpty(formattedDescription)) { hasDescription = true; // formattedDescription = formattedDescription.replaceAll("[\\t\\n\\r]+", "\n"); tv.setText(formattedDescription); tv.setVisibility(View.VISIBLE); } else { tv.setVisibility(View.GONE); } } private void setUpInfoImage(ImageView iv){ if(hasDescription || hasTags){ iv.setVisibility(View.VISIBLE); } } private void launchSearchActivity(String query) { Intent intent = new Intent(getContext(), SearchableActivity.class); intent.setAction(Intent.ACTION_SEARCH); Bundle bundle = new Bundle(); bundle.putString(SearchManager.QUERY, query); intent.putExtras(bundle); getContext().startActivity(intent); } private void removeListeners() { // videosRecyclerView.removeOnScrollListener(recyclerViewOnScrollListener); } private void setUpRxBusSubscription(){ Subscription rxBusSubscription = RxBus.getInstance().toObserverable() .observeOn(AndroidSchedulers.mainThread()) // UI Thread .subscribe(new Action1<Object>() { @Override public void call(Object event) { // if (event == null || !isResumed()) { // return; // } if (event == null) { return; } if(event instanceof SearchPerformedEvent) { String query = ((SearchPerformedEvent)event).getQuery(); if (!TextUtils.isEmpty(query)) { launchSearchActivity(query); } } } }); compositeSubscription.add(rxBusSubscription); } // endregion }