com.ayuget.redface.ui.fragment.TopicFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.ayuget.redface.ui.fragment.TopicFragment.java

Source

/*
 * Copyright 2015 Ayuget
 *
 * 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.ayuget.redface.ui.fragment;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.ayuget.redface.R;
import com.ayuget.redface.data.api.MDEndpoints;
import com.ayuget.redface.data.api.model.Topic;
import com.ayuget.redface.ui.UIConstants;
import com.ayuget.redface.ui.activity.MultiPaneActivity;
import com.ayuget.redface.ui.activity.WritePrivateMessageActivity;
import com.ayuget.redface.ui.adapter.TopicPageAdapter;
import com.ayuget.redface.ui.event.GoToPostEvent;
import com.ayuget.redface.ui.event.PageLoadedEvent;
import com.ayuget.redface.ui.event.PageRefreshRequestEvent;
import com.ayuget.redface.ui.event.PageRefreshedEvent;
import com.ayuget.redface.ui.event.PageSelectedEvent;
import com.ayuget.redface.ui.event.ScrollToPostEvent;
import com.ayuget.redface.ui.event.TopicPageCountUpdatedEvent;
import com.ayuget.redface.ui.event.WritePrivateMessageEvent;
import com.ayuget.redface.ui.misc.PagePosition;
import com.ayuget.redface.ui.misc.SnackbarHelper;
import com.ayuget.redface.ui.misc.TopicPosition;
import com.ayuget.redface.ui.misc.UiUtils;
import com.hannesdorfmann.fragmentargs.annotation.Arg;
import com.rengwuxian.materialedittext.MaterialEditText;
import com.squareup.otto.Subscribe;

import java.util.ArrayList;

import javax.inject.Inject;

import butterknife.InjectView;

public class TopicFragment extends ToolbarFragment implements ViewPager.OnPageChangeListener {
    private static final String LOG_TAG = TopicFragment.class.getSimpleName();

    private static final String ARG_TOPIC_POSITIONS_STACK = "topicPositionsStack";

    private TopicPageAdapter topicPageAdapter;

    private MaterialEditText goToPageEditText;

    private ArrayList<TopicPosition> topicPositionsStack;

    private int previousViewPagerState = ViewPager.SCROLL_STATE_IDLE;

    private boolean userScrolledViewPager = false;

    @Inject
    MDEndpoints mdEndpoints;

    @InjectView(R.id.pager)
    ViewPager pager;

    @InjectView(R.id.titlestrip)
    PagerTabStrip pagerTitleStrip;

    /**
     * Topic currently displayed
     */
    @Arg
    Topic topic;

    /**
     * Page currently displayed in the viewPager
     */
    @Arg
    int currentPage;

    /**
     * Current page position
     */
    @Arg(required = false)
    PagePosition currentPagePosition;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (topicPageAdapter == null) {
            topicPageAdapter = new TopicPageAdapter(getChildFragmentManager(), topic, currentPage);
        }

        if (savedInstanceState != null) {
            topicPositionsStack = savedInstanceState.getParcelableArrayList(ARG_TOPIC_POSITIONS_STACK);
        }

        if (topicPositionsStack == null) {
            topicPositionsStack = new ArrayList<>();
        }

        setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        View rootView = inflateRootView(R.layout.fragment_topic, inflater, container);
        pagerTitleStrip.setDrawFullUnderline(false);
        pagerTitleStrip.setTabIndicatorColor(getResources().getColor(R.color.theme_primary));
        pager.setAdapter(topicPageAdapter);
        pager.setCurrentItem(currentPage - 1);

        return rootView;
    }

    @Override
    public void onResume() {
        super.onResume();

        pager.addOnPageChangeListener(this);
    }

    @Override
    public void onPause() {
        super.onPause();

        pager.removeOnPageChangeListener(this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putParcelableArrayList(ARG_TOPIC_POSITIONS_STACK, topicPositionsStack);
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        // Ignore event
    }

    @Override
    public void onPageSelected(int position) {
        currentPage = position + 1;
        bus.post(new PageSelectedEvent(topic, currentPage));
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        // Keep track of scroll state in order to detect if scrolling has been done
        // manually by the user, or programatically. It allows us to disable some automatic
        // scrolling behavior that can be annoying (and buggy) in some corner cases
        if (previousViewPagerState == ViewPager.SCROLL_STATE_DRAGGING && state == ViewPager.SCROLL_STATE_SETTLING) {
            userScrolledViewPager = true;

            // Reset current page position because user triggered page change
            currentPagePosition = null;
        } else if (previousViewPagerState == ViewPager.SCROLL_STATE_SETTLING
                && state == ViewPager.SCROLL_STATE_IDLE) {
            userScrolledViewPager = false;
        }

        previousViewPagerState = state;
    }

    @Override
    public void onCreateOptionsMenu(Toolbar toolbar) {
        toolbar.inflateMenu(R.menu.menu_topic);
    }

    @Override
    public void onToolbarInitialized(Toolbar toolbar) {
        MultiPaneActivity hostActivity = (MultiPaneActivity) getActivity();

        if (!hostActivity.isTwoPaneMode()) {
            showUpButton();
        }

        toolbar.setTitle(topic.getSubject());
    }

    /**
     * Method to be invoked by child fragments when a batch operation on Posts has started.
     */
    public void onBatchOperation(boolean active) {
        MultiPaneActivity hostActivity = (MultiPaneActivity) getActivity();

        if (!hostActivity.isTwoPaneMode()) {
            if (active) {
                pagerTitleStrip.setBackgroundColor(UiUtils.getActionModeBackgroundColor(getActivity()));
            } else {
                pagerTitleStrip.setBackgroundColor(UiUtils.getRegularPagerTitleStripBackgroundColor(getActivity()));
            }
        }
    }

    /**
     * Event fired by the webview contained in the viewpager child fragments once the page has
     * been loaded. It allow us to set the page position only once the DOM is ready, otherwise
     * initial posiion is broken.
     */
    @Subscribe
    public void onTopicPageLoaded(PageLoadedEvent event) {
        Log.d(LOG_TAG, String.format(
                "@%d -> Received topicPageLoaded event (topic='%s', page='%d'), current(topic='%s', page='%d', currentPagePosition='%s')",
                System.identityHashCode(this), event.getTopic().getSubject(), event.getPage(), topic.getSubject(),
                currentPage, currentPagePosition));
        if (event.getTopic().equals(topic) && event.getPage() == currentPage) {
            if (currentPagePosition != null && !userScrolledViewPager) {
                event.getTopicPageView().setPagePosition(currentPagePosition);
            }
        }
    }

    /**
     * Event fired by the data layer when we detect that new pages have been added
     * to a topic. It allows us to update the UI properly. This is completely mandatory
     * for "hot" topics, when a lot of content is added in a short period of time.
     */
    @Subscribe
    public void onTopicPageCountUpdated(TopicPageCountUpdatedEvent event) {
        if (event.getTopic() == topic) {
            topic.setPagesCount(event.getNewPageCount());
            topicPageAdapter.notifyDataSetChanged();
        }
    }

    @Subscribe
    public void onWritePrivateMessage(WritePrivateMessageEvent event) {
        MultiPaneActivity hostActivity = (MultiPaneActivity) getActivity();

        if (hostActivity.canLaunchReplyActivity()) {
            hostActivity.setCanLaunchReplyActivity(false);

            Intent intent = new Intent(getActivity(), WritePrivateMessageActivity.class);
            intent.putExtra(UIConstants.ARG_PM_RECIPIENT, event.getRecipient());

            getActivity().startActivityForResult(intent, UIConstants.NEW_PM_REQUEST_CODE);
        }

    }

    @Subscribe
    public void onGoToPost(GoToPostEvent event) {
        topicPositionsStack.add(new TopicPosition(currentPage, currentPagePosition));

        currentPagePosition = event.getPagePosition();

        if (currentPage == event.getPage()) {
            event.getTopicPageView().setPagePosition(currentPagePosition);
        } else {
            currentPage = event.getPage();

            if (pager != null) {
                pager.setCurrentItem(currentPage - 1);
            }
        }
    }

    /**
     * Callback called by the activity when the back key has been pressed
     * @return true if event was consumed, false otherwise
     */
    public boolean onBackPressed() {
        if (topicPositionsStack.size() == 0) {
            return false;
        } else {
            TopicPosition topicPosition = topicPositionsStack.remove(topicPositionsStack.size() - 1);

            currentPagePosition = topicPosition.getPagePosition();

            if (currentPage == topicPosition.getPage()) {
                bus.post(new ScrollToPostEvent(topic, currentPage, currentPagePosition));
            } else {
                currentPage = topicPosition.getPage();
                pager.setCurrentItem(currentPage - 1);
            }

            return true;
        }
    }

    /**
     * Returns current page position
     */
    public PagePosition getCurrentPagePosition() {
        return currentPagePosition;
    }

    /**
     * Updates position of currently displayed topic page
     * @param position new position
     */
    public void setCurrentPagePosition(PagePosition position) {
        currentPagePosition = position;
    }

    /**
     * Returns the currently displayed topic
     */
    public Topic getTopic() {
        return topic;
    }

    /**
     * Returns the initial displayed page
     */
    public int getCurrentPage() {
        return currentPage;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        switch (id) {
        case R.id.action_refresh_topic:
            bus.post(new PageRefreshRequestEvent(topic));
            break;
        case R.id.action_go_to_first_page:
            pager.setCurrentItem(0);
            return true;
        case R.id.action_go_to_last_page:
            pager.setCurrentItem(topic.getPagesCount() - 1);
            return true;

        case R.id.action_go_to_specific_page:
            showGoToPageDialog();
            return true;

        case R.id.action_copy_link:
            UiUtils.copyToClipboard(getActivity(), mdEndpoints.topic(topic, currentPage));
            break;
        case R.id.action_share:
            UiUtils.shareText(getActivity(), mdEndpoints.topic(topic));
            break;
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * Clears internal navigation stack
     */
    @Override
    public void clearInternalStack() {
        topicPositionsStack.clear();
    }

    public void showGoToPageDialog() {
        MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
                .customView(R.layout.dialog_go_to_page, true).positiveText(R.string.dialog_go_to_page_positive_text)
                .negativeText(android.R.string.cancel).theme(themeManager.getMaterialDialogTheme())
                .callback(new MaterialDialog.ButtonCallback() {
                    @Override
                    public void onPositive(MaterialDialog dialog) {
                        try {
                            int pageNumber = Integer.valueOf(goToPageEditText.getText().toString());
                            pager.setCurrentItem(pageNumber - 1);
                        } catch (NumberFormatException e) {
                            Log.e(LOG_TAG, String.format("Invalid page number entered : %s",
                                    goToPageEditText.getText().toString()), e);
                            SnackbarHelper.make(TopicFragment.this, R.string.invalid_page_number).show();
                        }
                    }

                    @Override
                    public void onNegative(MaterialDialog dialog) {
                    }
                }).build();

        final View positiveAction = dialog.getActionButton(DialogAction.POSITIVE);
        goToPageEditText = (MaterialEditText) dialog.getCustomView().findViewById(R.id.page_number);

        goToPageEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (s.toString().trim().length() > 0) {
                    try {
                        int pageNumber = Integer.valueOf(s.toString());
                        positiveAction.setEnabled(pageNumber >= 1 && pageNumber <= topic.getPagesCount());
                    } catch (NumberFormatException e) {
                        positiveAction.setEnabled(false);
                    }
                } else {
                    positiveAction.setEnabled(false);
                }
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        dialog.show();
        positiveAction.setEnabled(false);
    }
}