io.github.hidroh.materialistic.BaseWebFragment.java Source code

Java tutorial

Introduction

Here is the source code for io.github.hidroh.materialistic.BaseWebFragment.java

Source

/*
 * Copyright (c) 2015 Ha Duy Trung
 *
 * 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 io.github.hidroh.materialistic;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.NestedScrollView;
import android.text.TextUtils;
import android.view.Gravity;
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.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.widget.ViewSwitcher;

import javax.inject.Inject;
import javax.inject.Named;

import io.github.hidroh.materialistic.annotation.Synthetic;
import io.github.hidroh.materialistic.data.ItemManager;
import io.github.hidroh.materialistic.widget.AdBlockWebViewClient;
import io.github.hidroh.materialistic.widget.CacheableWebView;
import io.github.hidroh.materialistic.widget.PopupMenu;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;

abstract class BaseWebFragment extends LazyLoadFragment implements Scrollable, KeyDelegate.BackInterceptor {

    static final String ACTION_FULLSCREEN = BaseWebFragment.class.getName() + ".ACTION_FULLSCREEN";
    static final String EXTRA_FULLSCREEN = BaseWebFragment.class.getName() + ".EXTRA_FULLSCREEN";
    private static final String STATE_FULLSCREEN = "state:fullscreen";
    private static final String STATE_CONTENT = "state:content";
    private static final String STATE_URL = "state:url";
    @Synthetic
    WebView mWebView;
    private NestedScrollView mScrollView;
    @Synthetic
    boolean mExternalRequired = false;
    @Inject
    @Named(ActivityModule.HN)
    ItemManager mItemManager;
    @Inject
    PopupMenu mPopupMenu;
    private KeyDelegate.NestedScrollViewHelper mScrollableHelper;
    private final Preferences.Observable mPreferenceObservable = new Preferences.Observable();
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            setFullscreen(intent.getBooleanExtra(BaseWebFragment.EXTRA_FULLSCREEN, false));
        }
    };
    private ViewGroup mFullscreenView;
    private ViewGroup mScrollViewContent;
    @Synthetic
    ImageButton mButtonRefresh;
    private ViewSwitcher mControls;
    private EditText mEditText;
    private View mButtonMore;
    private View mButtonNext;
    protected ProgressBar mProgressBar;
    private boolean mFullscreen;
    protected String mContent;
    @Synthetic
    String mUrl;
    private AppUtils.SystemUiHelper mSystemUiHelper;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mPreferenceObservable.subscribe(context, this::onPreferenceChanged, R.string.pref_readability_font,
                R.string.pref_readability_line_height, R.string.pref_readability_text_size);
        LocalBroadcastManager.getInstance(context).registerReceiver(mReceiver, new IntentFilter(ACTION_FULLSCREEN));
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            mFullscreen = savedInstanceState.getBoolean(STATE_FULLSCREEN, false);
            mContent = savedInstanceState.getString(STATE_CONTENT);
            mUrl = savedInstanceState.getString(STATE_URL);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        final View view = getLayoutInflater(savedInstanceState).inflate(R.layout.fragment_web, container, false);
        mFullscreenView = (ViewGroup) view.findViewById(R.id.fullscreen);
        mScrollViewContent = (ViewGroup) view.findViewById(R.id.scroll_view_content);
        mScrollView = (NestedScrollView) view.findViewById(R.id.nested_scroll_view);
        mControls = (ViewSwitcher) view.findViewById(R.id.control_switcher);
        mWebView = (WebView) view.findViewById(R.id.web_view);
        mButtonRefresh = (ImageButton) view.findViewById(R.id.button_refresh);
        mButtonMore = view.findViewById(R.id.button_more);
        mButtonNext = view.findViewById(R.id.button_next);
        mButtonNext.setEnabled(false);
        mEditText = (EditText) view.findViewById(R.id.edittext);
        setUpWebControls(view);
        setUpWebView(view);
        return view;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setHasOptionsMenu(true);
        mScrollableHelper = new KeyDelegate.NestedScrollViewHelper(mScrollView);
        mSystemUiHelper = new AppUtils.SystemUiHelper(getActivity().getWindow());
        mSystemUiHelper.setEnabled(!getResources().getBoolean(R.bool.multi_pane));
        if (mFullscreen) {
            setFullscreen(true);
        }
    }

    @Override
    protected void createOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_font_options, menu);
    }

    @Override
    protected void prepareOptionsMenu(Menu menu) {
        boolean fontOptionsVisible = !TextUtils.isEmpty(mContent);
        menu.findItem(R.id.menu_font_options).setVisible(fontOptionsVisible);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.menu_font_options) {
            showPreferences();
            return true;
        }
        return true;
    }

    @Override
    public void onResume() {
        super.onResume();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mWebView.onResume();
        }
        mWebView.resumeTimers();
    }

    @Override
    public void onStop() {
        super.onStop();
        pauseWebView();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(STATE_FULLSCREEN, mFullscreen);
        outState.putString(STATE_CONTENT, mContent);
        outState.putString(STATE_URL, mUrl);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mPreferenceObservable.unsubscribe(getActivity());
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mWebView.destroy();
    }

    @Override
    public void scrollToTop() {
        if (mFullscreen) {
            mWebView.pageUp(true);
        } else {
            mScrollableHelper.scrollToTop();
        }
    }

    @Override
    public boolean scrollToNext() {
        if (mFullscreen) {
            mWebView.pageDown(false);
            return true;
        } else {
            return mScrollableHelper.scrollToNext();
        }
    }

    @Override
    public boolean scrollToPrevious() {
        if (mFullscreen) {
            mWebView.pageUp(false);
            return true;
        } else {
            return mScrollableHelper.scrollToPrevious();
        }
    }

    @Override
    public boolean onBackPressed() {
        if (mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return false;
    }

    void showEmptyView() {
        // override to show empty view
    }

    final void loadUrl(String url) {
        mUrl = url;
        setWebSettings(true);
        mWebView.loadUrl(url);
    }

    final void loadContent(String content) {
        mContent = content;
        getActivity().supportInvalidateOptionsMenu();
        if (!TextUtils.isEmpty(content)) {
            setWebSettings(false);
            mWebView.loadDataWithBaseURL(null, AppUtils.wrapHtml(getActivity(), content), "text/html", "UTF-8",
                    null);
        } else {
            showEmptyView();
        }
    }

    private void pauseWebView() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mWebView.onPause();
        }
        mWebView.pauseTimers();
    }

    private void setUpWebControls(View view) {
        view.findViewById(R.id.toolbar_web).setOnClickListener(v -> scrollToTop());
        view.findViewById(R.id.button_back).setOnClickListener(v -> mWebView.goBack());
        view.findViewById(R.id.button_forward).setOnClickListener(v -> mWebView.goForward());
        view.findViewById(R.id.button_clear).setOnClickListener(v -> {
            mSystemUiHelper.setFullscreen(true);
            reset();
            mControls.showNext();
        });
        view.findViewById(R.id.button_find).setOnClickListener(v -> {
            mEditText.requestFocus();
            toggleSoftKeyboard(true);
            mControls.showNext();
        });
        mButtonRefresh.setOnClickListener(v -> {
            if (mWebView.getProgress() == 100) {
                mWebView.loadUrl("about:blank");
                load();
            } else {
                mWebView.stopLoading();
            }
        });
        view.findViewById(R.id.button_exit).setOnClickListener(v -> LocalBroadcastManager.getInstance(getActivity())
                .sendBroadcast(new Intent(BaseWebFragment.ACTION_FULLSCREEN).putExtra(EXTRA_FULLSCREEN, false)));
        mButtonNext.setOnClickListener(v -> mWebView.findNext(true));
        mButtonMore.setOnClickListener(v -> mPopupMenu.create(getActivity(), mButtonMore, Gravity.NO_GRAVITY)
                .inflate(R.menu.menu_web).setOnMenuItemClickListener(item -> {
                    if (item.getItemId() == R.id.menu_font_options) {
                        showPreferences();
                        return true;
                    }
                    if (item.getItemId() == R.id.menu_zoom_in) {
                        mWebView.zoomIn();
                        return true;
                    }
                    if (item.getItemId() == R.id.menu_zoom_out) {
                        mWebView.zoomOut();
                        return true;
                    }
                    return false;
                }).setMenuItemVisible(R.id.menu_font_options, !TextUtils.isEmpty(mContent)).show());
        mEditText.setOnEditorActionListener((v, actionId, event) -> {
            findInPage();
            return true;
        });
    }

    private void setUpWebView(View view) {
        mProgressBar = (ProgressBar) view.findViewById(R.id.progress);
        mWebView.setBackgroundColor(Color.TRANSPARENT);
        mWebView.setWebViewClient(new AdBlockWebViewClient(Preferences.adBlockEnabled(getActivity())));
        mWebView.setWebChromeClient(new CacheableWebView.ArchiveClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                mProgressBar.setVisibility(VISIBLE);
                mProgressBar.setProgress(newProgress);
                if (!TextUtils.isEmpty(mUrl)) {
                    mWebView.setBackgroundColor(Color.WHITE);
                }
                if (newProgress == 100) {
                    mProgressBar.setVisibility(GONE);
                    mWebView.setVisibility(mExternalRequired ? GONE : VISIBLE);
                }
                mButtonRefresh.setImageResource(
                        newProgress == 100 ? R.drawable.ic_refresh_white_24dp : R.drawable.ic_clear_white_24dp);
            }
        });
        mWebView.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> {
            if (getActivity() == null) {
                return;
            }
            final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            if (intent.resolveActivity(getActivity().getPackageManager()) == null) {
                return;
            }
            mExternalRequired = true;
            mWebView.setVisibility(GONE);
            view.findViewById(R.id.empty).setVisibility(VISIBLE);
            view.findViewById(R.id.download_button).setOnClickListener(v -> startActivity(intent));
        });
        AppUtils.toggleWebViewZoom(mWebView.getSettings(), false);
    }

    @SuppressLint("SetJavaScriptEnabled")
    private void setWebSettings(boolean isRemote) {
        mWebView.getSettings().setLoadWithOverviewMode(isRemote);
        mWebView.getSettings().setUseWideViewPort(isRemote);
        mWebView.getSettings().setJavaScriptEnabled(true);
    }

    @Synthetic
    void setFullscreen(boolean isFullscreen) {
        if (getView() == null) {
            return;
        }
        mFullscreen = isFullscreen;
        mControls.setVisibility(isFullscreen ? VISIBLE : View.GONE);
        AppUtils.toggleWebViewZoom(mWebView.getSettings(), isFullscreen);
        ViewGroup.LayoutParams params = mWebView.getLayoutParams();
        if (isFullscreen) {
            mScrollView.removeView(mScrollViewContent);
            mFullscreenView.addView(mScrollViewContent);
            params.height = ViewGroup.LayoutParams.MATCH_PARENT;
        } else {
            reset();
            mWebView.pageUp(true);
            mFullscreenView.removeView(mScrollViewContent);
            mScrollView.addView(mScrollViewContent);
            params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        }
        mWebView.setLayoutParams(params);
    }

    private void showPreferences() {
        Bundle args = new Bundle();
        args.putInt(PopupSettingsFragment.EXTRA_TITLE, R.string.font_options);
        args.putIntArray(PopupSettingsFragment.EXTRA_XML_PREFERENCES, new int[] { R.xml.preferences_readability });
        ((DialogFragment) Fragment.instantiate(getActivity(), PopupSettingsFragment.class.getName(), args))
                .show(getFragmentManager(), PopupSettingsFragment.class.getName());
    }

    private void onPreferenceChanged(int key, boolean contextChanged) {
        if (!contextChanged) {
            load();
        }
    }

    private void reset() {
        mEditText.setText(null);
        mButtonNext.setEnabled(false);
        toggleSoftKeyboard(false);
        mWebView.clearMatches();
    }

    private void findInPage() {
        String query = mEditText.getText().toString().trim();
        if (TextUtils.isEmpty(query)) {
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            mWebView.setFindListener((activeMatchOrdinal, numberOfMatches, isDoneCounting) -> {
                if (isDoneCounting) {
                    handleFindResults(numberOfMatches);
                }
            });
            mWebView.findAllAsync(query);
        } else {
            //noinspection deprecation
            handleFindResults(mWebView.findAll(query));
        }
    }

    private void handleFindResults(int numberOfMatches) {
        mButtonNext.setEnabled(numberOfMatches > 0);
        if (numberOfMatches == 0) {
            Toast.makeText(getContext(), R.string.no_matches, Toast.LENGTH_SHORT).show();
        } else {
            toggleSoftKeyboard(false);
        }
    }

    private void toggleSoftKeyboard(boolean visible) {
        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (visible) {
            imm.showSoftInput(mEditText, InputMethodManager.SHOW_IMPLICIT);
        } else {
            imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
        }
    }
}