package com.tevinjeffrey.rutgersct.ui.sectioninfo; import android.animation.AnimatorSet; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.os.Bundle; import android.support.design.widget.CollapsingToolbarLayout; import android.support.design.widget.FloatingActionButton; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewCompat; import android.support.v7.widget.Toolbar; import android.text.Html; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.squareup.okhttp.OkHttpClient; import com.squareup.otto.Bus; import com.tevinjeffrey.rmp.common.Professor; import com.tevinjeffrey.rutgersct.R; import com.tevinjeffrey.rutgersct.RutgersCTApp; import com.tevinjeffrey.rutgersct.ui.courseinfo.CourseInfoView; import com.tevinjeffrey.rutgersct.ui.trackedsections.TrackedSectionsView; import com.tevinjeffrey.rutgersct.ui.utils.RatingLayoutInflater; import com.tevinjeffrey.rutgersct.database.DatabaseHandler; import com.tevinjeffrey.rutgersct.rutgersapi.RetroRutgers; import com.tevinjeffrey.rutgersct.rutgersapi.model.Course; import com.tevinjeffrey.rutgersct.rutgersapi.utils.SectionUtils; import com.tevinjeffrey.rutgersct.ui.base.MVPFragment; import com.tevinjeffrey.rutgersct.utils.Utils; import org.apache.commons.lang3.StringUtils; import java.util.Collections; import javax.inject.Inject; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; import icepick.Icicle; import static android.view.View.GONE; import static android.view.View.VISIBLE; public class SectionInfoFragment extends MVPFragment implements SectionInfoView { private static final String TAG = SectionInfoFragment.class.getSimpleName(); @Bind(R.id.prof_ratings_container) ViewGroup ratingsContainer; @Bind(R.id.prof_ratings_root) ViewGroup ratingsRoot; @Bind(R.id.semesterText) TextView mSemesterText; @Bind(R.id.course_title_text) TextView mCourseTitleText; @Bind(R.id.sectionNumber_text) TextView mSectionNumberText; @Bind(R.id.indexNumber_text) TextView mIndexNumberText; @Bind(R.id.subtitle) TextView mCreditsText; @Bind(R.id.instructors_text) TextView mInstructorsText; @Bind(R.id.instructors_container) ViewGroup mInstructorsContainer; @Bind(R.id.exam_code_text) TextView mExamCodeText; @Bind(R.id.toolbar) Toolbar mToolbar; @Bind(R.id.section_notes_text) TextView mSectionNotesText; @Bind(R.id.section_notes_layout) RelativeLayout mSectionNotesLayout; @Bind(R.id.section_comments_text) TextView mSectionCommentsText; @Bind(R.id.section_comments_layout) RelativeLayout mSectionCommentsLayout; @Bind(R.id.section_crosslist_text) TextView mSectionCrossListText; @Bind(R.id.section_crosslist_layout) RelativeLayout mSectionCrossListLayout; @Bind(R.id.section_subtitle_text) TextView mSectionSubtitleText; @Bind(R.id.section_subtitle_layout) RelativeLayout mSectionSubtitleLayout; @Bind(R.id.section_permission_text) TextView mSectionPermissionText; @Bind(R.id.section_permission_layout) RelativeLayout mSectionPermissionLayout; @Bind(R.id.section_open_to_text) TextView mSectionOpenToText; @Bind(R.id.section_open_to_layout) RelativeLayout mSectionOpenLayout; @Bind(R.id.section_times_container) LinearLayout mSectionTimeContainer; @Bind(R.id.add_courses_fab) FloatingActionButton mFab; @Bind(R.id.collapsing_toolbar) CollapsingToolbarLayout mCollapsingToolbar; @Icicle Course.Section selectedSection; @Icicle SectionInfoViewState mViewState = new SectionInfoViewState(); @Inject RetroRutgers mRetroRutgers; @Inject DatabaseHandler mDatabaseHandler; @Inject Bus mBus; @Inject OkHttpClient mClient; public SectionInfoFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); if (getArguments() != null) { selectedSection = getArguments().getParcelable(CourseInfoView.SELECTED_SECTION); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Context contextThemeWrapper; // create ContextThemeWrapper from the original Activity Context with the custom theme if (selectedSection.isOpenStatus()) { contextThemeWrapper = Utils.wrapContextTheme(getActivity(), R.style.RutgersCT_Green); } else { contextThemeWrapper = Utils.wrapContextTheme(getActivity(), R.style.RutgersCT_Red); } // clone the inflater using the ContextThemeWrapper LayoutInflater themedInflator = inflater.cloneInContext(contextThemeWrapper); final View rootView = themedInflator.inflate(R.layout.fragment_section_info, container, false); ButterKnife.bind(this, rootView); return rootView; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); //Recreate presenter if necessary. if (mBasePresenter == null) { mBasePresenter = new SectionInfoPresenterImpl(selectedSection); RutgersCTApp.getObjectGraph(getParentActivity()).inject(mBasePresenter); } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mViewState.apply(this, savedInstanceState != null); //Attach view to presenter mBasePresenter.attachView(this); //Load data depending on if the view is currently refreshing if (mIsInitialLoad) { mViewState.shouldAnimateFabIn = false; } //Requires a database access and the results should not be saved. getPresenter().setFabState(false); getPresenter().loadRMP(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_fragment_info, menu); } @OnClick(R.id.add_courses_fab) public void fabClick(View view) { getPresenter().toggleFab(); } @Override public void showSectionTracked(boolean sectionIsAdded, boolean shouldAnimateView) { final int COLOR = ContextCompat.getColor(getParentActivity(), R.color.accent); final int COLOR_DARK = ContextCompat.getColor(getParentActivity(), R.color.accent_dark); final int ROTATION_NORMAL = 0; final int ROTATION_ADDED = 225; final int DURATION = 500; if (shouldAnimateView) { if (sectionIsAdded != mViewState.isSectionAdded) { ViewCompat.animate(mFab).setDuration(DURATION).setInterpolator(new DecelerateInterpolator()) .rotation(sectionIsAdded ? ROTATION_ADDED : ROTATION_NORMAL); //I would much prefer to animate from the current coolor to the next but the fab has // no method to get the current color and I'm not desparate enough to manage it myself. // As for now, the fab will only animate on user click. Not from a db update. ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", sectionIsAdded ? COLOR : COLOR_DARK, sectionIsAdded ? COLOR_DARK : COLOR ); colorAnim.setDuration(500); colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { if (mFab != null) mFab.setBackgroundTintList(ColorStateList.valueOf((Integer) animation.getAnimatedValue())); } }); colorAnim.setEvaluator(new ArgbEvaluator()); colorAnim.start(); } } else { //Using ViewCompat to set the tint list is bugged on pre lollipop. mFab.setBackgroundTintList(ColorStateList.valueOf(sectionIsAdded ? COLOR_DARK : COLOR)); ViewCompat.setRotation(mFab, sectionIsAdded ? ROTATION_ADDED : ROTATION_NORMAL); } mViewState.isSectionAdded = sectionIsAdded; } @Override public void showRatingsLayout() { ratingsContainer.setVisibility(VISIBLE); } @Override public void hideRatingsLoading() { ViewGroup progress = ButterKnife.findById(ratingsRoot, R.id.rmp_progressview); progress.setVisibility(GONE); } @Override public void addErrorProfessor(String name) { addRMPView(new RatingLayoutInflater(getParentActivity(), null) .getErrorLayout(name, selectedSection)); } @Override public void addRMPProfessor(Professor professor) { RatingLayoutInflater ratingLayoutInflater = new RatingLayoutInflater(getParentActivity(), professor); addRMPView(ratingLayoutInflater.getProfessorLayout()); } @Override public void initToolbar() { setToolbar(mToolbar); getParentActivity().getSupportActionBar().setDisplayShowTitleEnabled(false); } private void addRMPView(View view) { view.setAlpha(0); ViewCompat.animate(view).setStartDelay(200).alpha(1).start(); //Onclick intercepts vertical scroll /*viewGroup.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Object url = v.getTag(); if (url != null) { Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse((String) url)); context.startActivity(i); } } });*/ ratingsContainer.addView(view); } public void initViews() { setSectionNumber(); setSectionIndex(); setSectionCredits(); setCourseTitle(); setSectionNotes(); setSectionComments(); setSectionOpenTo(); setSectionPermission(); setSectionCrossList(); setSectionSubtitle(); setExamCode(); setTimes(); setInstructors(); setSemester(); } public void showFab(boolean animate) { if (animate) { AnimatorSet set = new AnimatorSet(); set.playTogether( ObjectAnimator.ofFloat(mFab, "scaleX", 0, 1), ObjectAnimator.ofFloat(mFab, "scaleY", 0, 1), ObjectAnimator.ofFloat(mFab, "alpha", 0, 1) ); set.setInterpolator(new DecelerateInterpolator()); set.setStartDelay(400); set.setDuration(250).start(); } else { ViewCompat.setScaleX(mFab, 1); ViewCompat.setScaleY(mFab, 1); ViewCompat.setAlpha(mFab, 1); } } private void setSemester() { mSemesterText.setText(selectedSection.getRequest().getSemester().toString()); } private void setSectionNumber() { mSectionNumberText.setText(selectedSection.getNumber()); } private void setSectionIndex() { mIndexNumberText.setText(selectedSection.getIndex()); } private void setSectionCredits() { mCreditsText.setText(String.valueOf(selectedSection.getCourse().getCredits())); } private void setCourseTitle() { mToolbar.setTitle(""); mCourseTitleText.setText(selectedSection.getCourse().getTrueTitle()); } private void setSectionNotes() { if (!selectedSection.hasNotes()) { mSectionNotesLayout.setVisibility(View.GONE); } else { mSectionNotesLayout.setVisibility(View.VISIBLE); mSectionNotesText.setText(Html.fromHtml(selectedSection.getSectionNotes())); mSectionNotesText.setMovementMethod(LinkMovementMethod.getInstance()); } } private void setSectionComments() { if (!selectedSection.hasComments()) { mSectionCommentsLayout.setVisibility(View.GONE); } else { mSectionCommentsLayout.setVisibility(View.VISIBLE); mSectionCommentsText.setText(Html.fromHtml(StringUtils.join(selectedSection.getComments(), ", "))); mSectionCommentsText.setMovementMethod(LinkMovementMethod.getInstance()); } } private void setSectionOpenTo() { if (!selectedSection.hasMajors()) { mSectionOpenLayout.setVisibility(View.GONE); } else { boolean isMajorHeaderSet = false; boolean isUnitHeaderSet = false; StringBuilder sb = new StringBuilder(); for (Course.Section.Majors i : selectedSection.getMajors()) { if (i.isMajorCode()) { if (!isMajorHeaderSet) { isMajorHeaderSet = true; sb.append("MAJORS: "); } sb.append(i.getCode()); sb.append(", "); } else if (i.isUnitCode()) { if (!isUnitHeaderSet) { isUnitHeaderSet = true; sb.append("SCHOOLS: "); } sb.append(i.getCode()); sb.append(", "); } } mSectionOpenLayout.setVisibility(View.VISIBLE); mSectionOpenToText.setText(Html.fromHtml(sb.toString())); } } private void setSectionPermission() { if (!selectedSection.hasSpecialPermission()) { mSectionPermissionLayout.setVisibility(View.GONE); } else { mSectionPermissionLayout.setVisibility(View.VISIBLE); mSectionPermissionText.setText(Html.fromHtml(selectedSection.getSpecialPermissionAddCodeDescription())); mSectionPermissionText.setMovementMethod(LinkMovementMethod.getInstance()); } } private void setSectionCrossList() { if (!selectedSection.hasCrossListed()) { mSectionCrossListLayout.setVisibility(View.GONE); } else { StringBuilder sb = new StringBuilder(); for (Course.Section.CrossListedSections i : selectedSection.getCrossListedSections()) { sb.append(i.getFullCrossListedSection()); sb.append(", "); } mSectionCrossListLayout.setVisibility(View.VISIBLE); mSectionCrossListText.setText(Html.fromHtml(sb.toString())); mSectionCrossListText.setMovementMethod(LinkMovementMethod.getInstance()); } } private void setSectionSubtitle() { if (!selectedSection.hasSubtitle()) { mSectionSubtitleLayout.setVisibility(View.GONE); } else { mSectionSubtitleLayout.setVisibility(View.VISIBLE); mSectionSubtitleText.setText(Html.fromHtml(selectedSection.getSubtitle())); mSectionSubtitleText.setMovementMethod(LinkMovementMethod.getInstance()); } } private void setExamCode() { mExamCodeText.setText(String.valueOf(selectedSection.getExamCode())); } private void setTimes() { LayoutInflater inflater = LayoutInflater.from(getParentActivity()); //sort times so that Monday > Tuesday and Lecture > Recitation Collections.sort(selectedSection.getMeetingTimes()); for (Course.Section.MeetingTimes time : selectedSection.getMeetingTimes()) { View timeLayout = inflater.inflate(R.layout.section_item_time, mSectionTimeContainer, false); TextView dayText = ButterKnife.findById(timeLayout, R.id.section_item_time_info_day_text); TextView timeText = ButterKnife.findById(timeLayout, R.id.section_item_time_info_meeting_time_text); TextView locationText = ButterKnife.findById(timeLayout, R.id.section_item_time_info_location_text); TextView meetingTimeText = ButterKnife.findById(timeLayout, R.id.section_item_time_info_meeting_type); dayText.setText(SectionUtils.getMeetingDayName(time)); timeText.setText(SectionUtils.getMeetingHours(time)); locationText.setText(SectionUtils.getClassLocation(time)); meetingTimeText.setText(time.getMeetingModeDesc()); mSectionTimeContainer.addView(timeLayout); } } private void setInstructors() { if (selectedSection.getInstructors().size() != 0) { mInstructorsText.setText(selectedSection.getToStringInstructors(" | ")); } else { mInstructorsContainer.setVisibility(View.GONE); } } private SectionInfoPresenter getPresenter() { return (SectionInfoPresenter) mBasePresenter; } public static SectionInfoFragment newInstance(Course.Section selectedSection) { final SectionInfoFragment newInstance = new SectionInfoFragment(); final Bundle arguments = new Bundle(); arguments.putParcelable(CourseInfoView.SELECTED_SECTION, selectedSection); arguments.putParcelable(TrackedSectionsView.REQUEST, selectedSection.getRequest()); newInstance.setArguments(arguments); return newInstance; } @Override public String toString() { return TAG; } }