/* * Copyright 2014 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.samples.apps.iosched.videolibrary; import android.annotation.TargetApi; import android.app.Activity; import android.app.Fragment; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TextView; import com.google.samples.apps.iosched.R; import com.google.samples.apps.iosched.archframework.ModelWithLoaderManager; import com.google.samples.apps.iosched.archframework.PresenterImpl; import com.google.samples.apps.iosched.archframework.UpdatableView; import com.google.samples.apps.iosched.injection.ModelProvider; import com.google.samples.apps.iosched.provider.ScheduleContract; import com.google.samples.apps.iosched.ui.widget.DrawShadowFrameLayout; import com.google.samples.apps.iosched.util.ImageLoader; import com.google.samples.apps.iosched.util.UIUtils; import com.google.samples.apps.iosched.videolibrary.VideoLibraryModel.VideoLibraryQueryEnum; import com.google.samples.apps.iosched.videolibrary.VideoLibraryModel.VideoLibraryUserActionEnum; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.google.samples.apps.iosched.util.LogUtils.makeLogTag; /** * This Fragment displays all the videos of past Google I/O sessions. You can also filter them per * year and/or topics. */ public class VideoLibraryFilteredFragment extends Fragment implements UpdatableView<VideoLibraryModel, VideoLibraryQueryEnum, VideoLibraryUserActionEnum> { private static final String TAG = makeLogTag(VideoLibraryFilteredFragment.class); private DrawerLayout mDrawerLayout = null; private View mEmptyView = null; private ImageLoader mImageLoader; private List<UserActionListener> mListeners = new ArrayList<>(); private VideoLibraryFilteredContainer mParent; private RadioGroup mTopicsFilterRadioGroup = null; private RecyclerView mVideoList = null; private RadioGroup mYearsFilterRadioGroup = null; @Override public void addListener(UserActionListener toAdd) { mListeners.add(toAdd); } @Override public void displayData(final VideoLibraryModel model, final VideoLibraryQueryEnum query) { if ((VideoLibraryModel.VideoLibraryQueryEnum.VIDEOS == query || VideoLibraryModel.VideoLibraryQueryEnum.MY_VIEWED_VIDEOS == query) && model.getVideos() != null) { displayVideos(model); } if (VideoLibraryModel.VideoLibraryQueryEnum.FILTERS == query) { Map<Integer, String> specialYearEntries = new HashMap<>(); specialYearEntries.put(VideoLibraryModel.ALL_YEARS, getString(R.string.all)); updateRadioGroup(mYearsFilterRadioGroup, model.getYears(), model.getSelectedYear(), specialYearEntries); Map<String, String> specialTopicEntries = new HashMap<>(); specialTopicEntries.put(VideoLibraryModel.ALL_TOPICS, getString(R.string.all)); specialTopicEntries.put(VideoLibraryModel.KEYNOTES_TOPIC, VideoLibraryModel.KEYNOTES_TOPIC); List<String> topics = model.getTopics(); topics.remove(VideoLibraryModel.KEYNOTES_TOPIC); updateRadioGroup(mTopicsFilterRadioGroup, model.getTopics(), model.getSelectedTopic(), specialTopicEntries); } } @Override public void displayErrorMessage(final VideoLibraryQueryEnum query) { // No UI changes upon query error } @Override public void displayUserActionResult(final VideoLibraryModel model, final VideoLibraryUserActionEnum userAction, final boolean success) { switch (userAction) { case CHANGE_FILTER: displayVideos(model); break; } } @Override public Context getContext() { return getActivity(); } @Override public Uri getDataUri(final VideoLibraryQueryEnum query) { switch (query) { case VIDEOS: case FILTERS: return ScheduleContract.Videos.CONTENT_URI; case MY_VIEWED_VIDEOS: return ScheduleContract.MyViewedVideos.CONTENT_URI; default: return Uri.EMPTY; } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mImageLoader = new ImageLoader(getActivity(), android.R.color.transparent); mYearsFilterRadioGroup = (RadioGroup) getActivity().findViewById(R.id.years_radio_group); mTopicsFilterRadioGroup = (RadioGroup) getActivity().findViewById(R.id.topics_radio_group); mDrawerLayout = (DrawerLayout) getActivity().findViewById(R.id.drawer_layout); mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow_flipped, GravityCompat.END); initPresenter(); } @Override public void onAttach(final Activity activity) { super.onAttach(activity); if (activity instanceof VideoLibraryFilteredContainer) { mParent = (VideoLibraryFilteredContainer) activity; } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View root = inflater.inflate(R.layout.video_library_filtered_frag, container, false); mVideoList = (RecyclerView) root.findViewById(R.id.videos_list); mEmptyView = root.findViewById(android.R.id.empty); getActivity().overridePendingTransition(0, 0); return root; } @Override public void onDetach() { mParent = null; super.onDetach(); } @Override public void onResume() { super.onResume(); getActivity().invalidateOptionsMenu(); final DrawShadowFrameLayout drawShadowFrameLayout = (DrawShadowFrameLayout) getActivity().findViewById(R.id.main_content); if (drawShadowFrameLayout != null) { // configure video fragment's top clearance to take our overlaid Toolbar into account. drawShadowFrameLayout.setShadowTopOffset(UIUtils.calculateActionBarSize(getActivity())); } } private void displayVideos(VideoLibraryModel model) { if (!model.hasVideos()) { mEmptyView.setVisibility(View.VISIBLE); return; } final GridLayoutManager glm = (GridLayoutManager) mVideoList.getLayoutManager(); final VideoTrackAdapter adapter = VideoTrackAdapter.createVerticalGrid(getActivity(), model.getAllVideos(), mImageLoader, mListeners, glm.getSpanCount()); mVideoList.setAdapter(adapter); glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(final int position) { return adapter.getSpanCount(position); } }); updateParent(model.getSelectedTopic(), model.getSelectedTopicImageUrl(), model.getSelectedTopicColor(), model.getSelectedYear()); mEmptyView.setVisibility(View.GONE); } private void initPresenter() { VideoLibraryModel model = ModelProvider .provideVideoLibraryModel(getDataUri(VideoLibraryQueryEnum.VIDEOS), getDataUri(VideoLibraryQueryEnum.MY_VIEWED_VIDEOS), getDataUri(VideoLibraryQueryEnum.FILTERS), getActivity(), getLoaderManager()); // Instantiate a new model with initial filter values from the intent call. String topicIdFilter = VideoLibraryModel.ALL_TOPICS; int yearFilter = VideoLibraryModel.ALL_YEARS; Bundle extras = getActivity().getIntent().getExtras(); if (extras != null) { topicIdFilter = extras.getString(VideoLibraryFilteredActivity.KEY_FILTER_TOPIC, VideoLibraryModel.ALL_TOPICS); yearFilter = extras.getInt(VideoLibraryFilteredActivity.KEY_FILTER_YEAR, VideoLibraryModel.ALL_YEARS); } model.setSelectedTopic(topicIdFilter); model.setSelectedYear(yearFilter); PresenterImpl presenter = new PresenterImpl(model, this, VideoLibraryUserActionEnum.values(), VideoLibraryQueryEnum.values()); presenter.loadInitialQueries(); } /** * Called when the user has selected a new filter for videos. */ private void onVideoFilterChanged(Object filter) { for (UserActionListener listener : mListeners) { Bundle args = new Bundle(); args.putInt(ModelWithLoaderManager.KEY_RUN_QUERY_ID, VideoLibraryModel.VideoLibraryQueryEnum.VIDEOS.getId()); if (filter instanceof Integer) { args.putInt(VideoLibraryModel.KEY_YEAR, (Integer) filter); } else if (filter instanceof String) { args.putString(VideoLibraryModel.KEY_TOPIC, (String) filter); } listener.onUserAction(VideoLibraryModel.VideoLibraryUserActionEnum.CHANGE_FILTER, args); } mDrawerLayout.closeDrawer(GravityCompat.END); } /** * Sets the title of the activity depending on the year and topic filters. */ private void updateParent(@Nullable String trackName, @Nullable String trackImageUrl, @ColorInt int trackColor, int year) { if (mParent != null) { String title; if (!trackName.equals(VideoLibraryModel.ALL_TOPICS) && year != VideoLibraryModel.ALL_YEARS) { title = getString(R.string.title_year_and_topic_filtered_video_library, year, trackName); } else if (!trackName.equals(VideoLibraryModel.ALL_TOPICS) && trackName.equals(VideoLibraryModel.KEYNOTES_TOPIC)) { title = getString(R.string.keynote_group_title); } else if (!trackName.equals(VideoLibraryModel.ALL_TOPICS)) { title = getString(R.string.title_topic_filtered_video_library, trackName); } else if (year != VideoLibraryModel.ALL_YEARS) { title = getString(R.string.title_year_filtered_video_library, year); } else { title = getString(R.string.title_video_library); } mParent.filtersUpdated(title, trackImageUrl, trackColor); } } /** * Generates RadioButton for each item of the {@code values} list and adds them to the {@code * radioGroup}. The item equals to {@code selectedValue} will be checked initially. Items with * special Labels can be added using {@code specialValues}. They will be added on top and in * uppercase characters. */ private <T extends Comparable> void updateRadioGroup(final RadioGroup radioGroup, List<T> values, T selectedValue, Map<T, String> specialValues) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE); if (radioGroup == null) { return; } // Add special Values to the list List<T> specialItemsList = new ArrayList<>(specialValues.keySet()); Collections.sort(specialItemsList); for (T keys : specialItemsList) { values.add(0, keys); } radioGroup.removeAllViews(); radioGroup.clearCheck(); int idCounter = 0; for (final T value : values) { View buttonLayout = inflater.inflate( R.layout.video_library_filter_radio_button, radioGroup, false); final RadioButton button = (RadioButton) buttonLayout.findViewById(R.id.button); radioGroup.addView(buttonLayout); // Set the Label of the Radio Button. TextView text = (TextView) buttonLayout.findViewById(R.id.text); text.setText(specialValues.get(value) == null ? value.toString() : specialValues.get(value)); // We have to give different IDs to all the RadioButtons inside the RadioGroup so that // only one can be checked at a time. button.setId(idCounter); idCounter++; // Trigger a RadioButton click when clicking the Text. text.setOnClickListener(new View.OnClickListener() { @Override @TargetApi(15) public void onClick(View v) { button.callOnClick(); } }); // When Clicking the RadioButton filter when re-filter the videos. button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { radioGroup.check(button.getId()); onVideoFilterChanged(value); } }); if (selectedValue.equals(value)) { radioGroup.check(button.getId()); } } } public interface VideoLibraryFilteredContainer { void filtersUpdated(@NonNull String title, @Nullable String selectionImage, @ColorInt int trackColor); } }