Untitled

mail@pastecode.io avatar
unknown
plain_text
3 years ago
44 kB
1
Indexable
Never
package com.folioreader.fragments;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.core.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.webkit.JavascriptInterface;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;
import android.widget.Toast;

import com.folioreader.AnnotationEpubSourceType;
import com.folioreader.Config;
import com.folioreader.R;
import com.folioreader.activity.FolioActivity;
import com.folioreader.model.Highlight;
import com.folioreader.model.ReloadData;
import com.folioreader.model.RewindIndex;
import com.folioreader.model.Sentence;
import com.folioreader.model.WebViewPosition;
import com.folioreader.quickaction.ActionItem;
import com.folioreader.quickaction.QuickAction;
import com.folioreader.smil.TextElement;
import com.folioreader.sqlite.HighLightTable;
import com.folioreader.util.AppUtil;
import com.folioreader.util.HighlightUtil;
import com.folioreader.util.UiUtil;
import com.folioreader.view.ObservableWebView;
import com.folioreader.view.VerticalSeekbar;
import com.squareup.otto.Subscribe;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@SuppressLint("SetJavaScriptEnabled")
public class FolioPageFragment extends Fragment {

    public static final String KEY_FRAGMENT_FOLIO_POSITION = "com.folioreader.fragments.FolioPageFragment.POSITION";
    public static final String KEY_FRAGMENT_FOLIO_BOOK_TITLE = "com.folioreader.fragments.FolioPageFragment.BOOK_TITLE";
    public static final String KEY_FRAGMENT_EPUB_FILE_NAME = "com.folioreader.fragments.FolioPageFragment.EPUB_FILE_NAME";
    public static final String KEY_FRAGMENT_EPUB_DESTINATION_PATH = "com.folioreader.fragments.FolioPageFragment.EPUB_DESTINATION_PATH";
    public static final String KEY_FRAGMENT_EPUB_SOURCE_TYPE = "com.folioreader.fragments.FolioPageFragment.EPUB_SOURCE_TYPE";
    public static final String SP_FOLIO_PAGE_FRAGMENT = "com.folioreader.fragments.FolioPageFragment.SP_FOLIO_PAGE_FRAGMENT";
    public static final String TAG = FolioPageFragment.class.getSimpleName();

    private static final String KEY_IS_SMIL_AVAILABLE = "com.folioreader.fragments.FolioPageFragment.IS_SMIL_AVAILABLE";
    private static final int ACTION_ID_COPY = 1001;
    private static final int ACTION_ID_SHARE = 1002;
    private static final int ACTION_ID_HIGHLIGHT = 1003;
    private static final int ACTION_ID_DEFINE = 1004;
    private static final int ACTION_ID_HIGHLIGHT_COLOR = 1005;
    private static final int ACTION_ID_DELETE = 1006;
    private static final int ACTION_ID_HIGHLIGHT_YELLOW = 1007;
    private static final int ACTION_ID_HIGHLIGHT_GREEN = 1008;
    private static final int ACTION_ID_HIGHLIGHT_BLUE = 1009;
    private static final int ACTION_ID_HIGHLIGHT_PINK = 1010;
    private static final int ACTION_ID_HIGHLIGHT_UNDERLINE = 1011;
    private static final String KEY_TEXT_ELEMENTS = "text_elements";

    private WebViewPosition mWebviewposition;
    private String mBookTitle;
    private String mHtmlContent;
    private String mPageHref;
    private View mRootView;
    private Context mContext;
    private VerticalSeekbar mScrollSeekbar;
    private ObservableWebView mWebview;
    private TextView mPagesLeftTextView, mMinutesLeftTextView;
    private FolioPageFragmentCallback mActivityCallback;
    private int mScrollY;
    private int mTotalMinutes;
    private String mSelectedText;
    private boolean mIsSpeaking = true;
    private Map<String, String> mHighlightMap;
    private Handler mHandler = new Handler();
    private Animation mFadeInAnimation, mFadeOutAnimation;
    private ArrayList<TextElement> mTextElementList;
    private int mPosition = -1;
    private boolean mIsSmilAvailable;
    private int mPos;
    private boolean mIsPageReloaded;
    private int mLastWebviewScrollpos;
    private Runnable mHideSeekbarRunnable = new Runnable() {
        @Override
        public void run() {
            fadeoutSeekbarIfVisible();
        }
    };
    private MutableLiveData<Boolean> isFragmentVisible = new MutableLiveData<>();

