|
@@ -0,0 +1,314 @@
|
|
|
|
+package com.kdanmobile.reader.screen.contextmenu
|
|
|
|
+
|
|
|
|
+import android.content.Context
|
|
|
|
+import android.graphics.Color
|
|
|
|
+import android.graphics.Point
|
|
|
|
+import android.graphics.PointF
|
|
|
|
+import android.graphics.drawable.Drawable
|
|
|
|
+import android.graphics.drawable.GradientDrawable
|
|
|
|
+import android.graphics.drawable.StateListDrawable
|
|
|
|
+import android.os.Build
|
|
|
|
+import android.support.v4.content.ContextCompat
|
|
|
|
+import android.support.v7.widget.MyRoundRectDrawableWithShadow
|
|
|
|
+import android.view.Gravity
|
|
|
|
+import android.view.LayoutInflater
|
|
|
|
+import android.view.View
|
|
|
|
+import android.widget.LinearLayout
|
|
|
|
+import android.widget.PopupWindow
|
|
|
|
+import android.widget.TextView
|
|
|
|
+import com.kdanmobile.kmpdfkit.annotation.freeText.view.KMPDFFreeTextEditView
|
|
|
|
+import com.kdanmobile.kmpdfkit.manager.KMPDFFactory
|
|
|
|
+import com.kdanmobile.kmpdfkit.manager.controller.*
|
|
|
|
+import com.kdanmobile.kmpdfkit.manager.listener.KMPDFContextMenuCallback
|
|
|
|
+import com.kdanmobile.reader.R
|
|
|
|
+import com.kdanmobile.reader.utils.DensityUtil
|
|
|
|
+
|
|
|
|
+open class MyKMPDFContextMenuCallback(private val kmpdfFactory: KMPDFFactory?) : KMPDFContextMenuCallback {
|
|
|
|
+
|
|
|
|
+ private var popupWindow: PopupWindow? = null
|
|
|
|
+
|
|
|
|
+ private var textBoxContextMenuActionListener: TextBoxContextMenuActionListener? = null
|
|
|
|
+
|
|
|
|
+ open fun onLongPress() {}
|
|
|
|
+
|
|
|
|
+ override fun onDismissContextMenu(type: KMPDFContextMenuCallback.ContextMenuType?, view: View?) {
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun onShowContextMenu(type: KMPDFContextMenuCallback.ContextMenuType?, view: View?) {
|
|
|
|
+ if (null != view && null == popupWindow) {
|
|
|
|
+
|
|
|
|
+ // create context menu depended on ContextMenuType
|
|
|
|
+ val context = view.context!!
|
|
|
|
+ val contentView = when (type) {
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Markup -> createMarkupContextMenuView(context)
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.INK -> createInkContextMenuView(context)
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.SelectText -> createSelectTextContextMenuView(context)
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Shape -> createShapeContextMenuView(context)
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Freetext -> createTextBoxContextMenuView(context)
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Signature -> createSignatureContextMenuView(context)
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Stamp -> createStampContextMenuView(context)
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.LongPress -> createLongPressContextMenuView(context)
|
|
|
|
+ else -> LinearLayout(context)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // LongPress on TextBox
|
|
|
|
+ if (type == KMPDFContextMenuCallback.ContextMenuType.Freetext) {
|
|
|
|
+ if (view is KMPDFFreeTextEditView) {
|
|
|
|
+ view.setOnLoogPressListener {
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ val position = computeDisplayPosition(context, type, view, contentView)
|
|
|
|
+
|
|
|
|
+ popupWindow = PopupWindow(contentView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, true)
|
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
|
|
+ popupWindow?.elevation = context.resources.getDimension(R.dimen.reader_context_menu_window_elevation)
|
|
|
|
+ } else {
|
|
|
|
+ setElevationBelowAndroidKitKat(context, contentView)
|
|
|
|
+ }
|
|
|
|
+ popupWindow?.isOutsideTouchable = false
|
|
|
|
+ popupWindow?.isFocusable = false
|
|
|
|
+ popupWindow?.showAtLocation(view, Gravity.LEFT or Gravity.TOP, position.x, position.y)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun computeDisplayPosition(context: Context, type: KMPDFContextMenuCallback.ContextMenuType?, view: View, contentView: View): Point {
|
|
|
|
+ // get the size of context menu
|
|
|
|
+ contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
|
|
|
|
+ val windowWidth = contentView.measuredWidth
|
|
|
|
+ val windowHeight = contentView.measuredHeight
|
|
|
|
+
|
|
|
|
+ // get position y offset and margin of context menu
|
|
|
|
+ val margin = context.resources.getDimensionPixelSize(R.dimen.reader_context_menu_window_position_margin)
|
|
|
|
+ val offset = context.resources.getDimensionPixelSize(when (type) {
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Markup,
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.INK -> R.dimen.reader_context_menu_window_position_offset_markup
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.SelectText -> R.dimen.reader_context_menu_window_position_offset_select_text
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Shape,
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Freetext,
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Signature,
|
|
|
|
+ KMPDFContextMenuCallback.ContextMenuType.Stamp -> R.dimen.reader_context_menu_window_position_offset_annotation
|
|
|
|
+ else -> R.dimen.reader_context_menu_window_position_offset
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // get location of view
|
|
|
|
+ val anchorLoc = arrayOf(0, 0).toIntArray()
|
|
|
|
+ view.getLocationOnScreen(anchorLoc)
|
|
|
|
+
|
|
|
|
+ // compute the position of context menu
|
|
|
|
+ val screenHeight = DensityUtil.getScreenHeightPx(context)
|
|
|
|
+ val screenWidth = DensityUtil.getScreenWidthPx(context)
|
|
|
|
+ val topPositionY = anchorLoc[1] - windowHeight - offset
|
|
|
|
+ val bottomPositionY = anchorLoc[1] + view.height + offset
|
|
|
|
+ val leftPositionX = anchorLoc[0] - windowWidth - offset
|
|
|
|
+ val rightPositionX = anchorLoc[0] + view.width + offset
|
|
|
|
+
|
|
|
|
+ // determine the final position of context menu
|
|
|
|
+ val positionY = when {
|
|
|
|
+ topPositionY - margin > 0 -> topPositionY // top
|
|
|
|
+ screenHeight - windowHeight - bottomPositionY - margin > 0 -> bottomPositionY // bottom
|
|
|
|
+ else -> (topPositionY + bottomPositionY) / 2 // center
|
|
|
|
+ }
|
|
|
|
+ val positionX = when {
|
|
|
|
+ positionY == topPositionY || positionY == bottomPositionY -> (leftPositionX + rightPositionX) / 2 // center
|
|
|
|
+ leftPositionX - margin > 0 -> leftPositionX // left
|
|
|
|
+ screenWidth - windowWidth - rightPositionX - margin > 0 -> rightPositionX // right
|
|
|
|
+ else -> (leftPositionX + rightPositionX) / 2 // center
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return Point(positionX, positionY)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun dismissPopupWindow() {
|
|
|
|
+ popupWindow?.dismiss()
|
|
|
|
+ popupWindow = null
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun setElevationBelowAndroidKitKat(context: Context, view: View) {
|
|
|
|
+ val elevation = context.resources.getDimension(R.dimen.reader_context_menu_window_elevation)
|
|
|
|
+ val drawable = MyRoundRectDrawableWithShadow(context.resources, Color.TRANSPARENT, 0f, elevation, elevation)
|
|
|
|
+ setViewBackground(view, drawable)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun setViewBackground(view: View, drawable: Drawable) {
|
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
|
|
+ view.background = drawable
|
|
|
|
+ } else {
|
|
|
|
+ view.setBackgroundDrawable(drawable)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createTextBoxSelector(context: Context, topLeft: Boolean, topRight: Boolean, bottomRight: Boolean, bottomLeft: Boolean): Drawable {
|
|
|
|
+ val radius = context.resources.getDimension(R.dimen.reader_context_menu_text_box_radius)
|
|
|
|
+ val topLeftRadius = if (topLeft) PointF(radius, radius) else PointF()
|
|
|
|
+ val topRightRadius = if (topRight) PointF(radius, radius) else PointF()
|
|
|
|
+ val bottomRightRadius = if (bottomRight) PointF(radius, radius) else PointF()
|
|
|
|
+ val bottomLeftRadius = if (bottomLeft) PointF(radius, radius) else PointF()
|
|
|
|
+ val cornerRadii = floatArrayOf(topLeftRadius.x, topLeftRadius.y, topRightRadius.x, topRightRadius.y, bottomRightRadius.x, bottomRightRadius.y, bottomLeftRadius.x, bottomLeftRadius.y)
|
|
|
|
+
|
|
|
|
+ val normalDrawable = GradientDrawable()
|
|
|
|
+ normalDrawable.cornerRadii = cornerRadii
|
|
|
|
+ normalDrawable.setColor(ContextCompat.getColor(context, R.color.reader_contextMenu_bgNormal))
|
|
|
|
+ val pressedDrawable = GradientDrawable()
|
|
|
|
+ pressedDrawable.cornerRadii = cornerRadii
|
|
|
|
+ pressedDrawable.setColor(ContextCompat.getColor(context, R.color.reader_contextMenu_bgPressed))
|
|
|
|
+ val drawable = StateListDrawable()
|
|
|
|
+ drawable.addState(intArrayOf(android.R.attr.state_pressed), pressedDrawable)
|
|
|
|
+ drawable.addState(intArrayOf(android.R.attr.state_enabled), normalDrawable)
|
|
|
|
+ return drawable
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createMarkupContextMenuView(context: Context): View {
|
|
|
|
+ /** Just set HIGH_LIGHT then highlight, strike, underline will be triggered. **/
|
|
|
|
+ /** WTF !!!!!!!!!!! **/
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
|
|
|
|
+ contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
|
|
|
|
+ val kmpdfMarkupController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.MARKER_UP) as KMPDFMarkupController?
|
|
|
|
+ kmpdfMarkupController?.deleteMarkupAnnotView()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createInkContextMenuView(context: Context): View {
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
|
|
|
|
+ contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
|
|
|
|
+ val kmpdfInkController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.INK) as KMPDFInkController?
|
|
|
|
+ kmpdfInkController?.deleteInkAnnotView()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createSelectTextContextMenuView(context: Context): View {
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_select_text, null)
|
|
|
|
+
|
|
|
|
+ val btnCopy = contentView.findViewById<TextView>(R.id.btnCopy_contextMenu)
|
|
|
|
+ val btnHighlight = contentView.findViewById<TextView>(R.id.btnHighlight_contextMenu)
|
|
|
|
+ val btnUnderline = contentView.findViewById<TextView>(R.id.btnUnderline_contextMenu)
|
|
|
|
+ val btnStrikeout = contentView.findViewById<TextView>(R.id.btnStrikeout_contextMenu)
|
|
|
|
+
|
|
|
|
+ setViewBackground(btnCopy, createTextBoxSelector(context, true, false, false, true))
|
|
|
|
+ setViewBackground(btnHighlight, createTextBoxSelector(context, false, false, false, false))
|
|
|
|
+ setViewBackground(btnUnderline, createTextBoxSelector(context, false, false, false, false))
|
|
|
|
+ setViewBackground(btnStrikeout, createTextBoxSelector(context, false, true, true, false))
|
|
|
|
+
|
|
|
|
+ val kmpdfSelectTextController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.SELECT_TEXT) as KMPDFSelectTextController?
|
|
|
|
+ btnCopy.setOnClickListener {
|
|
|
|
+ kmpdfSelectTextController?.copySelectedText()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ btnHighlight.setOnClickListener {
|
|
|
|
+ kmpdfSelectTextController?.highlightSelectedText()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ btnUnderline.setOnClickListener {
|
|
|
|
+ kmpdfSelectTextController?.underlineSelectedText()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ btnStrikeout.setOnClickListener {
|
|
|
|
+ kmpdfSelectTextController?.strikeoutSelectedText()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createShapeContextMenuView(context: Context): View {
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
|
|
|
|
+ contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
|
|
|
|
+ val kmpdfShapeAnnotController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.SHAPE) as KMPDFShapeAnnotController?
|
|
|
|
+ kmpdfShapeAnnotController?.deleteShapeAnnotView()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createTextBoxContextMenuView(context: Context): View {
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_textbox, null)
|
|
|
|
+
|
|
|
|
+ val btnDelete = contentView.findViewById<TextView>(R.id.btnDelete_contextMenu)
|
|
|
|
+ val btnStyle = contentView.findViewById<TextView>(R.id.btnStyle_contextMenu)
|
|
|
|
+ val btnEdit = contentView.findViewById<TextView>(R.id.btnEdit_contextMenu)
|
|
|
|
+ val btnCopy = contentView.findViewById<TextView>(R.id.btnCopy_contextMenu)
|
|
|
|
+
|
|
|
|
+ setViewBackground(btnDelete, createTextBoxSelector(context, true, false, false, true))
|
|
|
|
+ setViewBackground(btnStyle, createTextBoxSelector(context, false, false, false, false))
|
|
|
|
+ setViewBackground(btnEdit, createTextBoxSelector(context, false, false, false, false))
|
|
|
|
+ setViewBackground(btnCopy, createTextBoxSelector(context, false, true, true, false))
|
|
|
|
+
|
|
|
|
+ btnDelete.setOnClickListener {
|
|
|
|
+ textBoxContextMenuActionListener?.onDelete()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ btnStyle.setOnClickListener {
|
|
|
|
+ textBoxContextMenuActionListener?.onEditStyle()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ btnEdit.setOnClickListener {
|
|
|
|
+ textBoxContextMenuActionListener?.onEditText()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ btnCopy.setOnClickListener {
|
|
|
|
+ textBoxContextMenuActionListener?.onCopy()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createSignatureContextMenuView(context: Context): View {
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_signature, null)
|
|
|
|
+
|
|
|
|
+ val btnDelete = contentView.findViewById<TextView>(R.id.btnDelete_contextMenu)
|
|
|
|
+ val btnAdd = contentView.findViewById<TextView>(R.id.btnAdd_contextMenu)
|
|
|
|
+
|
|
|
|
+ setViewBackground(btnDelete, createTextBoxSelector(context, true, false, false, true))
|
|
|
|
+ setViewBackground(btnAdd, createTextBoxSelector(context, false, true, true, false))
|
|
|
|
+
|
|
|
|
+ val kmpdfSignatureController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.SIGNATURE) as KMPDFSignatureController?
|
|
|
|
+ btnDelete.setOnClickListener {
|
|
|
|
+ kmpdfSignatureController?.deleteSignatureAnnotView()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ btnAdd.setOnClickListener {
|
|
|
|
+ kmpdfSignatureController?.saveSignatureAnnot()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createStampContextMenuView(context: Context): View {
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_normal, null)
|
|
|
|
+ contentView.findViewById<TextView>(R.id.btnDelete_contextMenu).setOnClickListener {
|
|
|
|
+ val kmpdfStampController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.STAMP) as KMPDFStampController?
|
|
|
|
+ kmpdfStampController?.deleteStampAnnotView()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private fun createLongPressContextMenuView(context: Context): View {
|
|
|
|
+ val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
|
|
|
+ val contentView = layoutInflater.inflate(R.layout.view_context_menu_long_press, null)
|
|
|
|
+ contentView.findViewById<TextView>(R.id.btnPaste_contextMenu).setOnClickListener {
|
|
|
|
+ val kmpdfLongPressCreateAnnotController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.LONGCLICK) as KMPDFLongPressCreateAnnotController?
|
|
|
|
+ kmpdfLongPressCreateAnnotController?.longPress_Paste()
|
|
|
|
+ onLongPress()
|
|
|
|
+ dismissPopupWindow()
|
|
|
|
+ }
|
|
|
|
+ return contentView
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fun setTextBoxContextMenuActions(listener: TextBoxContextMenuActionListener) {
|
|
|
|
+ textBoxContextMenuActionListener = listener
|
|
|
|
+ }
|
|
|
|
+}
|