package org.theotech.ceaselessandroid.fragment; import android.app.Activity; import android.app.Fragment; import android.app.SearchManager; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.MenuItemCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.SearchView; import com.google.android.gms.analytics.Tracker; import com.squareup.picasso.Picasso; import com.viewpagerindicator.CirclePageIndicator; import org.theotech.ceaselessandroid.CeaselessApplication; import org.theotech.ceaselessandroid.R; import org.theotech.ceaselessandroid.activity.MainActivity; import org.theotech.ceaselessandroid.cache.CacheManager; import org.theotech.ceaselessandroid.cache.LocalDailyCacheManagerImpl; import org.theotech.ceaselessandroid.image.DownloadFileAsyncTask; import org.theotech.ceaselessandroid.image.ImageURLService; import org.theotech.ceaselessandroid.image.ImageURLServiceImpl; import org.theotech.ceaselessandroid.person.AlreadyPrayedForAllContactsException; import org.theotech.ceaselessandroid.person.PersonManager; import org.theotech.ceaselessandroid.person.PersonManagerImpl; import org.theotech.ceaselessandroid.realm.pojo.PersonPOJO; import org.theotech.ceaselessandroid.scripture.ScriptureData; import org.theotech.ceaselessandroid.scripture.ScriptureService; import org.theotech.ceaselessandroid.scripture.ScriptureServiceImpl; import org.theotech.ceaselessandroid.transformer.ZoomOutPageTransformer; import org.theotech.ceaselessandroid.util.AnalyticsUtils; import org.theotech.ceaselessandroid.util.CommonUtils; import org.theotech.ceaselessandroid.util.Constants; import java.io.File; import java.util.ArrayList; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; public class HomeFragment extends Fragment { private static final String TAG = HomeFragment.class.getSimpleName(); @Bind(R.id.home_view) ViewPager viewPager; @Bind(R.id.home_indicator) CirclePageIndicator indicator; private MainActivity activity; private boolean useCache; private FragmentStateListener mListener; private CacheManager cacheManager = null; private ImageURLService imageService = null; private ScriptureService scriptureService = null; private PersonManager personManager = null; private Tracker mTracker; private SearchView searchView; private Integer numberOfPeopleToPrayForDaily; public HomeFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); // notify fragment state try { mListener = (FragmentStateListener) getActivity(); } catch (ClassCastException e) { throw new ClassCastException(getActivity().toString() + " must implement FragmentStateListener"); } try { activity = (MainActivity) getActivity(); } catch (ClassCastException e) { throw new ClassCastException(getActivity().toString() + " must be an instanceof MainActivity"); } Bundle currentState = new Bundle(); currentState.putInt(Constants.HOME_SECTION_NUMBER_BUNDLE_ARG, 0); mListener.notify(new FragmentState(getString(R.string.nav_home), currentState)); // do not use the cache if we're trying to get more people. Bundle bundle = getArguments(); if (bundle != null && bundle.containsKey(Constants.USE_CACHE_BUNDLE_ARG)) { this.useCache = bundle.getBoolean(Constants.USE_CACHE_BUNDLE_ARG); } else { this.useCache = true; } cacheManager = LocalDailyCacheManagerImpl.getInstance(activity); imageService = ImageURLServiceImpl.getInstance(); scriptureService = ScriptureServiceImpl.getInstance(activity); personManager = PersonManagerImpl.getInstance(activity); CeaselessApplication application = (CeaselessApplication) activity.getApplication(); mTracker = application.getDefaultTracker(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // set title activity.setTitle(getString(R.string.nav_home)); // create view and bind View view = inflater.inflate(R.layout.fragment_home, container, false); ButterKnife.bind(this, view); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); numberOfPeopleToPrayForDaily = Integer.parseInt(preferences.getString(Constants.NUMBER_OF_PEOPLE_TO_PRAY_FOR, "3")); return view; } private void prepareCache() { // if we're not using the cache, set the default page to the first if (!useCache) { Log.d(TAG, "resetting page index to 0"); cacheManager.cachePageIndex(0); } // decide whether or not to fetch a new verse image String verseImageURL = cacheManager.getCachedVerseImageURL(); if (!useCache || verseImageURL == null) { updateBackgroundImage(); new ImageFetcher(activity).execute(); } // verse title and text ScriptureData scriptureData = cacheManager.getCachedScripture(); if (!useCache || scriptureData == null) { ScriptureData scripture = scriptureService.getScripture(); if (scripture != null) { Log.d(TAG, "scripture = " + scripture); // cache cacheManager.cacheScripture(scripture); } else { Log.e(TAG, "Could not fetch scripture!"); } } // people to pray for List<String> personIds = cacheManager.getCachedPersonIdsToPrayFor(); if (!useCache || personIds == null || personIds.size() < numberOfPeopleToPrayForDaily) { List<PersonPOJO> personPOJOs; try { personPOJOs = personManager.getNextPeopleToPrayFor(numberOfPeopleToPrayForDaily); } catch (AlreadyPrayedForAllContactsException e) { // TODO: Celebrate! try { personPOJOs = personManager.getNextPeopleToPrayFor(numberOfPeopleToPrayForDaily); } catch (AlreadyPrayedForAllContactsException e1) { // TODO: Something is really wrong if this happens, not sure what to do here throw new RuntimeException(e1); } } personIds = new ArrayList<>(); for (PersonPOJO personPOJO : personPOJOs) { personIds.add(personPOJO.getId()); } cacheManager.cachePersonIdsToPrayFor(personIds); } // now that the cache is updated, mark it ready for use. useCache = true; } private void prepareViewPager() { viewPager.setOffscreenPageLimit(numberOfPeopleToPrayForDaily + 1); final FragmentStatePagerAdapter pagerAdapter = getFragmentStatePagerAdapter(); viewPager.setAdapter(pagerAdapter); viewPager.setPageTransformer(true, new ZoomOutPageTransformer()); // since this gets called multiple times, we need to clear any existing onpagechangelisteners. // otherwise the listeners will accumulate. For example, open a quickcontent intent and go back. // suddenly you have two onPageChangeListeners attached. // Question: Does this mean that we maybe don't even need to configure the viewpager every single time? viewPager.clearOnPageChangeListeners(); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { ICardPageFragment card = (ICardPageFragment) pagerAdapter.getItem(position); cacheManager.cachePageIndex(viewPager.getCurrentItem()); AnalyticsUtils.sendScreenViewHit(mTracker, card.getCardName()); Bundle newState = new Bundle(); newState.putInt(Constants.HOME_SECTION_NUMBER_BUNDLE_ARG, position); if (position > 0 && position < numberOfPeopleToPrayForDaily + 1) { List<String> personIds = cacheManager.getCachedPersonIdsToPrayFor(); if (personIds != null && personIds.size() >= position) { String personId = personIds.get(position - 1); newState.putString(Constants.PERSON_ID_BUNDLE_ARG, personId); } } // notify fragment state FragmentState fragmentState = new FragmentState(getString(R.string.nav_home), newState); mListener.notify(fragmentState); } @Override public void onPageScrollStateChanged(int state) { } }); // wire up the indicator indicator.setViewPager(viewPager); // set the page if required Integer cachedPageIndex = cacheManager.getCachedPageIndex(); if (cachedPageIndex != null) { Log.d(TAG, "setting pager to " + cachedPageIndex); viewPager.setCurrentItem(cachedPageIndex); } } private FragmentStatePagerAdapter getFragmentStatePagerAdapter() { return new FragmentStatePagerAdapter(((AppCompatActivity) activity).getSupportFragmentManager()) { @Override public android.support.v4.app.Fragment getItem(int position) { android.support.v4.app.Fragment fragment; Bundle bundle = new Bundle(); if (position == 0) { fragment = new ScriptureCardSupportFragment(); } else if (position == getCount() - 1) { fragment = new ProgressCardSupportFragment(); } else { List<String> personIds = cacheManager.getCachedPersonIdsToPrayFor(); // we need at least as many people as there are slots to fill if (personIds != null && personIds.size() >= position) { String personId = personIds.get(position - 1); PersonPOJO person = personManager.getPerson(personId); if (person == null) { fragment = new BlankSupportFragment(); } else { fragment = PersonSupportFragment.newInstance(personId); bundle.putInt(Constants.HOME_SECTION_NUMBER_BUNDLE_ARG, position); } } else { fragment = new BlankSupportFragment(); } } // update the fragment's bundle so it has the data it needs bundle.putBoolean(Constants.USE_CACHE_BUNDLE_ARG, useCache); if (fragment.getArguments() != null) { fragment.getArguments().putAll(bundle); } else { fragment.setArguments(bundle); } return fragment; } @Override public int getCount() { if (cacheManager == null || cacheManager.getCachedPersonIdsToPrayFor() == null) { return Constants.NUM_AUXILIARY_CARDS; } return cacheManager.getCachedPersonIdsToPrayFor().size() + Constants.NUM_AUXILIARY_CARDS; } }; } private void updateBackgroundImage() { File nextBackgroundImage = new File(activity.getCacheDir(), Constants.NEXT_BACKGROUND_IMAGE); File currentBackgroundImage = new File(activity.getCacheDir(), Constants.CURRENT_BACKGROUND_IMAGE); // move cached next background image if (nextBackgroundImage.exists()) { if (nextBackgroundImage.renameTo(currentBackgroundImage)) { Log.d(TAG, "Updated the background image to use from " + nextBackgroundImage + " to " + currentBackgroundImage); Log.d(TAG, "New image size: " + currentBackgroundImage.length()); Picasso.with(activity).invalidate(currentBackgroundImage); // clear the picasso cache CommonUtils.setupBackgroundImage(activity, (ImageView) activity.findViewById(R.id.backgroundImageView)); } else { Log.d(TAG, "Could not update the background image to use."); } } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (!activity.getHomeFragmentCreated()) { // if the activity was just created and hence the HomeFragment // was created for the first time, start on the first page. // otherwise, we start on the page where the HomeFragment was before cacheManager.cachePageIndex(0); activity.setHomeFragmentCreated(true); } } @Override public void onResume() { super.onResume(); AnalyticsUtils.sendScreenViewHit(mTracker, "HomeScreen"); boolean searchViewFocused = searchView != null && searchView.hasFocus(); // create the pager so we see the cards if (activity.getHomeFragmentCreated() && !searchViewFocused) { prepareCache(); prepareViewPager(); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu, menu); MenuItem searchItem = menu.findItem(R.id.search); SearchManager searchManager = (SearchManager) activity.getSystemService(Context.SEARCH_SERVICE); searchView = (SearchView) MenuItemCompat.getActionView(searchItem); searchView.setSearchableInfo( searchManager.getSearchableInfo(activity.getComponentName())); super.onCreateOptionsMenu(menu, inflater); } private class ImageFetcher extends AsyncTask<String, Void, String> { private Activity activity; public ImageFetcher(Activity activity) { this.activity = activity; } @Override protected String doInBackground(String... params) { return imageService.getImageURL(); } @Override protected void onPostExecute(String imageUrl) { if (imageUrl != null) { Log.d(TAG, "imageUrl = " + imageUrl); // cache cacheManager.cacheVerseImageURL(imageUrl); try { // fetch new background image File nextBackgroundImage = new File(activity.getCacheDir(), Constants.NEXT_BACKGROUND_IMAGE); new DownloadFileAsyncTask(activity, imageUrl, nextBackgroundImage).execute(); } catch (Exception e) { Log.e(TAG, "Error fetching scripture image!"); e.printStackTrace(); } } else { Log.e(TAG, "Could not fetch scripture image!"); } } } }