    public static FolioPageFragment newInstance(int position, String bookTitle, String epubFileName, ArrayList<TextElement> textElementArrayList, boolean isSmileAvailable) {
        FolioPageFragment fragment = new FolioPageFragment();
        Bundle args = new Bundle();
        args.putInt(KEY_FRAGMENT_FOLIO_POSITION, position);
        args.putString(KEY_FRAGMENT_FOLIO_BOOK_TITLE, bookTitle);
        args.putString(KEY_FRAGMENT_EPUB_FILE_NAME, epubFileName);
        args.putParcelableArrayList(KEY_TEXT_ELEMENTS, textElementArrayList);
        args.putBoolean(KEY_IS_SMIL_AVAILABLE, isSmileAvailable);
        fragment.setArguments(args);
        return fragment;
    }

    public static FolioPageFragment newInstance(int position,
                                                String bookTitle,
                                                String epubFileName,
                                                String destinationPath,
                                                @AnnotationEpubSourceType.EpubSourceType int sourceType,
                                                ArrayList<TextElement> textElementArrayList,
                                                boolean isSmileAvailable) {
        FolioPageFragment fragment = new FolioPageFragment();
        Bundle args = new Bundle();
        args.putInt(KEY_FRAGMENT_FOLIO_POSITION, position);
        args.putString(KEY_FRAGMENT_FOLIO_BOOK_TITLE, bookTitle);
        args.putString(KEY_FRAGMENT_EPUB_FILE_NAME, epubFileName);
        args.putString(KEY_FRAGMENT_EPUB_DESTINATION_PATH, destinationPath);
        args.putInt(KEY_FRAGMENT_EPUB_SOURCE_TYPE, sourceType);
        args.putParcelableArrayList(KEY_TEXT_ELEMENTS, textElementArrayList);
        args.putBoolean(KEY_IS_SMIL_AVAILABLE, isSmileAvailable);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mContext = getActivity();

        if (getActivity() instanceof FolioPageFragmentCallback) {
            mActivityCallback = (FolioPageFragmentCallback) getActivity();
        }

        mPosition = getArguments().getInt(KEY_FRAGMENT_FOLIO_POSITION);
        mBookTitle = getArguments().getString(KEY_FRAGMENT_FOLIO_BOOK_TITLE);
        mIsSmilAvailable = getArguments().getBoolean(KEY_IS_SMIL_AVAILABLE);
        mTextElementList = getArguments().getParcelableArrayList(KEY_TEXT_ELEMENTS);

        mHtmlContent = getHtmlContent(mActivityCallback.getChapterHtmlContent(mPosition));
        mPageHref = mActivityCallback.getPageHref(mPosition);

        mRootView = View.inflate(getActivity(), R.layout.folio_page_fragment, null);
        mWebview = mRootView.findViewById(R.id.contentWebView);
        mPagesLeftTextView = mRootView.findViewById(R.id.pagesLeft);
        mMinutesLeftTextView = mRootView.findViewById(R.id.minutesLeft);

        FolioActivity.BUS.register(this);

        initSeekbar();
        initAnimations();
        observeFragmentVisibility();

        return mRootView;
    }

    private void observeFragmentVisibility() {
        isFragmentVisible.observe(this, new Observer<Boolean>() {
            @Override
            public void onChanged(@Nullable Boolean isVisible) {
                if (isVisible) initWebView(mHtmlContent);
            }
        });
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        float positionTopView = mWebview.getTop();
        float contentHeight = mWebview.getContentHeight();
        float currentScrollPosition = mScrollY;
        float percentWebview = (currentScrollPosition - positionTopView) / contentHeight;
        float webviewsize = mWebview.getContentHeight() - mWebview.getTop();
        float positionInWV = webviewsize * percentWebview;
        mScrollY = Math.round(mWebview.getTop() + positionInWV);
    }


