package com.kdanmobile.reader import android.annotation.SuppressLint import android.app.Activity import android.app.Dialog import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders import android.content.Intent import android.net.Uri import android.os.Build import android.os.Bundle import android.support.constraint.ConstraintLayout import android.support.constraint.ConstraintSet import android.support.design.widget.Snackbar import android.support.v4.content.ContextCompat import android.support.v7.app.AlertDialog import android.support.v7.app.AppCompatActivity import android.util.DisplayMetrics import android.view.* import android.view.animation.AnimationUtils import android.widget.EditText import android.widget.LinearLayout import android.widget.TextView import android.widget.Toast import com.kdanmobile.kmpdfkit.globaldata.KMPDFAnnotEditMode import com.kdanmobile.kmpdfkit.pdfcommon.KMPDFReaderView import com.kdanmobile.kmpdfkit.pdfcommon.PDFInfo import com.kdanmobile.reader.Utils.applyConstraintSet import com.kdanmobile.reader.annotationattribute.AnnotationAttribute import com.kdanmobile.reader.annotationattribute.AnnotationColor import com.kdanmobile.reader.annotationattribute.InkAttribute import com.kdanmobile.reader.password.DialogPasswordActivity import com.kdanmobile.reader.screen.contextmenu.TextBoxContextMenuActionListener import com.kdanmobile.reader.screen.model.SharePrefsModel import com.kdanmobile.reader.screen.reader.mediabox.MediaBoxView import com.kdanmobile.reader.screen.reader.mediabox.shape.ShapeTabView import com.kdanmobile.reader.screen.reader.mediabox.signature.SignatureTabView import com.kdanmobile.reader.screen.reader.mediabox.stamp.StampTabView import com.kdanmobile.reader.screen.reader.mediabox.textbox.TextBoxTabView import com.kdanmobile.reader.screen.view.* import com.kdanmobile.reader.setting.ReaderSettingDialogFragment import com.kdanmobile.reader.setting.ReaderSettingListener import com.kdanmobile.reader.thumb.PdfThumbActivity import com.kdanmobile.reader.utils.AnimationUtil import com.kdanmobile.reader.utils.DensityUtil import com.kdanmobile.reader.utils.UriToPathUtil import com.kdanmobile.reader.view.AnnotationAttributeView import com.kdanmobile.reader.view.AnnotationAttributeWindow import kotlinx.android.synthetic.main.activity_reader.* import java.io.File import java.util.* import kotlin.properties.Delegates abstract class ReaderActivity : AppCompatActivity() { abstract fun onClickShare() abstract fun onClickKdanCloud() abstract fun onClickTextReflow() abstract fun onClickFileInfo() abstract fun onClickPrint() abstract fun onClickUserGuide() abstract fun transferThumbIntent(): Intent abstract fun provideReaderSettingDialogFragment(): ReaderSettingDialogFragment open fun saveCurrentPageIndex(filename: String, currentPage: Int) {} open fun loadCurrentPageIndex(filename: String, defaultValue: Int): Int = 0 companion object { const val KEY_FILE_ABSOLUTE = "file_absolutepath" const val THUMB = 221 const val REQUEST_PASSWORD = 222 } protected val file: File? get() { return viewModel.file } protected var filePath: String? = null private set protected val pdfInfo: PDFInfo? get() { return viewModel.pdfInfo } protected val isPasswordProtected: Boolean get() { return viewModel.isPasswordProtected } protected val currentPageIndex: Int get() { return viewModel.pdfInfoHandler.getCurrentPage() } protected val pageCount: Int get() { return viewModel.pdfInfoHandler.getPdfPageCount() } protected val password: String get() { return viewModel.password } private lateinit var viewModel: ReaderViewModel private var isShowPasswordActivity = false // For hide/show toolbars private var isHideToolbar = false private lateinit var originConstraintSet: ConstraintSet private var menuItemBookmark: MenuItem? = null private val UI_ANIMATION_DURATION = 300L private val FRAGMENT_READER_SETTING_TAG = "ReaderSetting" private var w_318: Int = 0 private var w_240: Int = 0 private var w_left: Int = 0 private var oldLeftToolbarType = ReaderViewModel.LeftToolbarType.NONE private var snackbarMediaBox: Snackbar? = null private var isHidePdfPage: Boolean by Delegates.observable(false) { property, oldValue, newValue -> if (newValue == oldValue) return@observable // println("${property.name} changed from $oldValue to $newValue") tv_readerActivity_pdfPage.clearAnimation() when (newValue) { true -> tv_readerActivity_pdfPage.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_out)) false -> tv_readerActivity_pdfPage.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in)) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) setContentView(R.layout.activity_reader) setSupportActionBar(toolbar_readerActivity) isShowPasswordActivity = savedInstanceState?.getBoolean("isShowPasswordActivity") ?: false filePath = savedInstanceState?.getString("filePath") val displayMetrics = DisplayMetrics() windowManager.defaultDisplay.getMetrics(displayMetrics) val width = Math.min(DensityUtil.getScreenWidthPx(baseContext), DensityUtil.getScreenHeightPx(baseContext)) w_318 = 318 * width / 800 w_240 = 240 * width / 800 w_left = resources.getDimension(R.dimen.reader_left_right_toolbar_icon_width).toInt() cloneOriginConstraintSet() setupToolbar() setupLeftToolbar() setupRightSideToolbar() setupBottomToolbar() setupMediaBoxView() val factory = ReaderViewModelFactory() viewModel = ViewModelProviders.of(this, factory).get(ReaderViewModel::class.java) ReaderModel.onViewModelCreate(viewModel) viewModel.isOpenedFileLiveData.observe(this, Observer(this::onIsOpenedFileUpdate)) viewModel.fileNameLiveData.observe(this, Observer { tv_readerActivity_title.text = it }) viewModel.annotationModeLiveData.observe(this, Observer(this::onAnnotationModeUpdate)) viewModel.annotationEitModeLiveData.observe(this, Observer(this::onAnnotationEditModeUpdate)) viewModel.isCopyModeLiveData.observe(this, Observer (this::onIsCopyModeUpdate)) viewModel.highLightAttributeLiveData.observe(this, Observer(this::onHighlightAttributeUpdate)) viewModel.strikeAttributeLiveData.observe(this, Observer(this::onStrikeAttributeUpdate)) viewModel.underLineAttributeLiveData.observe(this, Observer(this::onUnderlineAttributeUpdate)) viewModel.inkAttributeLiveData.observe(this, Observer(this::onInkAttributeUpdate)) viewModel.isOpenedFileLiveData.value?.also { isOpened -> if (isShowPasswordActivity) return@also if (isOpened) return@also val uri = if (intent.action == Intent.ACTION_VIEW) { val uri = intent.data filePath = UriToPathUtil.getInstance().getPath(applicationContext, uri) uri } else { filePath = intent.getStringExtra(KEY_FILE_ABSOLUTE) Uri.parse(filePath) } viewModel.openPdfFile(applicationContext, uri, password, Runnable { requestPassword() }, intent.type) } setupRightToolbar() viewModel.pageIndexLiveData.observe(this, Observer(this::onPageIndexChanged)) viewModel.isPageInBookmarksLiveData.observe(this, Observer(this::onIsPageInBookmarksChanged)) viewModel.isLeftToolbarOpenLiveData.observe(this, Observer(this::onLeftToolbarOpenStateChanged)) viewModel.leftToolbarTypeLiveData.observe(this, Observer(this::onLeftToolbarTypeChanged)) isHidePdfPage = true applySetting() if (savedInstanceState != null) { val settingDialog = supportFragmentManager.findFragmentByTag(FRAGMENT_READER_SETTING_TAG) as ReaderSettingDialogFragment? settingDialog?.setReaderSettingListener(readerSettingListener) } setupPdfChangedListener() } override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) outState?.putBoolean("isShowPasswordActivity", isShowPasswordActivity) outState?.putString("filePath", filePath) } private fun requestPassword(isIncorrectPassword: Boolean = false) { isShowPasswordActivity = true val intent = Intent(baseContext, DialogPasswordActivity::class.java) val bundle = Bundle() bundle.putBoolean("isIncorrectPassword", isIncorrectPassword) intent.putExtras(bundle) startActivityForResult(intent, REQUEST_PASSWORD) } override fun onBackPressed() { when { mediaBoxView.isShown -> mediaBoxView.dismiss() else -> super.onBackPressed() } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.reader_more, menu) menuItemBookmark = menu?.findItem(R.id.item_reader_bookmark) onIsPageInBookmarksChanged(viewModel.isPageInBookmarksLiveData.value) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { menu?.findItem(R.id.item_reader_more_print)?.isVisible = false } // TODO: Check is pdf file or epub file, these action support only pdf file val isPdf = true if (!isPdf) { menu?.apply { findItem(R.id.item_reader_more_text_reflow)?.isVisible = false findItem(R.id.item_reader_more_file_info)?.isVisible = false findItem(R.id.item_reader_more_print)?.isVisible = false } } return true } @SuppressLint("RestrictedApi") override fun onPrepareOptionsPanel(view: View?, menu: Menu?): Boolean { /** Force show action menu item icon **/ menu?.also { if ("MenuBuilder" != it::javaClass.get().simpleName) return@also try { val method = it.javaClass.getDeclaredMethod("setOptionalIconsVisible", java.lang.Boolean.TYPE) method.isAccessible = true method.invoke(it, true) } catch (e: Exception) { // Do nothing } } return super.onPrepareOptionsPanel(view, menu) } protected fun getPageText(pageIndex: Int) = viewModel.getPageText(pageIndex) private fun cloneOriginConstraintSet() { if (!isBelowKitkat()) { originConstraintSet = ConstraintSet().apply { clone(constrainLayout_readerActivity_root) } } } private fun onIsCopyModeUpdate(isCopyMode: Boolean?) { if (isCopyMode == null) return when (isCopyMode) { true -> hideTopLeftBottomToolbars() false -> showAllToolbars() } } private fun onHighlightAttributeUpdate(annotationAttribute: AnnotationAttribute?) { if (annotationAttribute == null) return view_readerActivity_highLightStroke.setBackgroundColor(annotationAttribute.color) } private fun onStrikeAttributeUpdate(annotationAttribute: AnnotationAttribute?) { if (annotationAttribute == null) return view_readerActivity_strikeStroke.setBackgroundColor(annotationAttribute.color) } private fun onUnderlineAttributeUpdate(annotationAttribute: AnnotationAttribute?) { if (annotationAttribute == null) return view_readerActivity_underlineStroke.setBackgroundColor(annotationAttribute.color) } private fun onInkAttributeUpdate(inkAttribute: InkAttribute?) { if (inkAttribute == null) return val color = inkAttribute.color AnnotationColor.values().forEach { if (ContextCompat.getColor(this, it.colorResId) == color) { val drawableResId = when (it) { AnnotationColor.Color1 -> R.drawable.ic_reader_right_toolbar_ink_color1 AnnotationColor.Color2 -> R.drawable.ic_reader_right_toolbar_ink_color2 AnnotationColor.Color3 -> R.drawable.ic_reader_right_toolbar_ink_color3 AnnotationColor.Color4 -> R.drawable.ic_reader_right_toolbar_ink_color4 AnnotationColor.Color5 -> R.drawable.ic_reader_right_toolbar_ink_color5 AnnotationColor.Color6 -> R.drawable.ic_reader_right_toolbar_ink_color6 AnnotationColor.Color7 -> R.drawable.ic_reader_right_toolbar_ink_color7 AnnotationColor.Color8 -> R.drawable.ic_reader_right_toolbar_ink_color8 AnnotationColor.Color9 -> R.drawable.ic_reader_right_toolbar_ink_color9 AnnotationColor.Color10 -> R.drawable.ic_reader_right_toolbar_ink_color10 } iv_readerActivity_ink.setImageResource(drawableResId) return } } } private fun onAnnotationModeUpdate(annotationMode: ReaderViewModel.AnnotationMode?) { if (annotationMode == null) return if (viewModel.isCrop) return val map = HashMap().apply { put(ReaderViewModel.AnnotationMode.Highlight, iv_readerActivity_highLight) put(ReaderViewModel.AnnotationMode.Strike, iv_readerActivity_strike) put(ReaderViewModel.AnnotationMode.Underline, iv_readerActivity_underline) put(ReaderViewModel.AnnotationMode.Ink, iv_readerActivity_ink) } map.forEach { if (it.key == annotationMode) { val color = ContextCompat.getColor(this, R.color.reader_right_toolbar_selected_bg) it.value.setBackgroundColor(color) } else { it.value.setBackgroundDrawable(null) } } when (annotationMode == ReaderViewModel.AnnotationMode.None) { true -> showAllToolbars() false -> hideTopLeftBottomToolbars() } ReaderModel.onPdfChangedListener?.onPageUpdated(arrayListOf(currentPageIndex)) } private fun onAnnotationEditModeUpdate(mode: KMPDFAnnotEditMode.Mode?) { when (mode) { KMPDFAnnotEditMode.Mode.NULL -> { showAllToolbars() isHideToolbar = false snackbarMediaBox?.dismiss() snackbarMediaBox = null } KMPDFAnnotEditMode.Mode.SIGN_MODIFY -> { hideAllToolbars() isHideToolbar = true } KMPDFAnnotEditMode.Mode.FREETEXT_MODIFY, KMPDFAnnotEditMode.Mode.STAMP_MODIFY, KMPDFAnnotEditMode.Mode.SHAPE_MODIFY -> { hideAllToolbars() isHideToolbar = true snackbarMediaBox?.dismiss() snackbarMediaBox = null } else -> {} } isHidePdfPage = true ReaderModel.onPdfChangedListener?.onPageUpdated(arrayListOf(currentPageIndex)) } private fun onIsOpenedFileUpdate(isOpened: Boolean?) { if (isOpened == null) return val container = viewGroup_readerActivity_container container.removeAllViews() if (!isOpened) return val context = this val readerView = object : KMPDFReaderView(context) { @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(motionEvent: MotionEvent): Boolean { if (motionEvent.action == MotionEvent.ACTION_UP) { if (viewModel.isCopyModeLiveData.value == true) { if (viewModel.copySelection()) { val context = this@ReaderActivity Toast.makeText(context, R.string.reader_copy_text_success, Toast.LENGTH_SHORT).show() } } } return super.onTouchEvent(motionEvent) } override fun onTapMainDocArea() { super.onTapMainDocArea() when (isHideToolbar) { true -> { showAllToolbars() viewModel.clearSelection() } false -> hideAllToolbars() } isHideToolbar = !isHideToolbar } override fun onMoveToChild(pageIndex: Int) { super.onMoveToChild(pageIndex) viewModel.setPageIndex(pageIndex) } override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean { val isEditMode = viewModel.annotationModeLiveData.value != ReaderViewModel.AnnotationMode.None val isCopyMode = viewModel.isCopyModeLiveData.value != false if (!isEditMode && !isCopyMode && !isHideToolbar) { hideAllToolbars() isHideToolbar = true } isHidePdfPage = isEditMode || isCopyMode return super.onScroll(e1, e2, distanceX, distanceY) } } viewModel.setReaderView(readerView) if (!filePath.isNullOrEmpty()) { val defaultValue = viewModel.pageIndexLiveData.value ?: 0 val pageIndex = loadCurrentPageIndex(filePath as String, defaultValue) viewModel.pdfInfoHandler.setCurrentPage(pageIndex) } initTextBoxContextMenuActions() container.addView(readerView) if (SharePrefsModel(this).isCropModeEnable.value == true) { val settingDialog = supportFragmentManager.findFragmentByTag(FRAGMENT_READER_SETTING_TAG) as ReaderSettingDialogFragment? settingDialog?.dismiss() readerView.post { readerSettingListener.onCropModeEnableChanged(true) } } } private fun initTextBoxContextMenuActions() { viewModel.setTextBoxContextMenuActions(object : TextBoxContextMenuActionListener { override fun onDelete(): Boolean { viewModel.deleteSelectedTextBox() return true } override fun onEditStyle(): Boolean { mediaBoxView.showTextBoxStyleView() viewModel.editSelectedTextBoxStyle() return true } override fun onEditText(): Boolean { hideAllToolbars() isHideToolbar = true viewModel.editSelectedTextBoxText() return true } override fun onCopy(): Boolean { viewModel.copySelectedTextBox() return true } }) } override fun onStop() { viewModel.saveModifyingAnnotation() viewModel.temporarySave() if (!filePath.isNullOrEmpty()) { saveCurrentPageIndex(filePath as String, currentPageIndex) } super.onStop() } private fun onPageIndexChanged(pageIndex: Int?) { pageIndex?.also { viewModel.setBookmarkDisplay(pageIndex) ReaderModel.onPdfChangedListener?.onPageSelected(pageIndex) tv_readerActivity_pdfPage.post { tv_readerActivity_pdfPage.text="${(pageIndex) + 1}/${viewModel.pdfInfoHandler.getPdfPageCount()}" } } } private fun onIsPageInBookmarksChanged(isPageInBookmarks: Boolean?) { isPageInBookmarks?.let { if (it) { menuItemBookmark?.icon = ContextCompat.getDrawable(this, R.drawable.ic_bookmark_fill) } else { menuItemBookmark?.icon = ContextCompat.getDrawable(this, R.drawable.ic_bookmark_border) } } } private fun isBelowKitkat(): Boolean { return true // return Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT } private fun showAllToolbars() { if (isBelowKitkat()) { val duration = ((1 - toolbar_readerActivity.alpha) * UI_ANIMATION_DURATION).toLong() AnimationUtil.showViewFromTopToBottom(toolbar_readerActivity, duration) AnimationUtil.showViewFromBottomToTop(viewGroup_readerActivity_bottomToolbar, duration) AnimationUtil.showViewFromLeftToRight(viewGroup_readerActivity_leftToolbar, duration) AnimationUtil.showViewFromRightToLeft(viewGroup_readerActivity_rightToolbar, duration) } else { constrainLayout_readerActivity_root.applyConstraintSet(originConstraintSet, UI_ANIMATION_DURATION) } isHidePdfPage = true } private fun hideAllToolbars() { if (isBelowKitkat()) { val duration = (toolbar_readerActivity.alpha * UI_ANIMATION_DURATION).toLong() AnimationUtil.hideViewFromBottomToTop(toolbar_readerActivity, duration) AnimationUtil.hideViewFromTopToBottom(viewGroup_readerActivity_bottomToolbar, duration) AnimationUtil.hideViewFromRightToLeft(viewGroup_readerActivity_leftToolbar, duration) AnimationUtil.hideViewFromLeftToRight(viewGroup_readerActivity_rightToolbar, duration) hideSearchViewSoftKeyboard() } else { constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_all, UI_ANIMATION_DURATION) } } private fun hideTopLeftBottomToolbars() { if (isBelowKitkat()) { val duration = (toolbar_readerActivity.alpha * UI_ANIMATION_DURATION).toLong() AnimationUtil.hideViewFromBottomToTop(toolbar_readerActivity, duration) AnimationUtil.hideViewFromTopToBottom(viewGroup_readerActivity_bottomToolbar, duration) AnimationUtil.hideViewFromRightToLeft(viewGroup_readerActivity_leftToolbar, duration) hideSearchViewSoftKeyboard() } else { constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_top_left_bottom, UI_ANIMATION_DURATION) } } private fun setupPdfChangedListener() { ReaderModel.onPdfChangedListener = object : OnPdfChangedListener { override fun onPageCreated(pages: List) { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun onPageDeleted(pages: List) { val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0) if (view is LeftToolbarView) { view.updateContent() view.onScrollToContent(currentPageIndex, true) } } override fun onPageSelected(pageIndex: Int) { val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0) if (view is LeftToolbarView) { view.onScrollToContent(currentPageIndex, true) } } override fun onPageUpdated(pages: List) { val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0) if (view is LeftToolbarView) { view.updateContent() view.onScrollToContent(currentPageIndex, true) } } } } private fun updateBookmarkView() { val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0) if (view is BookmarkView) { view.updateContent() view.onScrollToContent(currentPageIndex, true) } } private fun setupToolbar() { toolbar_readerActivity.setNavigationOnClickListener { finish() } toolbar_readerActivity.setOnMenuItemClickListener { when (it.itemId) { R.id.item_reader_bookmark -> onClickBookmark() R.id.item_reader_more_text_reflow -> onClickTextReflow() R.id.item_reader_more_file_info -> onClickFileInfo() R.id.item_reader_more_print -> onClickPrint() R.id.item_reader_more_user_guide -> onClickUserGuide() } return@setOnMenuItemClickListener true } } private fun onClickBookmark() { viewModel.isPageInBookmarksLiveData.value?.let { if (!it) { showAddBookmarkDialog() } else { showDeleteBookmarkDialog() } } } private fun showAddBookmarkDialog() { val alertDialogBuilder = AlertDialog.Builder(this) val editText = EditText(this) val layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT) editText.layoutParams = layoutParams val defaultTitle = getString(R.string.dialogAddBookmark_page) + " " + (viewModel.pdfInfoHandler.getCurrentPage() + 1) editText.setText(defaultTitle, TextView.BufferType.EDITABLE) editText.setSelection(0, defaultTitle.length) alertDialogBuilder.setTitle(getString(R.string.reader_alert_dialog_title_add_bookmark)) alertDialogBuilder.setView(editText) alertDialogBuilder.setPositiveButton(getString(R.string.reader_alert_dialog_button_confirm)) { dialog, which -> viewModel.addBookmark(editText.text.toString()) updateBookmarkView() } alertDialogBuilder.setNegativeButton(getString(R.string.reader_alert_dialog_button_cancel)) { dialog, which -> } alertDialogBuilder.create().show() editText.requestFocus() } private fun getBookmarkTitle(page: Int): String { val bookmarks = viewModel.bookmarkHandler.getBookmarks() for (bookmark in bookmarks) { if (bookmark.pageNum == page) { return bookmark.title } } return "" } private fun showDeleteBookmarkDialog() { val alertDialogBuilder = AlertDialog.Builder(this) alertDialogBuilder.setTitle(getString(R.string.reader_alert_dialog_title_delete_bookmark)) val bookmarkTitle = getBookmarkTitle(viewModel.pdfInfoHandler.getCurrentPage()) val message = String.format(getString(R.string.reader_alert_dialog_message_delete_bookmark), bookmarkTitle) alertDialogBuilder.setMessage(message) alertDialogBuilder.setPositiveButton(getString(R.string.reader_alert_dialog_button_confirm)) { dialog, which -> viewModel.deleteBookmark() updateBookmarkView() } alertDialogBuilder.setNegativeButton(getString(R.string.reader_alert_dialog_button_cancel)) { dialog, which -> } alertDialogBuilder.create().show() } private fun hideSearchViewSoftKeyboard() { val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0) if (view is SearchView) { view.hideSoftKeyboard() } } private fun setupLeftToolbar() { viewGroup_readerActivity_leftToolbar.setScroll(false) setLeftToolbarWidth(w_240) viewGroup_readerActivity_leftToolbar.smoothScrollTo(w_240, 0, 0) val child = layoutInflater.inflate(R.layout.view_thumbnail, null) linearLayout_readerActivity_leftToolbarContainer.addView(child) fun onClickLeftToolbarItem(leftToolbarType: ReaderViewModel.LeftToolbarType) { viewModel.setLeftToolbarType(leftToolbarType) updateLeftToolbarOpenState(leftToolbarType) } iv_readerActivity_thumbnail.setOnClickListener { onClickLeftToolbarItem(ReaderViewModel.LeftToolbarType.THUMBNAIL) } iv_readerActivity_bookmark.setOnClickListener { onClickLeftToolbarItem(ReaderViewModel.LeftToolbarType.BOOKMARK) } iv_readerActivity_outline.setOnClickListener { onClickLeftToolbarItem(ReaderViewModel.LeftToolbarType.OUTLINE) } iv_readerActivity_search.setOnClickListener { onClickLeftToolbarItem(ReaderViewModel.LeftToolbarType.SEARCH) } } private val readerSettingListener = object : ReaderSettingListener { override fun onReadModeChanged(readMode: Int) { viewModel.readMode = when (readMode) { ReadingModeSelectView.modeDay -> ReaderViewModel.ReadMode.READ_MODE_DAY ReadingModeSelectView.modeNight -> ReaderViewModel.ReadMode.READ_MODE_NIGHT ReadingModeSelectView.modeLilac -> ReaderViewModel.ReadMode.READ_MODE_SOFT ReadingModeSelectView.modeSefia -> ReaderViewModel.ReadMode.USER_DEFINED else -> ReaderViewModel.ReadMode.READ_MODE_DAY } } override fun onCropModeEnableChanged(enable: Boolean) { viewModel.isCrop = enable val buttons = arrayOf(iv_readerActivity_highLight, iv_readerActivity_strike, iv_readerActivity_underline, iv_readerActivity_ink, ib_readerActivity_bottomToolbarMediaBox) if (enable) { viewModel.stopAnnotationMode() val color = ContextCompat.getColor(baseContext, R.color.reader_right_toolbar_disabled_bg) for (button in buttons) { button.isEnabled = false button.setBackgroundColor(color) } } else { for (button in buttons) { button.isEnabled = true button.setBackgroundDrawable(null) } } } override fun onShowStateBarEnableChanged(enable: Boolean, dialog: Dialog?) { when (enable) { true -> { dialog?.window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) } false -> { dialog?.window?.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) } } } override fun onTurnPageDirectionChanged(direction: Int) { viewModel.viewDirection = when (direction == 0) { true -> ReaderViewModel.ViewDirection.VerticalSinglePageContinues false -> ReaderViewModel.ViewDirection.HorizontalSinglePage } } override fun onShowTurnPageBtnEnableChanged(enable: Boolean) { when (enable) { true -> { ib_readerActivity_bottomToolbarPrevious.visibility = View.VISIBLE ib_readerActivity_bottomToolbarNext.visibility = View.VISIBLE } false -> { ib_readerActivity_bottomToolbarPrevious.visibility = View.GONE ib_readerActivity_bottomToolbarNext.visibility = View.GONE } } } override fun onLockScreenSleepEnableChanged(enable: Boolean) { when (enable) { true -> window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) false -> window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } } override fun onShowCommentToolEnableChanged(enable: Boolean) { } override fun onShowBOTAToolEnableChanged(enable: Boolean) { } } private fun setupRightSideToolbar() { iv_readerActivity_setting.setOnClickListener { val settingDialog = provideReaderSettingDialogFragment() settingDialog.show(supportFragmentManager, FRAGMENT_READER_SETTING_TAG) settingDialog.setReaderSettingListener(readerSettingListener) } } private fun applySetting() { val model = SharePrefsModel(this) readerSettingListener.onReadModeChanged(model.readMode.value ?: 0) readerSettingListener.onShowStateBarEnableChanged(model.isShowStateBarEnable.value ?: false, null) readerSettingListener.onTurnPageDirectionChanged(model.turnPageDirection.value ?: 0) readerSettingListener.onShowTurnPageBtnEnableChanged(model.isShowTurnPageBtnEnable.value ?: false) readerSettingListener.onLockScreenSleepEnableChanged(model.isLockScreenSleepEnable.value ?: false) readerSettingListener.onShowCommentToolEnableChanged(model.isShowCommentToolEnable.value ?: false) readerSettingListener.onShowBOTAToolEnableChanged(model.isShowBOTAToolEnable.value ?: false) } private fun setupBottomToolbar() { ib_readerActivity_bottomToolbarMediaBox.setOnClickListener { mediaBoxView.show() } ib_readerActivity_bottomToolbarViewAll.setOnClickListener { onClickBottomThumb1() } ib_readerActivity_bottomToolbarPrevious.setOnClickListener { val handler = viewModel.pdfInfoHandler val pageIndex = handler.getCurrentPage() val previousPageIndex = Math.max(pageIndex - 1, 0) handler.setCurrentPage(previousPageIndex) } ib_readerActivity_bottomToolbarNext.setOnClickListener { val handler = viewModel.pdfInfoHandler val pageIndex = handler.getCurrentPage() val nextPageIndex = Math.min(pageIndex + 1, handler.getPdfPageCount()) handler.setCurrentPage(nextPageIndex) } ib_readerActivity_bottomToolbarKdanCloud.setOnClickListener { onClickKdanCloud() } ib_readerActivity_bottomToolbarShare.setOnClickListener { onClickShare() } } private fun setupMediaBoxView() { fun showSnackbar(title: String, btnText: String) { snackbarMediaBox = Snackbar.make(mediaBoxView, title, Snackbar.LENGTH_INDEFINITE) .setAction(btnText) { viewModel.clearSelection() mediaBoxView.post { mediaBoxView.show() snackbarMediaBox?.dismiss() snackbarMediaBox = null } } snackbarMediaBox?.setActionTextColor(ContextCompat.getColor(this, R.color.bright_blue)) snackbarMediaBox?.show() } mediaBoxView.apply { onShowListener = Runnable { onMediaBoxShown() snackbarMediaBox?.dismiss() snackbarMediaBox = null } onDismissListener = Runnable { onMediaBoxDismissed() snackbarMediaBox?.dismiss() snackbarMediaBox = null } onClickAddButtonListener = object : MediaBoxView.OnClickHeaderButtonListener { override fun onClickTextBoxAddButton(textBoxTabView: TextBoxTabView) { dismiss(false) viewModel.setTextBoxAttribute(textBoxTabView.getTextBoxAttribute()) showSnackbar(resources.getString(R.string.reader_mediaBox_snakebar_textBox), resources.getString(R.string.reader_mediaBox_snakebar_undo)) } override fun onClickTextBoxStyleApplyButton(textBoxTabView: TextBoxTabView) { dismiss(false) viewModel.setTextBoxAttribute(textBoxTabView.getTextBoxAttribute(), true) } override fun onClickSignatureAddButton(signatureTabView: SignatureTabView) { dismiss(false) viewModel.setSignatureAttribute(signatureTabView.getSignatureAttribute()) showSnackbar(resources.getString(R.string.reader_mediaBox_snakebar_signature), resources.getString(R.string.reader_mediaBox_snakebar_undo)) } override fun onClickStampAddButton(stampTabView: StampTabView) { dismiss(false) viewModel.setStampAttribute(stampTabView.getStampAttribute()) showSnackbar(resources.getString(R.string.reader_mediaBox_snakebar_stamp), resources.getString(R.string.reader_mediaBox_snakebar_undo)) } override fun onClickShapeAddButton(shapeTabView: ShapeTabView) { dismiss(false) viewModel.setShapeAttribute(shapeTabView.getShapeAttribute()) showSnackbar(resources.getString(R.string.reader_mediaBox_snakebar_shape), resources.getString(R.string.reader_mediaBox_snakebar_undo)) } } } } private fun setupRightToolbar() { iv_readerActivity_highLight.apply { setOnClickListener { viewModel.onClickHighlightBtn() } setOnLongClickListener { btn -> viewModel.onLongClickHighlightBtn() val context = this@ReaderActivity AnnotationAttributeWindow(context, true).also { window -> viewModel.highLightAttributeLiveData.value?.let { attr -> window.annotationAttributeView.annotationAttribute = attr } window.annotationAttributeView.onChangeListener = object : AnnotationAttributeView.OnChangeListener { override fun onChange(annotationAttributeView: AnnotationAttributeView) { viewModel.setHighLightAttributes(annotationAttributeView.annotationAttribute) } } val contentView = window.contentView.apply { val w = Utils.makeDropDownMeasureSpec(window.width) val y = Utils.makeDropDownMeasureSpec(window.height) measure(w, y) } val space = resources.getDimension(R.dimen.reader_annotation_property_setting_window_right_toolbar_space) val xOff = (-contentView.measuredWidth - space).toInt() val yOff = -btn.height window.showAsDropDown(btn, xOff, yOff) } return@setOnLongClickListener true } } iv_readerActivity_strike.apply { setOnClickListener { viewModel.onClickStrikeBtn() } setOnLongClickListener { btn -> viewModel.onLongClickStrikeBtn() val context = this@ReaderActivity AnnotationAttributeWindow(context, true).also { window -> viewModel.strikeAttributeLiveData.value?.let { attr -> window.annotationAttributeView.annotationAttribute = attr } window.annotationAttributeView.onChangeListener = object : AnnotationAttributeView.OnChangeListener { override fun onChange(annotationAttributeView: AnnotationAttributeView) { viewModel.setStrikeOutAttributes(annotationAttributeView.annotationAttribute) } } val contentView = window.contentView.apply { val w = Utils.makeDropDownMeasureSpec(window.width) val y = Utils.makeDropDownMeasureSpec(window.height) measure(w, y) } val space = resources.getDimension(R.dimen.reader_annotation_property_setting_window_right_toolbar_space) val xOff = (-contentView.measuredWidth - space).toInt() val yOff = -btn.height window.showAsDropDown(btn, xOff, yOff) } return@setOnLongClickListener true } } iv_readerActivity_underline.apply { setOnClickListener { viewModel.onClickUnderlineBtn() } setOnLongClickListener { btn -> viewModel.onLongClickUnderlineBtn() val context = this@ReaderActivity AnnotationAttributeWindow(context, true).also { window -> viewModel.underLineAttributeLiveData.value?.let { attr -> window.annotationAttributeView.annotationAttribute = attr } window.annotationAttributeView.onChangeListener = object : AnnotationAttributeView.OnChangeListener { override fun onChange(annotationAttributeView: AnnotationAttributeView) { viewModel.setUnderLineAttributes(annotationAttributeView.annotationAttribute) } } val contentView = window.contentView.apply { val w = Utils.makeDropDownMeasureSpec(window.width) val y = Utils.makeDropDownMeasureSpec(window.height) measure(w, y) } val space = resources.getDimension(R.dimen.reader_annotation_property_setting_window_right_toolbar_space) val xOff = (-contentView.measuredWidth - space).toInt() val yOff = -btn.height window.showAsDropDown(btn, xOff, yOff) } return@setOnLongClickListener true } } iv_readerActivity_ink.apply { setOnClickListener { viewModel.onClickInkBtn() } setOnLongClickListener { btn -> viewModel.onLongClickInkBtn() val context = this@ReaderActivity AnnotationAttributeWindow(context, false).also { window -> viewModel.inkAttributeLiveData.value?.let { attr -> window.annotationAttributeView.inkAttribute = attr } window.annotationAttributeView.onChangeListener = object : AnnotationAttributeView.OnChangeListener { override fun onChange(annotationAttributeView: AnnotationAttributeView) { viewModel.setInkAttributes(annotationAttributeView.inkAttribute) } } val contentView = window.contentView.apply { val w = Utils.makeDropDownMeasureSpec(window.width) val y = Utils.makeDropDownMeasureSpec(window.height) measure(w, y) } val space = resources.getDimension(R.dimen.reader_annotation_property_setting_window_right_toolbar_space) val xOff = (-contentView.measuredWidth - space).toInt() val yOff = -contentView.measuredHeight window.showAsDropDown(btn, xOff, yOff) } return@setOnLongClickListener true } } } private fun setLeftToolbarWidth(width: Int) { var params = viewGroup_readerActivity_leftToolbar.layoutParams as ConstraintLayout.LayoutParams params.width = width + w_left params.height = 0 viewGroup_readerActivity_leftToolbar.layoutParams = params params = linearLayout_readerActivity_leftToolbarContainer.layoutParams as ConstraintLayout.LayoutParams params.width = width linearLayout_readerActivity_leftToolbarContainer.layoutParams = params } private fun updateLeftToolbarOpenState(type: ReaderViewModel.LeftToolbarType) { val isLeftToolbarOpen = viewModel.isLeftToolbarOpenLiveData.value ?: false viewModel.setIsLeftToolbarOpen(!isLeftToolbarOpen || oldLeftToolbarType != type) cloneOriginConstraintSet() } private fun onMediaBoxShown() { hideAllToolbars() isHideToolbar = true } private fun onMediaBoxDismissed() { showAllToolbars() isHideToolbar = false viewModel.clearSelection() } private fun setLeftToolbarContentView(leftToolbarType: ReaderViewModel.LeftToolbarType) { if (oldLeftToolbarType != leftToolbarType) { linearLayout_readerActivity_leftToolbarContainer.removeAllViews() val view = when (leftToolbarType) { ReaderViewModel.LeftToolbarType.NONE, ReaderViewModel.LeftToolbarType.THUMBNAIL -> { val thumbnailView = ThumbnailView(this) thumbnailView.setHandlers(viewModel.pdfInfoHandler, viewModel.thumbnailHandler) thumbnailView } ReaderViewModel.LeftToolbarType.BOOKMARK -> { val bookmarkView = BookmarkView(this) bookmarkView.setHandlers(viewModel.pdfInfoHandler, viewModel.thumbnailHandler, viewModel.bookmarkHandler) bookmarkView } ReaderViewModel.LeftToolbarType.OUTLINE -> { val outlineView = OutlineView(this) outlineView.setHandlers(viewModel.pdfInfoHandler, viewModel.outlineHandler) outlineView } ReaderViewModel.LeftToolbarType.SEARCH -> { val searchView = SearchView(this) searchView.setHandlers(viewModel.pdfInfoHandler, viewModel.searchHandler) searchView } } linearLayout_readerActivity_leftToolbarContainer.addView(view as View) oldLeftToolbarType = leftToolbarType } } private fun getLeftToolbarContentWidth(): Int { return when (viewModel.leftToolbarTypeLiveData.value == ReaderViewModel.LeftToolbarType.THUMBNAIL) { true -> w_240 false -> w_318 } } private fun onLeftToolbarTypeChanged(leftToolbarType: ReaderViewModel.LeftToolbarType?) { updateLeftToolbarIcons() setLeftToolbarWidth(getLeftToolbarContentWidth()) cloneOriginConstraintSet() if (leftToolbarType != null) { setLeftToolbarContentView(leftToolbarType) } } private fun onLeftToolbarOpenStateChanged(open: Boolean?) { updateLeftToolbarIcons() when (open == true) { true -> viewGroup_readerActivity_leftToolbar.smoothScrollTo(0, 0, UI_ANIMATION_DURATION.toInt()) false -> viewGroup_readerActivity_leftToolbar.smoothScrollTo(getLeftToolbarContentWidth(), 0, UI_ANIMATION_DURATION.toInt()) } } private fun updateLeftToolbarIcons() { iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_left_toolbar_thumbnails) iv_readerActivity_bookmark.setImageResource(R.drawable.ic_left_toolbar_bookmarks) iv_readerActivity_outline.setImageResource(R.drawable.ic_left_toolbar_outline) iv_readerActivity_search.setImageResource(R.drawable.ic_left_toolbar_search) if (viewModel.isLeftToolbarOpenLiveData.value == true) { when (viewModel.leftToolbarTypeLiveData.value) { ReaderViewModel.LeftToolbarType.NONE -> {} ReaderViewModel.LeftToolbarType.THUMBNAIL -> iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_left_toolbar_thumbnails_selected) ReaderViewModel.LeftToolbarType.BOOKMARK -> iv_readerActivity_bookmark.setImageResource(R.drawable.ic_left_toolbar_bookmarks_selected) ReaderViewModel.LeftToolbarType.OUTLINE -> iv_readerActivity_outline.setImageResource(R.drawable.ic_left_toolbar_outline_selected) ReaderViewModel.LeftToolbarType.SEARCH -> iv_readerActivity_search.setImageResource(R.drawable.ic_left_toolbar_search_selected) } } } private fun onClickBottomThumb1() { val intent = transferThumbIntent() startActivityForResult(intent, THUMB) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK){ when (requestCode) { THUMB -> { val mode = data?.getIntExtra("operate", -1) when (mode) { PdfThumbActivity.THUMB_NORMAL -> { val pageIndex = data.getIntExtra("result", 0) viewModel.pdfInfoHandler.setCurrentPage(pageIndex) viewModel.setPageIndex(pageIndex) } } } REQUEST_PASSWORD -> { val password = data?.getStringExtra("password") ?: "" if (password.isEmpty()) { finish() } else { viewModel.isOpenedFileLiveData.value?.also { isOpened -> if (isOpened) return@also val filePath = intent.getStringExtra(KEY_FILE_ABSOLUTE) val uri = Uri.parse(filePath) viewModel.openPdfFile(this, uri, password, Runnable { requestPassword(true) }, intent.type) } } } } } } }