private void handleHighlightAyah(int sura, int ayah, HighlightType type, boolean scrollToAyah) {
    mImageView.highlightAyah(sura, ayah, type);
    if (scrollToAyah && mQuranPageLayout.canScroll()) {
      final RectF highlightBounds =
          ImageAyahUtils.getYBoundsForHighlight(mCoordinatesData, sura, ayah);
      if (highlightBounds != null) {
        int screenHeight = QuranScreenInfo.getInstance().getHeight();

        Matrix matrix = mImageView.getImageMatrix();
        matrix.mapRect(highlightBounds);

        int currentScrollY = mQuranPageLayout.getCurrentScrollY();
        final boolean topOnScreen =
            highlightBounds.top > currentScrollY
                && highlightBounds.top < currentScrollY + screenHeight;
        final boolean bottomOnScreen =
            highlightBounds.bottom > currentScrollY
                && highlightBounds.bottom < currentScrollY + screenHeight;

        if (!topOnScreen || !bottomOnScreen) {
          int y = (int) highlightBounds.top - (int) (0.05 * screenHeight);
          mQuranPageLayout.smoothScrollLayoutTo(y);
        }
      }
    }
    mImageView.invalidate();
  }
 @Override
 public void highlightAyat(int page, Set<String> ayahKeys, HighlightType type) {
   if (page == pageNumber && mQuranPageLayout != null) {
     mImageView.highlightAyat(ayahKeys, type);
     mImageView.invalidate();
   }
 }
 public void unHighlightAyah() {
   View v = mQuranPage.getCurrentPage();
   if (v != null) {
     HighlightingImageView iv = (HighlightingImageView) v.findViewById(R.id.page_image);
     if (iv != null) {
       HighlightingImageView hi = (HighlightingImageView) iv;
       hi.unhighlight();
       mQuranPage.invalidate();
     }
   }
 }
  private void handleLongPress(MotionEvent event) {
    QuranAyah result = getAyahFromCoordinates(event.getX(), event.getY());
    if (result != null) {
      mImageView.highlightAyah(result.getSura(), result.getAyah());
      mImageView.invalidate();
      mImageView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);

      // TODO Temporary UI until new UI is implemented
      new ShowAyahMenuTask().execute(result.getSura(), result.getAyah(), mPageNumber);
    }
  }
 private void handleHighlightAyah(int sura, int ayah) {
   if (mImageView == null) {
     return;
   }
   mImageView.highlightAyah(sura, ayah);
   if (mScrollView != null) {
     AyahBounds yBounds = mImageView.getYBoundsForCurrentHighlight();
     if (yBounds != null) {
       int screenHeight = QuranScreenInfo.getInstance().getHeight();
       int y = yBounds.getMinY() - (int) (0.05 * screenHeight);
       mScrollView.smoothScrollTo(mScrollView.getScrollX(), y);
     }
   }
   mImageView.invalidate();
 }
 public void highlightAyah(int sura, int ayah) {
   View v = mQuranPage.getCurrentPage();
   HighlightingImageView iv = (HighlightingImageView) v.findViewById(R.id.page_image);
   if (iv != null) {
     HighlightingImageView hi = (HighlightingImageView) iv;
     hi.highlightAyah(sura, ayah);
     if (QuranSettings.getInstance().isAutoScroll()
         && v.getResources().getConfiguration().orientation
             == Configuration.ORIENTATION_LANDSCAPE) {
       AyahBounds yBounds = hi.getYBoundsForCurrentHighlight();
       if (yBounds != null) mQuranPage.scrollToAyah(R.id.page_scroller, yBounds);
     }
     mQuranPage.invalidate();
   }
 }
  @Override
  public void onLoadImageResponse(BitmapDrawable drawable, Response response) {
    pageLoadTask = null;
    if (mQuranPageLayout == null || !isAdded()) {
      return;
    }

    if (drawable != null) {
      mImageView.setImageDrawable(drawable);
      // TODO we should toast a warning if we couldn't save the image
      // (which would likely happen if we can't write to the sdcard,
      // but just got the page from the web).
    } else if (response != null) {
      // failed to get the image... let's notify the user
      final int errorCode = response.getErrorCode();
      final int errorRes;
      switch (errorCode) {
        case Response.ERROR_SD_CARD_NOT_FOUND:
          errorRes = R.string.sdcard_error;
          break;
        case Response.ERROR_DOWNLOADING_ERROR:
          errorRes = R.string.download_error_network;
          break;
        default:
          errorRes = R.string.download_error_general;
      }
      mQuranPageLayout.showError(errorRes);
      mQuranPageLayout.setOnClickListener(
          v -> {
            if (ayahSelectedListener != null) {
              ayahSelectedListener.onClick(EventType.SINGLE_TAP);
            }
          });
    }
  }
 public void cleanup() {
   android.util.Log.d(TAG, "cleaning up page " + mPageNumber);
   mImageView.setImageDrawable(null);
   mImageView = null;
   if (mTranslationDialog != null) {
     mTranslationDialog.dismiss();
     mTranslationDialog = null;
   }
 }
  protected void updateViewForUser(View v, boolean loading, boolean pageNotFound) {
    TextView tv = (TextView) v.findViewById(R.id.txtPageNotFound);
    HighlightingImageView iv = (HighlightingImageView) v.findViewById(R.id.page_image);

    if ((loading) || (pageNotFound)) {
      if (QuranSettings.getInstance().isNightMode()) {
        tv.setTextColor(Color.WHITE);
      }
      tv.setText(loading ? R.string.pageLoading : R.string.pageNotFound);
      if (!loading && mHasBeenOutOfMemory != null && mHasBeenOutOfMemory)
        tv.setText(R.string.couldNotLoadPage);
      tv.setVisibility(View.VISIBLE);
      iv.setVisibility(View.GONE);
    } else {
      iv.adjustNightMode();
      tv.setVisibility(View.GONE);
      iv.setVisibility(View.VISIBLE);
    }
  }
  public void cleanup() {
    Timber.d("cleaning up page %d", pageNumber);
    handler.removeCallbacksAndMessages(null);
    if (pageLoadTask != null) {
      pageLoadTask.cancel(false);
    }

    if (mQuranPageLayout != null) {
      mImageView.setImageDrawable(null);
      mQuranPageLayout = null;
    }
  }
 @Override
 public AyahToolBar.AyahToolBarPosition getToolBarPosition(
     int sura, int ayah, int toolBarWidth, int toolBarHeight) {
   final List<AyahBounds> bounds =
       mCoordinatesData == null ? null : mCoordinatesData.get(sura + ":" + ayah);
   final int screenWidth = mImageView == null ? 0 : mImageView.getWidth();
   if (bounds != null && screenWidth > 0) {
     final int screenHeight = QuranScreenInfo.getInstance().getHeight();
     AyahToolBar.AyahToolBarPosition position =
         ImageAyahUtils.getToolBarPosition(
             bounds,
             mImageView.getImageMatrix(),
             screenWidth,
             screenHeight,
             toolBarWidth,
             toolBarHeight);
     // If we're in landscape mode (wrapped in SV) update the y-offset
     position.yScroll = 0 - mQuranPageLayout.getCurrentScrollY();
     return position;
   }
   return null;
 }
  @Override
  public void updateView() {
    Context context = getActivity();
    if (context == null || !isAdded()) {
      return;
    }

    final QuranSettings settings = QuranSettings.getInstance(context);
    final boolean useNewBackground = settings.useNewBackground();
    final boolean isNightMode = settings.isNightMode();
    overlayText = settings.shouldOverlayPageInfo();
    mQuranPageLayout.updateView(isNightMode, useNewBackground, 1);
    if (!settings.highlightBookmarks()) {
      mImageView.unHighlight(HighlightType.BOOKMARK);
    }
  }
  @Override
  public View onCreateView(
      LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    final Context context = getActivity();
    mQuranPageLayout = new QuranImagePageLayout(context);
    mQuranPageLayout.setPageController(this, pageNumber);
    mImageView = mQuranPageLayout.getImageView();

    if (mCoordinatesData != null) {
      mImageView.setCoordinateData(mCoordinatesData);
    }
    updateView();

    justCreated = true;
    return mQuranPageLayout;
  }
  @Override
  public View onCreateView(
      LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    final View view = inflater.inflate(R.layout.quran_page_layout, container, false);
    view.setBackgroundDrawable((mPageNumber % 2 == 0 ? mLeftGradient : mRightGradient));
    int lineImageId = R.drawable.dark_line;
    int leftBorderImageId = R.drawable.border_left;
    int rightBorderImageId = R.drawable.border_right;

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());

    Resources res = getResources();
    if (!prefs.getBoolean(Constants.PREF_USE_NEW_BACKGROUND, true)) {
      view.setBackgroundColor(res.getColor(R.color.page_background));
    }

    boolean nightMode = false;
    if (prefs.getBoolean(Constants.PREF_NIGHT_MODE, false)) {
      leftBorderImageId = R.drawable.night_left_border;
      rightBorderImageId = R.drawable.night_right_border;
      lineImageId = R.drawable.light_line;
      view.setBackgroundColor(Color.BLACK);
      nightMode = true;
    }

    ImageView leftBorder = (ImageView) view.findViewById(R.id.left_border);
    ImageView rightBorder = (ImageView) view.findViewById(R.id.right_border);
    if (mPageNumber % 2 == 0) {
      rightBorder.setVisibility(View.GONE);
      leftBorder.setBackgroundResource(leftBorderImageId);
    } else {
      rightBorder.setVisibility(View.VISIBLE);
      rightBorder.setBackgroundResource(rightBorderImageId);
      leftBorder.setBackgroundResource(lineImageId);
    }

    mImageView = (HighlightingImageView) view.findViewById(R.id.page_image);
    mImageView.setNightMode(nightMode);

    mScrollView = (ScrollView) view.findViewById(R.id.page_scroller);

    final GestureDetector gestureDetector = new GestureDetector(new PageGestureDetector());
    OnTouchListener gestureListener =
        new OnTouchListener() {
          @Override
          public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
          }
        };
    mImageView.setOnTouchListener(gestureListener);
    mImageView.setClickable(true);
    mImageView.setLongClickable(true);

    mOverlayText = prefs.getBoolean(Constants.PREF_OVERLAY_PAGE_INFO, true);

    if (mCoordinateData != null) {
      mImageView.setCoordinateData(mCoordinateData);
    }

    if (mPageBoundsRect != null) {
      mImageView.setPageBounds(mPageBoundsRect);
      if (mOverlayText) {
        mImageView.setOverlayText(mPageNumber, true);
      }
    }

    return view;
  }
  private QuranAyah getAyahFromCoordinates(float xc, float yc) {
    if (mCoordinateData == null) {
      return null;
    }

    float[] pageXY = mImageView.getPageXY(xc, yc);
    float x = pageXY[0];
    float y = pageXY[1];

    int closestLine = -1;
    int closestDelta = -1;

    SparseArray<List<String>> lineAyahs = new SparseArray<List<String>>();
    Set<String> keys = mCoordinateData.keySet();
    for (String key : keys) {
      List<AyahBounds> bounds = mCoordinateData.get(key);
      if (bounds == null) {
        continue;
      }

      for (AyahBounds b : bounds) {
        // only one AyahBound will exist for an ayah on a particular line
        int line = b.getLine();
        List<String> items = lineAyahs.get(line);
        if (items == null) {
          items = new ArrayList<String>();
        }
        items.add(key);
        lineAyahs.put(line, items);

        if (b.getMaxX() >= x && b.getMinX() <= x && b.getMaxY() >= y && b.getMinY() <= y) {
          return getAyahFromKey(key);
        }

        int delta = Math.min((int) Math.abs(b.getMaxY() - y), (int) Math.abs(b.getMinY() - y));
        if (closestDelta == -1 || delta < closestDelta) {
          closestLine = b.getLine();
          closestDelta = delta;
        }
      }
    }

    if (closestLine > -1) {
      int leastDeltaX = -1;
      String closestAyah = null;
      List<String> ayat = lineAyahs.get(closestLine);
      if (ayat != null) {
        Log.d(TAG, "no exact match, " + ayat.size() + " candidates.");
        for (String ayah : ayat) {
          List<AyahBounds> bounds = mCoordinateData.get(ayah);
          if (bounds == null) {
            continue;
          }
          for (AyahBounds b : bounds) {
            if (b.getLine() > closestLine) {
              // this is the last ayah in ayat list
              break;
            }

            if (b.getLine() == closestLine) {
              // if x is within the x of this ayah, that's our answer
              if (b.getMaxX() >= x && b.getMinX() <= x) {
                return getAyahFromKey(ayah);
              }

              // otherwise, keep track of the least delta and return it
              int delta =
                  Math.min((int) Math.abs(b.getMaxX() - x), (int) Math.abs(b.getMinX() - x));
              if (leastDeltaX == -1 || delta < leastDeltaX) {
                closestAyah = ayah;
                leastDeltaX = delta;
              }
            }
          }
        }
      }

      if (closestAyah != null) {
        Log.d(TAG, "fell back to closest ayah of " + closestAyah);
        return getAyahFromKey(closestAyah);
      }
    }
    return null;
  }
 @Override
 public void unHighlightAyat() {
   mImageView.unhighlight();
 }
 @Override
 public void unHighlightAyah(int sura, int ayah, HighlightType type) {
   mImageView.unHighlight(sura, ayah, type);
 }
 @Override
 public void unHighlightAyahs(HighlightType type) {
   mImageView.unHighlight(type);
 }