    private void initWebView(String htmlContent) {
        mWebview.setFragment(FolioPageFragment.this);
        mWebview.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int height = (int) Math.floor(mWebview.getContentHeight() * mWebview.getCurrentScale());
                int webViewHeight = mWebview.getMeasuredHeight();
                mScrollSeekbar.setMaximum(height - webViewHeight);
            }
        });

        mWebview.getSettings().setJavaScriptEnabled(true);
        mWebview.getSettings().setAllowFileAccess(true);
        mWebview.getSettings().setDefaultTextEncodingName("utf-8");
        mWebview.getSettings().setUseWideViewPort(true);
        mWebview.getSettings().setLoadWithOverviewMode(true);
        mWebview.getSettings().setBuiltInZoomControls(true);
        mWebview.getSettings().setDisplayZoomControls(false);

        //<editor-fold desc="Improve webView performance">
        mWebview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        mWebview.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ONLY);
        mWebview.getSettings().setAppCacheEnabled(true);
        mWebview.getSettings().setDomStorageEnabled(true);
        //</editor-fold>

        mWebview.setVerticalScrollBarEnabled(false);
        mWebview.setHorizontalScrollBarEnabled(false);

        //<editor-fold desc="Disable webView selection text">
        mWebview.setLongClickable(false);
        mWebview.setHapticFeedbackEnabled(false);
        mWebview.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                return true;
            }
        });
        //</editor-fold>

        mWebview.setScrollListener(new ObservableWebView.ScrollListener() {
            @Override
            public void onScrollChange(int percent) {
                if (mWebview.getScrollY() != 0) {
                    mScrollY = mWebview.getScrollY();
                    ((FolioActivity) getActivity()).setLastWebViewPosition(mScrollY);
                }
                mScrollSeekbar.setProgressAndThumb(percent);
                updatePagesLeftText(percent);

            }
        });

        mWebview.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                updateTextSize();
                updateIndicatorView();
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                if (isAdded()) {
                    updateIndicatorView();

                    if (mWebviewposition != null) {
                        setWebViewPosition(mWebviewposition.getWebviewPos());
                    } else if (!((FolioActivity) getActivity()).isbookOpened() && isCurrentFragment()) {
                        setWebViewPosition(AppUtil.getPreviousBookStateWebViewPosition(mContext, mBookTitle));
                        ((FolioActivity) getActivity()).setIsbookOpened(true);
                    } else if (mIsPageReloaded) {
                        mIsPageReloaded = false;
                    }

                    mWebview.loadUrl("javascript:alert(getReadingTime())");
                    if (!mIsSmilAvailable) {
                        mWebview.loadUrl("javascript:alert(wrappingSentencesWithinPTags())");
                        mWebview.loadUrl(String.format(getString(R.string.setmediaoverlaystyle),
                                Highlight.HighlightStyle.classForStyle(Highlight.HighlightStyle.Normal)));
                    }
                }
            }

            @Override
            public void onScaleChanged(WebView view, float oldScale, float newScale) {
                super.onScaleChanged(view, oldScale, newScale);
                mWebview.setScale(newScale);
            }

            @SuppressWarnings("deprecation")
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (!url.isEmpty() && url.length() > 0) {
                    if (Uri.parse(url).getScheme().startsWith("highlight")) {
                        final Pattern pattern = Pattern.compile(getString(R.string.pattern));
                        try {
                            String htmlDecode = URLDecoder.decode(url, "UTF-8");
                            Matcher matcher = pattern.matcher(htmlDecode.substring(12));
                            if (matcher.matches()) {
                                double left = Double.parseDouble(matcher.group(1));
                                double top = Double.parseDouble(matcher.group(2));
                                double width = Double.parseDouble(matcher.group(3));
                                double height = Double.parseDouble(matcher.group(4));
                                onHighlight((int) (UiUtil.convertDpToPixel((float) left,
                                        getActivity())),
                                        (int) (UiUtil.convertDpToPixel((float) top,
                                                getActivity())),
                                        (int) (UiUtil.convertDpToPixel((float) width,
                                                getActivity())),
                                        (int) (UiUtil.convertDpToPixel((float) height,
                                                getActivity())));
                            }
                        } catch (UnsupportedEncodingException e) {
                            Log.d(TAG, e.getMessage());
                        }
                    } else {
                        if (url.contains("storage")) {
                            mActivityCallback.setPagerToPosition(url);
                        } else {
                            // Otherwise, give the default behavior (open in browser)
                            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                            startActivity(intent);
                        }
                    }
                }
                return true;
            }

            @TargetApi(Build.VERSION_CODES.N)
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                if (request != null && request.getUrl() != null) {
                    String url = request.getUrl().toString();
                    if (request.getUrl().getScheme().startsWith("highlight")) {
                        final Pattern pattern = Pattern.compile(getString(R.string.pattern));
                        try {
                            String htmlDecode = URLDecoder.decode(url, "UTF-8");
                            Matcher matcher = pattern.matcher(htmlDecode.substring(12));
                            if (matcher.matches()) {
                                double left = Double.parseDouble(matcher.group(1));
                                double top = Double.parseDouble(matcher.group(2));
                                double width = Double.parseDouble(matcher.group(3));
                                double height = Double.parseDouble(matcher.group(4));
                                onHighlight((int) (UiUtil.convertDpToPixel((float) left,
                                        getActivity())),
                                        (int) (UiUtil.convertDpToPixel((float) top,
                                                getActivity())),
                                        (int) (UiUtil.convertDpToPixel((float) width,
                                                getActivity())),
                                        (int) (UiUtil.convertDpToPixel((float) height,
                                                getActivity())));
                            }
                        } catch (UnsupportedEncodingException e) {
                            Log.d(TAG, e.getMessage());
                        }
                    } else {
                        if (url.contains("storage")) {
                            mActivityCallback.setPagerToPosition(url);
                        } else {
                            // Otherwise, give the default behavior (open in browser)
                            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                            startActivity(intent);
                        }
                    }
                }
                return true;
            }
        });

        mWebview.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int progress) {

                if (view.getProgress() == 100) {
                    mWebview.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mWebview.scrollTo(0, mScrollY);
                        }
                    }, 100);
                }
            }

            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Log.d("FolioPageFragment", "Message from js: " + message);
                if (FolioPageFragment.this.isVisible()) {
                    if (TextUtils.isDigitsOnly(message)) {
                        mTotalMinutes = Math.round(Integer.parseInt(message) / 60);
                        ((FolioActivity) getActivity()).setMaxDuration(Double.parseDouble(message));
                    } else {
                        final Pattern pattern = Pattern.compile(getString(R.string.pattern));
                        Matcher matcher = pattern.matcher(message);
                        if (matcher.matches()) {
                            double left = Double.parseDouble(matcher.group(1));
                            double top = Double.parseDouble(matcher.group(2));
                            double width = Double.parseDouble(matcher.group(3));
                            double height = Double.parseDouble(matcher.group(4));
                            showTextSelectionMenu((int) (UiUtil.convertDpToPixel((float) left,
                                    getActivity())),
                                    (int) (UiUtil.convertDpToPixel((float) top,
                                            getActivity())),
                                    (int) (UiUtil.convertDpToPixel((float) width,
                                            getActivity())),
                                    (int) (UiUtil.convertDpToPixel((float) height,
                                            getActivity())));
                        } else {
                            if (mIsSpeaking && (!message.equals("undefined"))) {
                                if (isCurrentFragment()) {
                                    Sentence sentence = new Sentence(message);
                                    FolioActivity.BUS.post(sentence);
                                }
                            }
                        }
                    }
                    result.confirm();
                }
                return true;
            }
        });

        //TODO : disable text selection
