? = null
+ private set
+ var onItemClickListener: OnItemClickListener? = null
+
+ constructor(context: Context, dataBundle: Bundle) : super() {
+ Log.v(LOG_TAG, "-> constructor")
+
+ this.context = context
+ listViewType = ListViewType.fromString(dataBundle.getString("ListViewType"))
+ searchItemList = dataBundle.getParcelableArrayList("DATA")
+ }
+
+ fun changeDataBundle(dataBundle: Bundle) {
+
+ listViewType = ListViewType.fromString(dataBundle.getString(ListViewType.KEY))
+ searchItemList = dataBundle.getParcelableArrayList("DATA")
+ notifyDataSetChanged()
+ }
+
+ override fun getItemCount(): Int {
+
+ return if (searchItemList == null || searchItemList!!.size == 0) {
+ 1
+ } else {
+ searchItemList!!.size
+ }
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return listViewType.value
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+
+ val viewHolder: ViewHolder
+
+ when (viewType) {
+
+ ListViewType.INIT_VIEW.value -> {
+
+ val itemView: View = LayoutInflater.from(context)
+ .inflate(R.layout.item_search_init, parent, false)
+ viewHolder = InitViewHolder(itemView)
+ }
+
+ ListViewType.LOADING_VIEW.value -> {
+
+ val itemView: View = LayoutInflater.from(context)
+ .inflate(R.layout.item_search_loading, parent, false)
+ viewHolder = LoadingViewHolder(itemView)
+ }
+
+ ListViewType.NORMAL_VIEW.value -> {
+
+ val itemView: View = LayoutInflater.from(context)
+ .inflate(R.layout.item_search_normal, parent, false)
+ viewHolder = NormalViewHolder(itemView)
+ }
+
+ ListViewType.EMPTY_VIEW.value -> {
+
+ val itemView: View = LayoutInflater.from(context)
+ .inflate(R.layout.item_search_empty, parent, false)
+ viewHolder = EmptyViewHolder(itemView)
+ }
+
+ ListViewType.FAILURE_VIEW.value -> {
+
+ val itemView: View = LayoutInflater.from(context)
+ .inflate(R.layout.item_search_failure, parent, false)
+ viewHolder = FailureViewHolder(itemView)
+ }
+
+ else -> throw UnsupportedOperationException("Unknown viewType = $viewType")
+ }
+
+ return viewHolder
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+
+ val viewHolder = holder as ViewHolder
+
+ when (listViewType) {
+
+ ListViewType.INIT_VIEW -> {
+ }
+
+ ListViewType.LOADING_VIEW -> {
+ }
+
+ ListViewType.NORMAL_VIEW -> viewHolder.onBind(position)
+
+ ListViewType.EMPTY_VIEW -> {
+ }
+
+ ListViewType.FAILURE_VIEW -> {
+ }
+
+ else -> {
+ }
+ }
+ }
+
+ inner class InitViewHolder(itemView: View) : ViewHolder(itemView) {
+ init {
+ listViewType = ListViewType.INIT_VIEW
+ }
+ }
+
+ inner class LoadingViewHolder(itemView: View) : ViewHolder(itemView) {
+ init {
+ listViewType = ListViewType.LOADING_VIEW
+ }
+ }
+
+ inner class NormalViewHolder(itemView: View) : ViewHolder(itemView), View.OnClickListener {
+
+ val textViewCount: TextView = itemView.findViewById(R.id.textViewCount)
+ val textViewTitle: TextView = itemView.findViewById(R.id.textViewTitle)
+ val textViewResult: TextView = itemView.findViewById(R.id.textViewResult)
+ lateinit var searchItem: SearchItem
+
+ init {
+ listViewType = ListViewType.NORMAL_VIEW
+ }
+
+ override fun onBind(position: Int) {
+
+ itemPosition = position
+ searchItem = searchItemList!![position]
+
+ when (searchItem.searchItemType) {
+
+ SearchItemType.SEARCH_COUNT_ITEM -> {
+ val count: Int = searchItem.primaryContents?.toInt()!!
+ textViewCount.text = context.resources.getQuantityString(
+ R.plurals.numberOfSearchResults, count, count)
+ textViewCount.visibility = View.VISIBLE
+ textViewTitle.visibility = View.GONE
+ textViewResult.visibility = View.GONE
+
+ itemView.setOnClickListener(null)
+ }
+
+ SearchItemType.PAGE_TITLE_ITEM -> {
+ textViewTitle.text = searchItem.primaryContents
+ textViewTitle.visibility = View.VISIBLE
+ textViewCount.visibility = View.GONE
+ textViewResult.visibility = View.GONE
+
+ itemView.setOnClickListener(null)
+ }
+
+ SearchItemType.SEARCH_RESULT_ITEM -> {
+
+ val spannableString = SpannableString(searchItem.textBefore
+ + searchItem.matchQuery
+ + searchItem.textAfter)
+ val from = searchItem.textBefore.length
+ val to = from + searchItem.matchQuery.length
+ spannableString.setSpan(StyleSpan(Typeface.BOLD), from, to, 0)
+ spannableString.setSpan(UnderlineSpan(), from, to, 0)
+ textViewResult.text = spannableString
+
+ textViewResult.visibility = View.VISIBLE
+ textViewCount.visibility = View.GONE
+ textViewTitle.visibility = View.GONE
+
+ itemView.setOnClickListener(this)
+ }
+ }
+ }
+
+ override fun onClick(v: View?) {
+ onItemClickListener?.onItemClick(this@SearchAdapter, this,
+ itemPosition, itemId)
+ }
+ }
+
+ inner class EmptyViewHolder(itemView: View) : ViewHolder(itemView) {
+ init {
+ listViewType = ListViewType.EMPTY_VIEW
+ }
+ }
+
+ inner class FailureViewHolder(itemView: View) : ViewHolder(itemView) {
+ init {
+ listViewType = ListViewType.FAILURE_VIEW
+ }
+ }
+}
\ No newline at end of file
diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/adapter/ViewHolder.kt b/folioreader/src/main/java/com/folioreader/ui/folio/adapter/ViewHolder.kt
new file mode 100644
index 000000000..517a4b707
--- /dev/null
+++ b/folioreader/src/main/java/com/folioreader/ui/folio/adapter/ViewHolder.kt
@@ -0,0 +1,11 @@
+package com.folioreader.ui.folio.adapter
+
+import android.support.v7.widget.RecyclerView
+import android.view.View
+
+open class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var listViewType: ListViewType = ListViewType.UNKNOWN_VIEW
+ var itemPosition: Int = -1
+
+ open fun onBind(position: Int) {}
+}
\ No newline at end of file
diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/fragment/DictionaryFragment.java b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/DictionaryFragment.java
index ea6dc543c..84e658edb 100644
--- a/folioreader/src/main/java/com/folioreader/ui/folio/fragment/DictionaryFragment.java
+++ b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/DictionaryFragment.java
@@ -3,10 +3,12 @@
import android.app.Dialog;
import android.app.SearchManager;
import android.content.Intent;
+import android.graphics.Color;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
+import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
@@ -16,10 +18,12 @@
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.folioreader.Config;
import com.folioreader.Constants;
import com.folioreader.R;
import com.folioreader.model.dictionary.Dictionary;
@@ -29,6 +33,8 @@
import com.folioreader.ui.base.WikipediaCallBack;
import com.folioreader.ui.base.WikipediaTask;
import com.folioreader.ui.folio.adapter.DictionaryAdapter;
+import com.folioreader.util.AppUtil;
+import com.folioreader.util.UiUtil;
import java.io.IOException;
@@ -36,7 +42,8 @@
* @author gautam chibde on 4/7/17.
*/
-public class DictionaryFragment extends DialogFragment implements DictionaryCallBack, WikipediaCallBack {
+public class DictionaryFragment extends DialogFragment
+ implements DictionaryCallBack, WikipediaCallBack {
private static final String TAG = "DictionaryFragment";
@@ -50,11 +57,12 @@ public class DictionaryFragment extends DialogFragment implements DictionaryCall
private LinearLayout wikiLayout;
private WebView wikiWebView;
private DictionaryAdapter mAdapter;
+ private ImageView imageViewClose;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setStyle(STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog);
+ setStyle(STYLE_NO_TITLE, 0);
word = getArguments().getString(Constants.SELECTED_WORD);
mediaPlayer = new MediaPlayer();
}
@@ -74,6 +82,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
+
noNetwork = (TextView) view.findViewById(R.id.no_network);
progressBar = (ProgressBar) view.findViewById(R.id.progress);
dictResults = (RecyclerView) view.findViewById(R.id.rv_dict_results);
@@ -114,7 +123,8 @@ public void onClick(View v) {
}
});
- view.findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() {
+ imageViewClose = view.findViewById(R.id.btn_close);
+ imageViewClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
@@ -122,9 +132,51 @@ public void onClick(View v) {
});
dictResults.setLayoutManager(new LinearLayoutManager(getActivity()));
mAdapter = new DictionaryAdapter(getActivity(), this);
+
+ configureTheme(view);
+
loadDictionary();
}
+ private void configureTheme(View view) {
+
+ Config config = AppUtil.getSavedConfig(getContext());
+ assert config != null;
+ assert getContext() != null;
+ final int themeColor = config.getThemeColor();
+
+ UiUtil.setColorIntToDrawable(themeColor, imageViewClose.getDrawable());
+ LinearLayout layoutHeader = view.findViewById(R.id.layout_header);
+ layoutHeader.setBackgroundDrawable(UiUtil.getShapeDrawable(themeColor));
+ UiUtil.setColorIntToDrawable(themeColor, progressBar.getIndeterminateDrawable());
+ UiUtil.setShapeColor(googleSearch, themeColor);
+
+ if (config.isNightMode()) {
+ view.findViewById(R.id.toolbar).setBackgroundColor(Color.BLACK);
+ view.findViewById(R.id.contentView).setBackgroundColor(Color.BLACK);
+ dictionary.setBackgroundDrawable(UiUtil.createStateDrawable(themeColor, Color.BLACK));
+ wikipedia.setBackgroundDrawable(UiUtil.createStateDrawable(themeColor, Color.BLACK));
+ dictionary.setTextColor(UiUtil.getColorList(Color.BLACK, themeColor));
+ wikipedia.setTextColor(UiUtil.getColorList(Color.BLACK, themeColor));
+ int nightTextColor = ContextCompat.getColor(getContext(), R.color.night_text_color);
+ wikiWord.setTextColor(nightTextColor);
+ wikiWord.setBackgroundColor(Color.BLACK);
+ def.setTextColor(nightTextColor);
+ def.setBackgroundColor(Color.BLACK);
+ noNetwork.setTextColor(nightTextColor);
+
+ } else {
+ view.findViewById(R.id.contentView).setBackgroundColor(Color.WHITE);
+ dictionary.setTextColor(UiUtil.getColorList(Color.WHITE, themeColor));
+ wikipedia.setTextColor(UiUtil.getColorList(Color.WHITE, themeColor));
+ dictionary.setBackgroundDrawable(UiUtil.createStateDrawable(themeColor, Color.WHITE));
+ wikipedia.setBackgroundDrawable(UiUtil.createStateDrawable(themeColor, Color.WHITE));
+ wikiWord.setBackgroundColor(Color.WHITE);
+ def.setBackgroundColor(Color.WHITE);
+ googleSearch.setTextColor(Color.WHITE);
+ }
+ }
+
private void loadDictionary() {
if(noNetwork.getVisibility() == View.VISIBLE || googleSearch.getVisibility() == View.VISIBLE) {
noNetwork.setVisibility(View.GONE);
diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java
index 2024e2e7c..3068af25e 100644
--- a/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java
+++ b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java
@@ -1,1156 +1,1189 @@
-package com.folioreader.ui.folio.fragment;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Intent;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.content.LocalBroadcastManager;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-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.WebResourceResponse;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.bossturban.webviewmarker.TextSelectionSupport;
-import com.folioreader.Config;
-import com.folioreader.Constants;
-import com.folioreader.FolioReader;
-import com.folioreader.R;
-import com.folioreader.model.HighLight;
-import com.folioreader.model.HighlightImpl;
-import com.folioreader.model.ReadPosition;
-import com.folioreader.model.ReadPositionImpl;
-import com.folioreader.model.event.MediaOverlayHighlightStyleEvent;
-import com.folioreader.model.event.MediaOverlayPlayPauseEvent;
-import com.folioreader.model.event.MediaOverlaySpeedEvent;
-import com.folioreader.model.event.ReloadDataEvent;
-import com.folioreader.model.event.RewindIndexEvent;
-import com.folioreader.model.event.UpdateHighlightEvent;
-import com.folioreader.model.quickaction.ActionItem;
-import com.folioreader.model.quickaction.QuickAction;
-import com.folioreader.model.sqlite.HighLightTable;
-import com.folioreader.ui.base.HtmlTask;
-import com.folioreader.ui.base.HtmlTaskCallback;
-import com.folioreader.ui.base.HtmlUtil;
-import com.folioreader.ui.folio.activity.FolioActivityCallback;
-import com.folioreader.ui.folio.mediaoverlay.MediaController;
-import com.folioreader.ui.folio.mediaoverlay.MediaControllerCallbacks;
-import com.folioreader.util.AppUtil;
-import com.folioreader.util.HighlightUtil;
-import com.folioreader.util.SMILParser;
-import com.folioreader.util.UiUtil;
-import com.folioreader.view.FolioWebView;
-import com.folioreader.view.LoadingView;
-import com.folioreader.view.MediaControllerView;
-import com.folioreader.view.VerticalSeekbar;
-import com.folioreader.view.WebViewPager;
-
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-import org.readium.r2_streamer.model.publication.link.Link;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Created by mahavir on 4/2/16.
- */
-@SuppressWarnings("PMD.AvoidDuplicateLiterals")
-public class FolioPageFragment
- extends Fragment
- implements HtmlTaskCallback, MediaControllerCallbacks, FolioWebView.SeekBarListener {
-
- public static final String LOG_TAG = FolioPageFragment.class.getSimpleName();
- public static final String KEY_FRAGMENT_FOLIO_POSITION = "com.folioreader.ui.folio.fragment.FolioPageFragment.POSITION";
- public static final String KEY_FRAGMENT_FOLIO_BOOK_TITLE = "com.folioreader.ui.folio.fragment.FolioPageFragment.BOOK_TITLE";
- public static final String KEY_FRAGMENT_EPUB_FILE_NAME = "com.folioreader.ui.folio.fragment.FolioPageFragment.EPUB_FILE_NAME";
- private static final String KEY_IS_SMIL_AVAILABLE = "com.folioreader.ui.folio.fragment.FolioPageFragment.IS_SMIL_AVAILABLE";
- private static final String BUNDLE_READ_POSITION_CONFIG_CHANGE = "BUNDLE_READ_POSITION_CONFIG_CHANGE";
-
- 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 static final String SPINE_ITEM = "spine_item";
-
- private String mHtmlString = null;
- private boolean hasMediaOverlay = false;
- private String mAnchorId;
- private String rangy = "";
- private String highlightId;
-
- private ReadPosition lastReadPosition;
- private Bundle outState;
- private Bundle savedInstanceState;
-
- private View mRootView;
-
- private LoadingView loadingView;
- private VerticalSeekbar mScrollSeekbar;
- private FolioWebView mWebview;
- private WebViewPager webViewPager;
- private TextSelectionSupport mTextSelectionSupport;
- private TextView mPagesLeftTextView, mMinutesLeftTextView;
- private FolioActivityCallback mActivityCallback;
-
- private int mTotalMinutes;
- private String mSelectedText;
- private Animation mFadeInAnimation, mFadeOutAnimation;
-
- private Link spineItem;
- private int mPosition = -1;
- private String mBookTitle;
- private String mEpubFileName = null;
- private boolean mIsPageReloaded;
-
- private String highlightStyle;
-
- private MediaController mediaController;
- private Config mConfig;
- private String mBookId;
-
- public static FolioPageFragment newInstance(int position, String bookTitle, Link spineRef, String bookId) {
- 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(FolioReader.INTENT_BOOK_ID, bookId);
- args.putSerializable(SPINE_ITEM, spineRef);
- fragment.setArguments(args);
- return fragment;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater,
- ViewGroup container, Bundle savedInstanceState) {
-
- this.savedInstanceState = savedInstanceState;
-
- if (getActivity() instanceof FolioActivityCallback)
- mActivityCallback = (FolioActivityCallback) getActivity();
-
- EventBus.getDefault().register(this);
- if ((savedInstanceState != null)
- && savedInstanceState.containsKey(KEY_FRAGMENT_FOLIO_POSITION)
- && savedInstanceState.containsKey(KEY_FRAGMENT_FOLIO_BOOK_TITLE)) {
- mPosition = savedInstanceState.getInt(KEY_FRAGMENT_FOLIO_POSITION);
- mBookTitle = savedInstanceState.getString(KEY_FRAGMENT_FOLIO_BOOK_TITLE);
- mEpubFileName = savedInstanceState.getString(KEY_FRAGMENT_EPUB_FILE_NAME);
- mBookId = getArguments().getString(FolioReader.INTENT_BOOK_ID);
- spineItem = (Link) savedInstanceState.getSerializable(SPINE_ITEM);
- } else {
- mPosition = getArguments().getInt(KEY_FRAGMENT_FOLIO_POSITION);
- mBookTitle = getArguments().getString(KEY_FRAGMENT_FOLIO_BOOK_TITLE);
- mEpubFileName = getArguments().getString(KEY_FRAGMENT_EPUB_FILE_NAME);
- spineItem = (Link) getArguments().getSerializable(SPINE_ITEM);
- mBookId = getArguments().getString(FolioReader.INTENT_BOOK_ID);
- }
-
- if (spineItem != null) {
- if (spineItem.properties.contains("media-overlay")) {
- mediaController = new MediaController(getActivity(), MediaController.MediaType.SMIL, this);
- hasMediaOverlay = true;
- } else {
- mediaController = new MediaController(getActivity(), MediaController.MediaType.TTS, this);
- mediaController.setTextToSpeech(getActivity());
- }
- }
- highlightStyle = HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.Normal);
- mRootView = inflater.inflate(R.layout.folio_page_fragment, container, false);
- mPagesLeftTextView = (TextView) mRootView.findViewById(R.id.pagesLeft);
- mMinutesLeftTextView = (TextView) mRootView.findViewById(R.id.minutesLeft);
-
- mConfig = AppUtil.getSavedConfig(getContext());
-
- loadingView = mRootView.findViewById(R.id.loadingView);
- initSeekbar();
- initAnimations();
- initWebView();
- updatePagesLeftTextBg();
-
- return mRootView;
- }
-
- private String getWebviewUrl() {
- return Constants.LOCALHOST + mBookTitle + "/" + spineItem.href;
- }
-
- /**
- * [EVENT BUS FUNCTION]
- * Function triggered from {@link MediaControllerView#initListeners()} when pause/play
- * button is clicked
- *
- * @param event of type {@link MediaOverlayPlayPauseEvent} contains if paused/played
- */
- @SuppressWarnings("unused")
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void pauseButtonClicked(MediaOverlayPlayPauseEvent event) {
- if (isAdded()
- && spineItem.href.equals(event.getHref())) {
- mediaController.stateChanged(event);
- }
- }
-
- /**
- * [EVENT BUS FUNCTION]
- * Function triggered from {@link MediaControllerView#initListeners()} when speed
- * change buttons are clicked
- *
- * @param event of type {@link MediaOverlaySpeedEvent} contains selected speed
- * type HALF,ONE,ONE_HALF and TWO.
- */
- @SuppressWarnings("unused")
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void speedChanged(MediaOverlaySpeedEvent event) {
- mediaController.setSpeed(event.getSpeed());
- }
-
- /**
- * [EVENT BUS FUNCTION]
- * Function triggered from {@link MediaControllerView#initListeners()} when new
- * style is selected on button click.
- *
- * @param event of type {@link MediaOverlaySpeedEvent} contains selected style
- * of type DEFAULT,UNDERLINE and BACKGROUND.
- */
- @SuppressWarnings("unused")
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void styleChanged(MediaOverlayHighlightStyleEvent event) {
- if (isAdded()) {
- switch (event.getStyle()) {
- case DEFAULT:
- highlightStyle =
- HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.Normal);
- break;
- case UNDERLINE:
- highlightStyle =
- HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.DottetUnderline);
- break;
- case BACKGROUND:
- highlightStyle =
- HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.TextColor);
- break;
- }
- mWebview.loadUrl(String.format(getString(R.string.setmediaoverlaystyle), highlightStyle));
- }
- }
-
- /**
- * [EVENT BUS FUNCTION]
- * Function triggered when any EBook configuration is changed.
- *
- * @param reloadDataEvent empty POJO.
- */
- @SuppressWarnings("unused")
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void reload(ReloadDataEvent reloadDataEvent) {
-
- if (isCurrentFragment())
- getLastReadPosition();
-
- if (isAdded()) {
- loadingView.updateTheme();
- loadingView.show();
- mIsPageReloaded = true;
- setHtml(true);
- updatePagesLeftTextBg();
- }
- }
-
- /**
- * [EVENT BUS FUNCTION]
- *
- * Function triggered when highlight is deleted and page is needed to
- * be updated.
- *
- * @param event empty POJO.
- */
- @SuppressWarnings("unused")
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void updateHighlight(UpdateHighlightEvent event) {
- if (isAdded()) {
- this.rangy = HighlightUtil.generateRangyString(getPageName());
- loadRangy(mWebview, this.rangy);
- }
- }
-
- public void scrollToAnchorId(String href) {
-
- if (!TextUtils.isEmpty(href) && href.indexOf('#') != -1) {
- mAnchorId = href.substring(href.lastIndexOf('#') + 1);
- if (loadingView != null && loadingView.getVisibility() != View.VISIBLE) {
- loadingView.show();
- mWebview.loadUrl(String.format(getString(R.string.go_to_anchor), mAnchorId));
- mAnchorId = null;
- }
- }
- }
-
- @SuppressWarnings("unused")
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void resetCurrentIndex(RewindIndexEvent resetIndex) {
- if (isCurrentFragment()) {
- mWebview.loadUrl("javascript:rewindCurrentIndex()");
- }
- }
-
- @Override
- public void onReceiveHtml(String html) {
- if (isAdded()) {
- mHtmlString = html;
- setHtml(false);
- }
- }
-
- private void setHtml(boolean reloaded) {
- if (spineItem != null) {
- String ref = spineItem.href;
- if (!reloaded && spineItem.properties.contains("media-overlay")) {
- mediaController.setSMILItems(SMILParser.parseSMIL(mHtmlString));
- mediaController.setUpMediaPlayer(spineItem.mediaOverlay, spineItem.mediaOverlay.getAudioPath(spineItem.href), mBookTitle);
- }
- mConfig = AppUtil.getSavedConfig(getContext());
-
- String path = "";
- int forwardSlashLastIndex = ref.lastIndexOf('/');
- if (forwardSlashLastIndex != -1)
- path = ref.substring(0, forwardSlashLastIndex + 1);
-
- String mimeType;
- if (spineItem.typeLink.equalsIgnoreCase(getString(R.string.xhtml_mime_type))) {
- mimeType = getString(R.string.xhtml_mime_type);
- } else {
- mimeType = getString(R.string.html_mime_type);
- }
-
- mWebview.loadDataWithBaseURL(
- Constants.LOCALHOST + mBookTitle + "/" + path,
- HtmlUtil.getHtmlContent(getContext(), mHtmlString, mConfig),
- mimeType,
- "UTF-8",
- null);
- }
- }
-
- @SuppressWarnings("unused")
- @JavascriptInterface
- public String getDirection() {
- return mActivityCallback.getDirection().toString();
- }
-
- public void scrollToLast() {
-
- boolean isPageLoading = loadingView == null || loadingView.getVisibility() == View.VISIBLE;
- Log.v(LOG_TAG, "-> scrollToLast -> isPageLoading = " + isPageLoading);
-
- if (!isPageLoading) {
- loadingView.show();
- mWebview.loadUrl("javascript:scrollToLast()");
- }
- }
-
- public void scrollToFirst() {
-
- boolean isPageLoading = loadingView == null || loadingView.getVisibility() == View.VISIBLE;
- Log.v(LOG_TAG, "-> scrollToFirst -> isPageLoading = " + isPageLoading);
-
- if (!isPageLoading) {
- loadingView.show();
- mWebview.loadUrl("javascript:scrollToFirst()");
- }
- }
-
- private void initWebView() {
-
- FrameLayout webViewLayout = mRootView.findViewById(R.id.webViewLayout);
- mWebview = webViewLayout.findViewById(R.id.folioWebView);
- webViewPager = webViewLayout.findViewById(R.id.webViewPager);
-
- if (getActivity() instanceof FolioActivityCallback)
- mWebview.setFolioActivityCallback((FolioActivityCallback) getActivity());
-
- if (getActivity() instanceof FolioWebView.ToolBarListener)
- mWebview.setToolBarListener((FolioWebView.ToolBarListener) getActivity());
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
- WebView.setWebContentsDebuggingEnabled(true);
-
- setupScrollBar();
- mWebview.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View view, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- int height =
- (int) Math.floor(mWebview.getContentHeight() * mWebview.getScale());
- int webViewHeight = mWebview.getMeasuredHeight();
- mScrollSeekbar.setMaximum(height - webViewHeight);
- }
- });
-
- mWebview.getSettings().setJavaScriptEnabled(true);
- mWebview.setVerticalScrollBarEnabled(false);
- mWebview.getSettings().setAllowFileAccess(true);
-
- mWebview.setHorizontalScrollBarEnabled(false);
-
- mWebview.addJavascriptInterface(this, "Highlight");
- mWebview.addJavascriptInterface(this, "FolioPageFragment");
- mWebview.addJavascriptInterface(webViewPager, "WebViewPager");
- mWebview.addJavascriptInterface(loadingView, "LoadingView");
- mWebview.addJavascriptInterface(mWebview, "FolioWebView");
-
- mWebview.setScrollListener(new FolioWebView.ScrollListener() {
- @Override
- public void onScrollChange(int percent) {
-
- mScrollSeekbar.setProgressAndThumb(percent);
- updatePagesLeftText(percent);
- }
- });
-
- mWebview.setWebViewClient(webViewClient);
- mWebview.setWebChromeClient(webChromeClient);
-
- 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.getSettings().setDefaultTextEncodingName("utf-8");
- new HtmlTask(this).execute(getWebviewUrl());
- }
-
- private WebViewClient webViewClient = new WebViewClient() {
- @Override
- public void onPageFinished(WebView view, String url) {
-
- if (isAdded()) {
-
- mWebview.loadUrl("javascript:getCompatMode()");
- mWebview.loadUrl("javascript:alert(getReadingTime())");
-
- if (!hasMediaOverlay)
- mWebview.loadUrl("javascript:wrappingSentencesWithinPTags()");
-
- if (mActivityCallback.getDirection() == Config.Direction.HORIZONTAL)
- mWebview.loadUrl("javascript:initHorizontalDirection()");
-
- view.loadUrl(String.format(getString(R.string.setmediaoverlaystyle),
- HighlightImpl.HighlightStyle.classForStyle(
- HighlightImpl.HighlightStyle.Normal)));
-
- String rangy = HighlightUtil.generateRangyString(getPageName());
- FolioPageFragment.this.rangy = rangy;
- if (!rangy.isEmpty())
- loadRangy(mWebview, rangy);
-
- if (mIsPageReloaded) {
-
- if (isCurrentFragment()) {
- mWebview.loadUrl(String.format("javascript:scrollToSpan(%b, %s)",
- lastReadPosition.isUsingId(), lastReadPosition.getValue()));
- } else {
- if (mPosition == mActivityCallback.getChapterPosition() - 1) {
- // Scroll to last, the page before current page
- mWebview.loadUrl("javascript:scrollToLast()");
- } else {
- // Make loading view invisible for all other fragments
- loadingView.hide();
- }
- }
-
- mIsPageReloaded = false;
-
- } else if (!TextUtils.isEmpty(mAnchorId)) {
- mWebview.loadUrl(String.format(getString(R.string.go_to_anchor), mAnchorId));
- mAnchorId = null;
-
- } else if (!TextUtils.isEmpty(highlightId)) {
- mWebview.loadUrl(String.format(getString(R.string.go_to_highlight), highlightId));
- highlightId = null;
-
- } else if (isCurrentFragment()) {
-
- ReadPosition readPosition;
- if (savedInstanceState == null) {
- Log.v(LOG_TAG, "-> onPageFinished -> took from getEntryReadPosition");
- readPosition = mActivityCallback.getEntryReadPosition();
- } else {
- Log.v(LOG_TAG, "-> onPageFinished -> took from bundle");
- readPosition = savedInstanceState.getParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE);
- savedInstanceState.remove(BUNDLE_READ_POSITION_CONFIG_CHANGE);
- }
-
- if (readPosition != null) {
- Log.v(LOG_TAG, "-> scrollToSpan -> " + readPosition.getValue());
- mWebview.loadUrl(String.format("javascript:scrollToSpan(%b, %s)",
- readPosition.isUsingId(), readPosition.getValue()));
- } else {
- loadingView.hide();
- }
-
- } else {
-
- if (mPosition == mActivityCallback.getChapterPosition() - 1) {
- // Scroll to last, the page before current page
- mWebview.loadUrl("javascript:scrollToLast()");
- } else {
- // Make loading view invisible for all other fragments
- loadingView.hide();
- }
- }
- }
- }
-
- @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(LOG_TAG, e.getMessage());
- }
- } else {
- if (url.contains("storage")) {
- mActivityCallback.setPagerToPosition(url);
- } else if (url.endsWith(".xhtml") || url.endsWith(".html")) {
- mActivityCallback.goToChapter(url);
- } else {
- // Otherwise, give the default behavior (open in browser)
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(intent);
- }
- }
- }
- return true;
- }
-
- // prevent favicon.ico to be loaded automatically
- @Override
- public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
- if (url.toLowerCase().contains("/favicon.ico")) {
- try {
- return new WebResourceResponse("image/png", null, null);
- } catch (Exception e) {
- Log.e(LOG_TAG, "shouldInterceptRequest failed", e);
- }
- }
- return null;
- }
-
- // prevent favicon.ico to be loaded automatically
- @Override
- @SuppressLint("NewApi")
- public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
- if (!request.isForMainFrame()
- && request.getUrl().getPath() != null
- && request.getUrl().getPath().endsWith("/favicon.ico")) {
- try {
- return new WebResourceResponse("image/png", null, null);
- } catch (Exception e) {
- Log.e(LOG_TAG, "shouldInterceptRequest failed", e);
- }
- }
- return null;
- }
- };
-
- private WebChromeClient webChromeClient = new WebChromeClient() {
-
- @Override
- public void onProgressChanged(WebView view, int progress) {
- }
-
- @Override
- public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
- if (FolioPageFragment.this.isVisible()) {
- String rangyPattern = "\\d+\\$\\d+\\$\\d+\\$\\w+\\$";
- Pattern pattern = Pattern.compile(rangyPattern);
- Matcher matcher = pattern.matcher(message);
- if (matcher.matches()) {
- HighlightImpl highlightImpl = HighLightTable.getHighlightForRangy(message);
- if (HighLightTable.deleteHighlight(message)) {
- String rangy = HighlightUtil.generateRangyString(getPageName());
- loadRangy(view, rangy);
- mTextSelectionSupport.endSelectionMode();
- if (highlightImpl != null) {
- HighlightUtil.sendHighlightBroadcastEvent(
- FolioPageFragment.this.getActivity().getApplicationContext(),
- highlightImpl,
- HighLight.HighLightAction.DELETE);
- }
- }
- } else if (TextUtils.isDigitsOnly(message)) {
- try {
- mTotalMinutes = Integer.parseInt(message);
- } catch (NumberFormatException e) {
- mTotalMinutes = 0;
- }
- } else {
- pattern = Pattern.compile(getString(R.string.pattern));
- 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 {
- // to handle TTS playback when highlight is deleted.
- Pattern p = Pattern.compile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}");
- if (!p.matcher(message).matches() && (!message.equals("undefined")) && isCurrentFragment()) {
- mediaController.speakAudio(message);
- }
- }
- }
- result.confirm();
- }
- return true;
- }
- };
-
- /**
- * Calls the /assets/js/Bridge.js#getFirstVisibleSpan(boolean)
- */
- @Override
- public void onStop() {
- super.onStop();
- Log.v(LOG_TAG, "-> onStop -> " + spineItem.originalHref + " -> " + isCurrentFragment());
-
- mediaController.stop();
- //TODO save last media overlay item
-
- if (isCurrentFragment())
- getLastReadPosition();
- }
-
- public ReadPosition getLastReadPosition() {
- Log.v(LOG_TAG, "-> getLastReadPosition -> " + spineItem.originalHref);
-
- try {
- synchronized (this) {
- boolean isHorizontal = mActivityCallback.getDirection() ==
- Config.Direction.HORIZONTAL;
- mWebview.loadUrl("javascript:getFirstVisibleSpan(" + isHorizontal +")");
-
- wait(2000);
- }
- } catch (InterruptedException e) {
- Log.e(LOG_TAG, "-> " + e);
- }
-
- return lastReadPosition;
- }
-
- /**
- * Callback method called from /assets/js/Bridge.js#getFirstVisibleSpan(boolean)
- * and then ReadPositionImpl is broadcast to {@link FolioReader#readPositionReceiver}
- *
- * @param usingId if span tag has id then true or else false
- * @param value if usingId true then span id else span index
- */
- @SuppressWarnings("unused")
- @JavascriptInterface
- public void storeFirstVisibleSpan(boolean usingId, String value) {
-
- synchronized (this) {
- lastReadPosition = new ReadPositionImpl(mBookId, spineItem.getId(),
- spineItem.getOriginalHref(), mPosition, usingId, value);
- Intent intent = new Intent(FolioReader.ACTION_SAVE_READ_POSITION);
- intent.putExtra(FolioReader.EXTRA_READ_POSITION, lastReadPosition);
- LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
-
- notify();
- }
- }
-
- @SuppressWarnings("unused")
- @JavascriptInterface
- public void setHorizontalPageCount(int horizontalPageCount) {
- Log.v(LOG_TAG, "-> setHorizontalPageCount = " + horizontalPageCount
- + " -> " + spineItem.originalHref);
-
- mWebview.setHorizontalPageCount(horizontalPageCount);
- }
-
- private void loadRangy(WebView view, String rangy) {
- view.loadUrl(String.format("javascript:if(typeof ssReader !== \"undefined\"){ssReader.setHighlights('%s');}", rangy));
- }
-
- private void setupScrollBar() {
- UiUtil.setColorToImage(getActivity(), mConfig.getThemeColor(), mScrollSeekbar.getProgressDrawable());
- Drawable thumbDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.icons_sroll);
- UiUtil.setColorToImage(getActivity(), mConfig.getThemeColor(), (thumbDrawable));
- mScrollSeekbar.setThumb(thumbDrawable);
- }
-
- private void initSeekbar() {
- mScrollSeekbar = (VerticalSeekbar) mRootView.findViewById(R.id.scrollSeekbar);
- mScrollSeekbar.getProgressDrawable()
- .setColorFilter(getResources()
- .getColor(R.color.app_green),
- PorterDuff.Mode.SRC_IN);
- }
-
- private void updatePagesLeftTextBg() {
-
- if (mConfig.isNightMode()) {
- mRootView.findViewById(R.id.indicatorLayout)
- .setBackgroundColor(Color.parseColor("#131313"));
- } else {
- mRootView.findViewById(R.id.indicatorLayout)
- .setBackgroundColor(Color.WHITE);
- }
- }
-
- private void updatePagesLeftText(int scrollY) {
- try {
- int currentPage = (int) (Math.ceil((double) scrollY / mWebview.getWebViewHeight()) + 1);
- int totalPages =
- (int) Math.ceil((double) mWebview.getContentHeightVal()
- / mWebview.getWebViewHeight());
- 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 | IllegalStateException 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) {
- fadeOutSeekBarIfVisible();
- }
-
- @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);
- }
- }
-
- public void fadeOutSeekBarIfVisible() {
- if (mScrollSeekbar.getVisibility() == View.VISIBLE) {
- mScrollSeekbar.startAnimation(mFadeOutAnimation);
- }
- }
-
- @Override
- public void onDestroyView() {
- mFadeInAnimation.setAnimationListener(null);
- mFadeOutAnimation.setAnimationListener(null);
- EventBus.getDefault().unregister(this);
- super.onDestroyView();
- }
-
- /**
- * If called, this method will occur after onStop() for applications targeting platforms
- * starting with Build.VERSION_CODES.P. For applications targeting earlier platform versions
- * this method will occur before onStop() and there are no guarantees about whether it will
- * occur before or after onPause()
- *
- * @see Activity#onSaveInstanceState(Bundle) of Build.VERSION_CODES.P
- */
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- this.outState = outState;
-
- if (isCurrentFragment())
- Log.v(LOG_TAG, "-> onSaveInstanceState");
-
- outState.putInt(KEY_FRAGMENT_FOLIO_POSITION, mPosition);
- outState.putString(KEY_FRAGMENT_FOLIO_BOOK_TITLE, mBookTitle);
- outState.putString(KEY_FRAGMENT_EPUB_FILE_NAME, mEpubFileName);
- outState.putSerializable(SPINE_ITEM, spineItem);
- }
-
- public void highlight(HighlightImpl.HighlightStyle style, boolean isCreated) {
- if (isCreated) {
- mWebview.loadUrl(String.format("javascript:if(typeof ssReader !== \"undefined\"){ssReader.highlightSelection('%s');}", HighlightImpl.HighlightStyle.classForStyle(style)));
- } else {
- mWebview.loadUrl(String.format("javascript:setHighlightStyle('%s')", "highlight_" + HighlightImpl.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 =
- (ViewGroup) 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)));
- if (!mSelectedText.trim().contains(" ")) {
- 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(getActivity(), mSelectedText);
- Toast.makeText(getActivity(), getString(R.string.copied), Toast.LENGTH_SHORT).show();
- mTextSelectionSupport.endSelectionMode();
- } else if (actionId == ACTION_ID_SHARE) {
- UiUtil.share(getActivity(), mSelectedText);
- } else if (actionId == ACTION_ID_DEFINE) {
- showDictDialog(mSelectedText);
- mTextSelectionSupport.endSelectionMode();
- } else if (actionId == ACTION_ID_HIGHLIGHT) {
- onHighlight(view, width, height, true);
- }
- }
-
- private void showDictDialog(String mSelectedText) {
- DictionaryFragment dictionaryFragment = new DictionaryFragment();
- Bundle b = new Bundle();
- b.putString(Constants.SELECTED_WORD, mSelectedText);
- dictionaryFragment.setArguments(b);
- dictionaryFragment.show(getFragmentManager(), DictionaryFragment.class.getName());
- }
-
- 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 =
- (ViewGroup) 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,
- getResources().getDrawable(R.drawable.colors_marker)));
- quickAction.addActionItem(new ActionItem(ACTION_ID_DELETE,
- getResources().getDrawable(R.drawable.ic_action_discard)));
- quickAction.addActionItem(new ActionItem(ACTION_ID_SHARE,
- getResources().getDrawable(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(getActivity(), mSelectedText);
- mTextSelectionSupport.endSelectionMode();
- } else if (actionId == ACTION_ID_DELETE) {
- highlightRemove();
- }
- }
-
- private void onHighlightColors(final View view, final boolean isCreated) {
- ViewGroup root =
- (ViewGroup) 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,
- getResources().getDrawable(R.drawable.ic_yellow_marker)));
- quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_GREEN,
- getResources().getDrawable(R.drawable.ic_green_marker)));
- quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_BLUE,
- getResources().getDrawable(R.drawable.ic_blue_marker)));
- quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_PINK,
- getResources().getDrawable(R.drawable.ic_pink_marker)));
- quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_UNDERLINE,
- getResources().getDrawable(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(HighlightImpl.HighlightStyle.Yellow, isCreated);
- } else if (actionId == ACTION_ID_HIGHLIGHT_GREEN) {
- highlight(HighlightImpl.HighlightStyle.Green, isCreated);
- } else if (actionId == ACTION_ID_HIGHLIGHT_BLUE) {
- highlight(HighlightImpl.HighlightStyle.Blue, isCreated);
- } else if (actionId == ACTION_ID_HIGHLIGHT_PINK) {
- highlight(HighlightImpl.HighlightStyle.Pink, isCreated);
- } else if (actionId == ACTION_ID_HIGHLIGHT_UNDERLINE) {
- highlight(HighlightImpl.HighlightStyle.Underline, isCreated);
- }
- mTextSelectionSupport.endSelectionMode();
- }
-
- @Override
- public void resetCurrentIndex() {
- if (isCurrentFragment()) {
- mWebview.loadUrl("javascript:rewindCurrentIndex()");
- }
- }
-
- @SuppressWarnings("unused")
- @JavascriptInterface
- public void onReceiveHighlights(String html) {
- if (html != null) {
- rangy = HighlightUtil.createHighlightRangy(getActivity().getApplicationContext(),
- html,
- mBookId,
- getPageName(),
- mPosition,
- rangy);
- }
- }
-
- private String getPageName() {
- return mBookTitle + "$" + spineItem.href;
- }
-
- @Override
- public void highLightText(String fragmentId) {
- mWebview.loadUrl(String.format(getString(R.string.audio_mark_id), fragmentId));
- }
-
- @Override
- public void highLightTTS() {
- mWebview.loadUrl("javascript:alert(getSentenceWithIndex('epub-media-overlay-playing'))");
- }
-
- @JavascriptInterface
- public void getUpdatedHighlightId(String id, String style) {
- if (id != null) {
- HighlightImpl highlightImpl = HighLightTable.updateHighlightStyle(id, style);
- if (highlightImpl != null) {
- HighlightUtil.sendHighlightBroadcastEvent(
- getActivity().getApplicationContext(),
- highlightImpl,
- HighLight.HighLightAction.MODIFY);
- }
- final String rangyString = HighlightUtil.generateRangyString(getPageName());
- getActivity().runOnUiThread(new Runnable() {
- public void run() {
- loadRangy(mWebview, rangyString);
- }
- });
-
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (isCurrentFragment()) {
- if (outState != null)
- outState.putParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE, lastReadPosition);
- mActivityCallback.storeLastReadPosition(lastReadPosition);
- }
- if (mWebview != null) mWebview.destroy();
- }
-
- private boolean isCurrentFragment() {
-// Log.d(LOG_TAG, "-> isCurrentFragment -> "
-// + ", isAdded = " + isAdded()
-// + ", mActivityCallback.getChapterPosition() = " + mActivityCallback.getChapterPosition()
-// + ", mPosition = " + mPosition);
- return isAdded() && mActivityCallback.getChapterPosition() == mPosition;
- }
-
- @Override
- public void onError() {
- }
-
- public void scrollToHighlightId(String highlightId) {
- this.highlightId = highlightId;
-
- if (loadingView != null && loadingView.getVisibility() != View.VISIBLE) {
- loadingView.show();
- mWebview.loadUrl(String.format(getString(R.string.go_to_highlight), highlightId));
- this.highlightId = null;
- }
- }
-}
+package com.folioreader.ui.folio.fragment;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.Fragment;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.content.LocalBroadcastManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+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.WebResourceResponse;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.bossturban.webviewmarker.TextSelectionSupport;
+import com.folioreader.Config;
+import com.folioreader.Constants;
+import com.folioreader.FolioReader;
+import com.folioreader.R;
+import com.folioreader.model.HighLight;
+import com.folioreader.model.HighlightImpl;
+import com.folioreader.model.ReadPosition;
+import com.folioreader.model.ReadPositionImpl;
+import com.folioreader.model.event.MediaOverlayHighlightStyleEvent;
+import com.folioreader.model.event.MediaOverlayPlayPauseEvent;
+import com.folioreader.model.event.MediaOverlaySpeedEvent;
+import com.folioreader.model.event.ReloadDataEvent;
+import com.folioreader.model.event.RewindIndexEvent;
+import com.folioreader.model.event.UpdateHighlightEvent;
+import com.folioreader.model.quickaction.ActionItem;
+import com.folioreader.model.quickaction.QuickAction;
+import com.folioreader.model.search.SearchItem;
+import com.folioreader.model.sqlite.HighLightTable;
+import com.folioreader.ui.base.HtmlTask;
+import com.folioreader.ui.base.HtmlTaskCallback;
+import com.folioreader.ui.base.HtmlUtil;
+import com.folioreader.ui.folio.activity.FolioActivityCallback;
+import com.folioreader.ui.folio.mediaoverlay.MediaController;
+import com.folioreader.ui.folio.mediaoverlay.MediaControllerCallbacks;
+import com.folioreader.util.AppUtil;
+import com.folioreader.util.HighlightUtil;
+import com.folioreader.util.SMILParser;
+import com.folioreader.util.UiUtil;
+import com.folioreader.view.FolioWebView;
+import com.folioreader.view.LoadingView;
+import com.folioreader.view.VerticalSeekbar;
+import com.folioreader.view.WebViewPager;
+
+import org.apache.commons.text.StringEscapeUtils;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+import org.readium.r2_streamer.model.publication.link.Link;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by mahavir on 4/2/16.
+ */
+@SuppressWarnings("PMD.AvoidDuplicateLiterals")
+public class FolioPageFragment
+ extends Fragment
+ implements HtmlTaskCallback, MediaControllerCallbacks, FolioWebView.SeekBarListener {
+
+ public static final String LOG_TAG = FolioPageFragment.class.getSimpleName();
+ public static final String KEY_FRAGMENT_FOLIO_POSITION = "com.folioreader.ui.folio.fragment.FolioPageFragment.POSITION";
+ public static final String KEY_FRAGMENT_FOLIO_BOOK_TITLE = "com.folioreader.ui.folio.fragment.FolioPageFragment.BOOK_TITLE";
+ public static final String KEY_FRAGMENT_EPUB_FILE_NAME = "com.folioreader.ui.folio.fragment.FolioPageFragment.EPUB_FILE_NAME";
+ private static final String KEY_IS_SMIL_AVAILABLE = "com.folioreader.ui.folio.fragment.FolioPageFragment.IS_SMIL_AVAILABLE";
+ private static final String BUNDLE_READ_POSITION_CONFIG_CHANGE = "BUNDLE_READ_POSITION_CONFIG_CHANGE";
+ public static final String BUNDLE_SEARCH_ITEM = "BUNDLE_SEARCH_ITEM";
+
+ 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 static final String SPINE_ITEM = "spine_item";
+
+ private String mHtmlString = null;
+ private boolean hasMediaOverlay = false;
+ private String mAnchorId;
+ private String rangy = "";
+ private String highlightId;
+
+ private ReadPosition lastReadPosition;
+ private Bundle outState;
+ private Bundle savedInstanceState;
+
+ private View mRootView;
+
+ private LoadingView loadingView;
+ private VerticalSeekbar mScrollSeekbar;
+ private FolioWebView mWebview;
+ private WebViewPager webViewPager;
+ private TextSelectionSupport mTextSelectionSupport;
+ private TextView mPagesLeftTextView, mMinutesLeftTextView;
+ private FolioActivityCallback mActivityCallback;
+
+ private int mTotalMinutes;
+ private String mSelectedText;
+ private Animation mFadeInAnimation, mFadeOutAnimation;
+
+ private Link spineItem;
+ private int mPosition = -1;
+ private String mBookTitle;
+ private String mEpubFileName = null;
+ private boolean mIsPageReloaded;
+
+ private String highlightStyle;
+
+ private MediaController mediaController;
+ private Config mConfig;
+ private String mBookId;
+ public SearchItem searchItemVisible;
+
+ public static FolioPageFragment newInstance(int position, String bookTitle, Link spineRef, String bookId) {
+ 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(FolioReader.INTENT_BOOK_ID, bookId);
+ args.putSerializable(SPINE_ITEM, spineRef);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ ViewGroup container, Bundle savedInstanceState) {
+
+ this.savedInstanceState = savedInstanceState;
+
+ if (getActivity() instanceof FolioActivityCallback)
+ mActivityCallback = (FolioActivityCallback) getActivity();
+
+ EventBus.getDefault().register(this);
+
+ mPosition = getArguments().getInt(KEY_FRAGMENT_FOLIO_POSITION);
+ mBookTitle = getArguments().getString(KEY_FRAGMENT_FOLIO_BOOK_TITLE);
+ mEpubFileName = getArguments().getString(KEY_FRAGMENT_EPUB_FILE_NAME);
+ spineItem = (Link) getArguments().getSerializable(SPINE_ITEM);
+ mBookId = getArguments().getString(FolioReader.INTENT_BOOK_ID);
+
+ if (savedInstanceState != null) {
+ searchItemVisible = savedInstanceState.getParcelable(BUNDLE_SEARCH_ITEM);
+ }
+
+ if (spineItem != null) {
+ if (spineItem.properties.contains("media-overlay")) {
+ mediaController = new MediaController(getActivity(), MediaController.MediaType.SMIL, this);
+ hasMediaOverlay = true;
+ } else {
+ mediaController = new MediaController(getActivity(), MediaController.MediaType.TTS, this);
+ mediaController.setTextToSpeech(getActivity());
+ }
+ }
+ highlightStyle = HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.Normal);
+ mRootView = inflater.inflate(R.layout.folio_page_fragment, container, false);
+ mPagesLeftTextView = (TextView) mRootView.findViewById(R.id.pagesLeft);
+ mMinutesLeftTextView = (TextView) mRootView.findViewById(R.id.minutesLeft);
+
+ mConfig = AppUtil.getSavedConfig(getContext());
+
+ loadingView = mRootView.findViewById(R.id.loadingView);
+ initSeekbar();
+ initAnimations();
+ initWebView();
+ updatePagesLeftTextBg();
+
+ return mRootView;
+ }
+
+ private String getWebviewUrl() {
+ return Constants.LOCALHOST + mBookTitle + "/" + spineItem.href;
+ }
+
+ /**
+ * [EVENT BUS FUNCTION]
+ * Function triggered from {@link MediaControllerFragment#initListeners()} when pause/play
+ * button is clicked
+ *
+ * @param event of type {@link MediaOverlayPlayPauseEvent} contains if paused/played
+ */
+ @SuppressWarnings("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void pauseButtonClicked(MediaOverlayPlayPauseEvent event) {
+ if (isAdded()
+ && spineItem.href.equals(event.getHref())) {
+ mediaController.stateChanged(event);
+ }
+ }
+
+ /**
+ * [EVENT BUS FUNCTION]
+ * Function triggered from {@link MediaControllerFragment#initListeners()} when speed
+ * change buttons are clicked
+ *
+ * @param event of type {@link MediaOverlaySpeedEvent} contains selected speed
+ * type HALF,ONE,ONE_HALF and TWO.
+ */
+ @SuppressWarnings("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void speedChanged(MediaOverlaySpeedEvent event) {
+ if (mediaController != null)
+ mediaController.setSpeed(event.getSpeed());
+ }
+
+ /**
+ * [EVENT BUS FUNCTION]
+ * Function triggered from {@link MediaControllerFragment#initListeners()} when new
+ * style is selected on button click.
+ *
+ * @param event of type {@link MediaOverlaySpeedEvent} contains selected style
+ * of type DEFAULT,UNDERLINE and BACKGROUND.
+ */
+ @SuppressWarnings("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void styleChanged(MediaOverlayHighlightStyleEvent event) {
+ if (isAdded()) {
+ switch (event.getStyle()) {
+ case DEFAULT:
+ highlightStyle =
+ HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.Normal);
+ break;
+ case UNDERLINE:
+ highlightStyle =
+ HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.DottetUnderline);
+ break;
+ case BACKGROUND:
+ highlightStyle =
+ HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.TextColor);
+ break;
+ }
+ mWebview.loadUrl(String.format(getString(R.string.setmediaoverlaystyle), highlightStyle));
+ }
+ }
+
+ /**
+ * [EVENT BUS FUNCTION]
+ * Function triggered when any EBook configuration is changed.
+ *
+ * @param reloadDataEvent empty POJO.
+ */
+ @SuppressWarnings("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void reload(ReloadDataEvent reloadDataEvent) {
+
+ if (isCurrentFragment())
+ getLastReadPosition();
+
+ if (isAdded()) {
+ loadingView.updateTheme();
+ loadingView.show();
+ mIsPageReloaded = true;
+ setHtml(true);
+ updatePagesLeftTextBg();
+ }
+ }
+
+ /**
+ * [EVENT BUS FUNCTION]
+ *
+ * Function triggered when highlight is deleted and page is needed to
+ * be updated.
+ *
+ * @param event empty POJO.
+ */
+ @SuppressWarnings("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void updateHighlight(UpdateHighlightEvent event) {
+ if (isAdded()) {
+ this.rangy = HighlightUtil.generateRangyString(getPageName());
+ loadRangy(mWebview, this.rangy);
+ }
+ }
+
+ public void scrollToAnchorId(String href) {
+
+ if (!TextUtils.isEmpty(href) && href.indexOf('#') != -1) {
+ mAnchorId = href.substring(href.lastIndexOf('#') + 1);
+ if (loadingView != null && loadingView.getVisibility() != View.VISIBLE) {
+ loadingView.show();
+ mWebview.loadUrl(String.format(getString(R.string.go_to_anchor), mAnchorId));
+ mAnchorId = null;
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void resetCurrentIndex(RewindIndexEvent resetIndex) {
+ if (isCurrentFragment()) {
+ mWebview.loadUrl("javascript:rewindCurrentIndex()");
+ }
+ }
+
+ @Override
+ public void onReceiveHtml(String html) {
+ if (isAdded()) {
+ mHtmlString = html;
+ setHtml(false);
+ }
+ }
+
+ private void setHtml(boolean reloaded) {
+ if (spineItem != null) {
+ String ref = spineItem.href;
+ if (!reloaded && spineItem.properties.contains("media-overlay")) {
+ mediaController.setSMILItems(SMILParser.parseSMIL(mHtmlString));
+ mediaController.setUpMediaPlayer(spineItem.mediaOverlay, spineItem.mediaOverlay.getAudioPath(spineItem.href), mBookTitle);
+ }
+ mConfig = AppUtil.getSavedConfig(getContext());
+
+ String path = "";
+ int forwardSlashLastIndex = ref.lastIndexOf('/');
+ if (forwardSlashLastIndex != -1)
+ path = ref.substring(0, forwardSlashLastIndex + 1);
+
+ String mimeType;
+ if (spineItem.typeLink.equalsIgnoreCase(getString(R.string.xhtml_mime_type))) {
+ mimeType = getString(R.string.xhtml_mime_type);
+ } else {
+ mimeType = getString(R.string.html_mime_type);
+ }
+
+ mWebview.loadDataWithBaseURL(
+ Constants.LOCALHOST + mBookTitle + "/" + path,
+ HtmlUtil.getHtmlContent(getContext(), mHtmlString, mConfig),
+ mimeType,
+ "UTF-8",
+ null);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public String getDirection() {
+ return mActivityCallback.getDirection().toString();
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public int getTopDistraction() {
+ return mActivityCallback.getTopDistraction();
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public int getBottomDistraction() {
+ return mActivityCallback.getBottomDistraction();
+ }
+
+ public void scrollToLast() {
+
+ boolean isPageLoading = loadingView == null || loadingView.getVisibility() == View.VISIBLE;
+ Log.v(LOG_TAG, "-> scrollToLast -> isPageLoading = " + isPageLoading);
+
+ if (!isPageLoading) {
+ loadingView.show();
+ mWebview.loadUrl("javascript:scrollToLast()");
+ }
+ }
+
+ public void scrollToFirst() {
+
+ boolean isPageLoading = loadingView == null || loadingView.getVisibility() == View.VISIBLE;
+ Log.v(LOG_TAG, "-> scrollToFirst -> isPageLoading = " + isPageLoading);
+
+ if (!isPageLoading) {
+ loadingView.show();
+ mWebview.loadUrl("javascript:scrollToFirst()");
+ }
+ }
+
+ private void initWebView() {
+
+ FrameLayout webViewLayout = mRootView.findViewById(R.id.webViewLayout);
+ mWebview = webViewLayout.findViewById(R.id.folioWebView);
+ mWebview.setParentFragment(this);
+ webViewPager = webViewLayout.findViewById(R.id.webViewPager);
+
+ if (getActivity() instanceof FolioActivityCallback)
+ mWebview.setFolioActivityCallback((FolioActivityCallback) getActivity());
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
+ WebView.setWebContentsDebuggingEnabled(true);
+
+ setupScrollBar();
+ mWebview.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View view, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ int height =
+ (int) Math.floor(mWebview.getContentHeight() * mWebview.getScale());
+ int webViewHeight = mWebview.getMeasuredHeight();
+ mScrollSeekbar.setMaximum(height - webViewHeight);
+ }
+ });
+
+ mWebview.getSettings().setJavaScriptEnabled(true);
+ mWebview.setVerticalScrollBarEnabled(false);
+ mWebview.getSettings().setAllowFileAccess(true);
+
+ mWebview.setHorizontalScrollBarEnabled(false);
+
+ mWebview.addJavascriptInterface(this, "Highlight");
+ mWebview.addJavascriptInterface(this, "FolioPageFragment");
+ mWebview.addJavascriptInterface(webViewPager, "WebViewPager");
+ mWebview.addJavascriptInterface(loadingView, "LoadingView");
+ mWebview.addJavascriptInterface(mWebview, "FolioWebView");
+
+ mWebview.setScrollListener(new FolioWebView.ScrollListener() {
+ @Override
+ public void onScrollChange(int percent) {
+
+ mScrollSeekbar.setProgressAndThumb(percent);
+ updatePagesLeftText(percent);
+ }
+ });
+
+ mWebview.setWebViewClient(webViewClient);
+ mWebview.setWebChromeClient(webChromeClient);
+
+ 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.getSettings().setDefaultTextEncodingName("utf-8");
+ new HtmlTask(this).execute(getWebviewUrl());
+ }
+
+ private WebViewClient webViewClient = new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+
+ mWebview.loadUrl("javascript:getCompatMode()");
+ mWebview.loadUrl("javascript:alert(getReadingTime())");
+
+ if (!hasMediaOverlay)
+ mWebview.loadUrl("javascript:wrappingSentencesWithinPTags()");
+
+ if (mActivityCallback.getDirection() == Config.Direction.HORIZONTAL)
+ mWebview.loadUrl("javascript:initHorizontalDirection()");
+
+ view.loadUrl(String.format(getString(R.string.setmediaoverlaystyle),
+ HighlightImpl.HighlightStyle.classForStyle(
+ HighlightImpl.HighlightStyle.Normal)));
+
+ String rangy = HighlightUtil.generateRangyString(getPageName());
+ FolioPageFragment.this.rangy = rangy;
+ if (!rangy.isEmpty())
+ loadRangy(mWebview, rangy);
+
+ if (mIsPageReloaded) {
+
+ if (searchItemVisible != null) {
+ String escapedSearchQuery = StringEscapeUtils
+ .escapeJava(searchItemVisible.getSearchQuery());
+ String call = String.format(getString(R.string.highlight_search_result),
+ escapedSearchQuery, searchItemVisible.getOccurrenceInChapter());
+ mWebview.loadUrl(call);
+
+ } else if (isCurrentFragment()) {
+ mWebview.loadUrl(String.format("javascript:scrollToSpan(%b, %s)",
+ lastReadPosition.isUsingId(), lastReadPosition.getValue()));
+
+ } else {
+ if (mPosition == mActivityCallback.getCurrentChapterIndex() - 1) {
+ // Scroll to last, the page before current page
+ mWebview.loadUrl("javascript:scrollToLast()");
+ } else {
+ // Make loading view invisible for all other fragments
+ loadingView.hide();
+ }
+ }
+
+ mIsPageReloaded = false;
+
+ } else if (!TextUtils.isEmpty(mAnchorId)) {
+ mWebview.loadUrl(String.format(getString(R.string.go_to_anchor), mAnchorId));
+ mAnchorId = null;
+
+ } else if (!TextUtils.isEmpty(highlightId)) {
+ mWebview.loadUrl(String.format(getString(R.string.go_to_highlight), highlightId));
+ highlightId = null;
+
+ } else if (searchItemVisible != null) {
+ String escapedSearchQuery = StringEscapeUtils.escapeJava(searchItemVisible.getSearchQuery());
+ String call = String.format(getString(R.string.highlight_search_result),
+ escapedSearchQuery, searchItemVisible.getOccurrenceInChapter());
+ mWebview.loadUrl(call);
+
+ } else if (isCurrentFragment()) {
+
+ ReadPosition readPosition;
+ if (savedInstanceState == null) {
+ Log.v(LOG_TAG, "-> onPageFinished -> took from getEntryReadPosition");
+ readPosition = mActivityCallback.getEntryReadPosition();
+ } else {
+ Log.v(LOG_TAG, "-> onPageFinished -> took from bundle");
+ readPosition = savedInstanceState.getParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE);
+ savedInstanceState.remove(BUNDLE_READ_POSITION_CONFIG_CHANGE);
+ }
+
+ if (readPosition != null) {
+ Log.v(LOG_TAG, "-> scrollToSpan -> " + readPosition.getValue());
+ mWebview.loadUrl(String.format("javascript:scrollToSpan(%b, %s)",
+ readPosition.isUsingId(), readPosition.getValue()));
+ } else {
+ loadingView.hide();
+ }
+
+ } else {
+
+ if (mPosition == mActivityCallback.getCurrentChapterIndex() - 1) {
+ // Scroll to last, the page before current page
+ mWebview.loadUrl("javascript:scrollToLast()");
+ } else {
+ // Make loading view invisible for all other fragments
+ loadingView.hide();
+ }
+ }
+ }
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+
+ if (url.isEmpty())
+ return true;
+
+ 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.e(LOG_TAG, e.getMessage());
+ }
+ } else {
+ boolean urlOfEpub = mActivityCallback.goToChapter(url);
+
+ if (!urlOfEpub) {
+ // Otherwise, give the default behavior (open in browser)
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ startActivity(intent);
+ }
+ }
+ return true;
+ }
+
+ // prevent favicon.ico to be loaded automatically
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+ if (url.toLowerCase().contains("/favicon.ico")) {
+ try {
+ return new WebResourceResponse("image/png", null, null);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "shouldInterceptRequest failed", e);
+ }
+ }
+ return null;
+ }
+
+ // prevent favicon.ico to be loaded automatically
+ @Override
+ @SuppressLint("NewApi")
+ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
+ if (!request.isForMainFrame()
+ && request.getUrl().getPath() != null
+ && request.getUrl().getPath().endsWith("/favicon.ico")) {
+ try {
+ return new WebResourceResponse("image/png", null, null);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "shouldInterceptRequest failed", e);
+ }
+ }
+ return null;
+ }
+ };
+
+ private WebChromeClient webChromeClient = new WebChromeClient() {
+
+ @Override
+ public void onProgressChanged(WebView view, int progress) {
+ }
+
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
+ if (FolioPageFragment.this.isVisible()) {
+ String rangyPattern = "\\d+\\$\\d+\\$\\d+\\$\\w+\\$";
+ Pattern pattern = Pattern.compile(rangyPattern);
+ Matcher matcher = pattern.matcher(message);
+ if (matcher.matches()) {
+ HighlightImpl highlightImpl = HighLightTable.getHighlightForRangy(message);
+ if (HighLightTable.deleteHighlight(message)) {
+ String rangy = HighlightUtil.generateRangyString(getPageName());
+ loadRangy(view, rangy);
+ mTextSelectionSupport.endSelectionMode();
+ if (highlightImpl != null) {
+ HighlightUtil.sendHighlightBroadcastEvent(
+ FolioPageFragment.this.getActivity().getApplicationContext(),
+ highlightImpl,
+ HighLight.HighLightAction.DELETE);
+ }
+ }
+ } else if (TextUtils.isDigitsOnly(message)) {
+ try {
+ mTotalMinutes = Integer.parseInt(message);
+ } catch (NumberFormatException e) {
+ mTotalMinutes = 0;
+ }
+ } else {
+ pattern = Pattern.compile(getString(R.string.pattern));
+ 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 {
+ // to handle TTS playback when highlight is deleted.
+ Pattern p = Pattern.compile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}");
+ if (!p.matcher(message).matches() && (!message.equals("undefined")) && isCurrentFragment()) {
+ mediaController.speakAudio(message);
+ }
+ }
+ }
+ result.confirm();
+ }
+ return true;
+ }
+ };
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ Log.v(LOG_TAG, "-> onStop -> " + spineItem.originalHref + " -> " + isCurrentFragment());
+
+ mediaController.stop();
+ //TODO save last media overlay item
+
+ if (isCurrentFragment())
+ getLastReadPosition();
+ }
+
+ /**
+ * Calls the /assets/js/Bridge.js#getFirstVisibleSpan(boolean)
+ */
+ public ReadPosition getLastReadPosition() {
+ Log.v(LOG_TAG, "-> getLastReadPosition -> " + spineItem.originalHref);
+
+ try {
+ synchronized (this) {
+ boolean isHorizontal = mActivityCallback.getDirection() ==
+ Config.Direction.HORIZONTAL;
+ mWebview.loadUrl("javascript:getFirstVisibleSpan(" + isHorizontal + ")");
+
+ wait(2000);
+ }
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "-> ", e);
+ }
+
+ return lastReadPosition;
+ }
+
+ /**
+ * Callback method called from /assets/js/Bridge.js#getFirstVisibleSpan(boolean)
+ * and then ReadPositionImpl is broadcast to {@link FolioReader#readPositionReceiver}
+ *
+ * @param usingId if span tag has id then true or else false
+ * @param value if usingId true then span id else span index
+ */
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public void storeFirstVisibleSpan(boolean usingId, String value) {
+
+ synchronized (this) {
+ lastReadPosition = new ReadPositionImpl(mBookId, spineItem.getId(),
+ spineItem.getOriginalHref(), mPosition, usingId, value);
+ Intent intent = new Intent(FolioReader.ACTION_SAVE_READ_POSITION);
+ intent.putExtra(FolioReader.EXTRA_READ_POSITION, lastReadPosition);
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+
+ notify();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public void setHorizontalPageCount(int horizontalPageCount) {
+ Log.v(LOG_TAG, "-> setHorizontalPageCount = " + horizontalPageCount
+ + " -> " + spineItem.originalHref);
+
+ mWebview.setHorizontalPageCount(horizontalPageCount);
+ }
+
+ private void loadRangy(WebView view, String rangy) {
+ view.loadUrl(String.format("javascript:if(typeof ssReader !== \"undefined\"){ssReader.setHighlights('%s');}", rangy));
+ }
+
+ private void setupScrollBar() {
+ UiUtil.setColorIntToDrawable(mConfig.getThemeColor(), mScrollSeekbar.getProgressDrawable());
+ Drawable thumbDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.icons_sroll);
+ UiUtil.setColorIntToDrawable(mConfig.getThemeColor(), thumbDrawable);
+ mScrollSeekbar.setThumb(thumbDrawable);
+ }
+
+ private void initSeekbar() {
+ mScrollSeekbar = (VerticalSeekbar) mRootView.findViewById(R.id.scrollSeekbar);
+ mScrollSeekbar.getProgressDrawable()
+ .setColorFilter(getResources()
+ .getColor(R.color.app_green),
+ PorterDuff.Mode.SRC_IN);
+ }
+
+ private void updatePagesLeftTextBg() {
+
+ if (mConfig.isNightMode()) {
+ mRootView.findViewById(R.id.indicatorLayout)
+ .setBackgroundColor(Color.parseColor("#131313"));
+ } else {
+ mRootView.findViewById(R.id.indicatorLayout)
+ .setBackgroundColor(Color.WHITE);
+ }
+ }
+
+ private void updatePagesLeftText(int scrollY) {
+ try {
+ int currentPage = (int) (Math.ceil((double) scrollY / mWebview.getWebViewHeight()) + 1);
+ int totalPages =
+ (int) Math.ceil((double) mWebview.getContentHeightVal()
+ / mWebview.getWebViewHeight());
+ 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 | IllegalStateException exp) {
+ Log.e("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) {
+ fadeOutSeekBarIfVisible();
+ }
+
+ @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);
+ }
+ }
+
+ public void fadeOutSeekBarIfVisible() {
+ if (mScrollSeekbar.getVisibility() == View.VISIBLE) {
+ mScrollSeekbar.startAnimation(mFadeOutAnimation);
+ }
+ }
+
+ @Override
+ public void onDestroyView() {
+ mFadeInAnimation.setAnimationListener(null);
+ mFadeOutAnimation.setAnimationListener(null);
+ EventBus.getDefault().unregister(this);
+ super.onDestroyView();
+ }
+
+ /**
+ * If called, this method will occur after onStop() for applications targeting platforms
+ * starting with Build.VERSION_CODES.P. For applications targeting earlier platform versions
+ * this method will occur before onStop() and there are no guarantees about whether it will
+ * occur before or after onPause()
+ *
+ * @see Activity#onSaveInstanceState(Bundle) of Build.VERSION_CODES.P
+ */
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ this.outState = outState;
+
+ if (isCurrentFragment())
+ Log.v(LOG_TAG, "-> onSaveInstanceState");
+
+ outState.putParcelable(BUNDLE_SEARCH_ITEM, searchItemVisible);
+ }
+
+ public void highlight(HighlightImpl.HighlightStyle style, boolean isCreated) {
+ if (isCreated) {
+ mWebview.loadUrl(String.format("javascript:if(typeof ssReader !== \"undefined\"){ssReader.highlightSelection('%s');}", HighlightImpl.HighlightStyle.classForStyle(style)));
+ } else {
+ mWebview.loadUrl(String.format("javascript:setHighlightStyle('%s')", "highlight_" + HighlightImpl.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 =
+ (ViewGroup) 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)));
+ if (!mSelectedText.trim().contains(" ")) {
+ 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(getActivity(), mSelectedText);
+ Toast.makeText(getActivity(), getString(R.string.copied), Toast.LENGTH_SHORT).show();
+ mTextSelectionSupport.endSelectionMode();
+ } else if (actionId == ACTION_ID_SHARE) {
+ UiUtil.share(getActivity(), mSelectedText);
+ } else if (actionId == ACTION_ID_DEFINE) {
+ showDictDialog(mSelectedText);
+ mTextSelectionSupport.endSelectionMode();
+ } else if (actionId == ACTION_ID_HIGHLIGHT) {
+ onHighlight(view, width, height, true);
+ }
+ }
+
+ private void showDictDialog(String mSelectedText) {
+ DictionaryFragment dictionaryFragment = new DictionaryFragment();
+ Bundle b = new Bundle();
+ b.putString(Constants.SELECTED_WORD, mSelectedText);
+ dictionaryFragment.setArguments(b);
+ dictionaryFragment.show(getFragmentManager(), DictionaryFragment.class.getName());
+ }
+
+ 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 =
+ (ViewGroup) 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,
+ getResources().getDrawable(R.drawable.colors_marker)));
+ quickAction.addActionItem(new ActionItem(ACTION_ID_DELETE,
+ getResources().getDrawable(R.drawable.ic_action_discard)));
+ quickAction.addActionItem(new ActionItem(ACTION_ID_SHARE,
+ getResources().getDrawable(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(getActivity(), mSelectedText);
+ mTextSelectionSupport.endSelectionMode();
+ } else if (actionId == ACTION_ID_DELETE) {
+ highlightRemove();
+ }
+ }
+
+ private void onHighlightColors(final View view, final boolean isCreated) {
+ ViewGroup root =
+ (ViewGroup) 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,
+ getResources().getDrawable(R.drawable.ic_yellow_marker)));
+ quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_GREEN,
+ getResources().getDrawable(R.drawable.ic_green_marker)));
+ quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_BLUE,
+ getResources().getDrawable(R.drawable.ic_blue_marker)));
+ quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_PINK,
+ getResources().getDrawable(R.drawable.ic_pink_marker)));
+ quickAction.addActionItem(new ActionItem(ACTION_ID_HIGHLIGHT_UNDERLINE,
+ getResources().getDrawable(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(HighlightImpl.HighlightStyle.Yellow, isCreated);
+ } else if (actionId == ACTION_ID_HIGHLIGHT_GREEN) {
+ highlight(HighlightImpl.HighlightStyle.Green, isCreated);
+ } else if (actionId == ACTION_ID_HIGHLIGHT_BLUE) {
+ highlight(HighlightImpl.HighlightStyle.Blue, isCreated);
+ } else if (actionId == ACTION_ID_HIGHLIGHT_PINK) {
+ highlight(HighlightImpl.HighlightStyle.Pink, isCreated);
+ } else if (actionId == ACTION_ID_HIGHLIGHT_UNDERLINE) {
+ highlight(HighlightImpl.HighlightStyle.Underline, isCreated);
+ }
+ mTextSelectionSupport.endSelectionMode();
+ }
+
+ @Override
+ public void resetCurrentIndex() {
+ if (isCurrentFragment()) {
+ mWebview.loadUrl("javascript:rewindCurrentIndex()");
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public void onReceiveHighlights(String html) {
+ if (html != null) {
+ rangy = HighlightUtil.createHighlightRangy(getActivity().getApplicationContext(),
+ html,
+ mBookId,
+ getPageName(),
+ mPosition,
+ rangy);
+ }
+ }
+
+ private String getPageName() {
+ return mBookTitle + "$" + spineItem.href;
+ }
+
+ @Override
+ public void highLightText(String fragmentId) {
+ mWebview.loadUrl(String.format(getString(R.string.audio_mark_id), fragmentId));
+ }
+
+ @Override
+ public void highLightTTS() {
+ mWebview.loadUrl("javascript:alert(getSentenceWithIndex('epub-media-overlay-playing'))");
+ }
+
+ @JavascriptInterface
+ public void getUpdatedHighlightId(String id, String style) {
+ if (id != null) {
+ HighlightImpl highlightImpl = HighLightTable.updateHighlightStyle(id, style);
+ if (highlightImpl != null) {
+ HighlightUtil.sendHighlightBroadcastEvent(
+ getActivity().getApplicationContext(),
+ highlightImpl,
+ HighLight.HighLightAction.MODIFY);
+ }
+ final String rangyString = HighlightUtil.generateRangyString(getPageName());
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ loadRangy(mWebview, rangyString);
+ }
+ });
+
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (isCurrentFragment()) {
+ if (outState != null)
+ outState.putParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE, lastReadPosition);
+ mActivityCallback.storeLastReadPosition(lastReadPosition);
+ }
+ if (mWebview != null) mWebview.destroy();
+ }
+
+ private boolean isCurrentFragment() {
+// Log.d(LOG_TAG, "-> isCurrentFragment -> "
+// + ", isAdded = " + isAdded()
+// + ", mActivityCallback.getCurrentChapterIndex() = " + mActivityCallback.getCurrentChapterIndex()
+// + ", mPosition = " + mPosition);
+ return isAdded() && mActivityCallback.getCurrentChapterIndex() == mPosition;
+ }
+
+ @Override
+ public void onError() {
+ }
+
+ public void scrollToHighlightId(String highlightId) {
+ this.highlightId = highlightId;
+
+ if (loadingView != null && loadingView.getVisibility() != View.VISIBLE) {
+ loadingView.show();
+ mWebview.loadUrl(String.format(getString(R.string.go_to_highlight), highlightId));
+ this.highlightId = null;
+ }
+ }
+
+ public void highlightSearchItem(@NonNull SearchItem searchItem) {
+ Log.v(LOG_TAG, "-> highlightSearchItem");
+ this.searchItemVisible = searchItem;
+
+ if (loadingView != null && loadingView.getVisibility() != View.VISIBLE) {
+ loadingView.show();
+ String escapedSearchQuery = StringEscapeUtils.escapeJava(searchItem.getSearchQuery());
+ String call = String.format(getString(R.string.highlight_search_result),
+ escapedSearchQuery, searchItem.getOccurrenceInChapter());
+ mWebview.loadUrl(call);
+ }
+ }
+
+ public void resetSearchResults() {
+ Log.v(LOG_TAG, "-> resetSearchResults -> " + spineItem.originalHref);
+ mWebview.loadUrl(getString(R.string.reset_search_results));
+ searchItemVisible = null;
+ }
+}
diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/fragment/MediaControllerFragment.kt b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/MediaControllerFragment.kt
new file mode 100644
index 000000000..3d862e246
--- /dev/null
+++ b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/MediaControllerFragment.kt
@@ -0,0 +1,282 @@
+package com.folioreader.ui.folio.fragment
+
+import android.app.Dialog
+import android.os.Build
+import android.os.Bundle
+import android.support.design.widget.BottomSheetBehavior
+import android.support.design.widget.BottomSheetDialog
+import android.support.design.widget.BottomSheetDialogFragment
+import android.support.v4.app.FragmentManager
+import android.support.v4.content.ContextCompat
+import android.text.Html
+import android.util.Log
+import android.view.KeyEvent
+import android.view.MotionEvent
+import android.view.View
+import android.widget.ImageButton
+import android.widget.LinearLayout
+import android.widget.RelativeLayout
+import com.folioreader.Config
+import com.folioreader.R
+import com.folioreader.model.event.MediaOverlayHighlightStyleEvent
+import com.folioreader.model.event.MediaOverlaySpeedEvent
+import com.folioreader.util.AppUtil
+import com.folioreader.util.UiUtil
+import com.folioreader.view.MediaControllerCallback
+import com.folioreader.view.StyleableTextView
+import org.greenrobot.eventbus.EventBus
+
+class MediaControllerFragment : BottomSheetDialogFragment() {
+
+ companion object {
+ @JvmField
+ val LOG_TAG: String = MediaControllerFragment::class.java.simpleName
+ const val BUNDLE_IS_VISIBLE = "isVisible"
+
+ @JvmStatic
+ fun getInstance(supportFragmentManager: FragmentManager,
+ callback: MediaControllerCallback): MediaControllerFragment {
+
+ var mediaControllerFragment = supportFragmentManager.findFragmentByTag(LOG_TAG)
+ as MediaControllerFragment?
+ if (mediaControllerFragment == null)
+ mediaControllerFragment = MediaControllerFragment()
+ mediaControllerFragment.callback = callback
+ return mediaControllerFragment
+ }
+ }
+
+ private lateinit var config: Config
+ lateinit var callback: MediaControllerCallback
+ private var isPlaying: Boolean = false
+ private lateinit var bottomSheetDialog: BottomSheetDialog
+ private lateinit var bottomSheetBehavior: BottomSheetBehavior
+ private lateinit var mTouchOutsideView: View
+ var visible: Boolean = false
+
+ private var container: RelativeLayout? = null
+ private var prev_button: ImageButton? = null
+ private var play_button: ImageButton? = null
+ private var next_button: ImageButton? = null
+ private var playback_speed_Layout: LinearLayout? = null
+ private var btn_half_speed: StyleableTextView? = null
+ private var btn_one_x_speed: StyleableTextView? = null
+ private var btn_one_and_half_speed: StyleableTextView? = null
+ private var btn_twox_speed: StyleableTextView? = null
+ private var btn_backcolor_style: StyleableTextView? = null
+ private var btn_text_undeline_style: StyleableTextView? = null
+ private var btn_text_color_style: StyleableTextView? = null
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ Log.v(LOG_TAG, "-> onCreateDialog")
+
+ bottomSheetDialog = BottomSheetDialog(context!!)
+ var view = View.inflate(context, R.layout.view_audio_player, null)
+ bindViews(view)
+ bottomSheetDialog.setContentView(view)
+ bottomSheetBehavior = BottomSheetBehavior.from(view.parent as View)
+
+ mTouchOutsideView = ((view.parent as View).parent as View).findViewById(R.id.touch_outside)
+ mTouchOutsideView.setOnTouchListener { _, event ->
+
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ Log.v(LOG_TAG, "-> onTouch -> touch_outside -> ${getView()}")
+ dialog.hide()
+ visible = false
+ return@setOnTouchListener true
+ }
+ false
+ }
+
+ initViewStates()
+ onViewStateRestored(savedInstanceState)
+ return bottomSheetDialog
+ }
+
+ private fun bindViews(view: View) {
+
+ container = view.findViewById(R.id.container)
+ prev_button = view.findViewById(R.id.prev_button)
+ play_button = view.findViewById(R.id.play_button)
+ next_button = view.findViewById(R.id.next_button)
+ playback_speed_Layout = view.findViewById(R.id.playback_speed_Layout)
+ btn_half_speed = view.findViewById(R.id.btn_half_speed)
+ btn_one_x_speed = view.findViewById(R.id.btn_one_x_speed)
+ btn_one_and_half_speed = view.findViewById(R.id.btn_one_and_half_speed)
+ btn_twox_speed = view.findViewById(R.id.btn_twox_speed)
+ btn_backcolor_style = view.findViewById(R.id.btn_backcolor_style)
+ btn_text_undeline_style = view.findViewById(R.id.btn_text_undeline_style)
+ btn_text_color_style = view.findViewById(R.id.btn_text_color_style)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ Log.v(LOG_TAG, "-> onStart")
+
+ dialog.setOnKeyListener { _, keyCode, event ->
+ if (event.action == MotionEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
+ Log.v(LOG_TAG, "-> Back button pressed")
+ dialog.hide()
+ visible = false
+ return@setOnKeyListener true
+ }
+ false
+ }
+
+ bottomSheetBehavior.isHideable = false
+ bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
+
+ if (!visible)
+ dialog.hide()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ Log.v(LOG_TAG, "-> onSaveInstanceState -> $visible")
+ outState.putBoolean(BUNDLE_IS_VISIBLE, visible)
+ }
+
+ override fun onViewStateRestored(savedInstanceState: Bundle?) {
+ super.onViewStateRestored(savedInstanceState)
+ Log.v(LOG_TAG, "-> onViewStateRestored")
+
+ if (savedInstanceState == null)
+ return
+
+ visible = savedInstanceState.getBoolean(BUNDLE_IS_VISIBLE)
+ Log.v(LOG_TAG, "-> onViewStateRestored -> $visible")
+ }
+
+ fun show(fragmentManager: FragmentManager) {
+ Log.v(LOG_TAG, "-> show")
+
+ visible = true
+ if (isAdded) {
+ Log.v(LOG_TAG, "-> Is already added")
+ dialog.show()
+ } else {
+ Log.v(LOG_TAG, "-> Not added")
+ show(fragmentManager, MediaControllerFragment.LOG_TAG)
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ Log.v(LOG_TAG, "-> onDestroyView")
+ }
+
+ private fun initViewStates() {
+ config = AppUtil.getSavedConfig(context)
+
+ if (Build.VERSION.SDK_INT >= 24) {
+ btn_one_and_half_speed?.text = Html.fromHtml(context!!.getString(R.string.one_and_half_speed), 0)
+ btn_half_speed?.text = Html.fromHtml(context!!.getString(R.string.half_speed_text), 0)
+ btn_text_undeline_style?.text = Html.fromHtml(context!!.getString(R.string.style_underline), 0)
+ } else {
+ btn_one_and_half_speed?.text = Html.fromHtml(context!!.getString(R.string.one_and_half_speed))
+ btn_half_speed?.text = Html.fromHtml(context!!.getString(R.string.half_speed_text))
+ btn_text_undeline_style?.text = Html.fromHtml(context!!.getString(R.string.style_underline))
+ }
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
+ playback_speed_Layout?.visibility = View.GONE
+
+ if (config.isNightMode) setNightMode()
+
+ initColors()
+ initListeners()
+ }
+
+ private fun initColors() {
+
+ btn_half_speed?.setTextColor(UiUtil.getColorList(config.themeColor, ContextCompat.getColor(context!!, R.color.grey_color)))
+ btn_one_and_half_speed?.setTextColor(UiUtil.getColorList(config.themeColor, ContextCompat.getColor(context!!, R.color.grey_color)))
+ btn_twox_speed?.setTextColor(UiUtil.getColorList(config.themeColor, ContextCompat.getColor(context!!, R.color.grey_color)))
+ btn_one_x_speed?.setTextColor(UiUtil.getColorList(config.themeColor, ContextCompat.getColor(context!!, R.color.grey_color)))
+ btn_text_undeline_style?.setTextColor(UiUtil.getColorList(config.themeColor, ContextCompat.getColor(context!!, R.color.grey_color)))
+ btn_backcolor_style?.setTextColor(UiUtil.getColorList(ContextCompat.getColor(context!!, R.color.white), ContextCompat.getColor(context!!, R.color.grey_color)))
+ btn_backcolor_style?.setBackgroundDrawable(UiUtil.createStateDrawable(config.themeColor, ContextCompat.getColor(context!!, android.R.color.transparent)))
+ btn_text_color_style?.setTextColor(UiUtil.getColorList(config.themeColor, ContextCompat.getColor(context!!, R.color.grey_color)))
+ UiUtil.setColorIntToDrawable(config.themeColor, play_button?.drawable)
+ UiUtil.setColorIntToDrawable(config.themeColor, next_button?.drawable)
+ UiUtil.setColorIntToDrawable(config.themeColor, prev_button?.drawable)
+ }
+
+ private fun initListeners() {
+
+ play_button?.setOnClickListener {
+ callback.let {
+ if (isPlaying) {
+ callback.pause()
+ play_button?.setImageDrawable(ContextCompat.getDrawable(context!!, R.drawable.play_icon))
+ UiUtil.setColorIntToDrawable(config.themeColor, play_button?.drawable)
+ } else {
+ callback.play()
+ play_button?.setImageDrawable(ContextCompat.getDrawable(context!!, R.drawable.pause_btn))
+ UiUtil.setColorIntToDrawable(config.themeColor, play_button?.drawable)
+ }
+ isPlaying = !isPlaying
+ }
+ }
+
+ btn_half_speed?.setOnClickListener {
+ toggleSpeedControlButtons(true, false, false, false)
+ EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.HALF))
+ }
+
+ btn_one_x_speed?.setOnClickListener {
+ toggleSpeedControlButtons(false, true, false, false)
+ EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.ONE))
+ }
+
+ btn_one_and_half_speed?.setOnClickListener {
+ toggleSpeedControlButtons(false, false, true, false)
+ EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.ONE_HALF))
+ }
+
+ btn_twox_speed?.setOnClickListener {
+ toggleSpeedControlButtons(false, false, false, true)
+ EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.TWO))
+ }
+
+ btn_backcolor_style?.setOnClickListener {
+ toggleTextStyle(true, false, false)
+ EventBus.getDefault().post(MediaOverlayHighlightStyleEvent(MediaOverlayHighlightStyleEvent.Style.DEFAULT))
+ }
+
+ btn_text_undeline_style?.setOnClickListener {
+ toggleTextStyle(false, true, false)
+ EventBus.getDefault().post(MediaOverlayHighlightStyleEvent(MediaOverlayHighlightStyleEvent.Style.UNDERLINE))
+ }
+
+ btn_text_color_style?.setOnClickListener {
+ toggleTextStyle(false, false, true)
+ EventBus.getDefault().post(MediaOverlayHighlightStyleEvent(MediaOverlayHighlightStyleEvent.Style.BACKGROUND))
+ }
+ }
+
+ private fun toggleTextStyle(backColor: Boolean, underline: Boolean, textColor: Boolean) {
+ btn_backcolor_style?.isSelected = backColor
+ btn_text_undeline_style?.isSelected = underline
+ btn_text_color_style?.isSelected = textColor
+ }
+
+ private fun toggleSpeedControlButtons(half: Boolean, one: Boolean, oneHalf: Boolean, two: Boolean) {
+ btn_half_speed?.isSelected = half
+ btn_one_x_speed?.isSelected = one
+ btn_one_and_half_speed?.isSelected = oneHalf
+ btn_twox_speed?.isSelected = two
+ }
+
+ fun setPlayButtonDrawable() {
+ play_button?.setImageDrawable(ContextCompat.getDrawable(context!!, R.drawable.play_icon))
+ }
+
+ fun setNightMode() {
+ container?.setBackgroundColor(ContextCompat.getColor(context!!, R.color.night))
+ }
+
+ fun setDayMode() {
+ container?.setBackgroundColor(ContextCompat.getColor(context!!, R.color.white))
+ }
+}
\ No newline at end of file
diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/mediaoverlay/MediaController.java b/folioreader/src/main/java/com/folioreader/ui/folio/mediaoverlay/MediaController.java
index 52e92b0b9..8a7d95bd5 100644
--- a/folioreader/src/main/java/com/folioreader/ui/folio/mediaoverlay/MediaController.java
+++ b/folioreader/src/main/java/com/folioreader/ui/folio/mediaoverlay/MediaController.java
@@ -139,7 +139,7 @@ public void setUpMediaPlayer(MediaOverlays mediaOverlays, String path, String mB
mediaPlayer.prepare();
isMediaPlayerReady = true;
} catch (IOException e) {
- Log.d(TAG, e.getMessage());
+ Log.e(TAG, e.getMessage());
}
}
diff --git a/folioreader/src/main/java/com/folioreader/ui/tableofcontents/adapter/TOCAdapter.java b/folioreader/src/main/java/com/folioreader/ui/tableofcontents/adapter/TOCAdapter.java
index 242435e60..86c53fac3 100644
--- a/folioreader/src/main/java/com/folioreader/ui/tableofcontents/adapter/TOCAdapter.java
+++ b/folioreader/src/main/java/com/folioreader/ui/tableofcontents/adapter/TOCAdapter.java
@@ -114,7 +114,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
R.color.black));
}
if (tocLinkWrapper.getTocLink().href.equals(selectedHref)) {
- viewHolder.sectionTitle.setTextColor(ContextCompat.getColor(mContext, mConfig.getThemeColor()));
+ viewHolder.sectionTitle.setTextColor(mConfig.getThemeColor());
}
}
diff --git a/folioreader/src/main/java/com/folioreader/util/AppUtil.java b/folioreader/src/main/java/com/folioreader/util/AppUtil.java
index d6fef82dc..8e3b04c0f 100644
--- a/folioreader/src/main/java/com/folioreader/util/AppUtil.java
+++ b/folioreader/src/main/java/com/folioreader/util/AppUtil.java
@@ -1,9 +1,12 @@
package com.folioreader.util;
+import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
import com.folioreader.Config;
import com.folioreader.Constants;
@@ -92,7 +95,7 @@ public static void saveConfig(Context context, Config config) {
obj.put(Config.CONFIG_FONT, config.getFont());
obj.put(Config.CONFIG_FONT_SIZE, config.getFontSize());
obj.put(Config.CONFIG_IS_NIGHT_MODE, config.isNightMode());
- obj.put(Config.CONFIG_IS_THEME_COLOR, config.getThemeColor());
+ obj.put(Config.CONFIG_THEME_COLOR_INT, config.getThemeColor());
obj.put(Config.CONFIG_IS_TTS, config.isShowTts());
obj.put(Config.CONFIG_ALLOWED_DIRECTION, config.getAllowedDirection().toString());
obj.put(Config.CONFIG_DIRECTION, config.getDirection().toString());
@@ -158,6 +161,20 @@ public static String actionToString(int action) {
return Integer.toString(action);
}
}
+
+ public static void hideKeyboard(Activity activity) {
+
+ InputMethodManager imm = (InputMethodManager)
+ activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
+ //Find the currently focused view, so we can grab the correct window token from it.
+ View view = activity.getCurrentFocus();
+ //If no view currently has focus, create a new one, just so we can grab a window token
+ if (view == null)
+ view = new View(activity);
+ if (imm != null)
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ view.clearFocus();
+ }
}
diff --git a/folioreader/src/main/java/com/folioreader/util/FileUtil.java b/folioreader/src/main/java/com/folioreader/util/FileUtil.java
index a9d39d0a1..a2d7f312d 100644
--- a/folioreader/src/main/java/com/folioreader/util/FileUtil.java
+++ b/folioreader/src/main/java/com/folioreader/util/FileUtil.java
@@ -46,7 +46,7 @@ public static String saveEpubFileAndLoadLazyBook(final Context context, FolioAct
}
return filePath;
} catch (IOException e) {
- Log.d(TAG, e.getMessage());
+ Log.e(TAG, e.getMessage());
}
return null;
@@ -107,7 +107,7 @@ public static Boolean saveTempEpubFile(String filePath, String fileName, InputSt
inputStream.close();
outputStream.close();
} catch (IOException e) {
- Log.d(TAG, e.getMessage());
+ Log.e(TAG, e.getMessage());
}
return false;
}
diff --git a/folioreader/src/main/java/com/folioreader/util/UiUtil.java b/folioreader/src/main/java/com/folioreader/util/UiUtil.java
index 9ccb78946..96d98c21b 100644
--- a/folioreader/src/main/java/com/folioreader/util/UiUtil.java
+++ b/folioreader/src/main/java/com/folioreader/util/UiUtil.java
@@ -14,27 +14,36 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable;
+import android.os.Build;
+import android.support.annotation.ColorInt;
+import android.support.annotation.ColorRes;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.StateSet;
import android.view.View;
+import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
+import android.widget.EditText;
import android.widget.TextView;
+import com.folioreader.AppContext;
import com.folioreader.R;
import com.folioreader.view.UnderlinedTextView;
import java.lang.ref.SoftReference;
+import java.lang.reflect.Field;
import java.util.Hashtable;
/**
* Created by mahavir on 3/30/16.
*/
public class UiUtil {
+
+ private static final String LOG_TAG = UiUtil.class.getSimpleName();
+
public static void setCustomFont(View view, Context ctx, AttributeSet attrs,
int[] attributeSet, int fontId) {
TypedArray a = ctx.obtainStyledAttributes(attrs, attributeSet);
@@ -80,14 +89,15 @@ public static Typeface getFont(Context c, String name) {
}
}
- public static ColorStateList getColorList(Context context, int selectedColor, int unselectedColor) {
+ public static ColorStateList getColorList(@ColorInt int selectedColor,
+ @ColorInt int unselectedColor) {
int[][] states = new int[][]{
new int[]{android.R.attr.state_selected},
new int[]{}
};
int[] colors = new int[]{
- ContextCompat.getColor(context, selectedColor),
- ContextCompat.getColor(context, unselectedColor)
+ selectedColor,
+ unselectedColor
};
ColorStateList list = new ColorStateList(states, colors);
return list;
@@ -128,10 +138,7 @@ private static void setUnderLineColor(UnderlinedTextView underlinedTextView, Con
}
public static float convertDpToPixel(float dp, Context context) {
- Resources resources = context.getResources();
- DisplayMetrics metrics = resources.getDisplayMetrics();
- float px = dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
- return px;
+ return dp * context.getResources().getDisplayMetrics().density;
}
public static void copyToClipboard(Context context, String text) {
@@ -150,29 +157,163 @@ public static void share(Context context, String text) {
context.getResources().getText(R.string.send_to)));
}
+ public static void setColorIntToDrawable(@ColorInt int color, Drawable drawable) {
+ drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+ }
- public static void setColorToImage(Context context, int color, Drawable drawable) {
- drawable.setColorFilter(ContextCompat.getColor(context, color), PorterDuff.Mode.SRC_ATOP);
+ public static void setColorResToDrawable(@ColorRes int colorResId, Drawable drawable) {
+ try {
+ int color = ContextCompat.getColor(AppContext.get(), colorResId);
+ drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+ } catch (Resources.NotFoundException e) {
+ Log.e(LOG_TAG, "-> ", e);
+ }
}
+ public static void setEditTextCursorColor(EditText editText, @ColorInt int color) {
+ try {
+ // Get the cursor resource id
+ Field field = TextView.class.getDeclaredField("mCursorDrawableRes");
+ field.setAccessible(true);
+ int drawableResId = field.getInt(editText);
+
+ // Get the drawable and set a color filter
+ Drawable drawable = ContextCompat.getDrawable(editText.getContext(), drawableResId);
+ drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ Drawable[] drawables = {drawable, drawable};
+
+ if (Build.VERSION.SDK_INT == 15) {
+ // Get the editor
+ Class> drawableFieldClass = TextView.class;
+ // Set the drawables
+ field = drawableFieldClass.getDeclaredField("mCursorDrawable");
+ field.setAccessible(true);
+ field.set(editText, drawables);
+
+ } else if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 27) {
+ // Get the editor
+ field = TextView.class.getDeclaredField("mEditor");
+ field.setAccessible(true);
+ Object editor = field.get(editText);
+ // Set the drawables
+ field = editor.getClass().getDeclaredField("mCursorDrawable");
+ field.setAccessible(true);
+ field.set(editor, drawables);
+
+ } else if (Build.VERSION.SDK_INT >= 28) {
+ // TODO: -> Not working for 28
+ // Get the editor
+ field = TextView.class.getDeclaredField("mEditor");
+ field.setAccessible(true);
+ Object editor = field.get(editText);
+ // Set the drawables
+ field = editor.getClass().getDeclaredField("mDrawableForCursor");
+ field.setAccessible(true);
+ field.set(editor, drawables[0]);
+ }
+
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "-> ", e);
+ }
+ }
+
+ public static void setEditTextHandleColor(EditText editText, @ColorInt int color) {
+ try {
+ // Get the cursor resource id
+ Field fieldLeftRes = TextView.class.getDeclaredField("mTextSelectHandleLeftRes");
+ fieldLeftRes.setAccessible(true);
+ int leftDrawableResId = fieldLeftRes.getInt(editText);
+
+ Field fieldRightRes = TextView.class.getDeclaredField("mTextSelectHandleRightRes");
+ fieldRightRes.setAccessible(true);
+ int rightDrawableResId = fieldRightRes.getInt(editText);
+
+ Field fieldCenterRes = TextView.class.getDeclaredField("mTextSelectHandleRes");
+ fieldCenterRes.setAccessible(true);
+ int centerDrawableResId = fieldCenterRes.getInt(editText);
+
+ // Get the drawable and set a color filter
+ Drawable drawableLeft = ContextCompat.getDrawable(editText.getContext(), leftDrawableResId);
+ drawableLeft.setColorFilter(color, PorterDuff.Mode.SRC_IN);
+
+ Drawable drawableRight = ContextCompat.getDrawable(editText.getContext(), rightDrawableResId);
+ drawableRight.setColorFilter(color, PorterDuff.Mode.SRC_IN);
- public static StateListDrawable convertColorIntoStateDrawable(Context context, int colorSelected, int colorNormal) {
+ Drawable drawableCenter = ContextCompat.getDrawable(editText.getContext(), centerDrawableResId);
+ drawableCenter.setColorFilter(color, PorterDuff.Mode.SRC_IN);
+
+ if (Build.VERSION.SDK_INT == 15) {
+ // Get the editor
+ Class> drawableFieldClass = TextView.class;
+
+ // Set the drawables
+ Field fieldLeft = drawableFieldClass.getDeclaredField("mSelectHandleLeft");
+ fieldLeft.setAccessible(true);
+ fieldLeft.set(editText, drawableLeft);
+
+ Field fieldRight = drawableFieldClass.getDeclaredField("mSelectHandleRight");
+ fieldRight.setAccessible(true);
+ fieldRight.set(editText, drawableRight);
+
+ Field fieldCenter = drawableFieldClass.getDeclaredField("mSelectHandleCenter");
+ fieldCenter.setAccessible(true);
+ fieldCenter.set(editText, drawableCenter);
+
+ } else {
+ // Get the editor
+ Field fieldEditor = TextView.class.getDeclaredField("mEditor");
+ fieldEditor.setAccessible(true);
+ Object editor = fieldEditor.get(editText);
+
+ // Set the drawables
+ Field fieldLeft = editor.getClass().getDeclaredField("mSelectHandleLeft");
+ fieldLeft.setAccessible(true);
+ fieldLeft.set(editor, drawableLeft);
+
+ Field fieldRight = editor.getClass().getDeclaredField("mSelectHandleRight");
+ fieldRight.setAccessible(true);
+ fieldRight.set(editor, drawableRight);
+
+ Field fieldCenter = editor.getClass().getDeclaredField("mSelectHandleCenter");
+ fieldCenter.setAccessible(true);
+ fieldCenter.set(editor, drawableCenter);
+ }
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "-> ", e);
+ }
+ }
+
+ public static StateListDrawable createStateDrawable(@ColorInt int colorSelected,
+ @ColorInt int colorNormal) {
StateListDrawable stateListDrawable = new StateListDrawable();
- stateListDrawable.addState(new int[]{android.R.attr.state_selected}, new ColorDrawable(ContextCompat.getColor(context, colorSelected)));
- stateListDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(ContextCompat.getColor(context, colorNormal)));
+ stateListDrawable.addState(new int[]{android.R.attr.state_selected}, new ColorDrawable(colorSelected));
+ stateListDrawable.addState(StateSet.WILD_CARD, new ColorDrawable(colorNormal));
return stateListDrawable;
}
- public static GradientDrawable getShapeDrawable(Context context, int color) {
+ public static GradientDrawable getShapeDrawable(@ColorInt int color) {
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
- gradientDrawable.setStroke(pxToDp(2), ContextCompat.getColor(context, color));
- gradientDrawable.setColor(ContextCompat.getColor(context, color));
+ gradientDrawable.setStroke(pxToDp(2), color);
+ gradientDrawable.setColor(color);
gradientDrawable.setCornerRadius(pxToDp(3));
return gradientDrawable;
}
+ public static void setShapeColor(View view, @ColorInt int color) {
+ ((GradientDrawable) view.getBackground()).setColor(color);
+ }
+
public static int pxToDp(int px) {
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
+
+ public static void setStatusBarColor(Window window, @ColorInt int color) {
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ window.setStatusBarColor(color);
+ }
+ }
}
diff --git a/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt b/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt
index bf03e5aec..21ef1c31e 100644
--- a/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt
+++ b/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt
@@ -9,6 +9,7 @@ import android.os.Bundle
import android.support.design.widget.BottomSheetBehavior
import android.support.design.widget.BottomSheetDialog
import android.support.design.widget.BottomSheetDialogFragment
+import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.view.LayoutInflater
import android.view.View
@@ -21,6 +22,7 @@ import com.folioreader.R
import com.folioreader.model.event.ReloadDataEvent
import com.folioreader.ui.folio.activity.FolioActivity
import com.folioreader.ui.folio.activity.FolioActivityCallback
+import com.folioreader.ui.folio.fragment.MediaControllerFragment
import com.folioreader.util.AppUtil
import com.folioreader.util.UiUtil
import kotlinx.android.synthetic.main.view_config.*
@@ -83,13 +85,13 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() {
if (isNightMode) {
view_config_ib_day_mode.isSelected = false
view_config_ib_night_mode.isSelected = true
- UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_night_mode.drawable)
- UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_day_mode.drawable)
+ UiUtil.setColorIntToDrawable(config.themeColor, view_config_ib_night_mode.drawable)
+ UiUtil.setColorResToDrawable(R.color.app_gray, view_config_ib_day_mode.drawable)
} else {
view_config_ib_day_mode.isSelected = true
view_config_ib_night_mode.isSelected = false
- UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_day_mode!!.drawable)
- UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_night_mode.drawable)
+ UiUtil.setColorIntToDrawable(config.themeColor, view_config_ib_day_mode!!.drawable)
+ UiUtil.setColorResToDrawable(R.color.app_gray, view_config_ib_night_mode.drawable)
}
}
@@ -108,8 +110,8 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() {
view_config_ib_night_mode.isSelected = false
setToolBarColor()
setAudioPlayerBackground()
- UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_night_mode.drawable)
- UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_day_mode.drawable)
+ UiUtil.setColorResToDrawable(R.color.app_gray, view_config_ib_night_mode.drawable)
+ UiUtil.setColorIntToDrawable(config.themeColor, view_config_ib_day_mode.drawable)
}
view_config_ib_night_mode.setOnClickListener {
@@ -117,8 +119,8 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() {
toggleBlackTheme()
view_config_ib_day_mode.isSelected = false
view_config_ib_night_mode.isSelected = true
- UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_day_mode.drawable)
- UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_night_mode.drawable)
+ UiUtil.setColorResToDrawable(R.color.app_gray, view_config_ib_day_mode.drawable)
+ UiUtil.setColorIntToDrawable(config.themeColor, view_config_ib_night_mode.drawable)
setToolBarColor()
setAudioPlayerBackground()
}
@@ -150,7 +152,8 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() {
private fun configFonts() {
- val colorStateList = UiUtil.getColorList(activity, config.themeColor, R.color.grey_color)
+ val colorStateList = UiUtil.getColorList(config.themeColor,
+ ContextCompat.getColor(context!!, R.color.grey_color))
buttonVertical.setTextColor(colorStateList)
buttonHorizontal.setTextColor(colorStateList)
view_config_font_andada.setTextColor(colorStateList)
@@ -242,8 +245,8 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() {
private fun configSeekBar() {
val thumbDrawable = ContextCompat.getDrawable(activity!!, R.drawable.seekbar_thumb)
- UiUtil.setColorToImage(activity, config.themeColor, thumbDrawable)
- UiUtil.setColorToImage(activity, R.color.grey_color, view_config_font_size_seek_bar.progressDrawable)
+ UiUtil.setColorIntToDrawable(config.themeColor, thumbDrawable)
+ UiUtil.setColorResToDrawable(R.color.grey_color, view_config_font_size_seek_bar.progressDrawable)
view_config_font_size_seek_bar.thumb = thumbDrawable
view_config_font_size_seek_bar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
@@ -261,18 +264,21 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() {
private fun setToolBarColor() {
if (isNightMode) {
- ((context as Activity).findViewById(R.id.toolbar) as FolioToolbar).setDayMode()
+ activityCallback.setDayMode()
} else {
- ((context as Activity).findViewById(R.id.toolbar) as FolioToolbar).setNightMode()
+ activityCallback.setNightMode()
}
-
}
private fun setAudioPlayerBackground() {
+
+ var mediaControllerFragment: Fragment? = fragmentManager?.
+ findFragmentByTag(MediaControllerFragment.LOG_TAG) ?: return
+ mediaControllerFragment = mediaControllerFragment as MediaControllerFragment
if (isNightMode) {
- (context as Activity).findViewById(R.id.container).setBackgroundColor(ContextCompat.getColor(context!!, R.color.white))
+ mediaControllerFragment.setDayMode()
} else {
- (context as Activity).findViewById(R.id.container).setBackgroundColor(ContextCompat.getColor(context!!, R.color.night))
+ mediaControllerFragment.setNightMode()
}
}
}
diff --git a/folioreader/src/main/java/com/folioreader/view/FolioAppBarLayout.kt b/folioreader/src/main/java/com/folioreader/view/FolioAppBarLayout.kt
new file mode 100644
index 000000000..a4b71ae71
--- /dev/null
+++ b/folioreader/src/main/java/com/folioreader/view/FolioAppBarLayout.kt
@@ -0,0 +1,58 @@
+package com.folioreader.view
+
+import android.content.Context
+import android.graphics.Rect
+import android.support.design.widget.AppBarLayout
+import android.support.v4.view.ViewCompat
+import android.util.AttributeSet
+import android.util.Log
+
+class FolioAppBarLayout : AppBarLayout {
+
+ companion object {
+ @JvmField
+ val LOG_TAG: String = FolioAppBarLayout::class.java.simpleName
+ }
+
+ var navigationBarHeight: Int = 0
+
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
+
+ ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
+ Log.v(LOG_TAG, "-> onApplyWindowInsets")
+ // For API level 20 and above
+
+ navigationBarHeight = insets.systemWindowInsetBottom
+
+ setMargins(insets.systemWindowInsetLeft, insets.systemWindowInsetTop,
+ insets.systemWindowInsetRight)
+ insets
+ }
+ }
+
+ override fun fitSystemWindows(insets: Rect?): Boolean {
+ Log.v(LOG_TAG, "-> fitSystemWindows")
+ // For API level 19 and below
+
+ navigationBarHeight = insets!!.bottom
+
+ setMargins(insets.left, insets.top, insets.right)
+ return super.fitSystemWindows(insets)
+ }
+
+ private fun setMargins(left: Int, top: Int, right: Int) {
+
+ val marginLayoutParams = layoutParams as MarginLayoutParams
+ marginLayoutParams.leftMargin = left
+ marginLayoutParams.topMargin = top
+ marginLayoutParams.rightMargin = right
+ layoutParams = marginLayoutParams
+ }
+
+ fun setTopMargin(top: Int) {
+ val marginLayoutParams = layoutParams as MarginLayoutParams
+ marginLayoutParams.topMargin = top
+ layoutParams = marginLayoutParams
+ }
+}
\ No newline at end of file
diff --git a/folioreader/src/main/java/com/folioreader/view/FolioSearchView.kt b/folioreader/src/main/java/com/folioreader/view/FolioSearchView.kt
new file mode 100644
index 000000000..1b7977aad
--- /dev/null
+++ b/folioreader/src/main/java/com/folioreader/view/FolioSearchView.kt
@@ -0,0 +1,80 @@
+package com.folioreader.view
+
+import android.app.SearchManager
+import android.content.ComponentName
+import android.content.Context
+import android.support.v4.content.ContextCompat
+import android.support.v4.graphics.ColorUtils
+import android.support.v7.widget.SearchView
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import com.folioreader.Config
+import com.folioreader.R
+import com.folioreader.util.UiUtil
+
+class FolioSearchView : SearchView {
+
+ companion object {
+ @JvmField
+ val LOG_TAG: String = FolioSearchView::class.java.simpleName
+ }
+
+ private lateinit var searchAutoComplete: SearchView.SearchAutoComplete
+
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+
+ fun init(componentName: ComponentName, config: Config) {
+ Log.v(LOG_TAG, "-> init")
+
+ val searchManager: SearchManager = context.getSystemService(Context.SEARCH_SERVICE) as SearchManager
+ setSearchableInfo(searchManager.getSearchableInfo(componentName))
+ setIconifiedByDefault(false)
+
+ adjustLayout()
+ applyTheme(config)
+ }
+
+ private fun adjustLayout() {
+ Log.v(LOG_TAG, "-> adjustLayout")
+
+ // Hide searchHintIcon
+ val searchMagIcon: View = findViewById(R.id.search_mag_icon)
+ searchMagIcon.layoutParams = LinearLayout.LayoutParams(0, 0)
+
+ // Remove left margin of search_edit_frame
+ val searchEditFrame: View = findViewById(R.id.search_edit_frame)
+ (searchEditFrame.layoutParams as ViewGroup.MarginLayoutParams).leftMargin = 0
+ }
+
+ private fun applyTheme(config: Config) {
+ Log.v(LOG_TAG, "-> applyTheme")
+
+ val searchCloseButton: ImageView = findViewById(R.id.search_close_btn)
+ UiUtil.setColorIntToDrawable(config.themeColor, searchCloseButton.drawable)
+
+ searchAutoComplete = findViewById(R.id.search_src_text)
+ UiUtil.setEditTextCursorColor(searchAutoComplete, config.themeColor)
+ UiUtil.setEditTextHandleColor(searchAutoComplete, config.themeColor)
+ searchAutoComplete.highlightColor = ColorUtils.setAlphaComponent(config.themeColor, 85)
+ if (config.isNightMode) {
+ searchAutoComplete.setTextColor(ContextCompat.getColor(context, R.color.night_title_text_color))
+ searchAutoComplete.setHintTextColor(ContextCompat.getColor(context, R.color.night_text_color))
+ } else {
+ searchAutoComplete.setHintTextColor(ContextCompat.getColor(context, R.color.edit_text_hint_color))
+ }
+ }
+
+ fun setDayMode() {
+ searchAutoComplete.setTextColor(ContextCompat.getColor(context, R.color.black))
+ }
+
+ fun setNightMode() {
+ searchAutoComplete.setTextColor(ContextCompat.getColor(context, R.color.white))
+ }
+}
\ No newline at end of file
diff --git a/folioreader/src/main/java/com/folioreader/view/FolioToolbar.kt b/folioreader/src/main/java/com/folioreader/view/FolioToolbar.kt
deleted file mode 100644
index cea80ae3c..000000000
--- a/folioreader/src/main/java/com/folioreader/view/FolioToolbar.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.folioreader.view
-
-import android.app.Activity
-import android.content.Context
-import android.support.v4.content.ContextCompat
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.view.View
-import android.view.animation.AccelerateInterpolator
-import android.view.animation.DecelerateInterpolator
-import android.widget.RelativeLayout
-import com.folioreader.Config
-import com.folioreader.R
-import com.folioreader.util.AppUtil
-import com.folioreader.util.UiUtil
-import kotlinx.android.synthetic.main.folio_toolbar.view.*
-
-/**
- * Created by gautam on 15/5/18.
- */
-class FolioToolbar : RelativeLayout {
- private lateinit var config: Config
- var visible: Boolean = true
- lateinit var callback: FolioToolbarCallback
-
- constructor(context: Context) : this(context, null, 0)
- constructor(context: Context, attributes: AttributeSet?) : this(context, attributes, 0)
- constructor(context: Context, attributes: AttributeSet?, defStyle: Int) : super(context, attributes, defStyle) {
- LayoutInflater.from(context).inflate(R.layout.folio_toolbar, this)
- init()
- }
-
- private fun init() {
- config = AppUtil.getSavedConfig(context)
- if (config.isNightMode) setNightMode() else setDayMode()
- if (!config.isShowTts) btn_speaker.visibility = View.GONE
- initColors()
- initListeners()
- }
-
- private fun initColors() {
- UiUtil.setColorToImage(context, config.themeColor, btn_close.drawable)
- UiUtil.setColorToImage(context, config.themeColor, btn_drawer.drawable)
- UiUtil.setColorToImage(context, config.themeColor, btn_config.drawable)
- UiUtil.setColorToImage(context, config.themeColor, btn_speaker.drawable)
- }
-
- private fun initListeners() {
- btn_drawer.setOnClickListener {
- callback.startContentHighlightActivity()
- }
- btn_close.setOnClickListener {
- (context as Activity).finish()
- }
- btn_config.setOnClickListener {
- callback.showConfigBottomSheetDialogFragment()
- }
- btn_speaker.setOnClickListener {
- callback.showMediaController()
- }
- }
-
- fun setListeners(callback: FolioToolbarCallback) {
- this.callback = callback
- }
-
- fun setTitle(title: String?) {
- label_center?.text = title
- }
-
- fun showOrHideIfVisible() {
- if (visible) {
- hide()
- } else {
- show()
- }
- visible = !visible
- }
-
- fun show() {
- this.animate().translationY(0f)
- .setInterpolator(DecelerateInterpolator(2f))
- .start()
- }
-
- fun setNightMode() {
- toolbar_container.setBackgroundColor(ContextCompat.getColor(context, R.color.black))
- label_center.setTextColor(ContextCompat.getColor(context, R.color.white))
- }
-
- fun setDayMode() {
- toolbar_container.setBackgroundColor(ContextCompat.getColor(context, R.color.white))
- label_center.setTextColor(ContextCompat.getColor(context, R.color.black))
- }
-
- fun hide() {
- post({ this.animate().translationY((-this.height)
- .toFloat())
- .setInterpolator(AccelerateInterpolator(2f))
- .start() })
- }
-}
diff --git a/folioreader/src/main/java/com/folioreader/view/FolioToolbarCallback.kt b/folioreader/src/main/java/com/folioreader/view/FolioToolbarCallback.kt
deleted file mode 100644
index 14b90ff05..000000000
--- a/folioreader/src/main/java/com/folioreader/view/FolioToolbarCallback.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.folioreader.view
-
-interface FolioToolbarCallback {
- fun startContentHighlightActivity()
- fun showConfigBottomSheetDialogFragment()
- fun showMediaController()
-}
\ No newline at end of file
diff --git a/folioreader/src/main/java/com/folioreader/view/FolioWebView.java b/folioreader/src/main/java/com/folioreader/view/FolioWebView.java
index 08091ccef..7c9f7b9ed 100644
--- a/folioreader/src/main/java/com/folioreader/view/FolioWebView.java
+++ b/folioreader/src/main/java/com/folioreader/view/FolioWebView.java
@@ -1,261 +1,264 @@
-package com.folioreader.view;
-
-import android.content.Context;
-import android.os.Handler;
-import android.support.v4.view.GestureDetectorCompat;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.webkit.JavascriptInterface;
-import android.webkit.WebView;
-
-import com.folioreader.Config;
-import com.folioreader.R;
-import com.folioreader.ui.folio.activity.FolioActivityCallback;
-
-/**
- * @author by mahavir on 3/31/16.
- */
-public class FolioWebView extends WebView
- implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
-
- private static final String LOG_TAG = FolioWebView.class.getSimpleName();
- private float touchSlop;
- private int horizontalPageCount = 0;
- private float density;
- private ScrollListener mScrollListener;
- private SeekBarListener mSeekBarListener;
- private ToolBarListener mToolBarListener;
- private GestureDetectorCompat gestureDetector;
- private MotionEvent eventActionDown;
- private int pageWidthCssPixels;
- private WebViewPager webViewPager;
- private Handler handler;
- private FolioActivityCallback folioActivityCallback;
-
- public FolioWebView(Context context) {
- super(context);
- if (!isInEditMode())
- init();
- }
-
- public FolioWebView(Context context, AttributeSet attrs) {
- super(context, attrs);
- if (!isInEditMode())
- init();
- }
-
- public FolioWebView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- if (!isInEditMode())
- init();
- }
-
- private void init() {
-
- handler = new Handler();
- gestureDetector = new GestureDetectorCompat(getContext(), this);
- gestureDetector.setOnDoubleTapListener(this);
- density = getResources().getDisplayMetrics().density;
- touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
- }
-
- @SuppressWarnings("unused")
- @JavascriptInterface
- public void setCompatMode(String compatMode) {
- Log.v(LOG_TAG, "-> setCompatMode -> compatMode = " + compatMode);
- if (compatMode.equals(getContext().getString(R.string.back_compat))) {
- Log.e(LOG_TAG, "-> Web page loaded in Quirks mode. Please report to developer " +
- "for debugging with current EPUB file as many features might stop working " +
- "(ex. Horizontal scroll feature).");
- }
- }
-
- public void setFolioActivityCallback(FolioActivityCallback folioActivityCallback) {
- this.folioActivityCallback = folioActivityCallback;
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
-
- double widthDp = Math.ceil((getMeasuredWidth() / density));
- pageWidthCssPixels = (int) (widthDp * density);
- }
-
- public void setScrollListener(ScrollListener listener) {
- mScrollListener = listener;
- }
-
- public void setSeekBarListener(SeekBarListener listener) {
- mSeekBarListener = listener;
- }
-
- public void setToolBarListener(ToolBarListener listener) {
- mToolBarListener = listener;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onTouchEvent -> " + AppUtil.actionToString(event.getAction()));
-
- hideOrShowToolBar(event);
-
- if (folioActivityCallback.getDirection() == Config.Direction.HORIZONTAL) {
- return computeHorizontalScroll(event);
- } else {
- return computeVerticalScroll(event);
- }
- }
-
- private boolean computeVerticalScroll(MotionEvent event) {
- return super.onTouchEvent(event);
- }
-
- private boolean computeHorizontalScroll(MotionEvent event) {
- //Log.v(LOG_TAG, "-> computeHorizontalScroll");
-
- webViewPager.dispatchTouchEvent(event);
- boolean gestureReturn = gestureDetector.onTouchEvent(event);
- if (gestureReturn)
- return true;
- return super.onTouchEvent(event);
- }
-
- public int getScrollXForPage(int page) {
- //Log.v(LOG_TAG, "-> getScrollXForPage -> page = " + page);
- return page * pageWidthCssPixels;
- }
-
- private void hideOrShowToolBar(MotionEvent event) {
-
- switch (event.getAction()) {
-
- case MotionEvent.ACTION_DOWN:
- eventActionDown = MotionEvent.obtain(event);
- if (mSeekBarListener != null)
- mSeekBarListener.fadeInSeekBarIfInvisible();
- break;
-
- case MotionEvent.ACTION_UP:
- if (mToolBarListener != null &&
- ((Math.abs(event.getY() - eventActionDown.getY()) < touchSlop) &&
- (Math.abs(event.getX() - eventActionDown.getX()) < touchSlop))) {
- //SingleTap
- mToolBarListener.hideOrShowToolBar();
- }
- break;
- }
- }
-
- public void setHorizontalPageCount(int horizontalPageCount) {
- this.horizontalPageCount = horizontalPageCount;
-
- handler.post(new Runnable() {
- @Override
- public void run() {
- if (webViewPager == null)
- webViewPager = ((View) getParent()).findViewById(R.id.webViewPager);
-
- webViewPager.setHorizontalPageCount(FolioWebView.this.horizontalPageCount);
- }
- });
- }
-
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt) {
- if (mToolBarListener != null) mToolBarListener.hideToolBarIfVisible();
- if (mScrollListener != null) mScrollListener.onScrollChange(t);
- super.onScrollChanged(l, t, oldl, oldt);
- }
-
- public int getContentHeightVal() {
- return (int) Math.floor(this.getContentHeight() * this.getScale());
- }
-
- public int getWebViewHeight() {
- return this.getMeasuredHeight();
- }
-
- @Override
- public boolean onDown(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onDown -> " + event.toString());
-
- eventActionDown = MotionEvent.obtain(event);
- super.onTouchEvent(event);
- return true;
- }
-
- @Override
- public boolean onFling(MotionEvent event1, MotionEvent event2,
- float velocityX, float velocityY) {
-
- if (!webViewPager.isScrolling()) {
- //TODO: -> check for right edge to left flings from right edge
- // Need to complete the scroll as ViewPager thinks these touch events should not
- // scroll it's pages.
- //Log.d(LOG_TAG, "-> onFling -> completing scroll");
- invalidate();
- scrollTo(getScrollXForPage(webViewPager.getCurrentItem()), 0);
- }
- return true;
- }
-
- @Override
- public void onLongPress(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onLongPress -> " + event.toString());
- }
-
- @Override
- public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
- float distanceY) {
- //Log.v(LOG_TAG, "-> onScroll -> " + event1.toString() + event2.toString() + ", distanceX = " + distanceX + ", distanceY = " + distanceY);
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onShowPress -> " + event.toString());
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onSingleTapUp -> " + event.toString());
- return false;
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onDoubleTap -> " + event.toString());
- return false;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onDoubleTapEvent -> " + event.toString());
- return false;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent event) {
- //Log.v(LOG_TAG, "-> onSingleTapConfirmed -> " + event.toString());
- return false;
- }
-
- public interface ScrollListener {
- void onScrollChange(int percent);
- }
-
- public interface SeekBarListener {
- void fadeInSeekBarIfInvisible();
- }
-
- public interface ToolBarListener {
- void hideOrShowToolBar();
-
- void hideToolBarIfVisible();
- }
-}
+package com.folioreader.view;
+
+import android.content.Context;
+import android.os.Handler;
+import android.support.v4.view.GestureDetectorCompat;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebView;
+
+import com.folioreader.Config;
+import com.folioreader.R;
+import com.folioreader.ui.folio.activity.FolioActivityCallback;
+import com.folioreader.ui.folio.fragment.FolioPageFragment;
+
+/**
+ * @author by mahavir on 3/31/16.
+ */
+public class FolioWebView extends WebView {
+
+ private static final String LOG_TAG = FolioWebView.class.getSimpleName();
+ private int horizontalPageCount = 0;
+ private float density;
+ private ScrollListener mScrollListener;
+ private SeekBarListener mSeekBarListener;
+ private GestureDetectorCompat gestureDetector;
+ private MotionEvent eventActionDown;
+ private int pageWidthCssDp;
+ private int pageWidthCssPixels;
+ private WebViewPager webViewPager;
+ private Handler handler;
+ private FolioActivityCallback folioActivityCallback;
+ private FolioPageFragment parentFragment;
+
+ private enum LastScrollType {
+ USER, PROGRAMMATIC
+ }
+
+ private LastScrollType lastScrollType;
+
+ private class HorizontalGestureListener
+ extends GestureDetector.SimpleOnGestureListener {
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent event) {
+ Log.v(LOG_TAG, "-> onSingleTapUp");
+ folioActivityCallback.toggleSystemUI();
+ return false;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ //Log.d(LOG_TAG, "-> onScroll -> e1 = " + e1 + ", e2 = " + e2 + ", distanceX = " + distanceX + ", distanceY = " + distanceY);
+ lastScrollType = LastScrollType.USER;
+ return false;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ //Log.d(LOG_TAG, "-> onFling -> e1 = " + e1 + ", e2 = " + e2 + ", velocityX = " + velocityX + ", velocityY = " + velocityY);
+
+ if (!webViewPager.isScrolling()) {
+ // Need to complete the scroll as ViewPager thinks these touch events should not
+ // scroll it's pages.
+ //Log.d(LOG_TAG, "-> onFling -> completing scroll");
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ // Delayed to avoid inconsistency of scrolling in WebView
+ scrollTo(getScrollXPixelsForPage(webViewPager.getCurrentItem()), 0);
+ }
+ }, 100);
+ }
+
+ lastScrollType = LastScrollType.USER;
+ return true;
+ }
+
+ @Override
+ public boolean onDown(MotionEvent event) {
+ //Log.v(LOG_TAG, "-> onDown -> " + event.toString());
+
+ eventActionDown = MotionEvent.obtain(event);
+ FolioWebView.super.onTouchEvent(event);
+ return true;
+ }
+ }
+
+ private class VerticalGestureListener
+ extends GestureDetector.SimpleOnGestureListener {
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent event) {
+ Log.v(LOG_TAG, "-> onSingleTapUp");
+ folioActivityCallback.toggleSystemUI();
+ return false;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ //Log.v(LOG_TAG, "-> onScroll -> e1 = " + e1 + ", e2 = " + e2 + ", distanceX = " + distanceX + ", distanceY = " + distanceY);
+ lastScrollType = LastScrollType.USER;
+ return false;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ //Log.v(LOG_TAG, "-> onFling -> e1 = " + e1 + ", e2 = " + e2 + ", velocityX = " + velocityX + ", velocityY = " + velocityY);
+ lastScrollType = LastScrollType.USER;
+ return false;
+ }
+ }
+
+ public FolioWebView(Context context) {
+ super(context);
+ }
+
+ public FolioWebView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public FolioWebView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ private void init() {
+
+ handler = new Handler();
+ density = getResources().getDisplayMetrics().density;
+
+ if (folioActivityCallback.getDirection() == Config.Direction.HORIZONTAL) {
+ gestureDetector = new GestureDetectorCompat(getContext(), new HorizontalGestureListener());
+ } else {
+ gestureDetector = new GestureDetectorCompat(getContext(), new VerticalGestureListener());
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @JavascriptInterface
+ public void setCompatMode(String compatMode) {
+ Log.v(LOG_TAG, "-> setCompatMode -> compatMode = " + compatMode);
+ if (compatMode.equals(getContext().getString(R.string.back_compat))) {
+ Log.e(LOG_TAG, "-> Web page loaded in Quirks mode. Please report to developer " +
+ "for debugging with current EPUB file as many features might stop working " +
+ "(ex. Horizontal scroll feature).");
+ }
+ }
+
+ public void setParentFragment(FolioPageFragment parentFragment) {
+ this.parentFragment = parentFragment;
+ }
+
+ public void setFolioActivityCallback(FolioActivityCallback folioActivityCallback) {
+ this.folioActivityCallback = folioActivityCallback;
+ init();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+
+ pageWidthCssDp = (int) Math.ceil((getMeasuredWidth() / density));
+ pageWidthCssPixels = (int) (pageWidthCssDp * density);
+ }
+
+ public void setScrollListener(ScrollListener listener) {
+ mScrollListener = listener;
+ }
+
+ public void setSeekBarListener(SeekBarListener listener) {
+ mSeekBarListener = listener;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ //Log.v(LOG_TAG, "-> onTouchEvent -> " + AppUtil.actionToString(event.getAction()));
+
+ if (folioActivityCallback.getDirection() == Config.Direction.HORIZONTAL) {
+ return computeHorizontalScroll(event);
+ } else {
+ return computeVerticalScroll(event);
+ }
+ }
+
+ private boolean computeVerticalScroll(MotionEvent event) {
+
+ gestureDetector.onTouchEvent(event);
+ return super.onTouchEvent(event);
+ }
+
+ private boolean computeHorizontalScroll(MotionEvent event) {
+ //Log.v(LOG_TAG, "-> computeHorizontalScroll");
+
+ webViewPager.dispatchTouchEvent(event);
+ boolean gestureReturn = gestureDetector.onTouchEvent(event);
+ if (gestureReturn)
+ return true;
+ return super.onTouchEvent(event);
+ }
+
+ public int getScrollXDpForPage(int page) {
+ //Log.v(LOG_TAG, "-> getScrollXDpForPage -> page = " + page);
+ return page * pageWidthCssDp;
+ }
+
+ public int getScrollXPixelsForPage(int page) {
+ //Log.v(LOG_TAG, "-> getScrollXPixelsForPage -> page = " + page);
+ return page * pageWidthCssPixels;
+ }
+
+ public void setHorizontalPageCount(int horizontalPageCount) {
+ this.horizontalPageCount = horizontalPageCount;
+
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (webViewPager == null)
+ webViewPager = ((View) getParent()).findViewById(R.id.webViewPager);
+
+ webViewPager.setHorizontalPageCount(FolioWebView.this.horizontalPageCount);
+ }
+ });
+ }
+
+ @Override
+ public void scrollTo(int x, int y) {
+ super.scrollTo(x, y);
+ //Log.d(LOG_TAG, "-> scrollTo -> x = " + x);
+ lastScrollType = LastScrollType.PROGRAMMATIC;
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ if (mScrollListener != null) mScrollListener.onScrollChange(t);
+ super.onScrollChanged(l, t, oldl, oldt);
+
+ if (lastScrollType == LastScrollType.USER) {
+ //Log.d(LOG_TAG, "-> onScrollChanged -> scroll initiated by user");
+ loadUrl(getContext().getString(R.string.make_search_results_invisible));
+ parentFragment.searchItemVisible = null;
+ }
+
+ lastScrollType = null;
+ }
+
+ public int getContentHeightVal() {
+ return (int) Math.floor(this.getContentHeight() * this.getScale());
+ }
+
+ public int getWebViewHeight() {
+ return this.getMeasuredHeight();
+ }
+
+ public interface ScrollListener {
+ void onScrollChange(int percent);
+ }
+
+ public interface SeekBarListener {
+ void fadeInSeekBarIfInvisible();
+ }
+}
diff --git a/folioreader/src/main/java/com/folioreader/view/LoadingView.java b/folioreader/src/main/java/com/folioreader/view/LoadingView.java
index 8baa5701f..2be4b6d16 100644
--- a/folioreader/src/main/java/com/folioreader/view/LoadingView.java
+++ b/folioreader/src/main/java/com/folioreader/view/LoadingView.java
@@ -1,13 +1,13 @@
package com.folioreader.view;
import android.content.Context;
+import android.content.res.TypedArray;
import android.os.Handler;
import android.support.constraint.ConstraintLayout;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.webkit.JavascriptInterface;
-import android.widget.FrameLayout;
import android.widget.ProgressBar;
import com.folioreader.Config;
@@ -16,11 +16,10 @@
import com.folioreader.util.UiUtil;
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
-public class LoadingView extends FrameLayout {
+public class LoadingView extends ConstraintLayout {
- private ConstraintLayout rootView;
private ProgressBar progressBar;
- private static final int VISIBLE_DURATION = 6000;
+ private int maxVisibleDuration = -1;
private Handler handler;
private Runnable hideRunnable = new Runnable() {
@@ -54,12 +53,22 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
if (isInEditMode())
return;
+ TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
+ R.styleable.LoadingView,
+ 0, 0);
+
+ maxVisibleDuration = typedArray.getInt(R.styleable.LoadingView_maxVisibleDuration, -1);
+
handler = new Handler();
- rootView = findViewById(R.id.rootView);
progressBar = findViewById(R.id.progressBar);
+ setClickable(true);
+ setFocusable(true);
+
updateTheme();
- show();
+
+ if (getVisibility() == VISIBLE)
+ show();
}
public void updateTheme() {
@@ -67,11 +76,11 @@ public void updateTheme() {
Config config = AppUtil.getSavedConfig(getContext());
if (config == null)
config = new Config();
- UiUtil.setColorToImage(getContext(), config.getThemeColor(), progressBar.getIndeterminateDrawable());
+ UiUtil.setColorIntToDrawable(config.getThemeColor(), progressBar.getIndeterminateDrawable());
if (config.isNightMode()) {
- rootView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.webview_night));
+ setBackgroundColor(ContextCompat.getColor(getContext(), R.color.webview_night));
} else {
- rootView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.white));
+ setBackgroundColor(ContextCompat.getColor(getContext(), R.color.white));
}
}
@@ -81,8 +90,15 @@ public void show() {
//Log.d(LOG_TAG, "-> show");
handler.removeCallbacks(hideRunnable);
- setVisibility(VISIBLE);
- handler.postDelayed(hideRunnable, VISIBLE_DURATION);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ setVisibility(VISIBLE);
+ }
+ });
+
+ if (maxVisibleDuration > -1)
+ handler.postDelayed(hideRunnable, maxVisibleDuration);
}
@SuppressWarnings("unused")
@@ -91,20 +107,43 @@ public void hide() {
//Log.d(LOG_TAG, "-> hide");
handler.removeCallbacks(hideRunnable);
- setVisibility(INVISIBLE);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ setVisibility(INVISIBLE);
+ }
+ });
}
@SuppressWarnings("unused")
@JavascriptInterface
public void visible() {
//Log.d(LOG_TAG, "-> visible");
- setVisibility(VISIBLE);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ setVisibility(VISIBLE);
+ }
+ });
}
@SuppressWarnings("unused")
@JavascriptInterface
public void invisible() {
//Log.d(LOG_TAG, "-> invisible");
- setVisibility(INVISIBLE);
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ setVisibility(INVISIBLE);
+ }
+ });
+ }
+
+ public int getMaxVisibleDuration() {
+ return maxVisibleDuration;
+ }
+
+ public void setMaxVisibleDuration(int maxVisibleDuration) {
+ this.maxVisibleDuration = maxVisibleDuration;
}
}
diff --git a/folioreader/src/main/java/com/folioreader/view/MediaControllerView.kt b/folioreader/src/main/java/com/folioreader/view/MediaControllerView.kt
deleted file mode 100644
index 7a9f14f86..000000000
--- a/folioreader/src/main/java/com/folioreader/view/MediaControllerView.kt
+++ /dev/null
@@ -1,157 +0,0 @@
-package com.folioreader.view
-
-import android.content.Context
-import android.os.Build
-import android.support.v4.content.ContextCompat
-import android.text.Html
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.view.View
-import android.view.animation.AnimationUtils
-import android.widget.RelativeLayout
-import com.folioreader.Config
-import com.folioreader.R
-import com.folioreader.model.event.MediaOverlayHighlightStyleEvent
-import com.folioreader.model.event.MediaOverlaySpeedEvent
-import com.folioreader.util.AppUtil
-import com.folioreader.util.UiUtil
-import kotlinx.android.synthetic.main.view_audio_player.view.*
-import org.greenrobot.eventbus.EventBus
-
-/**
- * Created by gautam on 9/5/18.
- */
-class MediaControllerView : RelativeLayout {
- private lateinit var config: Config
- private var visible: Boolean = true
- lateinit var callback: MediaControllerCallback
- private var isPlaying: Boolean = false
-
- constructor(context: Context) : this(context, null, 0)
- constructor(context: Context, attributes: AttributeSet?) : this(context, attributes, 0)
- constructor(context: Context, attributes: AttributeSet?, defStyle: Int) : super(context, attributes, defStyle) {
- LayoutInflater.from(context).inflate(R.layout.view_audio_player, this)
- init()
- }
-
- private fun init() {
- config = AppUtil.getSavedConfig(context)
- btn_one_and_half_speed.text = Html.fromHtml(context.getString(R.string.one_and_half_speed))
- btn_half_speed.text = Html.fromHtml(context.getString(R.string.half_speed_text))
- btn_text_undeline_style.text = Html.fromHtml(context.getString(R.string.style_underline))
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- playback_speed_Layout.visibility = View.GONE
- }
- if (config.isNightMode) setNightMode()
- initColors()
- initListeners()
- }
-
- fun setListeners(callback: MediaControllerCallback) {
- this.callback = callback
- }
-
- private fun initColors() {
- btn_half_speed.setTextColor(UiUtil.getColorList(context, config.themeColor, R.color.grey_color))
- btn_one_and_half_speed.setTextColor(UiUtil.getColorList(context, config.themeColor, R.color.grey_color))
- btn_twox_speed.setTextColor(UiUtil.getColorList(context, config.themeColor, R.color.grey_color))
- btn_one_x_speed.setTextColor(UiUtil.getColorList(context, config.themeColor, R.color.grey_color))
- btn_text_undeline_style.setTextColor(UiUtil.getColorList(context, config.themeColor, R.color.grey_color))
- btn_backcolor_style.setTextColor(UiUtil.getColorList(context, R.color.white, R.color.grey_color))
- btn_backcolor_style.setBackgroundDrawable(UiUtil.convertColorIntoStateDrawable(context, config.themeColor, android.R.color.transparent))
- btn_text_color_style.setTextColor(UiUtil.getColorList(context, config.themeColor, R.color.grey_color))
- UiUtil.setColorToImage(context, config.themeColor, play_button.drawable)
- UiUtil.setColorToImage(context, config.themeColor, next_button.drawable)
- UiUtil.setColorToImage(context, config.themeColor, prev_button.drawable)
- }
-
- private fun initListeners() {
- shade.setOnClickListener { show() }
- play_button.setOnClickListener {
- callback.let {
- if (isPlaying) {
- callback.pause()
- play_button.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.play_icon))
- UiUtil.setColorToImage(context, config.themeColor, play_button.drawable)
- } else {
- callback.play()
- play_button.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.pause_btn))
- UiUtil.setColorToImage(context, config.themeColor, play_button.drawable)
- }
- isPlaying = !isPlaying
- }
- }
- btn_half_speed.setOnClickListener {
- toggleSpeedControlButtons(true, false, false, false)
- EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.HALF))
- }
-
- btn_one_x_speed.setOnClickListener {
- toggleSpeedControlButtons(false, true, false, false)
- EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.ONE))
- }
- btn_one_and_half_speed.setOnClickListener {
- toggleSpeedControlButtons(false, false, true, false)
- EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.ONE_HALF))
- }
- btn_twox_speed.setOnClickListener {
- toggleSpeedControlButtons(false, false, false, true)
- EventBus.getDefault().post(MediaOverlaySpeedEvent(MediaOverlaySpeedEvent.Speed.TWO))
- }
-
- btn_backcolor_style.setOnClickListener {
- toggleTextStyle(true, false, false)
- EventBus.getDefault().post(MediaOverlayHighlightStyleEvent(MediaOverlayHighlightStyleEvent.Style.DEFAULT))
- }
-
- btn_text_undeline_style.setOnClickListener {
- toggleTextStyle(false, true, false)
- EventBus.getDefault().post(MediaOverlayHighlightStyleEvent(MediaOverlayHighlightStyleEvent.Style.UNDERLINE))
-
- }
-
- btn_text_color_style.setOnClickListener {
- toggleTextStyle(false, false, true)
- EventBus.getDefault().post(MediaOverlayHighlightStyleEvent(MediaOverlayHighlightStyleEvent.Style.BACKGROUND))
- }
- }
-
- private fun toggleTextStyle(backcolor: Boolean, underline: Boolean, textColor: Boolean) {
- btn_backcolor_style.isSelected = backcolor
- btn_text_undeline_style.isSelected = underline
- btn_text_color_style.isSelected = textColor
- }
-
- private fun toggleSpeedControlButtons(half: Boolean, one: Boolean, oneHalf: Boolean, two: Boolean) {
- btn_half_speed.isSelected = half
- btn_one_x_speed.isSelected = one
- btn_one_and_half_speed.isSelected = oneHalf
- btn_twox_speed.isSelected = two
- }
-
- fun setPlayButtonDrawable() {
- play_button.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.play_icon))
- }
-
- private fun setNightMode() {
- container.setBackgroundColor(ContextCompat.getColor(context, R.color.night))
- }
-
- private fun open() {
- container.startAnimation(AnimationUtils.loadAnimation(context, R.anim.slide_up))
- container.visibility = View.VISIBLE
- shade.visibility = View.VISIBLE
- }
-
- fun show() {
- if (visible) open() else close()
- visible = !visible
- }
-
- private fun close() {
- container.startAnimation(AnimationUtils.loadAnimation(context, R.anim.slide_down))
- container.visibility = View.GONE
- shade.visibility = View.GONE
- }
-}
\ No newline at end of file
diff --git a/folioreader/src/main/java/com/folioreader/view/WebViewPager.java b/folioreader/src/main/java/com/folioreader/view/WebViewPager.java
index 91678c9ca..ca347b887 100644
--- a/folioreader/src/main/java/com/folioreader/view/WebViewPager.java
+++ b/folioreader/src/main/java/com/folioreader/view/WebViewPager.java
@@ -4,10 +4,12 @@
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -24,6 +26,13 @@ public class WebViewPager extends ViewPager {
private boolean takeOverScrolling;
private boolean scrolling;
private Handler handler;
+ private GestureDetectorCompat gestureDetector;
+
+ private enum LastGestureType {
+ OnSingleTapUp, OnLongPress, OnFling, OnScroll
+ }
+
+ private LastGestureType lastGestureType;
public WebViewPager(@NonNull Context context) {
super(context);
@@ -38,6 +47,7 @@ public WebViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
private void init() {
handler = new Handler();
+ gestureDetector = new GestureDetectorCompat(getContext(), new GestureListener());
addOnPageChangeListener(new OnPageChangeListener() {
@Override
@@ -48,12 +58,13 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse
scrolling = true;
if (takeOverScrolling && folioWebView != null) {
- int scrollX = folioWebView.getScrollXForPage(position) + positionOffsetPixels;
+ int scrollX = folioWebView.getScrollXPixelsForPage(position) + positionOffsetPixels;
//Log.d(LOG_TAG, "-> onPageScrolled -> scrollX = " + scrollX);
folioWebView.scrollTo(scrollX, 0);
}
if (positionOffsetPixels == 0) {
+ //Log.d(LOG_TAG, "-> onPageScrolled -> takeOverScrolling = false");
takeOverScrolling = false;
scrolling = false;
}
@@ -106,7 +117,6 @@ public void setCurrentPage(final int pageIndex) {
handler.post(new Runnable() {
@Override
public void run() {
- folioWebView.postInvalidate();
setCurrentItem(pageIndex, false);
}
});
@@ -119,7 +129,6 @@ public void setPageToLast() {
handler.post(new Runnable() {
@Override
public void run() {
- folioWebView.postInvalidate();
setCurrentItem(horizontalPageCount - 1);
}
});
@@ -132,20 +141,66 @@ public void setPageToFirst() {
handler.post(new Runnable() {
@Override
public void run() {
- folioWebView.postInvalidate();
setCurrentItem(0);
}
});
}
+ private class GestureListener extends GestureDetector.SimpleOnGestureListener {
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ WebViewPager.super.onTouchEvent(e);
+ return true;
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ //Log.d(LOG_TAG, "-> onSingleTapUp");
+ lastGestureType = LastGestureType.OnSingleTapUp;
+ return false;
+ }
+
+ @Override
+ public void onLongPress(MotionEvent e) {
+ super.onLongPress(e);
+ //Log.d(LOG_TAG, "-> onLongPress -> " + e);
+ lastGestureType = LastGestureType.OnLongPress;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ //Log.v(LOG_TAG, "-> onScroll -> e1 = " + e1 + ", e2 = " + e2 + ", distanceX = " + distanceX + ", distanceY = " + distanceY);
+ lastGestureType = LastGestureType.OnScroll;
+ return false;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ //Log.d(LOG_TAG, "-> onFling -> e1 = " + e1 + ", e2 = " + e2 + ", velocityX = " + velocityX + ", velocityY = " + velocityY);
+ lastGestureType = LastGestureType.OnFling;
+ return false;
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
//Log.d(LOG_TAG, "-> onTouchEvent -> " + AppUtil.actionToString(event.getAction()));
+ boolean gestureReturn = gestureDetector.onTouchEvent(event);
+ if (gestureReturn)
+ return true;
+
boolean superReturn = super.onTouchEvent(event);
- if (event.getAction() == MotionEvent.ACTION_UP)
- takeOverScrolling = true;
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ if (lastGestureType == LastGestureType.OnScroll ||
+ lastGestureType == LastGestureType.OnFling) {
+ //Log.d(LOG_TAG, "-> onTouchEvent -> takeOverScrolling = true, " + "lastGestureType = " + lastGestureType);
+ takeOverScrolling = true;
+ }
+ lastGestureType = null;
+ }
return superReturn;
}
@@ -170,7 +225,7 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) {
.inflate(R.layout.view_webview_pager, container, false);
// Debug code
- // Set alpha for folioWebView in folio_page_fragment.xml to 0.5f also.
+ // Set alpha for folioWebView in folio_page_fragment.xml to 0.5 also.
/*if (position % 2 == 0) {
view.setBackgroundResource(R.drawable.green_border_background);
} else {
diff --git a/sample/build.gradle b/sample/build.gradle
index 2b3913540..beedbf024 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -1,5 +1,7 @@
apply plugin: 'com.android.application'
apply plugin: 'checkstyle'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
android {
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
index 330ec6898..33da251d1 100644
--- a/sample/src/main/AndroidManifest.xml
+++ b/sample/src/main/AndroidManifest.xml
@@ -2,9 +2,6 @@
-
-
-