package org.petabytes.awesomeblogs.feeds; import android.content.Context; import android.content.res.Configuration; import android.graphics.Color; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.v4.view.ViewPager; import android.support.v4.widget.SwipeRefreshLayout; import android.text.TextUtils; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import com.androidadvance.topsnackbar.TSnackbar; import com.squareup.coordinators.Coordinators; import org.petabytes.api.source.local.Entry; import org.petabytes.api.source.local.Feed; import org.petabytes.awesomeblogs.AwesomeBlogsApp; import org.petabytes.awesomeblogs.R; import org.petabytes.awesomeblogs.util.Alerts; import org.petabytes.awesomeblogs.util.Analytics; import org.petabytes.awesomeblogs.util.Views; import org.petabytes.coordinator.Activity; import org.petabytes.coordinator.Coordinator; import org.petabytes.coordinator.PagerAdapter; import org.petabytes.coordinator.PagerFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Random; import butterknife.BindView; import fr.castorflex.android.smoothprogressbar.SmoothProgressBar; import fr.castorflex.android.verticalviewpager.VerticalViewPager; import hugo.weaving.DebugLog; import rx.functions.Action3; import rx.schedulers.Schedulers; import static org.petabytes.awesomeblogs.feeds.FeedsCoordinator.Type.CIRCLE; import static org.petabytes.awesomeblogs.feeds.FeedsCoordinator.Type.DIAGONAL; import static org.petabytes.awesomeblogs.feeds.FeedsCoordinator.Type.ENTIRE; import static org.petabytes.awesomeblogs.feeds.FeedsCoordinator.Type.ROWS; class FeedsCoordinator extends Coordinator { @BindView(R.id.refresh) SwipeRefreshLayout refreshView; @BindView(R.id.loading) View loadingView; @BindView(R.id.feeds) VerticalViewPager pagerView; @BindView(R.id.progress_bar) SmoothProgressBar progressBar; private final Context context; private final Action3<Integer, Integer, Integer> onPageSelectedAction; private @DrawerCoordinator.Category String category; private ViewPager.SimpleOnPageChangeListener onPageChangeListener; enum Type { ENTIRE, CIRCLE, DIAGONAL, ROWS } FeedsCoordinator(@NonNull Context context, @NonNull Action3<Integer, Integer, Integer> onPageSelectedAction) { this.context = context; this.onPageSelectedAction = onPageSelectedAction; } @DebugLog @Override public void attach(@NonNull View view) { super.attach(view); refreshView.setOnRefreshListener(() -> { load(category, true); Analytics.event(Analytics.Event.REFRESH); }); refreshView.setColorSchemeResources(R.color.colorAccent, R.color.background_1, R.color.background_22, R.color.background_6); pagerView.setOnPageChangeListener(onPageChangeListener = new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { onPageSelectedAction.call(position, pagerView.getAdapter().getCount(), getForegroundColor(position)); progressBar.setSmoothProgressDrawableColors(getProgressBarColors(position)); refreshView.setEnabled(refreshView.isRefreshing() || position == 0); } }); bind(AwesomeBlogsApp.get().api() .getFreshEntries() .filter(pair -> TextUtils.equals(category, pair.first) && !pair.second.isEmpty()), this::notifyFreshEntries); bind(AwesomeBlogsApp.get().api() .getSilentRefresh() .filter(pair -> TextUtils.equals(category, pair.first)) .map(pair -> pair.second), isRefreshing -> { Views.setVisibleOrGone(progressBar, isRefreshing); if (pagerView.getAdapter() != null && pagerView.getAdapter().getCount() > 0) { progressBar.setSmoothProgressDrawableColors(getProgressBarColors(0)); } }); } @DebugLog void onCategorySelect(@DrawerCoordinator.Category String category) { load(this.category = category, false); } private void load(@DrawerCoordinator.Category String category, boolean refresh) { if (!refresh) { Views.setVisible(loadingView); Views.setGone(pagerView); refreshView.setEnabled(false); } Views.setGone(progressBar); bind(AwesomeBlogsApp.get().api() .getFeed(category, refresh) .filter($ -> TextUtils.equals(this.category, category)) .map(Feed::getEntries) .map(this::categorize) .subscribeOn(Schedulers.io()), this::onLoad, $ -> onLoadError()); } private void onLoad(@NonNull List<Map<Type, List<Entry>>> entries) { Views.setGone(loadingView); Views.setVisible(pagerView); refreshView.setRefreshing(false); refreshView.setEnabled(true); pagerView.setAdapter(new PagerAdapter<>(entries, createPagerFactory())); pagerView.post(() -> onPageChangeListener.onPageSelected(pagerView.getCurrentItem())); } private void onLoadError() { Views.setGone(loadingView); refreshView.setRefreshing(false); refreshView.setEnabled(true); Alerts.show((Activity) context, R.string.error_title, R.string.error_unknown_feed); } private PagerFactory<Map<Type, List<Entry>>> createPagerFactory() { return entry -> { View view; if (entry.containsKey(ENTIRE)) { view = LayoutInflater.from(context).inflate(R.layout.entry_entire, null, false); Coordinators.bind(view, $ -> new EntryEntireCoordinator(context, entry.get(ENTIRE).get(0))); } else if (entry.containsKey(CIRCLE)) { view = LayoutInflater.from(context).inflate(R.layout.entry_circle, null, false); Coordinators.bind(view, $ -> new EntryCircleCoordinator(context, entry.get(CIRCLE).get(0))); } else if (entry.containsKey(DIAGONAL)) { view = LayoutInflater.from(context).inflate(R.layout.entry_diagonal, null, false); Coordinators.bind(view, $ -> new EntryDiagonalCoordinator(context, entry.get(DIAGONAL))); } else if (entry.containsKey(ROWS)) { view = LayoutInflater.from(context).inflate(R.layout.entry_rows, null, false); Coordinators.bind(view, $ -> new EntryRowsCoordinator(context, entry.get(ROWS))); } else { throw new IllegalArgumentException("Invalid entry."); } return view; }; } private List<Map<Type, List<Entry>>> categorize(@NonNull List<Entry> entries) { List<Map<Type, List<Entry>>> categorized = new ArrayList<>(); List<Entry> clone = new ArrayList<>(entries); int type = new Random().nextInt(3); if (type == 0 && clone.size() >= 2) { categorized.add(Collections.singletonMap(DIAGONAL, Arrays.asList(clone.remove(0), clone.remove(0)))); } else if (type == 1) { categorized.add(Collections.singletonMap(ENTIRE, Collections.singletonList(clone.remove(0)))); } else { categorized.add(Collections.singletonMap(CIRCLE, Collections.singletonList(clone.remove(0)))); } boolean isPortrait = context.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE; while (clone.size() > 0) { type = new Random().nextInt(4); if (type == 0 && clone.size() >= 2) { categorized.add(Collections.singletonMap(DIAGONAL, Arrays.asList(clone.remove(0), clone.remove(0)))); } else if (type == 1 && clone.size() >= (isPortrait ? 4 : 3)) { List<Entry> rows = isPortrait ? Arrays.asList(clone.remove(0), clone.remove(0), clone.remove(0), clone.remove(0)) : Arrays.asList(clone.remove(0), clone.remove(0), clone.remove(0)); categorized.add(Collections.singletonMap(ROWS, rows)); } else if (type == 2) { categorized.add(Collections.singletonMap(ENTIRE, Collections.singletonList(clone.remove(0)))); } else { categorized.add(Collections.singletonMap(CIRCLE, Collections.singletonList(clone.remove(0)))); } } return categorized; } @ColorInt private int getForegroundColor(int position) { Map<Type, List<Entry>> map = (Map<Type, List<Entry>>) ((PagerAdapter) pagerView.getAdapter()).getItem(position); if (map.keySet().contains(ENTIRE)) { return context.getResources().getColor(R.color.white); } else { return context.getResources().getColor(R.color.colorPrimaryDark); } } @ColorInt private int[] getProgressBarColors(int position) { Map<Type, List<Entry>> map = (Map<Type, List<Entry>>) ((PagerAdapter) pagerView.getAdapter()).getItem(position); if (map.keySet().contains(ENTIRE)) { return context.getResources().getIntArray(R.array.progress_bar_1); } else { return context.getResources().getIntArray(R.array.progress_bar_2); } } private void notifyFreshEntries(@NonNull Pair<String, List<Entry>> pair) { Analytics.event(Analytics.Event.NOTIFY_FRESH_ENTRIES); TSnackbar snack = TSnackbar.make(getView(), pair.second.size() == 1 ? context.getString(R.string.fresh_entries_title_0, pair.second.get(0).getTitle()) : context.getString(R.string.fresh_entries_title_1, pair.second.get(0).getTitle(), (pair.second.size() - 1)), 3500); TextView messageView = (TextView) snack.getView().findViewById(com.androidadvance.topsnackbar.R.id.snackbar_text); messageView.setTextColor(Color.WHITE); messageView.setMaxLines(2); snack.getView().setBackgroundResource(R.color.colorPrimaryDark); snack.setMaxWidth(3000); snack.getView().setOnClickListener($ -> { load(category, false); snack.dismiss(); Analytics.event(Analytics.Event.VIEW_FRESH_ENTRIES); }); snack.show(); } }