//        TextSelectionSupport mTextSelectionSupport = TextSelectionSupport.support(getActivity(), mWebview);
//        mTextSelectionSupport.setSelectionListener(new TextSelectionSupport.SelectionListener() {
//            @Override
//            public void startSelection() {
//            }
//
//            @Override
//            public void selectionChanged(String text) {
//                mSelectedText = text;
//                getActivity().runOnUiThread(new Runnable() {
//                    @Override
//                    public void run() {
//                        mWebview.loadUrl("javascript:alert(getRectForSelectedText())");
//                    }
//                });
//            }
//
//            @Override
//            public void endSelection() {
//
//            }
//        });
//        mWebview.addJavascriptInterface(this, "Highlight");

        mWebview.loadDataWithBaseURL(
                baseUrl(), mHtmlContent, "text/html", "UTF-8", null);
        ((FolioActivity) getActivity()).setLastWebViewPosition(mScrollY);

    }

    private void initSeekbar() {
        mScrollSeekbar = mRootView.findViewById(R.id.scrollSeekbar);
        mScrollSeekbar.getProgressDrawable()
                .setColorFilter(ContextCompat.getColor(getActivity(), R.color.app_blue),
                        PorterDuff.Mode.SRC_IN);
    }

    private String baseUrl() {
        return String.format("file://%s", mPageHref);
    }

    private void evaluateJavaScript(String javaScript) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            mWebview.evaluateJavascript("javascript:" + javaScript, null);
        } else {
            mWebview.loadUrl("javascript:" + javaScript);
        }
    }

    private String javaScriptCSS() {
        StringBuilder builder = new StringBuilder();
        builder.append("function addCSSRule(selector, newRule) {" +
                "if (document.styleSheets[0].addRule) {" +
                "document.styleSheets[0].addRule(selector, newRule);" +
                "} else {" +
                "ruleIndex = document.styleSheets[0].cssRules.length;" +
                "document.styleSheets[0].insertRule(selector + '{' + newRule + ';}', ruleIndex);" +
                "}" +
                "}");
        builder.append("addCSSRule('html', 'padding: 0px !important; word-wrap:break-word;');");
        builder.append("addCSSRule('img', 'display: block; margin: auto; horizontal-align: middle; height: auto !important; max-width: 100% !important;');");
        builder.append("addCSSRule('svg', 'horizontal-align: middle; max-width: 100% !important; height:auto; max-height: 100% !important;');");

        if (Config.getConfig(mContext).isNightMode()) {
            builder.append("addCSSRule('body', 'background-color: #131313 !important; -webkit-text-fill-color: #bcbeb0;');");
//        } else {
//            builder.append("document.styleSheets[0].cssRules[0].style.removeProperty('-webkit-text-fill-color');");
//            builder.append("addCSSRule('body', 'background-color: transparent !important');");
        }

        String fontFamily = "";
        switch (Config.getConfig(mContext).getFont()) {
            case 0:
                fontFamily = "andada, sans-serif";
                break;
            case 1:
                fontFamily = "lato, serif";
                break;
            case 2:
                fontFamily = "lora, serif";
                break;
            case 3:
                fontFamily = "raleway, sans-serif";
                break;
            default:
                break;
        }

        builder.append(String.format(Locale.US, "addCSSRule('body', 'font-family: %s !important;');", fontFamily));
        builder.append(String.format(Locale.US, "addCSSRule('p', 'text-align: left !important; line-height: 150%% !important; margin-bottom: 1em !important; font-family: %s !important;');", fontFamily));
        builder.append(String.format(Locale.US, "addCSSRule('span', 'font-family: %s !important;');", fontFamily));
        builder.append(String.format(Locale.US, "addCSSRule('div', 'font-family: %s !important;');", fontFamily));
        return builder.toString();
    }

    private void updateIndicatorView() {
        if (Config.getConfig(mContext).isNightMode()) {
            mRootView.findViewById(R.id.indicatorLayout)
                    .setBackgroundColor(Color.parseColor("#131313"));
        } else {
            mRootView.findViewById(R.id.indicatorLayout)
                    .setBackgroundColor(Color.WHITE);
        }
    }

    private void updateTextSize() {
        int fontSizePercentage;
        switch (Config.getConfig(mContext).getFontSize()) {
            case 0:
                fontSizePercentage = 80;
                break;
            case 2:
                fontSizePercentage = 120;
                break;
            case 3:
                fontSizePercentage = 140;
                break;
            case 4:
                fontSizePercentage = 160;
                break;
            default:
                fontSizePercentage = 100;
                break;
        }

        if (mActivityCallback.isFixedLayout()) {
            mWebview.getSettings().setTextZoom(fontSizePercentage);
        } else {
            mWebview.getSettings().setTextZoom(fontSizePercentage * 3);
        }
    }

    private void updatePagesLeftText(int scrollY) {
        try {
            int totalPages = (int) Math.ceil((double) mWebview.getContentHeightVal() / mWebview.getWebviewHeight());
            int currentPage = (int) (Math.ceil((double) scrollY / mWebview.getWebviewHeight()) + 1);
            int pagesRemaining = totalPages - currentPage;
            String pagesRemainingStrFormat =
                    pagesRemaining > 1 ?
                            getString(R.string.pages_left) : getString(R.string.page_left);
            String pagesRemainingStr = String.format(Locale.US,
                    pagesRemainingStrFormat, pagesRemaining);

            int minutesRemaining =
                    (int) Math.ceil((double) (pagesRemaining * mTotalMinutes) / totalPages);
            String minutesRemainingStr;
            if (minutesRemaining > 1) {
                minutesRemainingStr =
                        String.format(Locale.US, getString(R.string.minutes_left),
                                minutesRemaining);
            } else if (minutesRemaining == 1) {
                minutesRemainingStr =
                        String.format(Locale.US, getString(R.string.minute_left),
                                minutesRemaining);
            } else {
                minutesRemainingStr = getString(R.string.less_than_minute);
            }

            mMinutesLeftTextView.setText(minutesRemainingStr);
            mPagesLeftTextView.setText(pagesRemainingStr);
        } catch (java.lang.ArithmeticException exp) {
            Log.d("divide error", exp.toString());
        }
    }

    private void initAnimations() {
        mFadeInAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.fadein);
        mFadeInAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                mScrollSeekbar.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationEnd(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        mFadeOutAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.fadeout);
        mFadeOutAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mScrollSeekbar.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

    public void fadeInSeekbarIfInvisible() {
        if (mScrollSeekbar.getVisibility() == View.INVISIBLE ||
                mScrollSeekbar.getVisibility() == View.GONE) {
            mScrollSeekbar.startAnimation(mFadeInAnimation);
        }
    }

    private void fadeoutSeekbarIfVisible() {
        if (mScrollSeekbar.getVisibility() == View.VISIBLE) {
            mScrollSeekbar.startAnimation(mFadeOutAnimation);
        }
    }

    @Override
    public void onDestroyView() {
        mFadeInAnimation.setAnimationListener(null);
        mFadeOutAnimation.setAnimationListener(null);
        super.onDestroyView();
    }

    @Subscribe
    public void reload(ReloadData reloadData) {
        if (!isAdded()) return;

        mLastWebviewScrollpos = mWebview.getScrollY();
        switch (reloadData.getFlag()) {
            case ReloadData.FONT_SIZE:
                updateTextSize();
                break;
            default:
                mIsPageReloaded = true;
                String htmlContent = getHtmlContent(mActivityCallback.getChapterHtmlContent(mPosition));
                mWebview.loadDataWithBaseURL(baseUrl(), htmlContent, "text/html", "UTF-8", null);
                break;
        }

    }

    @Subscribe
    public void highLightString(Integer position) {
        if (isAdded()) {
            if (mTextElementList != null) {
                String src = mTextElementList.get(position.intValue()).getSrc();
                String[] temp = src.split("#");
                String textId = temp[1];
                mWebview.loadUrl(String.format(getString(R.string.audio_mark_id), textId));
            }

        }
    }

    @Subscribe
    public void getTextSentence(Boolean isSpeaking) {
        if (isCurrentFragment()) {
            mIsSpeaking = true;
            mWebview.loadUrl("javascript:alert(getSentenceWithIndex('epub-media-overlay-playing'))");
        }
    }

    @Subscribe
    public void setStyle(String style) {
        if (isAdded()) {
            mWebview.loadUrl(String.format(getString(R.string.setmediaoverlaystyle), style));
        }
    }

    private String getHtmlContent(String htmlContent) {
        String cssPath =
                String.format(getString(R.string.css_tag), "file:///android_asset/Style.css");
        String jsPath =
                String.format(getString(R.string.script_tag),
                        "file:///android_asset/Bridge.js");
        jsPath =
                jsPath + String.format(getString(R.string.script_tag),
                        "file:///android_asset/jquery-1.8.3.js");
        jsPath =
                jsPath + String.format(getString(R.string.script_tag),
                        "file:///android_asset/jpntext.js");
        jsPath =
                jsPath + String.format(getString(R.string.script_tag),
                        "file:///android_asset/rangy-core.js");
        jsPath =
                jsPath + String.format(getString(R.string.script_tag),
                        "file:///android_asset/rangy-serializer.js");
        jsPath =
                jsPath + String.format(getString(R.string.script_tag),
                        "file:///android_asset/android.selection.js");
        jsPath =
                jsPath + String.format(getString(R.string.script_tag_method_call),
                        "setMediaOverlayStyleColors('#C0ED72','#C0ED72')");

        String toInject = "\n" + cssPath + "\n" + jsPath + "\n</head>";
        htmlContent = htmlContent.replace("</head>", toInject);

        //TODO: Remark to replace original css
//        String toInject = "<head>\n" + cssPath + "\n" + jsPath + "\n</head>";
//        htmlContent = htmlContent.replaceAll("(<head>)(?s).*(</head>)", toInject);
        //

        htmlContent = htmlContent.replaceAll("\\r|\\n", "");
        htmlContent = htmlContent.replace("\t", "");

//TODO : remark to active highlight
//        ArrayList<Highlight> highlights = HighLightTable.getAllHighlights(mBookTitle);
//        for (Highlight highlight : highlights) {
//            String searchStr = highlight.getContentPre() + highlight.getContent() + highlight.getContentPost();
//            if (htmlContent.contains(searchStr)) {
//                String highlightStr =
//                        "<highlight id=\"" + highlight.getHighlightId() +
//                                "\" onclick=\"callHighlightURL(this);\" class=\"" +
//                                highlight.getType() + "\">" + highlight.getContent() + "</highlight>";
//                String replacement = highlight.getContentPre() + highlightStr + highlight.getContentPost();
//                htmlContent = htmlContent.replaceFirst(Pattern.quote(searchStr), replacement);
//            }
//        }

//        htmlContent = htmlContent.replaceAll("\\.\\.\\/", String.format("file://%s", parentPath()));

        // Disable styling
        htmlContent = htmlContent.replace("</body>", String.format("<script>%s</script></body>", javaScriptCSS()));

        return htmlContent;
    }

    public String getSelectedText() {
        return mSelectedText;
    }

    public void highlight(Highlight.HighlightStyle style, boolean isCreated) {
        if (isCreated) {
            mWebview.loadUrl(String.format(getString(R.string.getHighlightString),
                    Highlight.HighlightStyle.classForStyle(style)));
        } else {
            mWebview.loadUrl(String.format(getString(R.string.sethighlightstyle),
                    Highlight.HighlightStyle.classForStyle(style)));
        }


    }

    public void highlightRemove() {
        mWebview.loadUrl("javascript:alert(removeThisHighlight())");
    }

    public void showTextSelectionMenu(int x, int y, final int width, final int height) {
        final ViewGroup root =
                getActivity().getWindow()
                        .getDecorView().findViewById(android.R.id.content);
        final View view = new View(getActivity());
        view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
        view.setBackgroundColor(Color.TRANSPARENT);

        root.addView(view);

        view.setX(x);
        view.setY(y);
        final QuickAction quickAction =
                new QuickAction(getActivity(), QuickAction.HORIZONTAL);
        quickAction.addActionItem(new ActionItem(ACTION_ID_COPY,
                getString(R.string.copy)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT,
                getString(R.string.highlight)));
//        quickAction.addActionItem(new ActionItem(ACTION_ID_DEFINE,
//                getString(R.string.define)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_SHARE,
                getString(R.string.share)));
        quickAction.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() {
            @Override
            public void onItemClick(QuickAction source, int pos, int actionId) {
                quickAction.dismiss();
                root.removeView(view);
                onTextSelectionActionItemClicked(actionId, view, width, height);
            }
        });
        quickAction.show(view, width, height);
    }

    private void onTextSelectionActionItemClicked(int actionId, View view, int width, int height) {
        if (actionId == ACTION_ID_COPY) {
            UiUtil.copyToClipboard(mContext, mSelectedText);
            Toast.makeText(mContext, getString(R.string.copied), Toast.LENGTH_SHORT).show();
        } else if (actionId == ACTION_ID_SHARE) {
            UiUtil.share(mContext, mSelectedText);
        } else if (actionId == ACTION_ID_DEFINE) {
            //TODO: Check how to use define
        } else if (actionId == ACTION_ID_HIGHLIGHT) {
            onHighlight(view, width, height, true);
        }
    }

    private void onHighlight(int x, int y, int width, int height) {
        final View view = new View(getActivity());
        view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
        view.setBackgroundColor(Color.TRANSPARENT);
        view.setX(x);
        view.setY(y);
        onHighlight(view, width, height, false);
    }

    private void onHighlight(final View view, int width, int height, final boolean isCreated) {
        ViewGroup root =
                getActivity().getWindow().
                        getDecorView().findViewById(android.R.id.content);
        ViewGroup parent = (ViewGroup) view.getParent();
        if (parent == null) {
            root.addView(view);
        } else {
            final int index = parent.indexOfChild(view);
            parent.removeView(view);
            parent.addView(view, index);
        }

        final QuickAction quickAction = new QuickAction(getActivity(), QuickAction.HORIZONTAL);
        quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_COLOR,
                ContextCompat.getDrawable(getActivity(), R.drawable.colors_marker)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_DELETE,
                ContextCompat.getDrawable(getActivity(), R.drawable.ic_action_discard)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_SHARE,
                ContextCompat.getDrawable(getActivity(), R.drawable.ic_action_share)));
        final ViewGroup finalRoot = root;
        quickAction.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() {
            @Override
            public void onItemClick(QuickAction source, int pos, int actionId) {
                quickAction.dismiss();
                finalRoot.removeView(view);
                onHighlightActionItemClicked(actionId, view, isCreated);
            }
        });
        quickAction.show(view, width, height);
    }

    private void onHighlightActionItemClicked(int actionId, View view, boolean isCreated) {
        if (actionId == ACTION_ID_HIGHLIGHT_COLOR) {
            onHighlightColors(view, isCreated);
        } else if (actionId == ACTION_ID_SHARE) {
            UiUtil.share(mContext, mSelectedText);
        } else if (actionId == ACTION_ID_DELETE) {
            highlightRemove();
        }
    }

    private void onHighlightColors(final View view, final boolean isCreated) {
        ViewGroup root =
                getActivity().getWindow()
                        .getDecorView().findViewById(android.R.id.content);
        ViewGroup parent = (ViewGroup) view.getParent();
        if (parent == null) {
            root.addView(view);
        } else {
            final int index = parent.indexOfChild(view);
            parent.removeView(view);
            parent.addView(view, index);
        }

        final QuickAction quickAction = new QuickAction(getActivity(), QuickAction.HORIZONTAL);
        quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_YELLOW,
                ContextCompat.getDrawable(getActivity(), R.drawable.ic_yellow_marker)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_GREEN,
                ContextCompat.getDrawable(getActivity(), R.drawable.ic_green_marker)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_BLUE,
                ContextCompat.getDrawable(getActivity(), R.drawable.ic_blue_marker)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_PINK,
                ContextCompat.getDrawable(getActivity(), R.drawable.ic_pink_marker)));
        quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_UNDERLINE,
                ContextCompat.getDrawable(getActivity(), R.drawable.ic_underline_marker)));

        final ViewGroup finalRoot = root;
        quickAction.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() {
            @Override
            public void onItemClick(QuickAction source, int pos, int actionId) {
                quickAction.dismiss();
                finalRoot.removeView(view);
                onHighlightColorsActionItemClicked(actionId, view, isCreated);
            }
        });
        quickAction.show(view);
    }

    private void onHighlightColorsActionItemClicked(int actionId, View view, boolean isCreated) {
        if (actionId == ACTION_ID_HIGHLIGHT_YELLOW) {
            highlight(Highlight.HighlightStyle.Yellow, isCreated);
        } else if (actionId == ACTION_ID_HIGHLIGHT_GREEN) {
            highlight(Highlight.HighlightStyle.Green, isCreated);
        } else if (actionId == ACTION_ID_HIGHLIGHT_BLUE) {
            highlight(Highlight.HighlightStyle.Blue, isCreated);
        } else if (actionId == ACTION_ID_HIGHLIGHT_PINK) {
            highlight(Highlight.HighlightStyle.Pink, isCreated);
        } else if (actionId == ACTION_ID_HIGHLIGHT_UNDERLINE) {
            highlight(Highlight.HighlightStyle.Underline, isCreated);
        }
    }

    @JavascriptInterface
    public void getHighlightJson(String mJsonResponse) {
        if (mJsonResponse != null) {
            mHighlightMap = AppUtil.stringToJsonMap(mJsonResponse);
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mWebview.loadUrl("javascript:alert(getHTML())");
                }
            });
        }
    }

    @JavascriptInterface
    public void getHtmlAndSaveHighlight(String html) {
        if (html != null && mHighlightMap != null) {
            Highlight highlight =
                    HighlightUtil.matchHighlight(html, mHighlightMap.get("id"), mBookTitle, mPosition);
            highlight.setCurrentWebviewScrollPos(mWebview.getScrollY());
            highlight = ((FolioActivity) getActivity()).setCurrentPagerPostion(highlight);
            HighLightTable.insertHighlight(highlight);
        }
    }

    public void setWebViewPosition(final int position) {
        mWebview.postDelayed(new Runnable() {
            @Override
            public void run() {
                mWebview.scrollTo(0, position);
            }
        }, 300);
    }

    @JavascriptInterface
    public void getRemovedHighlightId(String id) {
        if (id != null) {
            HighLightTable.deleteHighlight(id);
        }
    }

    @JavascriptInterface
    public void getUpdatedHighlightId(String id, String style) {
        if (id != null) {
            HighLightTable.updateHighlightStyle(id, style);
        }
    }

    public void removeCallback() {
        mHandler.removeCallbacks(mHideSeekbarRunnable);
    }

    public void startCallback() {
        mHandler.postDelayed(mHideSeekbarRunnable, 3000);
    }

    @Subscribe
    public void resetCurrentIndex(RewindIndex resetIndex) {
        if (isCurrentFragment()) {
            mWebview.loadUrl("javascript:alert(rewindCurrentIndex())");
        }
    }

    private boolean isCurrentFragment() {
        return isAdded() && ((FolioActivity) getActivity()).getmChapterPosition() == mPos;
    }

    public void setFragmentPos(int pos) {
        mPos = pos;
    }

    @Subscribe
    public void setTextElementList(ArrayList<TextElement> textElementList) {
        if (textElementList != null && textElementList.size() > 0) {
            mIsSmilAvailable = true;
            mTextElementList = textElementList;
        }
    }

    @Subscribe
    public void setWebviewToHighlightPos(final WebViewPosition webViewPosition) {
        mWebviewposition = webViewPosition;
        if (isAdded()) {
            setWebViewPosition(mWebviewposition.getWebviewPos());
        }
    }

    public interface FolioPageFragmentCallback {
        String getChapterHtmlContent(int position);

        String getPageHref(int position);

        void hideOrshowToolBar();

        void hideToolBarIfVisible();

        void setPagerToPosition(String href);

        void setLastWebViewPosition(int position);

        boolean isFixedLayout();
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        isFragmentVisible.postValue(isVisibleToUser);
    }
}