Преглед на файлове

Merge branch 'master' into f-annotation and fixed some strings

# Conflicts:
#	reader/src/main/java/com/kdanmobile/reader/ReaderActivity.kt
#	reader/src/main/java/com/kdanmobile/reader/ReaderViewModel.kt
#	reader/src/main/res/values-de/strings.xml
#	reader/src/main/res/values-es/strings.xml
#	reader/src/main/res/values-fr/strings.xml
#	reader/src/main/res/values-it/strings.xml
#	reader/src/main/res/values-ja/strings.xml
#	reader/src/main/res/values-ko/strings.xml
#	reader/src/main/res/values-pt/strings.xml
#	reader/src/main/res/values-ru/strings.xml
#	reader/src/main/res/values-zh-rTW/strings.xml
#	reader/src/main/res/values-zh/strings.xml
#	reader/src/main/res/values/dimens.xml
#	reader/src/main/res/values/strings.xml
Wayne преди 5 години
родител
ревизия
419d9d7d84
променени са 98 файла, в които са добавени 3893 реда и са изтрити 34 реда
  1. 20 3
      app/src/main/java/com/kdanmobile/pdfreaderviewapp/MyReaderActivity.kt
  2. BIN
      app/src/main/jniLibs/armeabi-v7a/libkmpdf.so
  3. BIN
      app/src/main/jniLibs/armeabi/libkmpdf.so
  4. BIN
      app/src/main/jniLibs/mips/libkmpdf.so
  5. BIN
      app/src/main/jniLibs/x86/libkmpdf.so
  6. 6 1
      reader/build.gradle
  7. BIN
      reader/libs/kmpdfkit-1.0.7.aar
  8. 4 2
      reader/src/main/AndroidManifest.xml
  9. 358 14
      reader/src/main/java/com/kdanmobile/reader/ReaderActivity.kt
  10. 104 0
      reader/src/main/java/com/kdanmobile/reader/ReaderViewModel.kt
  11. 7 4
      reader/src/main/java/com/kdanmobile/reader/Utils.kt
  12. 144 0
      reader/src/main/java/com/kdanmobile/reader/screen/ViewerSettingActivity.kt
  13. 65 0
      reader/src/main/java/com/kdanmobile/reader/screen/ViewerSettingViewModel.kt
  14. 11 0
      reader/src/main/java/com/kdanmobile/reader/screen/ViewerSettingViewModelFactory.kt
  15. 115 0
      reader/src/main/java/com/kdanmobile/reader/screen/adapter/BookmarkAdapter.kt
  16. 59 0
      reader/src/main/java/com/kdanmobile/reader/screen/adapter/OutlineAdapter.kt
  17. 83 0
      reader/src/main/java/com/kdanmobile/reader/screen/adapter/SearchAdapter.kt
  18. 138 0
      reader/src/main/java/com/kdanmobile/reader/screen/adapter/ThumbnailAdapter.kt
  19. 83 0
      reader/src/main/java/com/kdanmobile/reader/screen/data/ViewerSettingSharePrefs.kt
  20. 8 0
      reader/src/main/java/com/kdanmobile/reader/screen/handler/BookmarkHandler.kt
  21. 8 0
      reader/src/main/java/com/kdanmobile/reader/screen/handler/OutlineHandler.kt
  22. 16 0
      reader/src/main/java/com/kdanmobile/reader/screen/handler/PdfInfoHandler.kt
  23. 14 0
      reader/src/main/java/com/kdanmobile/reader/screen/handler/SearchHandler.kt
  24. 17 0
      reader/src/main/java/com/kdanmobile/reader/screen/handler/ThumbnailHandler.kt
  25. 33 0
      reader/src/main/java/com/kdanmobile/reader/screen/model/SearchResultInfo.kt
  26. 17 0
      reader/src/main/java/com/kdanmobile/reader/screen/model/SearchTaskResult.kt
  27. 103 0
      reader/src/main/java/com/kdanmobile/reader/screen/model/SharePrefsModel.kt
  28. 26 0
      reader/src/main/java/com/kdanmobile/reader/screen/model/SimpleTextWatcher.kt
  29. 82 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/BookmarkView.kt
  30. 71 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/OutlineView.kt
  31. 97 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/ReadingModeSelectView.kt
  32. 51 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/RowSwitchView.kt
  33. 39 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/ScreenSettingView.kt
  34. 373 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/SearchView.kt
  35. 73 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/ThumbnailView.kt
  36. 51 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/ToolbarSettingView.kt
  37. 66 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/TurnPageModeSelectView.kt
  38. 294 0
      reader/src/main/java/com/kdanmobile/reader/utils/AnimationUtil.kt
  39. 46 0
      reader/src/main/java/com/kdanmobile/reader/utils/DensityUtil.kt
  40. 55 0
      reader/src/main/java/com/kdanmobile/reader/widget/drag/OnRecyclerItemClickListener.kt
  41. BIN
      reader/src/main/res/drawable-hdpi/ic_format_pdf_48dp.png
  42. BIN
      reader/src/main/res/drawable-hdpi/ic_stat_lock.png
  43. BIN
      reader/src/main/res/drawable-hdpi/ic_textfield_search.png
  44. BIN
      reader/src/main/res/drawable-hdpi/icon_line.webp
  45. BIN
      reader/src/main/res/drawable-xhdpi/ic_stat_lock.png
  46. BIN
      reader/src/main/res/drawable-xhdpi/ic_textfield_search.png
  47. BIN
      reader/src/main/res/drawable-xhdpi/icon_line.webp
  48. BIN
      reader/src/main/res/drawable-xxhdpi/ic_format_pdf_48dp.png
  49. BIN
      reader/src/main/res/drawable-xxhdpi/ic_stat_lock.png
  50. BIN
      reader/src/main/res/drawable/ic_stat_lock.png
  51. 7 0
      reader/src/main/res/drawable/rectangle_0000.xml
  52. 7 0
      reader/src/main/res/drawable/rectangle_6633b5e5.xml
  53. 11 0
      reader/src/main/res/drawable/rectangle_stroke_1_aaa_ffff.xml
  54. 11 0
      reader/src/main/res/drawable/rectangle_stroke_1_d5d5d5_ffff.xml
  55. 11 0
      reader/src/main/res/drawable/rectangle_stroke_4dp_33b5e5_0000.xml
  56. 8 0
      reader/src/main/res/drawable/selector_day_mode.xml
  57. 8 0
      reader/src/main/res/drawable/selector_edittext.xml
  58. 8 0
      reader/src/main/res/drawable/selector_lilac_mode.xml
  59. 8 0
      reader/src/main/res/drawable/selector_listview_item.xml
  60. 8 0
      reader/src/main/res/drawable/selector_night_mode.xml
  61. 8 0
      reader/src/main/res/drawable/selector_sefia_mode.xml
  62. 9 0
      reader/src/main/res/drawable/shape_day_mode.xml
  63. 9 0
      reader/src/main/res/drawable/shape_day_mode_checked.xml
  64. 9 0
      reader/src/main/res/drawable/shape_night_mode.xml
  65. 9 0
      reader/src/main/res/drawable/shape_night_mode_checked.xml
  66. 9 0
      reader/src/main/res/drawable/shape_sepia_mode.xml
  67. 9 0
      reader/src/main/res/drawable/shape_sepia_mode_checked.xml
  68. 9 0
      reader/src/main/res/drawable/shape_white_lilac_mode.xml
  69. 9 0
      reader/src/main/res/drawable/shape_white_lilac_mode_checked.xml
  70. 17 9
      reader/src/main/res/layout/activity_reader.xml
  71. 79 0
      reader/src/main/res/layout/activity_viewer_setting.xml
  72. 49 0
      reader/src/main/res/layout/item_bookmark.xml
  73. 46 0
      reader/src/main/res/layout/item_search.xml
  74. 36 0
      reader/src/main/res/layout/item_thumbnail.xml
  75. 45 0
      reader/src/main/res/layout/outline_entry.xml
  76. 32 0
      reader/src/main/res/layout/view_bookmark.xml
  77. 34 0
      reader/src/main/res/layout/view_outline.xml
  78. 88 0
      reader/src/main/res/layout/view_reading_mode_select.xml
  79. 29 0
      reader/src/main/res/layout/view_row_switch.xml
  80. 27 0
      reader/src/main/res/layout/view_screen_setting.xml
  81. 89 0
      reader/src/main/res/layout/view_search.xml
  82. 35 0
      reader/src/main/res/layout/view_thumbnail.xml
  83. 36 0
      reader/src/main/res/layout/view_toolbar_setting.xml
  84. 52 0
      reader/src/main/res/layout/view_turn_page_mode_select.xml
  85. 6 0
      reader/src/main/res/menu/reader_more.xml
  86. 25 0
      reader/src/main/res/values-de/strings.xml
  87. 24 0
      reader/src/main/res/values-es/strings.xml
  88. 24 0
      reader/src/main/res/values-fr/strings.xml
  89. 24 0
      reader/src/main/res/values-it/strings.xml
  90. 23 0
      reader/src/main/res/values-ja/strings.xml
  91. 24 0
      reader/src/main/res/values-ko/strings.xml
  92. 24 0
      reader/src/main/res/values-pt/strings.xml
  93. 24 0
      reader/src/main/res/values-ru/strings.xml
  94. 24 0
      reader/src/main/res/values-zh-rTW/strings.xml
  95. 24 0
      reader/src/main/res/values-zh/strings.xml
  96. 9 0
      reader/src/main/res/values/attrs.xml
  97. 3 1
      reader/src/main/res/values/dimens.xml
  98. 37 0
      reader/src/main/res/values/strings.xml

+ 20 - 3
app/src/main/java/com/kdanmobile/pdfreaderviewapp/MyReaderActivity.kt

@@ -1,12 +1,29 @@
 package com.kdanmobile.pdfreaderviewapp
 
-import android.content.Context
-import android.support.v7.app.AppCompatActivity
 import android.os.Bundle
 import com.kdanmobile.reader.ReaderActivity
-import java.io.File
 
 class MyReaderActivity : ReaderActivity() {
+    override fun onClickUserGuide() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun onClickPrint() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun onClickFileInfo() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun onClickTextReflow() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun onClickShare() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
     companion object {
         val KEY_FILE_ABSOLUTE = ReaderActivity.KEY_FILE_ABSOLUTE
     }

BIN
app/src/main/jniLibs/armeabi-v7a/libkmpdf.so


BIN
app/src/main/jniLibs/armeabi/libkmpdf.so


BIN
app/src/main/jniLibs/mips/libkmpdf.so


BIN
app/src/main/jniLibs/x86/libkmpdf.so


+ 6 - 1
reader/build.gradle

@@ -33,13 +33,18 @@ dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
 
     implementation 'com.android.support:appcompat-v7:28.0.0'
+    implementation 'com.android.support:design:28.0.0'
+    implementation 'com.android.support:cardview-v7:28.0.0'
+    implementation 'com.android.support:recyclerview-v7:28.0.0'
     implementation 'com.android.support.constraint:constraint-layout:1.1.3'
     implementation "android.arch.lifecycle:extensions:$lifecycleVersion"
     implementation "android.arch.lifecycle:common-java8:$lifecycleVersion"
     androidTestImplementation 'com.android.support.test:runner:1.0.2'
     androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+    api 'io.reactivex.rxjava2:rxandroid:2.1.0'
+    api 'io.reactivex.rxjava2:rxjava:2.2.2'
 
     testImplementation 'junit:junit:4.12'
 
-    api(name: 'kmpdfkit-1.0.7', ext: 'aar')
+    api(name: 'kmpdfkit-1.0.8', ext: 'aar')
 }

BIN
reader/libs/kmpdfkit-1.0.7.aar


+ 4 - 2
reader/src/main/AndroidManifest.xml

@@ -5,8 +5,10 @@
     <application>
         <activity
             android:name=".ReaderActivity"
-            android:theme="@style/ReaderActivityNoActionBarNoTitle"
-            />
+            android:theme="@style/ReaderActivityNoActionBarNoTitle" />
+        <activity
+            android:name=".screen.ViewerSettingActivity"
+            android:theme="@style/ReaderActivityNoActionBarNoTitle" />
     </application>
 
 </manifest>

+ 358 - 14
reader/src/main/java/com/kdanmobile/reader/ReaderActivity.kt

@@ -3,21 +3,45 @@ package com.kdanmobile.reader
 import android.annotation.SuppressLint
 import android.arch.lifecycle.Observer
 import android.arch.lifecycle.ViewModelProviders
+import android.content.Intent
 import android.net.Uri
 import android.os.Build
 import android.support.v7.app.AppCompatActivity
 import android.os.Bundle
+import android.support.constraint.ConstraintLayout
 import android.support.constraint.ConstraintSet
-import android.view.*
 import android.widget.Toast
 import com.kdanmobile.kmpdfkit.pdfcommon.KMPDFReaderView
 import com.kdanmobile.reader.Utils.applyConstraintSet
 import com.kdanmobile.reader.view.AnnotationPropertySettingView
 import com.kdanmobile.reader.view.AnnotationPropertySettingWindow
+import android.support.v4.content.ContextCompat
+import android.support.v7.app.AlertDialog
+import android.view.Menu
+import android.view.MenuItem
+import android.util.DisplayMetrics
+import android.view.MotionEvent
+import android.view.View
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.kdanmobile.reader.screen.view.BookmarkView
+import com.kdanmobile.reader.screen.view.OutlineView
+import com.kdanmobile.reader.screen.view.SearchView
+import com.kdanmobile.reader.screen.view.ThumbnailView
+import com.kdanmobile.reader.utils.AnimationUtil
+import com.kdanmobile.reader.utils.DensityUtil
+import com.kdanmobile.reader.screen.ViewerSettingActivity
 import kotlinx.android.synthetic.main.activity_reader.*
 import kotlin.Exception
 
-open class ReaderActivity : AppCompatActivity() {
+abstract class ReaderActivity : AppCompatActivity() {
+
+    abstract fun onClickShare()
+    abstract fun onClickTextReflow()
+    abstract fun onClickFileInfo()
+    abstract fun onClickPrint()
+    abstract fun onClickUserGuide()
 
     companion object {
         const val KEY_FILE_ABSOLUTE = "file_absolutepath"
@@ -29,12 +53,37 @@ open class ReaderActivity : AppCompatActivity() {
     private var isHideToolbar = false
     private lateinit var originConstraintSet: ConstraintSet
 
+    private var menuItemBookmark: MenuItem? = null
+
+    private val UI_ANIMATION_DURATION = 300L
+
+    private var w_318: Int = 0
+    private var w_240: Int = 0
+    private var w_left: Int = 0
+
+    private var isLeftToolbarOpen = false
+
+    enum class LeftToolbarType {
+        NONE, THUMBNAIL, BOOKMARK, OUTLINE, SEARCH
+    }
+    private var leftToolbarType = LeftToolbarType.NONE
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_reader)
         setSupportActionBar(toolbar_readerActivity)
 
+        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()
 
         val factory = ReaderViewModelFactory()
@@ -54,10 +103,13 @@ open class ReaderActivity : AppCompatActivity() {
             viewModel.openPdfFile(this, uri, intent.type)
         }
         setupRightToolbar()
+        viewModel.pageIndexLiveData.observe(this, Observer(this::onPageIndexChanged))
+        viewModel.isPageInBookmarksLiveData.observe(this, Observer(this::onIsPageInBookmarksChanged))
     }
 
     override fun onCreateOptionsMenu(menu: Menu?): Boolean {
         menuInflater.inflate(R.menu.reader_more, menu)
+        menuItemBookmark = menu?.findItem(R.id.item_reader_bookmark)
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
             menu?.findItem(R.id.item_reader_more_print)?.isVisible = false
         }
@@ -90,8 +142,10 @@ open class ReaderActivity : AppCompatActivity() {
     }
 
     private fun cloneOriginConstraintSet() {
-        originConstraintSet = ConstraintSet().apply {
-            clone(constrainLayout_readerActivity_root)
+        if (!isBelowKitkat()) {
+            originConstraintSet = ConstraintSet().apply {
+                clone(constrainLayout_readerActivity_root)
+            }
         }
     }
 
@@ -154,38 +208,204 @@ open class ReaderActivity : AppCompatActivity() {
 
             override fun onTapMainDocArea() {
                 super.onTapMainDocArea()
+                if (isBelowKitkat()) {
+                    isHideToolbar = toolbar_readerActivity.visibility != View.VISIBLE
+                            || viewGroup_readerActivity_bottomToolbar.visibility != View.VISIBLE
+                            || viewGroup_readerActivity_leftToolbar.visibility != View.VISIBLE
+                            || viewGroup_readerActivity_rightToolbar.visibility != View.VISIBLE
+                }
                 when (isHideToolbar) {
                     true -> showAllToolbars()
                     false -> hideAllToolbars()
                 }
                 isHideToolbar = !isHideToolbar
             }
+
+            override fun onMoveToChild(p0: Int) {
+                super.onMoveToChild(p0)
+                viewModel.setPageIndex(p0)
+                updateThumbnailViewSelectedPage()
+            }
+
+            override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
+                if (isBelowKitkat()) {
+                    isHideToolbar = toolbar_readerActivity.visibility != View.VISIBLE
+                            || viewGroup_readerActivity_bottomToolbar.visibility != View.VISIBLE
+                            || viewGroup_readerActivity_leftToolbar.visibility != View.VISIBLE
+                            || viewGroup_readerActivity_rightToolbar.visibility != View.VISIBLE
+                }
+                if (!isHideToolbar) {
+                    hideAllToolbars()
+                    isHideToolbar = false
+                }
+                return super.onScroll(e1, e2, distanceX, distanceY)
+            }
         }
         viewModel.setReaderView(readerView)
         container.addView(readerView)
     }
 
+    private fun onPageIndexChanged(pageIndex: Int?) {
+        pageIndex?.let {
+            viewModel.setBookmarkDisplay(pageIndex)
+        }
+    }
+
+    private fun onIsPageInBookmarksChanged(isPageInBookmarks: Boolean?) {
+        isPageInBookmarks?.let {
+            if (it) {
+                menuItemBookmark?.icon = ContextCompat.getDrawable(this, R.drawable.ic_bookmark)
+            } 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 (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
-            // TODO : Implement show toolbars on Android api level < 19 devices
+        if (isBelowKitkat()) {
+            AnimationUtil.showViewFromTopToBottom(toolbar_readerActivity, UI_ANIMATION_DURATION)
+            AnimationUtil.showViewFromBottomToTop(viewGroup_readerActivity_bottomToolbar, UI_ANIMATION_DURATION)
+            AnimationUtil.showViewFromLeftToRight(viewGroup_readerActivity_leftToolbar, UI_ANIMATION_DURATION)
+            AnimationUtil.showViewFromRightToLeft(viewGroup_readerActivity_rightToolbar, UI_ANIMATION_DURATION)
         } else {
-            constrainLayout_readerActivity_root.applyConstraintSet(originConstraintSet)
+            constrainLayout_readerActivity_root.applyConstraintSet(originConstraintSet, UI_ANIMATION_DURATION)
         }
     }
 
     private fun hideAllToolbars() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
-            // TODO : Implement hide toolbars on Android api level < 19 devices
+        if (isBelowKitkat()) {
+            AnimationUtil.hideViewFromBottomToTop(toolbar_readerActivity, UI_ANIMATION_DURATION)
+            AnimationUtil.hideViewFromTopToBottom(viewGroup_readerActivity_bottomToolbar, UI_ANIMATION_DURATION)
+            AnimationUtil.hideViewFromRightToLeft(viewGroup_readerActivity_leftToolbar, UI_ANIMATION_DURATION)
+            AnimationUtil.hideViewFromLeftToRight(viewGroup_readerActivity_rightToolbar, UI_ANIMATION_DURATION)
+            hideSearchViewSoftKeyboard()
         } else {
-            constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_all)
+            constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_all, UI_ANIMATION_DURATION)
         }
     }
 
     private fun hideTopLeftBottomToolbars() {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
-            // TODO : Implement hide toolbars on Android api level < 19 devices
+        if (isBelowKitkat()) {
+            AnimationUtil.hideViewFromBottomToTop(toolbar_readerActivity, UI_ANIMATION_DURATION)
+            AnimationUtil.hideViewFromTopToBottom(viewGroup_readerActivity_bottomToolbar, UI_ANIMATION_DURATION)
+            AnimationUtil.hideViewFromRightToLeft(viewGroup_readerActivity_leftToolbar, UI_ANIMATION_DURATION)
+            hideSearchViewSoftKeyboard()
         } else {
-            constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_top_left_bottom)
+            constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_top_left_bottom, UI_ANIMATION_DURATION)
+        }
+    }
+
+    private fun updateThumbnailViewSelectedPage() {
+        val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0)
+        if (view is ThumbnailView) {
+            val currentPage = viewModel.pdfInfoHandler.getCurrentPage()
+            view.onScrollToPosition(currentPage, true)
+        }
+    }
+
+    private fun updateBookmarkView() {
+        val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0)
+        if (view is BookmarkView) {
+            view.updateBookmark()
+        }
+    }
+
+    private fun setupToolbar() {
+        toolbar_readerActivity.setOnMenuItemClickListener {
+            when (it.itemId) {
+                R.id.item_reader_bookmark -> onClickBookmark()
+                R.id.item_reader_more_share -> onClickShare()
+                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)
+        cloneOriginConstraintSet()
+    }
+
+    private fun setupRightSideToolbar() {
+        iv_readerActivity_setting.setOnClickListener {
+            startActivity(Intent(this, ViewerSettingActivity::class.java))
         }
     }
 
@@ -269,7 +489,7 @@ open class ReaderActivity : AppCompatActivity() {
                 viewModel.onLongClickUnderlineBtn()
                 val context = this@ReaderActivity
                 AnnotationPropertySettingWindow(context, true).also { window ->
-                    viewModel.underLineAttributeLiveData.value?.let {  attr ->
+                    viewModel.underLineAttributeLiveData.value?.let { attr ->
                         window.annotationPropertySettingView.color = attr.color
                         window.annotationPropertySettingView.alpha = attr.alpha
                     }
@@ -326,4 +546,128 @@ open class ReaderActivity : AppCompatActivity() {
             }
         }
     }
+
+
+    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 changeLeftToolbarType(type: LeftToolbarType) {
+        iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_pagelist_thumbnail_nor)
+        iv_readerActivity_bookmark.setImageResource(R.drawable.ic_pagelist_bookmk_nor)
+        iv_readerActivity_outline.setImageResource(R.drawable.ic_pagelist_outline_nor)
+        iv_readerActivity_search.setImageResource(R.drawable.ic_pagelist_search_nor)
+
+        val width = when (type) {
+            LeftToolbarType.THUMBNAIL -> w_240
+            else -> w_318
+        }
+        setLeftToolbarWidth(width)
+
+        isLeftToolbarOpen = (!isLeftToolbarOpen || leftToolbarType != type)
+        if (isLeftToolbarOpen)
+            viewGroup_readerActivity_leftToolbar.smoothScrollTo(0, 0, UI_ANIMATION_DURATION.toInt())
+        else
+            viewGroup_readerActivity_leftToolbar.smoothScrollTo(width, 0, UI_ANIMATION_DURATION.toInt())
+        cloneOriginConstraintSet()
+    }
+
+    private fun onThumbnailClick() {
+        val type = LeftToolbarType.THUMBNAIL
+        changeLeftToolbarType(type)
+        if (isLeftToolbarOpen) {
+            if (leftToolbarType != type) {
+                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
+                val thumbnailView = ThumbnailView(this)
+                thumbnailView.setHandlers(viewModel.pdfInfoHandler, viewModel.thumbnailHandler)
+                linearLayout_readerActivity_leftToolbarContainer.addView(thumbnailView)
+            }
+            iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_pagelist_thumbnail_h)
+        } else {
+            iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_pagelist_thumbnail_nor)
+        }
+        leftToolbarType = type
+    }
+
+    private fun onBookmarkClick() {
+        val type = LeftToolbarType.BOOKMARK
+        changeLeftToolbarType(type)
+        if (isLeftToolbarOpen) {
+            if (leftToolbarType != type) {
+                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
+                val bookmarkView = BookmarkView(this)
+                bookmarkView.setHandlers(viewModel.pdfInfoHandler, viewModel.thumbnailHandler, viewModel.bookmarkHandler)
+                linearLayout_readerActivity_leftToolbarContainer.addView(bookmarkView)
+            }
+            iv_readerActivity_bookmark.setImageResource(R.drawable.ic_pagelist_bookmk_h)
+        } else {
+            iv_readerActivity_bookmark.setImageResource(R.drawable.ic_pagelist_bookmk_nor)
+        }
+        leftToolbarType = type
+    }
+
+    private fun onOutlineClick() {
+        val type = LeftToolbarType.OUTLINE
+        changeLeftToolbarType(type)
+        if (isLeftToolbarOpen) {
+            if (leftToolbarType != type) {
+                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
+                val outlineView = OutlineView(this)
+                outlineView.setHandlers(viewModel.pdfInfoHandler, viewModel.outlineHandler)
+                linearLayout_readerActivity_leftToolbarContainer.addView(outlineView)
+            }
+            iv_readerActivity_outline.setImageResource(R.drawable.ic_pagelist_outline_h)
+        } else {
+            iv_readerActivity_outline.setImageResource(R.drawable.ic_pagelist_outline_nor)
+        }
+        leftToolbarType = type
+    }
+
+    private fun onSearchClick() {
+        val type = LeftToolbarType.SEARCH
+        changeLeftToolbarType(type)
+        if (isLeftToolbarOpen) {
+            if (leftToolbarType != type) {
+                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
+                val searchView = SearchView(this)
+                searchView.setHandlers(viewModel.pdfInfoHandler, viewModel.searchHandler)
+                linearLayout_readerActivity_leftToolbarContainer.addView(searchView)
+            }
+            iv_readerActivity_search.setImageResource(R.drawable.ic_pagelist_search_h)
+        } else {
+            iv_readerActivity_search.setImageResource(R.drawable.ic_pagelist_search_nor)
+            hideSearchViewSoftKeyboard()
+        }
+        leftToolbarType = type
+    }
+
+    fun onClick(view: View) {
+        when (view.id) {
+            R.id.iv_readerActivity_thumbnail -> {
+                onThumbnailClick()
+            }
+            R.id.iv_readerActivity_bookmark -> {
+                onBookmarkClick()
+            }
+            R.id.iv_readerActivity_outline -> {
+                onOutlineClick()
+            }
+            R.id.iv_readerActivity_search -> {
+                onSearchClick()
+            }
+            R.id.iv_readerActivity_fullScreen -> {
+                hideTopLeftBottomToolbars()
+            }
+            else -> {
+
+            }
+        }
+    }
 }

+ 104 - 0
reader/src/main/java/com/kdanmobile/reader/ReaderViewModel.kt

@@ -1,9 +1,12 @@
 package com.kdanmobile.reader
 
+import android.arch.lifecycle.LiveData
 import android.arch.lifecycle.MutableLiveData
 import android.arch.lifecycle.ViewModel
 import android.content.Context
 import android.graphics.Color
+import android.graphics.Bitmap
+import android.graphics.RectF
 import android.net.Uri
 import com.kdanmobile.kmpdfkit.annotation.bean.*
 import com.kdanmobile.kmpdfkit.globaldata.Config
@@ -12,6 +15,8 @@ import com.kdanmobile.kmpdfkit.manager.controller.KMPDFDocumentController
 import com.kdanmobile.kmpdfkit.pdfcommon.KMPDFReaderView
 import com.kdanmobile.reader.annotationattribute.AnnotationAttribute
 import com.kdanmobile.reader.annotationattribute.InkAttribute
+import com.kdanmobile.kmpdfkit.pdfcommon.*
+import com.kdanmobile.reader.screen.handler.*
 
 class ReaderViewModel(private val pdfSdkLicense: String, private val pdfSdkRsaMsg: String) : ViewModel() {
 
@@ -73,6 +78,14 @@ class ReaderViewModel(private val pdfSdkLicense: String, private val pdfSdkRsaMs
     val annotationModeLiveData = MutableLiveData<AnnotationMode>().apply { value = AnnotationMode.None }
     var isCopyModeLiveData = MutableLiveData<Boolean>().apply { value = false }
 
+    val pageIndexLiveData: LiveData<Int>
+        get() = mPageIndexLiveData
+    val isPageInBookmarksLiveData: LiveData<Boolean>
+        get() = mIsPageInBookmarksLiveData
+
+    private val mPageIndexLiveData = MutableLiveData<Int>().apply { value = 0 }
+    private val mIsPageInBookmarksLiveData = MutableLiveData<Boolean>().apply { value = false }
+
     @JvmOverloads
     fun openPdfFile(context: Context, uri: Uri, type: String? = null): Boolean {
         if (!isVerified) {
@@ -254,6 +267,39 @@ class ReaderViewModel(private val pdfSdkLicense: String, private val pdfSdkRsaMs
         updateViewDirection()
     }
 
+    fun setPageIndex(pageIndex: Int){
+        mPageIndexLiveData.value = pageIndex
+    }
+
+    fun addBookmark(title: String) {
+        pageIndexLiveData.value?.let {
+            kmpdfDocumentController?.addBookmark(title, it)
+            setBookmarkDisplay(it)
+        }
+    }
+
+    fun deleteBookmark() {
+        pageIndexLiveData.value?.let {
+            kmpdfDocumentController?.deleteBookmarks(it)
+            setBookmarkDisplay(it)
+        }
+    }
+
+    fun setBookmarkDisplay(pageIndex: Int) {
+        kmpdfDocumentController?.let {
+            var isPageInBookmarks = false
+            it.bookmarks?.let {
+                for (bookmark in it) {
+                    if (bookmark.pageNum == pageIndex) {
+                        isPageInBookmarks = true
+                        break
+                    }
+                }
+            }
+            mIsPageInBookmarksLiveData.value = isPageInBookmarks
+        }
+    }
+
     private fun verifyLicense(context: Context): Boolean {
         val errorCode = KMPDFFactory.verifyLicense(context, pdfSdkLicense, pdfSdkRsaMsg)
         return errorCode == 0
@@ -270,4 +316,62 @@ class ReaderViewModel(private val pdfSdkLicense: String, private val pdfSdkRsaMs
             refresh(false)
         }
     }
+
+    val pdfInfoHandler = object : PdfInfoHandler {
+        override fun getOpenPdfFilename(): String {
+            return kmpdfFactory?.fileName ?: ""
+        }
+
+        override fun getPdfPageCount(): Int {
+            return kmpdfDocumentController?.getDocumentPageCount(false) ?: 0
+        }
+
+        override fun getCurrentPage(): Int {
+            return kmpdfDocumentController?.currentPageNum ?: 0
+        }
+
+        override fun setCurrentPage(page: Int): Boolean {
+            return kmpdfDocumentController?.gotoPage(page) ?: false
+        }
+
+        override fun textLines(page: Int): Array<Array<TextWord>> {
+            return kmpdfDocumentController?.textLines(page) ?: arrayOf()
+        }
+    }
+
+    val thumbnailHandler = object : ThumbnailHandler {
+        override fun getPdfBitmap(position: Int, picWidth: Int, mode: Int, isDrawAnnot: Boolean): Bitmap {
+            return kmpdfDocumentController?.covertPDFToBitmap(position, picWidth, mode, isDrawAnnot) ?: Bitmap.createBitmap(0, 0, Bitmap.Config.ARGB_4444)
+        }
+    }
+
+    val bookmarkHandler = object : BookmarkHandler {
+        override fun getBookmarks(): Array<Bookmark> {
+            return kmpdfDocumentController?.bookmarks ?: arrayOf()
+        }
+    }
+
+    val outlineHandler = object : OutlineHandler {
+        override fun getOutline(): Array<OutlineItem> {
+            return kmpdfDocumentController?.outline ?: arrayOf()
+        }
+    }
+
+    val searchHandler = object : SearchHandler {
+        override fun searchPage(page: Int, keyword: String): Array<RectF> {
+            return kmpdfDocumentController?.searchPage(page, keyword) ?: arrayOf()
+        }
+
+        override fun cleanPreviousSearchResults(keyword: String): Boolean {
+            return kmpdfDocumentController?.cleanPreviousSearchResults(keyword) ?: false
+        }
+
+        override fun cleanPreviousSearchResults(page: Int, keyword: String, rectArray: Array<RectF>): Boolean {
+            return kmpdfDocumentController?.setSearchResult(keyword, page, rectArray) ?: false
+        }
+
+        override fun stopSearchKeyWord(): Boolean {
+            return kmpdfDocumentController?.stopSearchKeyWord() ?: false
+        }
+    }
 }

+ 7 - 4
reader/src/main/java/com/kdanmobile/reader/Utils.kt

@@ -12,6 +12,7 @@ import android.support.v4.content.ContextCompat
 import android.support.v4.graphics.drawable.DrawableCompat
 import android.support.v7.widget.AppCompatImageButton
 import android.support.v7.widget.AppCompatImageView
+import android.transition.AutoTransition
 import android.transition.TransitionManager
 import android.view.View
 import android.view.ViewGroup
@@ -55,16 +56,18 @@ object Utils {
     }
 
     @RequiresApi(Build.VERSION_CODES.KITKAT)
-    fun ConstraintLayout.applyConstraintSet(constraintSet: ConstraintSet) {
-        TransitionManager.beginDelayedTransition(this)
+    fun ConstraintLayout.applyConstraintSet(constraintSet: ConstraintSet, duration: Long = 300) {
+        val transition = AutoTransition()
+        transition.duration = duration
+        TransitionManager.beginDelayedTransition(this, transition)
         constraintSet.applyTo(this)
     }
 
     @RequiresApi(Build.VERSION_CODES.KITKAT)
-    fun ConstraintLayout.applyConstraintSet(context: Context, @LayoutRes layoutResId: Int) {
+    fun ConstraintLayout.applyConstraintSet(context: Context, @LayoutRes layoutResId: Int, duration: Long = 300) {
         val constraintSet = ConstraintSet()
         constraintSet.clone(context, layoutResId)
-        this.applyConstraintSet(constraintSet)
+        this.applyConstraintSet(constraintSet, duration)
     }
 
     fun makeDropDownMeasureSpec(measureSpec: Int): Int {

+ 144 - 0
reader/src/main/java/com/kdanmobile/reader/screen/ViewerSettingActivity.kt

@@ -0,0 +1,144 @@
+package com.kdanmobile.reader.screen
+
+import android.arch.lifecycle.Observer
+import android.arch.lifecycle.ViewModelProviders
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+import android.view.MenuItem
+import android.widget.CompoundButton
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.model.SharePrefsModel
+import com.kdanmobile.reader.screen.view.ReadingModeSelectView
+import com.kdanmobile.reader.screen.view.TurnPageModeSelectView
+import kotlinx.android.synthetic.main.activity_viewer_setting.*
+
+class ViewerSettingActivity : AppCompatActivity() {
+
+    private lateinit var viewModel: ViewerSettingViewModel
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_viewer_setting)
+
+        viewModel = ViewModelProviders.of(this, ViewerSettingViewModelFactory(SharePrefsModel(applicationContext)))
+                .get(ViewerSettingViewModel::class.java)
+
+        viewModel.readMode.observe(this, Observer(this::onReadModeChanged))
+        viewModel.isCropModeEnable.observe(this, Observer(this::onCropModeEnableChanged))
+        viewModel.isShowStateBarEnable.observe(this, Observer(this::onShowStateBarEnableChanged))
+        viewModel.turnPageDirection.observe(this, Observer(this::onTurnPageDirectionChanged))
+        viewModel.isShowTurnPageBtnEnable.observe(this, Observer(this::onShowTurnPageBtnEnableChange))
+        viewModel.isLockScreenSleepEnable.observe(this, Observer(this::onLockScreenSleepEnableChange))
+        viewModel.isShowCommentToolEnable.observe(this, Observer(this::onShowCommentToolEnableChange))
+        viewModel.isShowBOTAToolEnable.observe(this, Observer(this::onShowBOTAToolEnableChange))
+
+        setupToolbar()
+        setupReadingModeView()
+        setupTurnPageView()
+        setupScreenSettingView()
+        setupToolbarSettingView()
+
+        rowSwitchView_smartCrop.onCheckedChangeListener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
+            viewModel.setCropModeEnable(isChecked)
+        }
+        rowSwitchView_showStateBar.onCheckedChangeListener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
+            viewModel.setShowStateBarEnable(isChecked)
+        }
+    }
+
+    private fun setupToolbar() {
+        setSupportActionBar(toolbar_viewerSetting)
+        supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_black_24dp)
+        supportActionBar?.setDisplayHomeAsUpEnabled(true)
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+        when (item?.itemId) {
+            android.R.id.home -> finish()
+        }
+        return super.onOptionsItemSelected(item)
+    }
+
+    private fun setupReadingModeView() {
+        readingModeSelectView.isLock = true
+        readingModeSelectView.onReadModeSelectListener = object : ReadingModeSelectView.OnReadModeSelectListener {
+            override fun onReadModeSelect(readMode: Int) {
+                viewModel.setReadMode(readMode)
+            }
+        }
+    }
+
+    private fun setupTurnPageView() {
+        turnPageModeSelectView.onTurnPageModeChangedListener = object : TurnPageModeSelectView.OnTurnPageModeChangedListener {
+            override fun onTurnPageModeChanged(direction: Int) {
+                viewModel.setTurnPageDirection(direction)
+            }
+        }
+        turnPageModeSelectView.onShowTurnPageBtnEnableChangedListener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
+            viewModel.setTurnPageButtonEnable(isChecked)
+        }
+    }
+
+    private fun setupScreenSettingView() {
+        screenSettingView.onCheckedChangeListener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
+            viewModel.setLockScreenSleepEnable(isChecked)
+        }
+    }
+
+    private fun setupToolbarSettingView() {
+        toolbarSettingView.onCheckedChangeListenerComment = CompoundButton.OnCheckedChangeListener { _, isChecked ->
+            viewModel.setShowCommentToolEnable(isChecked)
+        }
+        toolbarSettingView.onCheckedChangeListenerBOTA = CompoundButton.OnCheckedChangeListener { _, isChecked ->
+            viewModel.setShowBOTAToolEnable(isChecked)
+        }
+    }
+
+    private fun onReadModeChanged(readMode: Int?) {
+        readMode?.let {
+            readingModeSelectView.currentReadMode = it
+        }
+    }
+
+    private fun onCropModeEnableChanged(enable: Boolean?) {
+        enable?.let {
+            rowSwitchView_smartCrop.isChecked = it
+        }
+    }
+
+    private fun onShowStateBarEnableChanged(enable: Boolean?) {
+        enable?.let {
+            rowSwitchView_showStateBar.isChecked = it
+        }
+    }
+
+    private fun onTurnPageDirectionChanged(direction: Int?) {
+        direction?.let {
+            turnPageModeSelectView.direction = it
+        }
+    }
+
+    private fun onShowTurnPageBtnEnableChange(enable: Boolean?) {
+        enable?.let {
+            turnPageModeSelectView.isTurnPageBtnEnable = it
+        }
+    }
+
+    private fun onLockScreenSleepEnableChange(enable: Boolean?) {
+        enable?.let {
+            screenSettingView.isLockScreenSleepEnable = it
+        }
+    }
+
+    private fun onShowCommentToolEnableChange(enable: Boolean?) {
+        enable?.let {
+            toolbarSettingView.isShowCommentToolEnable = it
+        }
+    }
+
+    private fun onShowBOTAToolEnableChange(enable: Boolean?) {
+        enable?.let {
+            toolbarSettingView.isShowBOTAToolEnable = it
+        }
+    }
+}

+ 65 - 0
reader/src/main/java/com/kdanmobile/reader/screen/ViewerSettingViewModel.kt

@@ -0,0 +1,65 @@
+package com.kdanmobile.reader.screen
+
+import android.arch.lifecycle.LiveData
+import android.arch.lifecycle.ViewModel
+import com.kdanmobile.reader.screen.model.SharePrefsModel
+
+class ViewerSettingViewModel(private val sharePrefsModel: SharePrefsModel) : ViewModel() {
+
+    val readMode: LiveData<Int>
+        get() = sharePrefsModel.readMode
+
+    val isCropModeEnable: LiveData<Boolean>
+        get() = sharePrefsModel.isCropModeEnable
+
+    val isShowStateBarEnable: LiveData<Boolean>
+        get() = sharePrefsModel.isShowStateBarEnable
+
+    val turnPageDirection: LiveData<Int>
+        get() = sharePrefsModel.turnPageDirection
+
+    val isShowTurnPageBtnEnable: LiveData<Boolean>
+        get() = sharePrefsModel.isShowTurnPageBtnEnable
+
+    val isLockScreenSleepEnable: LiveData<Boolean>
+        get() = sharePrefsModel.isLockScreenSleepEnable
+
+    val isShowCommentToolEnable: LiveData<Boolean>
+        get() = sharePrefsModel.isShowCommentToolEnable
+
+    val isShowBOTAToolEnable: LiveData<Boolean>
+        get() = sharePrefsModel.isShowBOTAToolEnable
+
+    fun setReadMode(readMode: Int) {
+        sharePrefsModel.setReadMode(readMode)
+    }
+
+    fun setCropModeEnable(enable: Boolean) {
+        sharePrefsModel.setCropModeEnable(enable)
+    }
+
+    fun setShowStateBarEnable(enable: Boolean) {
+        sharePrefsModel.setShowStateBarEnable(enable)
+    }
+
+    fun setTurnPageDirection(direction: Int) {
+        sharePrefsModel.setTurnPageDirection(direction)
+    }
+
+    fun setTurnPageButtonEnable(enable: Boolean) {
+        sharePrefsModel.setTurnPageButtonEnable(enable)
+    }
+
+    fun setLockScreenSleepEnable(enable: Boolean) {
+        sharePrefsModel.setLockScreenSleepEnable(enable)
+    }
+
+    fun setShowCommentToolEnable(enable: Boolean) {
+        sharePrefsModel.setShowCommentToolEnable(enable)
+    }
+
+    fun setShowBOTAToolEnable(enable: Boolean) {
+        sharePrefsModel.setShowBOTAToolEnable(enable)
+    }
+}
+

+ 11 - 0
reader/src/main/java/com/kdanmobile/reader/screen/ViewerSettingViewModelFactory.kt

@@ -0,0 +1,11 @@
+package com.kdanmobile.reader.screen
+
+import android.arch.lifecycle.ViewModel
+import android.arch.lifecycle.ViewModelProvider
+import com.kdanmobile.reader.screen.model.SharePrefsModel
+
+class ViewerSettingViewModelFactory(private val sharePrefsModel: SharePrefsModel) : ViewModelProvider.Factory {
+    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
+        return ViewerSettingViewModel(sharePrefsModel) as T
+    }
+}

+ 115 - 0
reader/src/main/java/com/kdanmobile/reader/screen/adapter/BookmarkAdapter.kt

@@ -0,0 +1,115 @@
+package com.kdanmobile.reader.screen.adapter
+
+import android.graphics.Bitmap
+import android.support.v4.util.LruCache
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.RecyclerView.ViewHolder
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.RelativeLayout
+import android.widget.TextView
+import com.kdanmobile.kmpdfkit.pdfcommon.Bookmark
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.handler.ThumbnailHandler
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+
+class BookmarkAdapter(private val thumbnailHandler: ThumbnailHandler, private var bookmarkItems: Array<Bookmark>): RecyclerView.Adapter<BookmarkAdapter.BookmarkViewHolder>() {
+
+    companion object {
+        val maxMemory = Runtime.getRuntime().maxMemory() / 16
+
+        val mMemoryCache: LruCache<String, Bitmap> = object: LruCache<String, Bitmap>(maxMemory.toInt()) {
+            override fun sizeOf(key: String, value: Bitmap): Int {
+                return value.byteCount
+            }
+        }
+    }
+
+    fun setOutlineItems(bookmarkItems: Array<Bookmark>) {
+        this.bookmarkItems = bookmarkItems
+        notifyDataSetChanged()
+    }
+
+    override fun getItemCount(): Int {
+        return bookmarkItems.size
+    }
+
+    fun getItem(position: Int): Bookmark? {
+        return if (position >= 0 && position < bookmarkItems.size) bookmarkItems[position] else null
+    }
+
+    override fun onBindViewHolder(holder: BookmarkViewHolder, position: Int) {
+        val bookmark = bookmarkItems[holder.adapterPosition]
+        holder.msg.text = bookmark.title
+        holder.page.text = (bookmark.pageNum + 1).toString()
+        holder.loadThumbSync(bookmark.title + bookmark.pageNum + bookmark.createTime, bookmark.pageNum)
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookmarkViewHolder {
+        val view = View.inflate(parent.context, R.layout.item_bookmark, null)
+        return BookmarkViewHolder(parent, view)
+    }
+
+    override fun onViewRecycled(holder: BookmarkViewHolder) {
+        super.onViewRecycled(holder)
+        holder.stopLoadThumbSync()
+    }
+
+    inner class BookmarkViewHolder(parent: ViewGroup, itemView: View): ViewHolder(itemView) {
+        private val thumb: ImageView
+        internal val page: TextView
+        internal val msg: TextView
+        private var disposable: Disposable? = null
+
+        init {
+            val idReaderBookmarkFl = itemView.findViewById<View>(R.id.tv_fragmentPdfReaderBookmarkLvItem_rl) as RelativeLayout
+            val params = LinearLayout.LayoutParams((parent.measuredWidth - 20) / 2, (parent.measuredWidth - 20) * 9 / 14)
+            params.setMargins(10, 5, 10, 5)
+            idReaderBookmarkFl.layoutParams = params
+
+            thumb = itemView.findViewById<View>(R.id.iv_fragmentPdfReaderBookmarkLvItem_) as ImageView
+            page = itemView.findViewById<View>(R.id.tv_fragmentPdfReaderBookmarkLvItem_page) as TextView
+            msg = itemView.findViewById<View>(R.id.tv_fragmentPdfReaderBookmarkLvItem_name) as TextView
+        }
+
+        internal fun loadThumbSync(filename: String, page: Int) {
+            stopLoadThumbSync()
+
+            disposable = Observable.create<Bitmap> { emitter ->
+                val pageNameTag = filename + page
+                val bitmap: Bitmap
+                val value = mMemoryCache[pageNameTag]
+                if (null != value) {
+                    bitmap = value
+                } else {
+                    bitmap = thumbnailHandler.getPdfBitmap(page, 180, ThumbnailHandler.MODE_DAY, true)
+                    mMemoryCache.put(pageNameTag, bitmap)
+                }
+                emitter.onNext(bitmap)
+                emitter.onComplete()
+            }
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe({
+                        thumb.setImageBitmap(it)
+                        thumb.invalidate()
+                    }, {
+                        it.printStackTrace()
+                    })
+        }
+
+        internal fun stopLoadThumbSync() {
+            if (null != disposable && !disposable!!.isDisposed) {
+                disposable?.dispose()
+                disposable = null
+                thumb.setImageBitmap(null)
+                thumb.invalidate()
+            }
+        }
+    }
+}

+ 59 - 0
reader/src/main/java/com/kdanmobile/reader/screen/adapter/OutlineAdapter.kt

@@ -0,0 +1,59 @@
+package com.kdanmobile.reader.screen.adapter
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+import android.widget.TextView
+import com.kdanmobile.kmpdfkit.pdfcommon.OutlineItem
+import com.kdanmobile.reader.R
+
+class OutlineAdapter(private val outlineListItems: List<OutlineItem>): BaseAdapter() {
+
+    override fun getCount(): Int {
+        return outlineListItems.size
+    }
+
+    override fun getItem(position: Int): OutlineItem? {
+        return if (position >= 0 && position < outlineListItems.size) outlineListItems[position] else null
+    }
+
+    override fun getItemId(position: Int): Long {
+        return position.toLong()
+    }
+
+    override fun getView(position: Int, view: View?, parent: ViewGroup): View {
+        var view1 = view
+        val holderView: HolderView
+        if (view1 == null) {
+            view1 = LayoutInflater.from(parent.context).inflate(R.layout.outline_entry, null) as View
+            holderView = HolderView(view1)
+            view1.tag = holderView
+        } else {
+            holderView = view1.tag as HolderView
+        }
+
+        val item = getItem(position)
+        /****** 大纲层次缩进  */
+        var space = ""
+        val null_str = parent.context.getString(R.string.null_str)
+        for (i in 1 .. item!!.level) {
+            space += null_str + null_str
+        }
+
+        holderView.tv_name.text = space + item.title
+        holderView.tv_name.textSize = (15 - item.level * 1.2f)
+        holderView.tv_page.text = (item.page + 1).toString()
+        return view1
+    }
+
+    private class HolderView(view: View) {
+        var tv_name: TextView
+        var tv_page: TextView
+
+        init {
+            tv_name = view.findViewById<View>(R.id.tv_outlineEntry_title) as TextView
+            tv_page = view.findViewById<View>(R.id.tv_outlineEntry_page) as TextView
+        }
+    }
+}

+ 83 - 0
reader/src/main/java/com/kdanmobile/reader/screen/adapter/SearchAdapter.kt

@@ -0,0 +1,83 @@
+package com.kdanmobile.reader.screen.adapter
+
+import android.text.Html
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.BaseAdapter
+import android.widget.LinearLayout
+import android.widget.RelativeLayout
+import android.widget.TextView
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.model.SearchResultInfo
+import java.util.ArrayList
+
+class SearchAdapter(private var width: Int): BaseAdapter() {
+    private var list: MutableList<SearchResultInfo> = ArrayList()
+    private var selected = -1
+
+    fun clear() {
+        list.clear()
+    }
+
+    fun add(list: List<SearchResultInfo>) {
+        this.list.addAll(list)
+    }
+
+    override fun getCount(): Int {
+        return list.size
+    }
+
+    override fun getItem(position: Int): Any {
+        return list[position]
+    }
+
+    override fun getItemId(position: Int): Long {
+        return position.toLong()
+    }
+
+    fun setSelected(position: Int) {
+        this.selected = position
+        notifyDataSetChanged()
+    }
+
+    override fun getView(position: Int, view: View?, parent: ViewGroup): View {
+        var view1 = view
+        val item = list[position]
+        val holderView: HolderView
+        if (view1 == null) {
+            view1 = LayoutInflater.from(parent.context).inflate(R.layout.item_search, null) as View
+            holderView = HolderView()
+            holderView.tv_result = view1.findViewById<View>(R.id.tv_fragmentPdfReaderSearchLvItem_result) as TextView
+            holderView.tv_page = view1.findViewById<View>(R.id.tv_fragmentPdfReaderSearchLvItem_page) as TextView
+            holderView.view = view1.findViewById(R.id.view_fragmentPdfReaderSearchLvItem_selected)
+            holderView.rl = view1 .findViewById<View>(R.id.rl_fragmentPdfReaderSearchLvItem_) as RelativeLayout
+            val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
+            params.leftMargin = 21 * width / 800
+            params.rightMargin = 21 * width / 800
+            params.topMargin = 8 * width / 800
+            holderView.rl.layoutParams = params
+            view1.tag = holderView
+        } else {
+            holderView = view1.tag as HolderView
+        }
+
+        if (selected == position) {
+            holderView.view.setBackgroundResource(R.drawable.rectangle_6633b5e5)
+        } else {
+            holderView.view.setBackgroundResource(R.drawable.rectangle_0000)
+        }
+
+        holderView.tv_result.text = Html.fromHtml(item.result)
+        holderView.tv_page.text = (item.page + 1).toString()
+
+        return view1
+    }
+
+    private inner class HolderView {
+        lateinit var rl: RelativeLayout
+        lateinit var tv_result: TextView
+        lateinit var tv_page: TextView
+        lateinit var view: View
+    }
+}

+ 138 - 0
reader/src/main/java/com/kdanmobile/reader/screen/adapter/ThumbnailAdapter.kt

@@ -0,0 +1,138 @@
+package com.kdanmobile.reader.screen.adapter
+
+import android.graphics.Bitmap
+import android.support.v4.util.LruCache
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.RecyclerView.ViewHolder
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.TextView
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.handler.ThumbnailHandler
+import com.kdanmobile.reader.screen.adapter.ThumbnailAdapter.ThumbnailViewHolder
+import com.kdanmobile.reader.screen.handler.PdfInfoHandler
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+
+class ThumbnailAdapter(private val pdfInfoHandler: PdfInfoHandler, private val thumbnailHandler: ThumbnailHandler, private val filename: String = pdfInfoHandler.getOpenPdfFilename()): RecyclerView.Adapter<ThumbnailViewHolder>() {
+
+    companion object {
+        val maxMemory = Runtime.getRuntime().maxMemory() / 16
+
+        val mMemoryCache: LruCache<String, Bitmap> = object: LruCache<String, Bitmap>(maxMemory.toInt()) {
+            override fun sizeOf(key: String, value: Bitmap): Int {
+                return value.byteCount
+            }
+        }
+    }
+    private var currentPage = 0
+
+    init {
+        this.currentPage = pdfInfoHandler.getCurrentPage()
+    }
+
+    fun setCurrentPage(currentPage: Int) {
+        val oldCurrentPage = this.currentPage
+        this.currentPage = currentPage
+        notifyItemChanged(oldCurrentPage, false)
+        notifyItemChanged(currentPage, true)
+    }
+
+    fun clearMapSoftNotify() {
+        mMemoryCache.evictAll()
+        notifyDataSetChanged()
+    }
+
+    override fun getItemCount(): Int {
+        return pdfInfoHandler.getPdfPageCount()
+    }
+
+    override fun onBindViewHolder(holder: ThumbnailViewHolder, position: Int) {
+        holder.page.text = (holder.adapterPosition + 1).toString()
+        holder.onShowBorder(currentPage == holder.adapterPosition)
+        holder.loadThumbSync()
+    }
+
+    override fun onBindViewHolder(holder: ThumbnailViewHolder, position: Int, payloads: List<Any>) {
+        if (payloads.isEmpty()) {
+            onBindViewHolder(holder, position)
+        } else {
+            for (obj in payloads) {
+                if (obj is Boolean) {
+                    holder.onShowBorder(obj)
+                }
+            }
+        }
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThumbnailViewHolder {
+        val view = View.inflate(parent.context, R.layout.item_thumbnail, null)
+        return ThumbnailViewHolder(parent, view)
+    }
+
+    override fun onViewRecycled(holder: ThumbnailViewHolder) {
+        super.onViewRecycled(holder)
+        holder.stopLoadThumbSync()
+    }
+
+    inner class ThumbnailViewHolder(parent: ViewGroup, itemView: View): ViewHolder(itemView) {
+        private val thumb: ImageView
+        internal val page: TextView
+        private val border: View
+        private var disposable: Disposable? = null
+
+        init {
+            val idReaderThumbFl = itemView.findViewById<View>(R.id.id_reader_thumb_fl) as FrameLayout
+            val params = RecyclerView.LayoutParams(parent.measuredWidth - 20, (parent.measuredWidth - 20) * 9 / 7)
+            params.setMargins(10, 5, 10, 5)
+            idReaderThumbFl.layoutParams = params
+
+            thumb = itemView.findViewById<View>(R.id.iv_fragmentPdfReaderThumbLvItem_) as ImageView
+            page = itemView.findViewById<View>(R.id.tv_fragmentPdfReaderThumbLvItem_page) as TextView
+            border = itemView.findViewById(R.id.v_pdfThumbGvItem_)
+        }
+
+        internal fun onShowBorder(isShow: Boolean) {
+            border.visibility = if (isShow) View.VISIBLE else View.GONE
+        }
+
+        internal fun loadThumbSync() {
+            stopLoadThumbSync()
+
+            disposable = Observable.create<Bitmap> { emitter ->
+                val pageNameTag = filename + adapterPosition
+                val bitmap: Bitmap
+                val value = mMemoryCache[pageNameTag]
+                if (null != value) {
+                    bitmap = value
+                } else {
+                    bitmap = thumbnailHandler.getPdfBitmap(adapterPosition, 180, ThumbnailHandler.MODE_DAY, true)
+                    mMemoryCache.put(pageNameTag, bitmap)
+                }
+                emitter.onNext(bitmap)
+                emitter.onComplete()
+            }
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe({
+                        thumb.setImageBitmap(it)
+                        thumb.invalidate()
+                    }, {
+                        it.printStackTrace()
+                    })
+        }
+
+        internal fun stopLoadThumbSync() {
+            if (null != disposable && !disposable!!.isDisposed) {
+                disposable?.dispose()
+                disposable = null
+                thumb.setImageBitmap(null)
+                thumb.invalidate()
+            }
+        }
+    }
+}

+ 83 - 0
reader/src/main/java/com/kdanmobile/reader/screen/data/ViewerSettingSharePrefs.kt

@@ -0,0 +1,83 @@
+package com.kdanmobile.reader.screen.data
+
+import android.content.Context
+import android.content.SharedPreferences
+
+class ViewerSettingSharePrefs(val context: Context, sharedPrefsFileName: String) {
+    companion object {
+        const val readMode = "READ_MODE"
+        const val cropMode = "CROP_MODE"
+        const val stateBar = "STATE_BAR"
+        const val turnPageDirection = "TURN_PAGE_DIRECTION"
+        const val turnPageBtn = "TURN_PAGE_BUTTON"
+        const val screenSleep = "SCREEN_SLEEP"
+        const val commentTool = "COMMENT_TOOL"
+        const val botaTool = "BOTA_TOOL"
+    }
+
+    private var sharedPreferences: SharedPreferences = context.getSharedPreferences(sharedPrefsFileName, Context.MODE_PRIVATE)
+
+    fun getReadMode(): Int {
+        return sharedPreferences.getInt(readMode, 0)
+    }
+
+    fun setReadMode(showMode: Int) {
+        sharedPreferences.edit().putInt(readMode, showMode).apply()
+    }
+
+    fun isCropModeEnable(): Boolean {
+        return sharedPreferences.getBoolean(cropMode, false)
+    }
+
+    fun setCropModeEnable(enable: Boolean) {
+        sharedPreferences.edit().putBoolean(cropMode, enable).apply()
+    }
+
+    fun isShowStateBarEnable(): Boolean {
+        return sharedPreferences.getBoolean(stateBar, false)
+    }
+
+    fun setShowStateBarEnable(enable: Boolean) {
+        sharedPreferences.edit().putBoolean(stateBar, enable).apply()
+    }
+
+    fun getTurnPageDirection(): Int {
+        return sharedPreferences.getInt(turnPageDirection, 0)
+    }
+
+    fun setTurnPageDirection(direction: Int) {
+        sharedPreferences.edit().putInt(turnPageDirection, direction).apply()
+    }
+
+    fun isShowTurnPageButtonEnable(): Boolean {
+        return sharedPreferences.getBoolean(turnPageBtn, false)
+    }
+
+    fun setShowTurnPageButtonEnable(enable: Boolean) {
+        sharedPreferences.edit().putBoolean(turnPageBtn, enable).apply()
+    }
+
+    fun isLockScreenSleepEnable(): Boolean {
+        return sharedPreferences.getBoolean(screenSleep, false)
+    }
+
+    fun setLockScreenSleepEnable(enable: Boolean) {
+        sharedPreferences.edit().putBoolean(screenSleep, enable).apply()
+    }
+
+    fun isShowCommentToolEnable(): Boolean {
+        return sharedPreferences.getBoolean(commentTool, false)
+    }
+
+    fun setShowCommentToolEnable(enable: Boolean) {
+        sharedPreferences.edit().putBoolean(commentTool, enable).apply()
+    }
+
+    fun isShowBOTAToolEnable(): Boolean {
+        return sharedPreferences.getBoolean(botaTool, false)
+    }
+
+    fun setShowBOTAToolEnable(enable: Boolean) {
+        sharedPreferences.edit().putBoolean(botaTool, enable).apply()
+    }
+}

+ 8 - 0
reader/src/main/java/com/kdanmobile/reader/screen/handler/BookmarkHandler.kt

@@ -0,0 +1,8 @@
+package com.kdanmobile.reader.screen.handler
+
+import com.kdanmobile.kmpdfkit.pdfcommon.Bookmark
+
+interface BookmarkHandler {
+
+    fun getBookmarks(): Array<Bookmark>
+}

+ 8 - 0
reader/src/main/java/com/kdanmobile/reader/screen/handler/OutlineHandler.kt

@@ -0,0 +1,8 @@
+package com.kdanmobile.reader.screen.handler
+
+import com.kdanmobile.kmpdfkit.pdfcommon.OutlineItem
+
+interface OutlineHandler {
+
+    fun getOutline(): Array<OutlineItem>
+}

+ 16 - 0
reader/src/main/java/com/kdanmobile/reader/screen/handler/PdfInfoHandler.kt

@@ -0,0 +1,16 @@
+package com.kdanmobile.reader.screen.handler
+
+import com.kdanmobile.kmpdfkit.pdfcommon.TextWord
+
+interface PdfInfoHandler {
+
+    fun getOpenPdfFilename(): String
+
+    fun getPdfPageCount(): Int
+
+    fun getCurrentPage(): Int
+
+    fun setCurrentPage(page: Int): Boolean
+
+    fun textLines(page: Int): Array<Array<TextWord>>
+}

+ 14 - 0
reader/src/main/java/com/kdanmobile/reader/screen/handler/SearchHandler.kt

@@ -0,0 +1,14 @@
+package com.kdanmobile.reader.screen.handler
+
+import android.graphics.RectF
+
+interface SearchHandler {
+
+    fun searchPage(page: Int, keyword: String): Array<RectF>
+
+    fun cleanPreviousSearchResults(keyword: String): Boolean
+
+    fun cleanPreviousSearchResults(page: Int, keyword: String, rectArray: Array<RectF>): Boolean
+
+    fun stopSearchKeyWord(): Boolean
+}

+ 17 - 0
reader/src/main/java/com/kdanmobile/reader/screen/handler/ThumbnailHandler.kt

@@ -0,0 +1,17 @@
+package com.kdanmobile.reader.screen.handler
+
+import android.graphics.Bitmap
+
+interface ThumbnailHandler {
+
+    companion object {
+        val MODE_DAY = 0
+        val MODE_NIGHT = 1
+        val MODE_SEFIA = 2
+        val MODE_ETON_BLUE = 3
+        val MODE_CHROME_WHITE = 4
+        val MODE_WHITE_LILAC = 5
+    }
+
+    fun getPdfBitmap(position: Int, picWidth: Int, mode: Int = MODE_DAY, isDrawAnnot: Boolean = true): Bitmap
+}

+ 33 - 0
reader/src/main/java/com/kdanmobile/reader/screen/model/SearchResultInfo.kt

@@ -0,0 +1,33 @@
+package com.kdanmobile.reader.screen.model
+
+import android.graphics.RectF
+import com.kdanmobile.kmpdfkit.pdfcommon.TextWord
+
+class SearchResultInfo(var page: Int, var search: String, var rf: RectF, lines: Array<TextWord>) {
+    var result: String = ""
+
+    init {
+        for (line in lines) {
+            result = result + line.w + " "
+        }
+
+        val sb = StringBuilder()
+        var src = result.toLowerCase()
+        val seh = search.toLowerCase()
+        var index = src.indexOf(seh)
+        while (index >= 0) {
+            sb.append(src.subSequence(0, index))
+            sb.append("<font color=\"#ff0000\">")
+            result = result.substring(index)
+            sb.append(result.substring(0, search.length))
+            sb.append("</font>")
+            result = result.substring(search.length)
+            src = src.substring(index + search.length)
+            index = src.indexOf(seh)
+        }
+
+        sb.append(result)
+
+        result = sb.toString()
+    }
+}

+ 17 - 0
reader/src/main/java/com/kdanmobile/reader/screen/model/SearchTaskResult.kt

@@ -0,0 +1,17 @@
+package com.kdanmobile.reader.screen.model
+
+import android.graphics.RectF
+
+class SearchTaskResult(val txt: String, val pageNumber: Int, val searchBoxes: Array<RectF>) {
+    companion object {
+        private var singleton: SearchTaskResult? = null
+
+        fun get(): SearchTaskResult? {
+            return singleton
+        }
+
+        fun set(result: SearchTaskResult) {
+            singleton = result
+        }
+    }
+}

+ 103 - 0
reader/src/main/java/com/kdanmobile/reader/screen/model/SharePrefsModel.kt

@@ -0,0 +1,103 @@
+package com.kdanmobile.reader.screen.model
+
+import android.arch.lifecycle.LiveData
+import android.arch.lifecycle.MutableLiveData
+import android.content.Context
+import com.kdanmobile.reader.screen.data.ViewerSettingSharePrefs
+
+class SharePrefsModel(context: Context) {
+    companion object {
+        const val viewerSettingFileName = "viewer_setting"
+    }
+
+    val readMode: LiveData<Int>
+        get() = mReadMode
+
+    val isCropModeEnable: LiveData<Boolean>
+        get() = mIsCropModeEnable
+
+    val isShowStateBarEnable: LiveData<Boolean>
+        get() = mIsShowStateBarEnable
+
+    val turnPageDirection: LiveData<Int>
+        get() = mTurnPageDirection
+
+    val isShowTurnPageBtnEnable: LiveData<Boolean>
+        get() = mIsShowTurnPageBtnEnable
+
+    val isLockScreenSleepEnable: LiveData<Boolean>
+        get() = mIsLockScreenSleepEnable
+
+    val isShowCommentToolEnable: LiveData<Boolean>
+        get() = mIsShowCommentToolEnable
+
+    val isShowBOTAToolEnable: LiveData<Boolean>
+        get() = mIsShowBOTAToolEnable
+
+    private var mReadMode = MutableLiveData<Int>()
+
+    private var mIsCropModeEnable = MutableLiveData<Boolean>()
+
+    private var mIsShowStateBarEnable = MutableLiveData<Boolean>()
+
+    private var mTurnPageDirection = MutableLiveData<Int>()
+
+    private var mIsShowTurnPageBtnEnable = MutableLiveData<Boolean>()
+
+    private var mIsLockScreenSleepEnable = MutableLiveData<Boolean>()
+
+    private var mIsShowCommentToolEnable = MutableLiveData<Boolean>()
+
+    private var mIsShowBOTAToolEnable = MutableLiveData<Boolean>()
+
+    private val viewSettingSharePrefs = ViewerSettingSharePrefs(context, viewerSettingFileName).apply {
+        mReadMode.value = this.getReadMode()
+        mIsCropModeEnable.value = this.isCropModeEnable()
+        mIsShowStateBarEnable.value = this.isShowStateBarEnable()
+        mTurnPageDirection.value = this.getTurnPageDirection()
+        mIsShowTurnPageBtnEnable.value = this.isShowTurnPageButtonEnable()
+        mIsLockScreenSleepEnable.value = this.isLockScreenSleepEnable()
+        mIsShowCommentToolEnable.value = this.isShowCommentToolEnable()
+        mIsShowBOTAToolEnable.value = this.isShowBOTAToolEnable()
+    }
+
+    fun setReadMode(readMode: Int) {
+        viewSettingSharePrefs.setReadMode(readMode)
+        mReadMode.value = readMode
+    }
+
+    fun setCropModeEnable(enable: Boolean) {
+        viewSettingSharePrefs.setCropModeEnable(enable)
+        mIsCropModeEnable.value = enable
+    }
+
+    fun setShowStateBarEnable(enable: Boolean) {
+        viewSettingSharePrefs.setShowStateBarEnable(enable)
+        mIsShowStateBarEnable.value = enable
+    }
+
+    fun setTurnPageDirection(direction: Int) {
+        viewSettingSharePrefs.setTurnPageDirection(direction)
+        mTurnPageDirection.value = direction
+    }
+
+    fun setTurnPageButtonEnable(enable: Boolean) {
+        viewSettingSharePrefs.setShowTurnPageButtonEnable(enable)
+        mIsShowTurnPageBtnEnable.value = enable
+    }
+
+    fun setLockScreenSleepEnable(enable: Boolean) {
+        viewSettingSharePrefs.setLockScreenSleepEnable(enable)
+        mIsLockScreenSleepEnable.value = enable
+    }
+
+    fun setShowCommentToolEnable(enable: Boolean) {
+        viewSettingSharePrefs.setShowCommentToolEnable(enable)
+        mIsShowCommentToolEnable.value = enable
+    }
+
+    fun setShowBOTAToolEnable(enable: Boolean) {
+        viewSettingSharePrefs.setShowBOTAToolEnable(enable)
+        mIsShowBOTAToolEnable.value = enable
+    }
+}

+ 26 - 0
reader/src/main/java/com/kdanmobile/reader/screen/model/SimpleTextWatcher.kt

@@ -0,0 +1,26 @@
+package com.kdanmobile.reader.screen.model
+
+import android.text.Editable
+import android.text.TextWatcher
+
+/**
+ * @类名:SimpleTextWatcher
+ * @类描述:重写TextWatcher
+ * @作者:luozhipeng
+ * @创建时间:2015年7月7日-下午4:14:58
+ * @修改人:
+ * @修改时间:
+ * @修改备注:
+ * @版本:
+ * @Copyright:(c)-2015kdanmobile
+ */
+open class SimpleTextWatcher : TextWatcher {
+    override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {
+    }
+
+    override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
+    }
+
+    override fun afterTextChanged(editable: Editable) {
+    }
+}

+ 82 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/BookmarkView.kt

@@ -0,0 +1,82 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.RelativeLayout
+import com.kdanmobile.kmpdfkit.pdfcommon.Bookmark
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.adapter.BookmarkAdapter
+import com.kdanmobile.reader.screen.handler.BookmarkHandler
+import com.kdanmobile.reader.screen.handler.PdfInfoHandler
+import com.kdanmobile.reader.screen.handler.ThumbnailHandler
+import com.kdanmobile.reader.widget.drag.OnRecyclerItemClickListener
+import kotlinx.android.synthetic.main.view_bookmark.view.*
+import java.util.*
+
+class BookmarkView: RelativeLayout {
+    private lateinit var adapter: BookmarkAdapter
+    private var pdfInfoHandler: PdfInfoHandler? = null
+    private var bookmarkHandler: BookmarkHandler? = null
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_bookmark, this)
+        val layoutManager = LinearLayoutManager(context)
+        layoutManager.orientation = LinearLayoutManager.VERTICAL
+
+        id_km_bookmark_recycler.setHasFixedSize(true)
+        id_km_bookmark_recycler.layoutManager = layoutManager
+        id_km_bookmark_recycler.layoutManager = LinearLayoutManager(context)
+        id_km_bookmark_recycler.addOnItemTouchListener(object : OnRecyclerItemClickListener(id_km_bookmark_recycler) {
+            override fun onItemClick(viewHolder: RecyclerView.ViewHolder) {
+                val bookmark = adapter.getItem(viewHolder.adapterPosition)
+                if (null != bookmark) {
+                    pdfInfoHandler?.setCurrentPage(bookmark.pageNum)
+                }
+            }
+
+            override fun onItemLongClick(viewHolder: RecyclerView.ViewHolder) {
+
+            }
+        })
+    }
+
+    fun setHandlers(pdfInfoHandler: PdfInfoHandler, thumbnailHandler: ThumbnailHandler, bookmarkHandler: BookmarkHandler) {
+        this.pdfInfoHandler = pdfInfoHandler
+        this.bookmarkHandler = bookmarkHandler
+        adapter = BookmarkAdapter(thumbnailHandler, arrayOf())
+        id_km_bookmark_recycler.adapter = adapter
+        updateBookmark()
+    }
+
+    fun updateBookmark() {
+        if (null != bookmarkHandler) {
+            onRefreshBookmarkData(bookmarkHandler!!.getBookmarks())
+        }
+    }
+
+    private fun onRefreshBookmarkData(bookmarkItems: Array<Bookmark>) {
+        try {
+            if (bookmarkItems.isNotEmpty()) {
+                Arrays.sort(bookmarkItems) { lhs, rhs -> if (lhs.pageNum > rhs.pageNum) 1 else -1 }
+            }
+            adapter.setOutlineItems(bookmarkItems)
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+    }
+}

+ 71 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/OutlineView.kt

@@ -0,0 +1,71 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.RelativeLayout
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.adapter.OutlineAdapter
+import com.kdanmobile.reader.screen.handler.OutlineHandler
+import com.kdanmobile.reader.screen.handler.PdfInfoHandler
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+import kotlinx.android.synthetic.main.view_outline.view.*
+
+class OutlineView: RelativeLayout {
+    private lateinit var adapter: OutlineAdapter
+    private var pdfInfoHandler: PdfInfoHandler? = null
+    private var disposable: Disposable? = null
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_outline, this)
+
+        lv_viewPdfReaderOutline_.setOnItemClickListener { _, _, position, _ ->
+            val item = adapter.getItem(position)
+            if (null != item) {
+                pdfInfoHandler?.setCurrentPage(item.page)
+            }
+        }
+
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        if (null != disposable && !disposable!!.isDisposed) {
+            disposable?.dispose()
+            disposable = null
+        }
+    }
+
+    fun setHandlers(pdfInfoHandler: PdfInfoHandler, outlineHandler: OutlineHandler) {
+        this.pdfInfoHandler = pdfInfoHandler
+        disposable = Observable.create<OutlineAdapter> {
+            val outlineItems = outlineHandler.getOutline()
+            val copyList = outlineItems.toList()
+            it.onNext(OutlineAdapter(copyList))
+            it.onComplete()
+        }
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    adapter = it
+                    lv_viewPdfReaderOutline_.adapter = adapter
+                }, {
+                    it.printStackTrace()
+                })
+    }
+}

+ 97 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/ReadingModeSelectView.kt

@@ -0,0 +1,97 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.support.constraint.ConstraintLayout
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import com.kdanmobile.reader.R
+import kotlinx.android.synthetic.main.view_reading_mode_select.view.*
+
+class ReadingModeSelectView : ConstraintLayout {
+    companion object {
+        const val modeDay = 0
+        const val modeNight = 1
+        const val modeSefia = 2
+        const val modeLilac = 5
+    }
+
+    interface OnReadModeSelectListener {
+        fun onReadModeSelect(readMode: Int)
+    }
+
+    var onReadModeSelectListener: OnReadModeSelectListener? = null
+
+    var currentReadMode: Int? = null
+        set(value) {
+            field = value
+            when (value) {
+                modeDay -> setReadModeBtnActivated(btn_readingMode_day)
+                modeNight -> setReadModeBtnActivated(btn_readingMode_night)
+                modeSefia -> setReadModeBtnActivated(btn_readingMode_sefia)
+                modeLilac -> setReadModeBtnActivated(btn_readingMode_lilac)
+            }
+        }
+
+    var isLock: Boolean = false
+        set(value) {
+            field = value
+            setReadModeBtnLockVisible(isLock)
+        }
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_reading_mode_select, this).apply {
+            btn_readingMode_day.setOnClickListener {
+                onReadModeSelectListener?.onReadModeSelect(modeDay)
+                setReadModeBtnActivated(it)
+            }
+            btn_readingMode_lilac.setOnClickListener {
+                onReadModeSelectListener?.onReadModeSelect(modeLilac)
+                setReadModeBtnActivated(it)
+            }
+            btn_readingMode_night.setOnClickListener {
+                if (!isLock) {
+                    onReadModeSelectListener?.onReadModeSelect(modeNight)
+                    setReadModeBtnActivated(it)
+                }
+            }
+            btn_readingMode_sefia.setOnClickListener {
+                if (!isLock) {
+                    onReadModeSelectListener?.onReadModeSelect(modeSefia)
+                    setReadModeBtnActivated(it)
+                }
+            }
+            setReadModeBtnLockVisible(isLock)
+        }
+    }
+
+    private fun setReadModeBtnActivated(view: View?) {
+        btn_readingMode_day?.isActivated = false
+        btn_readingMode_lilac?.isActivated = false
+        btn_readingMode_night?.isActivated = false
+        btn_readingMode_sefia?.isActivated = false
+        view?.isActivated = true
+    }
+
+    private fun setReadModeBtnLockVisible(isVisible: Boolean) {
+        if (isVisible) {
+            iv_readingMode_night_lock?.visibility = View.VISIBLE
+            iv_readingMode_sefia_lock?.visibility = View.VISIBLE
+        } else {
+            iv_readingMode_night_lock?.visibility = View.INVISIBLE
+            iv_readingMode_sefia_lock?.visibility = View.INVISIBLE
+        }
+    }
+}

+ 51 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/RowSwitchView.kt

@@ -0,0 +1,51 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.support.constraint.ConstraintLayout
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.CompoundButton
+import com.kdanmobile.reader.R
+import kotlinx.android.synthetic.main.view_row_switch.view.*
+
+class RowSwitchView : ConstraintLayout {
+    var text = ""
+
+    var isChecked = false
+        set(value) {
+            field = value
+            rowSwitchView_switch?.isChecked = isChecked
+        }
+
+    var onCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
+        set(value) {
+            field = value
+            rowSwitchView_switch?.setOnCheckedChangeListener(onCheckedChangeListener)
+        }
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        initAttr(attrs)
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        initAttr(attrs)
+        initView()
+    }
+
+    private fun initAttr(attributeSet: AttributeSet) {
+        val typedArray = context.theme.obtainStyledAttributes(attributeSet, R.styleable.RowSwitchView, 0, 0)
+        text = typedArray.getString(R.styleable.RowSwitchView_text)
+        isChecked = typedArray.getBoolean(R.styleable.RowSwitchView_isChecked, false)
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_row_switch, this)
+        rowSwitchView_text.text = text
+        rowSwitchView_switch.isChecked = isChecked
+    }
+}

+ 39 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/ScreenSettingView.kt

@@ -0,0 +1,39 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.support.constraint.ConstraintLayout
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.CompoundButton
+import com.kdanmobile.reader.R
+import kotlinx.android.synthetic.main.view_screen_setting.view.*
+
+class ScreenSettingView : ConstraintLayout {
+    var onCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
+        set(value) {
+            field = value
+            rowSwitchView_lockScreenSleepEnable?.onCheckedChangeListener = value
+        }
+
+    var isLockScreenSleepEnable: Boolean = false
+        set(value) {
+            field = value
+            rowSwitchView_lockScreenSleepEnable?.isChecked = value
+        }
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_screen_setting, this)
+    }
+}

+ 373 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/SearchView.kt

@@ -0,0 +1,373 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.graphics.RectF
+import android.os.Handler
+import android.os.Message
+import android.text.InputType
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.view.inputmethod.InputMethodManager
+import android.widget.*
+import com.kdanmobile.kmpdfkit.pdfcommon.TextWord
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.adapter.SearchAdapter
+import com.kdanmobile.reader.screen.model.SearchResultInfo
+import com.kdanmobile.reader.screen.handler.PdfInfoHandler
+import com.kdanmobile.reader.screen.handler.SearchHandler
+import com.kdanmobile.reader.screen.model.SearchTaskResult
+import com.kdanmobile.reader.screen.model.SimpleTextWatcher
+import com.kdanmobile.reader.utils.DensityUtil
+import io.reactivex.Completable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+import java.util.ArrayList
+import kotlinx.android.synthetic.main.view_search.view.*
+import java.lang.ref.WeakReference
+
+class SearchView: RelativeLayout, View.OnClickListener {
+    private var pdfInfoHandler: PdfInfoHandler? = null
+    private var searchHandler: SearchHandler? = null
+    private lateinit var linearLayout: LinearLayout
+    private lateinit var tv_page: TextView
+    private lateinit var tv_text:TextView
+    private lateinit var et_search: EditText
+    private lateinit var lv: ListView
+    private lateinit var tv_tishi: TextView
+    private lateinit var adapter: SearchAdapter
+    private val list = ArrayList<SearchResultInfo>()
+
+    // 判断搜索的是否是页码 true 是页码
+    private var isPage = false
+
+    private var msgHandler: Handler? = null
+
+    private val MAX_SEARCH_RESULT = 200
+
+    private var isDone = false
+    private var deviceWidth: Int = 0
+
+    private var disposable: Disposable? = null
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_search, this)
+
+        initHandler()
+
+        initLayout()
+
+        setListener()
+
+        postDelayed( { showSoftKeyboard() }, 200)
+    }
+
+    fun setHandlers(pdfInfoHandler: PdfInfoHandler, searchHandler: SearchHandler) {
+        this.pdfInfoHandler = pdfInfoHandler
+        this.searchHandler = searchHandler
+    }
+
+    private fun initHandler() {
+
+        class WeakReferenceHandler(view: SearchView) : Handler() {
+            private val mView: WeakReference<SearchView> = WeakReference(view)
+
+            override fun handleMessage(msg: Message) {
+                val view = mView.get()
+                if (view != null) {
+                    when (msg.what) {
+                        10 -> {
+                            if (msg.obj is List<*>) {
+                                view.lv.visibility = View.VISIBLE
+                                view.tv_tishi.visibility = View.GONE
+                                val item = (msg.obj as List<*>).filterIsInstance<SearchResultInfo>()
+                                view.list.addAll(item)
+                                view.adapter.add(item)
+                                view.adapter.notifyDataSetChanged()
+                            }
+                        }
+                        20 -> search()
+                        30 -> {
+                            val position = msg.arg1
+                            val info = view.list[position]
+                            SearchTaskResult.set(SearchTaskResult(info.search, info.page, arrayOf(info.rf)))
+                            view.pdfInfoHandler?.setCurrentPage(view.list[position].page)
+                        }
+                    }
+                }
+            }
+        }
+        msgHandler = WeakReferenceHandler(this)
+    }
+
+    private fun initLayout() {
+
+        linearLayout = ll_fragmentPdfReaderSearch
+        tv_page = tv_fragmentPdfReaderSearch_page
+        tv_text = tv_fragmentPdfReaderSearch_text
+        et_search = et_fragmentPdfReaderSearch_
+
+        et_search.setHint(R.string.fragment_search_enter_text)
+        et_search.inputType = InputType.TYPE_CLASS_TEXT
+        et_search.isLongClickable = false
+        lv = lv_fragmentPdfReaderSearch_
+        tv_tishi = tv_fragmentPdfReaderSearch_tishi
+
+        var navigationHeight = 0
+        val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
+        if (resourceId > 0) {
+            val rid = resources.getIdentifier("config_showNavigationBar", "bool", "android")
+            if (resources.getBoolean(rid)) {
+                navigationHeight = resources.getDimensionPixelSize(resourceId)
+            }
+        }
+        val screenWidth = DensityUtil.getScreenWidthPx(context)
+        val screenHeight = DensityUtil.getScreenHeightPx(context)
+        val density = DensityUtil.getDensity(context)
+        val xDp = (screenWidth / density).toInt()
+        val yDp = ((screenHeight + navigationHeight) / density).toInt()
+        val isPhone = when (xDp >= 550 && yDp >= 550) {
+            true -> false
+            false -> true
+        }
+        deviceWidth = Math.min(screenWidth, screenHeight)
+
+        linearLayout.layoutParams = LinearLayout.LayoutParams(318 * deviceWidth / 800, LinearLayout.LayoutParams.MATCH_PARENT)
+
+        val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
+        params.leftMargin = 21 * deviceWidth / 800
+        params.rightMargin = 21 * deviceWidth / 800
+        params.topMargin = 8 * deviceWidth / 800
+        params.bottomMargin = 8 * deviceWidth / 800
+        et_search.layoutParams = params
+        val pad = (density * 4).toInt()
+        et_search.setPadding(pad, pad, pad, pad)
+
+        if (isPhone) {
+            tv_tishi.textSize = 18f
+        } else {
+            val textSize = deviceWidth.toFloat() / 800f / density
+            tv_tishi.textSize = 24 * textSize
+        }
+
+        adapter = SearchAdapter(deviceWidth)
+        lv.adapter = adapter
+    }
+
+    private fun setListener() {
+
+        tv_page.setOnClickListener(this)
+        tv_text.setOnClickListener(this)
+
+        lv.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
+            adapter.setSelected(position)
+
+            msgHandler?.sendMessageDelayed(msgHandler?.obtainMessage(30, position, 0), 50)
+        }
+
+        et_search.setOnEditorActionListener { _, actionId, _ ->
+            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+                if (!isPage && et_search.text.toString().length < 3) {
+                    val la = IntArray(2)
+                    et_search.getLocationOnScreen(la)
+                    val y = la[1]
+                    val toast = Toast.makeText(context, R.string.fileManager_thishi_search, Toast.LENGTH_SHORT)
+                    toast.setGravity(Gravity.TOP or Gravity.LEFT, 11 * deviceWidth / 800, y + 30 * deviceWidth / 800)
+                    toast.show()
+                } else {
+                    isDone = true
+                    msgHandler?.sendEmptyMessageDelayed(20, 100)
+                    hideSoftKeyboard()
+                }
+            }
+            return@setOnEditorActionListener false
+        }
+
+        et_search.addTextChangedListener(object : SimpleTextWatcher() {
+            override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
+                super.onTextChanged(sequence, start, before, count)
+                try {
+                    if (isPage && sequence.isNotEmpty()) {
+                        val c = sequence[sequence.length - 1]
+                        val index = sequence[0]
+                        if (c < '0' || c > '9' || index == '0') {
+                            val text = sequence.subSequence(0, sequence.length - 1).toString()
+                            et_search.setText(text)
+                            et_search.setSelection(text.length)
+                        }
+                        val searchText = et_search.text.toString()
+                        if (searchText.isNotEmpty()) {
+                            val page = Integer.parseInt(searchText)
+                            val pageCount = pdfInfoHandler?.getPdfPageCount() ?: 0
+                            if (page > pageCount) {
+                                val text = searchText.subSequence(0, searchText.length - 1).toString()
+                                et_search.setText(text)
+                                et_search.setSelection(text.length)
+                            }
+                        }
+                    }
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                    et_search.setText("")
+                }
+
+            }
+        })
+    }
+
+    override fun onClick(v: View) {
+
+        when (v.id) {
+            R.id.tv_fragmentPdfReaderSearch_page -> {
+                if (!isPage) {
+                    et_search.isLongClickable = false
+                    tv_page.setTextColor(-0xcc4a1b)
+                    tv_text.setTextColor(-0x505051)
+                    et_search.setText("")
+                    et_search.setHint(R.string.fragment_search_enter_page)
+                    et_search.inputType = InputType.TYPE_CLASS_NUMBER
+                    et_search.setSingleLine(true)
+
+                    lv.visibility = View.GONE
+                    tv_tishi.visibility = View.GONE
+
+                    showSoftKeyboard()
+                }
+
+                isPage = true
+            }
+            R.id.tv_fragmentPdfReaderSearch_text -> {
+                if (isPage) {
+                    et_search.isLongClickable = true
+                    tv_page.setTextColor(-0x505051)
+                    tv_text.setTextColor(-0xcc4a1b)
+                    et_search.setText("")
+                    et_search.setHint(R.string.fragment_search_enter_text)
+                    et_search.inputType = InputType.TYPE_CLASS_TEXT
+                    et_search.setSingleLine(true)
+
+                    lv.visibility = View.VISIBLE
+                    tv_tishi.visibility = View.GONE
+
+                    showSoftKeyboard()
+                }
+
+                isPage = false
+            }
+        }
+    }
+
+    private fun search() {
+        val searchText = et_search.text.toString()
+        if (searchText.isNotEmpty()) {
+            if (isPage) {
+                val page = Integer.parseInt(searchText)
+                if (page > 0) {
+                    pdfInfoHandler?.setCurrentPage(page - 1)
+                }
+            } else if (searchText.length >= 3) {
+                if (list.size > 0) {
+                    adapter.setSelected(-1)
+                    adapter.clear()
+                    list.clear()
+                    adapter.notifyDataSetChanged()
+                }
+
+                isDone = false
+                disposable = Completable.create {
+                    if (null != pdfInfoHandler && null != searchHandler) {
+                        val pageCount = pdfInfoHandler!!.getPdfPageCount()
+                        for (i in 0 until pageCount) {
+                            if (!isDone) {
+                                val results = searchHandler!!.searchPage(i, searchText)
+                                if (results.isNotEmpty()) {
+                                    val texts = pdfInfoHandler!!.textLines(i)
+                                    val list = dealData(texts, results, searchText, i)
+                                    msgHandler?.sendMessage(msgHandler?.obtainMessage(10, list))
+                                    if (this.list.size + list.size >= MAX_SEARCH_RESULT) {
+                                        isDone = true
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    it.onComplete()
+                }
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread())
+                        .subscribe({
+                            if (list.size < 1) {
+                                lv.visibility = View.GONE
+                                tv_tishi.visibility = View.VISIBLE
+                            }
+                        }, {
+                            it.printStackTrace()
+                        })
+            }
+        }
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        if (null != disposable && !disposable!!.isDisposed) {
+            disposable?.dispose()
+            disposable = null
+        }
+    }
+
+    private fun dealData(texts: Array<Array<TextWord>>?, results: Array<RectF>?, search: String, page: Int): List<SearchResultInfo> {
+        val list = ArrayList<SearchResultInfo>()
+        if (texts == null || results == null) {
+            return list
+        }
+        for (i in texts.indices) {
+            if (!isDone) {
+                val tw = texts[i]
+                for (j in tw.indices) {
+                    if (!isDone) {
+                        for (k in results.indices) {
+                            if (!isDone) {
+                                if (tw[j].contains(results[k])) {
+                                    list.add(SearchResultInfo(page, search, results[k], tw))
+                                    if (this.list.size + list.size >= MAX_SEARCH_RESULT) {
+                                        return list
+                                    }
+                                }
+                            }
+
+                        }
+                    }
+
+                }
+            }
+
+        }
+        return list
+    }
+
+    private fun showSoftKeyboard() {
+        val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+        et_search.requestFocus()
+        inputMethodManager.showSoftInput(et_search, InputMethodManager.RESULT_UNCHANGED_SHOWN)
+    }
+
+    fun hideSoftKeyboard() {
+        val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+        inputMethodManager.hideSoftInputFromWindow(et_search.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
+    }
+}

+ 73 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/ThumbnailView.kt

@@ -0,0 +1,73 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.RelativeLayout
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.screen.adapter.ThumbnailAdapter
+import com.kdanmobile.reader.screen.handler.PdfInfoHandler
+import com.kdanmobile.reader.screen.handler.ThumbnailHandler
+import com.kdanmobile.reader.widget.drag.OnRecyclerItemClickListener
+import kotlinx.android.synthetic.main.view_thumbnail.view.*
+
+class ThumbnailView: RelativeLayout {
+    private lateinit var adapter: ThumbnailAdapter
+    private var currentPage = 0
+    private var pdfInfoHandler: PdfInfoHandler? = null
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
+        initView()
+    }
+
+    constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_thumbnail, this)
+        val layoutManager = LinearLayoutManager(context)
+        layoutManager.orientation = LinearLayoutManager.VERTICAL
+
+        id_km_thumb_recycler.setHasFixedSize(true)
+        id_km_thumb_recycler.layoutManager = layoutManager
+        id_km_thumb_recycler.layoutManager = LinearLayoutManager(context)
+        id_km_thumb_recycler.addOnItemTouchListener(object : OnRecyclerItemClickListener(id_km_thumb_recycler) {
+            override fun onItemClick(viewHolder: RecyclerView.ViewHolder) {
+                onScrollToPosition(viewHolder.adapterPosition, true)
+                pdfInfoHandler?.setCurrentPage(viewHolder.adapterPosition)
+            }
+
+            override fun onItemLongClick(viewHolder: RecyclerView.ViewHolder) {
+
+            }
+        })
+    }
+
+    fun setHandlers(pdfInfoHandler: PdfInfoHandler, thumbnailHandler: ThumbnailHandler) {
+        this.pdfInfoHandler = pdfInfoHandler
+
+        adapter = ThumbnailAdapter(pdfInfoHandler, thumbnailHandler)
+        id_km_thumb_recycler.adapter = adapter
+        currentPage = pdfInfoHandler?.getCurrentPage()
+        onScrollToPosition(currentPage, true)
+    }
+
+    fun onScrollToPosition(position: Int, notify: Boolean) {
+        currentPage = position
+
+        if (notify) {
+            adapter.setCurrentPage(position)
+        }
+
+        if (null != id_km_thumb_recycler) {
+            id_km_thumb_recycler.scrollToPosition(position)
+        }
+    }
+}

+ 51 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/ToolbarSettingView.kt

@@ -0,0 +1,51 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.support.constraint.ConstraintLayout
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.CompoundButton
+import com.kdanmobile.reader.R
+import kotlinx.android.synthetic.main.view_toolbar_setting.view.*
+
+class ToolbarSettingView : ConstraintLayout {
+    var onCheckedChangeListenerComment: CompoundButton.OnCheckedChangeListener? = null
+        set(value) {
+            field = value
+            rowSwitchView_show_commentTool?.onCheckedChangeListener = value
+        }
+
+    var onCheckedChangeListenerBOTA: CompoundButton.OnCheckedChangeListener? = null
+        set(value) {
+            field = value
+            rowSwitchView_show_BOTATool?.onCheckedChangeListener = value
+        }
+
+    var isShowCommentToolEnable: Boolean = false
+        set(value) {
+            field = value
+            rowSwitchView_show_commentTool?.isChecked = value
+        }
+
+    var isShowBOTAToolEnable: Boolean = false
+        set(value) {
+            field = value
+            rowSwitchView_show_BOTATool?.isChecked = value
+        }
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_toolbar_setting, this)
+    }
+}

+ 66 - 0
reader/src/main/java/com/kdanmobile/reader/screen/view/TurnPageModeSelectView.kt

@@ -0,0 +1,66 @@
+package com.kdanmobile.reader.screen.view
+
+import android.content.Context
+import android.support.constraint.ConstraintLayout
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.CompoundButton
+import com.kdanmobile.reader.R
+import kotlinx.android.synthetic.main.view_turn_page_mode_select.view.*
+
+class TurnPageModeSelectView : ConstraintLayout {
+    companion object {
+        const val vertical = 0
+        const val horizontal = 1
+    }
+
+    interface OnTurnPageModeChangedListener {
+        fun onTurnPageModeChanged(direction: Int)
+    }
+
+    var onTurnPageModeChangedListener: OnTurnPageModeChangedListener? = null
+
+    var onShowTurnPageBtnEnableChangedListener: CompoundButton.OnCheckedChangeListener? = null
+        set(value) {
+            field = value
+            rowSwitchView_showTurnPageBtn?.onCheckedChangeListener = value
+        }
+
+    var direction: Int? = null
+        set(value) {
+            field = value
+            when (value) {
+                vertical -> radioBtn_turnPageMode_vertically.isChecked = true
+                horizontal -> radioBtn_turnPageMode_horizontally.isChecked = true
+            }
+        }
+
+    var isTurnPageBtnEnable: Boolean = false
+        set(value) {
+            field = value
+            rowSwitchView_showTurnPageBtn?.isChecked = value
+        }
+
+    constructor(context: Context) : super(context) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+        initView()
+    }
+
+    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
+        initView()
+    }
+
+    private fun initView() {
+        LayoutInflater.from(context).inflate(R.layout.view_turn_page_mode_select, this)
+
+        radioGroup_turnPageMode.setOnCheckedChangeListener { _, checkedId ->
+            when (checkedId) {
+                R.id.radioBtn_turnPageMode_vertically -> onTurnPageModeChangedListener?.onTurnPageModeChanged(vertical)
+                R.id.radioBtn_turnPageMode_horizontally -> onTurnPageModeChangedListener?.onTurnPageModeChanged(horizontal)
+            }
+        }
+    }
+}

+ 294 - 0
reader/src/main/java/com/kdanmobile/reader/utils/AnimationUtil.kt

@@ -0,0 +1,294 @@
+package com.kdanmobile.reader.utils
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
+import android.animation.PropertyValuesHolder
+import android.animation.ValueAnimator
+import android.os.Handler
+import android.os.Looper
+import android.view.View
+import android.view.animation.AccelerateInterpolator
+import android.view.animation.Animation
+import android.view.animation.LinearInterpolator
+
+/**
+ * @项目名称:PDFReader_android_for_as
+ * @包名称:com.kdanmobile.pdf.tools
+ * @文件名称:AnimationUtil
+ * @创建时间:15/9/12 - 上午11:29 - 11
+ * @创建人:luozhipeng
+ * @修改记录:
+ * @修改人: --------------------------------------
+ * @Copyright (c)-2015kdanmobile
+ */
+class AnimationUtil private constructor() {
+
+    init {
+        /* cannot be instantiated */
+        throw UnsupportedOperationException("cannot be instantiated")
+    }
+
+    companion object {
+        private var showTopToBottom: ObjectAnimator? = null
+        private var showBottomToTop: ObjectAnimator? = null
+        private var showRightToLeft: ObjectAnimator? = null
+        private var showLeftToRight: ObjectAnimator? = null
+
+        fun ViewScaleAnimation(view: View?, toScale: Float, duration: Long = 16000) {
+            if (view != null && view.animation != null) {
+                view.animation.start()
+                return
+            }
+            val anim1 = ObjectAnimator.ofFloat(view, "scaleX", 1.0f, toScale, 1.0f)
+            anim1.duration = duration
+            anim1.repeatMode = ValueAnimator.RESTART
+            anim1.repeatCount = Animation.INFINITE
+            val anim2 = ObjectAnimator.ofFloat(view, "scaleY", 1.0f, toScale, 1.0f)
+            anim2.duration = duration
+            anim2.repeatMode = ValueAnimator.RESTART
+            anim2.repeatCount = Animation.INFINITE
+            //        ObjectAnimator anim3 = ObjectAnimator.ofFloat(view, "alpha",
+            //                1.0f, 0.9f, 1.0f);
+            //        anim3.setDuration(16000);
+            //        anim3.setRepeatMode(Animation.RESTART);
+            //        anim3.setRepeatCount(Animation.INFINITE);
+            val animSet = AnimatorSet()
+            animSet.interpolator = LinearInterpolator()
+            animSet.playTogether(anim1, anim2)
+            animSet.start()
+        }
+
+        private fun ImageViewAnimation(view: View, duration: Long = 16000) {
+            val pvhX = PropertyValuesHolder.ofFloat("alpha", 1f, 0.4f, 1f)
+            val pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.2f, 1f)
+            val pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.2f, 1f)
+            val anim = ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ)
+            anim.repeatCount = Animation.INFINITE//1->2->1的循环模式
+            anim.repeatMode = ValueAnimator.RESTART//无限模式
+            anim.interpolator = AccelerateInterpolator()
+            anim.setDuration(duration).start()
+        }
+
+        /**
+         * 隐藏buttons控件,从控件顶部往底部回收隐藏
+         *
+         * @param view
+         */
+        fun hideViewFromTopToBottom(view: View?, duration: Long = 300) {
+            if (showBottomToTop != null && showBottomToTop!!.isRunning())
+                return;
+
+            if (view != null && view.visibility == View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0f)
+                val pvhY = PropertyValuesHolder.ofFloat("Y", view.top.toFloat(), view.top.toFloat() + view.height)
+                showBottomToTop = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhY)
+                showBottomToTop!!.interpolator = AccelerateInterpolator()
+                showBottomToTop!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator) {
+                        super.onAnimationEnd(animation)
+                        Handler(Looper.getMainLooper()).post { view.visibility = View.INVISIBLE }
+                    }
+                })
+                showBottomToTop!!.setDuration(duration).start()
+            }
+        }
+
+        /**
+         * 显示buttons控件,从控件底部往控件顶部扩展显示
+         *
+         * @param view
+         */
+        fun showViewFromBottomToTop(view: View?, duration: Long = 300) {
+            if (showBottomToTop != null && showBottomToTop!!.isRunning())
+                return;
+
+            if (view != null && view.visibility != View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 0f, 1.0f)
+                val pvhY = PropertyValuesHolder.ofFloat("Y", view.top.toFloat() + view.height, view.top.toFloat())
+                showBottomToTop = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhY)
+                showBottomToTop!!.interpolator = AccelerateInterpolator()
+                showBottomToTop!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationStart(animation: Animator) {
+                        super.onAnimationStart(animation)
+                        view.visibility = View.VISIBLE
+                    }
+                })
+                showBottomToTop!!.setDuration(duration).start()
+            }
+        }
+
+        fun showViewFromRightToLeft(view: View?, duration: Long = 300) {
+            if (showRightToLeft != null && showRightToLeft!!.isRunning)
+                return
+
+            if (view != null && view.visibility != View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 0f, 1.0f)
+                val pvhX = PropertyValuesHolder.ofFloat("X", view.left.toFloat() + view.width, view.left.toFloat())
+                showRightToLeft = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhX)
+                showRightToLeft!!.interpolator = AccelerateInterpolator()
+                showRightToLeft!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationStart(animation: Animator) {
+                        super.onAnimationStart(animation)
+                        view.visibility = View.VISIBLE
+                    }
+                })
+                showRightToLeft!!.setDuration(duration).start()
+            }
+        }
+
+        fun hideViewFromLeftToRight(view: View?, duration: Long = 300) {
+            if (showRightToLeft != null && showRightToLeft!!.isRunning)
+                return
+
+            if (view != null && view.visibility == View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0f)
+                val pvhX = PropertyValuesHolder.ofFloat("X", view.left.toFloat(), view.left.toFloat() + view.width)
+                showRightToLeft = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhX)
+                showRightToLeft!!.interpolator = AccelerateInterpolator()
+                showRightToLeft!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator) {
+                        super.onAnimationEnd(animation)
+                        Handler(Looper.getMainLooper()).post { view.visibility = View.INVISIBLE }
+                    }
+                })
+                showRightToLeft!!.setDuration(duration).start()
+            }
+        }
+
+        /**
+         * 显示buttons控件,从控件顶部往控件底部扩展显示
+         *
+         * @param view
+         */
+        fun showViewFromTopToBottom(view: View?, duration: Long = 300) {
+            if (showTopToBottom != null && showTopToBottom!!.isRunning)
+                return
+
+            if (view != null && view.visibility != View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 0f, 1.0f)
+                val pvhY = PropertyValuesHolder.ofFloat("Y", view.top.toFloat() - view.height, view.top.toFloat())
+                showTopToBottom = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhY)
+                showTopToBottom!!.interpolator = AccelerateInterpolator()
+                showTopToBottom!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationStart(animation: Animator) {
+                        super.onAnimationStart(animation)
+                        view.visibility = View.VISIBLE
+                    }
+                })
+                showTopToBottom!!.setDuration(duration).start()
+            }
+        }
+
+        /**
+         * 隐藏buttons控件,从控件底部往控件顶部收缩隐藏
+         *
+         * @param view
+         */
+        fun hideViewFromBottomToTop(view: View?, duration: Long = 300) {
+            if (showTopToBottom != null && showTopToBottom!!.isRunning)
+                return
+
+            if (view != null && view.visibility == View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0f)
+                val pvhY = PropertyValuesHolder.ofFloat("Y", view.top.toFloat(), view.top.toFloat() - view.height)
+                showTopToBottom = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhY)
+                showTopToBottom!!.interpolator = AccelerateInterpolator()
+                showTopToBottom!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator) {
+                        super.onAnimationEnd(animation)
+                        Handler(Looper.getMainLooper()).post { view.visibility = View.INVISIBLE }
+                    }
+                })
+                showTopToBottom!!.setDuration(duration).start()
+            }
+        }
+
+        fun showViewFromLeftToRight(view: View?, duration: Long = 300) {
+            if (showLeftToRight != null && showLeftToRight!!.isRunning)
+                return
+
+            if (view != null && view.visibility != View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 0f, 1.0f)
+                val pvhX = PropertyValuesHolder.ofFloat("X", view.left.toFloat() - view.width, view.left.toFloat())
+                showLeftToRight = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhX)
+                showLeftToRight!!.interpolator = AccelerateInterpolator()
+                showLeftToRight!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationStart(animation: Animator) {
+                        super.onAnimationStart(animation)
+                        view.visibility = View.VISIBLE
+                    }
+                })
+                showLeftToRight!!.setDuration(duration).start()
+            }
+        }
+
+        fun hideViewFromRightToLeft(view: View?, duration: Long = 300) {
+            if (showLeftToRight != null && showLeftToRight!!.isRunning)
+                return
+
+            if (view != null && view.visibility == View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0f)
+                val pvhX = PropertyValuesHolder.ofFloat("X", view.left.toFloat(), view.left.toFloat() - view.width)
+                showLeftToRight = ObjectAnimator.ofPropertyValuesHolder(view, pvhA, pvhX)
+                showLeftToRight!!.interpolator = AccelerateInterpolator()
+                showLeftToRight!!.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator) {
+                        super.onAnimationEnd(animation)
+                        Handler(Looper.getMainLooper()).post { view.visibility = View.INVISIBLE }
+                    }
+                })
+                showLeftToRight!!.setDuration(duration).start()
+            }
+        }
+
+        fun showViewAlpha(view: View?, duration: Long = 300) {
+            if (view != null && view.visibility != View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 0f, 1.0f)
+                val animAlpha = ObjectAnimator.ofPropertyValuesHolder(view, pvhA)
+                animAlpha.interpolator = AccelerateInterpolator()
+                animAlpha.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationStart(animation: Animator) {
+                        super.onAnimationStart(animation)
+                        view.visibility = View.VISIBLE
+                    }
+                })
+                animAlpha.setDuration(duration).start()
+            }
+        }
+
+        fun hideViewAlpha(view: View?, duration: Long = 300) {
+            if (view != null && view.visibility == View.VISIBLE) {
+                val pvhA = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0f)
+                val animAlpha = ObjectAnimator.ofPropertyValuesHolder(view, pvhA)
+                animAlpha.interpolator = AccelerateInterpolator()
+                animAlpha.addListener(object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator) {
+                        super.onAnimationEnd(animation)
+                        Handler(Looper.getMainLooper()).post { view.visibility = View.GONE }
+                    }
+                })
+                animAlpha.setDuration(duration).start()
+            }
+        }
+
+        /**
+         * 结束该动画
+         */
+        fun cancelAnimations() {
+            if (showTopToBottom != null)
+                showTopToBottom!!.cancel()
+            if (showBottomToTop != null)
+                showBottomToTop!!.cancel()
+            if (showLeftToRight != null)
+                showLeftToRight!!.cancel()
+            if (showRightToLeft != null)
+                showRightToLeft!!.cancel()
+            showTopToBottom = null
+            showBottomToTop = null
+            showRightToLeft = null
+            showLeftToRight = null
+        }
+    }
+}

+ 46 - 0
reader/src/main/java/com/kdanmobile/reader/utils/DensityUtil.kt

@@ -0,0 +1,46 @@
+package com.kdanmobile.reader.utils
+
+import android.content.Context
+
+
+class DensityUtil private constructor() {
+
+    init {
+        throw UnsupportedOperationException("cannot be instantiated")
+    }
+
+    companion object {
+
+        fun getDensityDpi(context: Context): Int {
+            return context.resources.displayMetrics.densityDpi
+        }
+
+        fun getDensity(context: Context): Float {
+            return context.resources.displayMetrics.density
+        }
+
+        fun getScreenWidthPx(context: Context): Int {
+            return context.resources.displayMetrics.widthPixels
+        }
+
+        fun getScreenHeightPx(context: Context): Int {
+            return context.resources.displayMetrics.heightPixels
+        }
+
+        fun dp2px(context: Context, dpVal: Float): Int {
+            return (dpVal * context.resources.displayMetrics.density + 0.5f).toInt()
+        }
+
+        fun sp2px(context: Context, spVal: Float): Int {
+            return (spVal * context.resources.displayMetrics.scaledDensity + 0.5f).toInt()
+        }
+
+        fun px2dp(context: Context, pxVal: Float): Float {
+            return pxVal / context.resources.displayMetrics.density
+        }
+
+        fun px2sp(context: Context, pxVal: Float): Float {
+            return pxVal / context.resources.displayMetrics.scaledDensity
+        }
+    }
+}

+ 55 - 0
reader/src/main/java/com/kdanmobile/reader/widget/drag/OnRecyclerItemClickListener.kt

@@ -0,0 +1,55 @@
+package com.kdanmobile.reader.widget.drag
+
+import android.support.v4.view.GestureDetectorCompat
+import android.support.v7.widget.RecyclerView
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.View
+
+/**
+ * @classname:OnRecyclerItemClickListener
+ * @author:luozhipeng
+ * @date:1/11/17 21:57
+ * @description:监控RecyclerView的点击事件,单击,长按
+ */
+abstract class OnRecyclerItemClickListener(private val recyclerView: RecyclerView) : RecyclerView.OnItemTouchListener {
+    private val mGestureDetector: GestureDetectorCompat
+
+    init {
+        mGestureDetector = GestureDetectorCompat(recyclerView.context, ItemTouchHelperGestureListener())
+    }
+
+    override fun onInterceptTouchEvent(recyclerView: RecyclerView, e: MotionEvent): Boolean {
+        mGestureDetector.onTouchEvent(e)
+        return false
+    }
+
+    override fun onTouchEvent(recyclerView: RecyclerView, e: MotionEvent) {
+        mGestureDetector.onTouchEvent(e)
+    }
+
+    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
+
+    private inner class ItemTouchHelperGestureListener : GestureDetector.SimpleOnGestureListener() {
+        override fun onSingleTapUp(e: MotionEvent): Boolean {
+            val child = recyclerView.findChildViewUnder(e.x, e.y)
+            if (child != null) {
+                val vh = recyclerView.getChildViewHolder(child)
+                onItemClick(vh)
+            }
+            return true
+        }
+
+        override fun onLongPress(e: MotionEvent) {
+            val child = recyclerView.findChildViewUnder(e.x, e.y)
+            if (child != null) {
+                val vh = recyclerView.getChildViewHolder(child)
+                onItemLongClick(vh)
+            }
+        }
+    }
+
+    abstract fun onItemClick(viewHolder: RecyclerView.ViewHolder)
+
+    abstract fun onItemLongClick(viewHolder: RecyclerView.ViewHolder)
+}

BIN
reader/src/main/res/drawable-hdpi/ic_format_pdf_48dp.png


BIN
reader/src/main/res/drawable-hdpi/ic_stat_lock.png


BIN
reader/src/main/res/drawable-hdpi/ic_textfield_search.png


BIN
reader/src/main/res/drawable-hdpi/icon_line.webp


BIN
reader/src/main/res/drawable-xhdpi/ic_stat_lock.png


BIN
reader/src/main/res/drawable-xhdpi/ic_textfield_search.png


BIN
reader/src/main/res/drawable-xhdpi/icon_line.webp


BIN
reader/src/main/res/drawable-xxhdpi/ic_format_pdf_48dp.png


BIN
reader/src/main/res/drawable-xxhdpi/ic_stat_lock.png


BIN
reader/src/main/res/drawable/ic_stat_lock.png


+ 7 - 0
reader/src/main/res/drawable/rectangle_0000.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <solid android:color="#0000" />
+
+</shape>

+ 7 - 0
reader/src/main/res/drawable/rectangle_6633b5e5.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <solid android:color="#6633b5e5" />
+
+</shape>

+ 11 - 0
reader/src/main/res/drawable/rectangle_stroke_1_aaa_ffff.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="1dp"
+        android:color="#aaa" />
+
+    <solid android:color="#fff"/>
+    
+</shape>

+ 11 - 0
reader/src/main/res/drawable/rectangle_stroke_1_d5d5d5_ffff.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="1dp"
+        android:color="#d5d5d5" />
+
+    <solid android:color="#fff"/>
+    
+</shape>

+ 11 - 0
reader/src/main/res/drawable/rectangle_stroke_4dp_33b5e5_0000.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="4dp"
+        android:color="#33b5e5" />
+
+    <solid android:color="#0000"/>
+    
+</shape>

+ 8 - 0
reader/src/main/res/drawable/selector_day_mode.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/shape_day_mode_checked" android:state_pressed="true" />
+    <item android:drawable="@drawable/shape_day_mode_checked" android:state_activated="true" />
+    <item android:drawable="@drawable/shape_day_mode" />
+
+</selector>

+ 8 - 0
reader/src/main/res/drawable/selector_edittext.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/rectangle_stroke_1_d5d5d5_ffff" android:state_pressed="true"/>
+    <item android:drawable="@drawable/rectangle_stroke_1_d5d5d5_ffff" android:state_enabled="true" android:state_focused="true"/>
+    <item android:drawable="@drawable/rectangle_stroke_1_aaa_ffff"/>
+
+</selector>

+ 8 - 0
reader/src/main/res/drawable/selector_lilac_mode.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/shape_white_lilac_mode_checked" android:state_pressed="true" />
+    <item android:drawable="@drawable/shape_white_lilac_mode_checked" android:state_activated="true" />
+    <item android:drawable="@drawable/shape_white_lilac_mode" />
+
+</selector>

+ 8 - 0
reader/src/main/res/drawable/selector_listview_item.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/rectangle_6633b5e5" android:state_pressed="true"/>
+    <item android:drawable="@drawable/rectangle_6633b5e5" android:state_enabled="true" android:state_focused="true"/>
+    <item android:drawable="@drawable/rectangle_0000"/>
+
+</selector>

+ 8 - 0
reader/src/main/res/drawable/selector_night_mode.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/shape_night_mode_checked" android:state_pressed="true" />
+    <item android:drawable="@drawable/shape_night_mode_checked" android:state_activated="true" />
+    <item android:drawable="@drawable/shape_night_mode" />
+
+</selector>

+ 8 - 0
reader/src/main/res/drawable/selector_sefia_mode.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/shape_sepia_mode_checked" android:state_pressed="true" />
+    <item android:drawable="@drawable/shape_sepia_mode_checked" android:state_activated="true" />
+    <item android:drawable="@drawable/shape_sepia_mode" />
+
+</selector>

+ 9 - 0
reader/src/main/res/drawable/shape_day_mode.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#ffffff" />
+    <stroke
+        android:width="2dp"
+        android:color="#ffffff" />
+    <corners android:radius="4dp" />
+</shape>

+ 9 - 0
reader/src/main/res/drawable/shape_day_mode_checked.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#ffffff" />
+    <stroke
+        android:width="2dp"
+        android:color="#0077fd" />
+    <corners android:radius="4dp" />
+</shape>

+ 9 - 0
reader/src/main/res/drawable/shape_night_mode.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#000000" />
+    <stroke
+        android:width="2dp"
+        android:color="#ffffff" />
+    <corners android:radius="4dp" />
+</shape>

+ 9 - 0
reader/src/main/res/drawable/shape_night_mode_checked.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#000000" />
+    <stroke
+        android:width="2dp"
+        android:color="#0077fd" />
+    <corners android:radius="4dp" />
+</shape>

+ 9 - 0
reader/src/main/res/drawable/shape_sepia_mode.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#eedebc" />
+    <stroke
+        android:width="2dp"
+        android:color="#ffffff" />
+    <corners android:radius="4dp" />
+</shape>

+ 9 - 0
reader/src/main/res/drawable/shape_sepia_mode_checked.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#eedebc" />
+    <stroke
+        android:width="2dp"
+        android:color="#0077fd" />
+    <corners android:radius="4dp" />
+</shape>

+ 9 - 0
reader/src/main/res/drawable/shape_white_lilac_mode.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#e2e2e2" />
+    <stroke
+        android:width="2dp"
+        android:color="#ffffff" />
+    <corners android:radius="4dp" />
+</shape>

+ 9 - 0
reader/src/main/res/drawable/shape_white_lilac_mode_checked.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#e2e2e2" />
+    <stroke
+        android:width="2dp"
+        android:color="#0077fd" />
+    <corners android:radius="4dp" />
+</shape>

+ 17 - 9
reader/src/main/res/layout/activity_reader.xml

@@ -45,47 +45,54 @@
     <com.kdanmobile.reader.view.HorizontalView
         android:id="@+id/viewGroup_readerActivity_leftToolbar"
         app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        android:background="@drawable/bg_reader_tool_bar_left"
+        app:layout_constraintTop_toBottomOf="@+id/toolbar_readerActivity"
+        app:layout_constraintBottom_toTopOf="@+id/viewGroup_readerActivity_bottomToolbar"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content">
         <android.support.constraint.ConstraintLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content">
-            <FrameLayout
-                android:id="@+id/frameLayout_readerActivity_leftToolbarContainer"
+            <LinearLayout
+                android:id="@+id/linearLayout_readerActivity_leftToolbarContainer"
+                app:layout_constraintRight_toLeftOf="@+id/viewGroup_readerActivity_leftToolbarButtons"
                 app:layout_constraintLeft_toLeftOf="parent"
-                app:layout_constraintRight_toRightOf="parent"
                 app:layout_constraintTop_toTopOf="parent"
                 app:layout_constraintBottom_toBottomOf="parent"
-                android:layout_width="0dp"
-                android:layout_height="0dp" />
+                android:background="@drawable/bg_reader_tool_bar_left"
+                android:orientation="vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
             <LinearLayout
                 android:id="@+id/viewGroup_readerActivity_leftToolbarButtons"
-                app:layout_constraintLeft_toLeftOf="parent"
+                app:layout_constraintLeft_toRightOf="@+id/linearLayout_readerActivity_leftToolbarContainer"
+                app:layout_constraintRight_toRightOf="parent"
                 app:layout_constraintTop_toTopOf="parent"
                 app:layout_constraintBottom_toBottomOf="parent"
+                android:background="@drawable/bg_reader_tool_bar_left"
                 android:orientation="vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content">
                 <ImageView
                     android:id="@+id/iv_readerActivity_thumbnail"
+                    android:onClick="onClick"
                     style="@style/ReaderLeftRightToolbarIImageButton"
                     android:src="@drawable/ic_pagelist_thumbnail_nor" />
                 <View style="@style/ReaderLeftToolbarDivider"/>
                 <ImageView
                     android:id="@+id/iv_readerActivity_bookmark"
+                    android:onClick="onClick"
                     style="@style/ReaderLeftRightToolbarIImageButton"
                     android:src="@drawable/ic_pagelist_bookmk_nor" />
                 <View style="@style/ReaderLeftToolbarDivider"/>
                 <ImageView
                     android:id="@+id/iv_readerActivity_outline"
+                    android:onClick="onClick"
                     style="@style/ReaderLeftRightToolbarIImageButton"
                     android:src="@drawable/ic_pagelist_outline_nor" />
                 <View style="@style/ReaderLeftToolbarDivider"/>
                 <ImageView
                     android:id="@+id/iv_readerActivity_search"
+                    android:onClick="onClick"
                     style="@style/ReaderLeftRightToolbarIImageButton"
                     android:src="@drawable/ic_pagelist_search_nor" />
             </LinearLayout>
@@ -109,6 +116,7 @@
                 <ImageView
                     android:id="@+id/iv_readerActivity_fullScreen"
                     android:src="@drawable/selector_tool_fullscreen"
+                    android:onClick="onClick"
                     app:layout_constraintTop_toTopOf="parent"
                     app:layout_constraintBottom_toTopOf="@id/view_readerActivity_rightToolbarDividerFullScreenCopy"
                     style="@style/ReaderLeftRightToolbarIImageButton" />

+ 79 - 0
reader/src/main/res/layout/activity_viewer_setting.xml

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".screen.ViewerSettingActivity">
+
+    <android.support.constraint.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar_viewerSetting"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:elevation="4dp"
+            android:minHeight="?attr/actionBarSize"
+            android:theme="@style/ReaderToolBarStyle"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <com.kdanmobile.reader.screen.view.ReadingModeSelectView
+            android:id="@+id/readingModeSelectView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/toolbar_viewerSetting" />
+
+        <com.kdanmobile.reader.screen.view.RowSwitchView
+            android:id="@+id/rowSwitchView_smartCrop"
+            android:layout_width="0dp"
+            android:layout_height="48dp"
+            android:layout_marginTop="24dp"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/readingModeSelectView"
+            app:text="@string/viewer_setting_switch_smart_crop" />
+
+        <com.kdanmobile.reader.screen.view.RowSwitchView
+            android:id="@+id/rowSwitchView_showStateBar"
+            android:layout_width="0dp"
+            android:layout_height="48dp"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/rowSwitchView_smartCrop"
+            app:text="@string/viewer_setting_switch_show_state_bar" />
+
+        <com.kdanmobile.reader.screen.view.TurnPageModeSelectView
+            android:id="@+id/turnPageModeSelectView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/rowSwitchView_showStateBar" />
+
+        <com.kdanmobile.reader.screen.view.ScreenSettingView
+            android:id="@+id/screenSettingView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/turnPageModeSelectView" />
+
+        <com.kdanmobile.reader.screen.view.ToolbarSettingView
+            android:id="@+id/toolbarSettingView"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/screenSettingView" />
+
+    </android.support.constraint.ConstraintLayout>
+</ScrollView>

+ 49 - 0
reader/src/main/res/layout/item_bookmark.xml

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal">
+
+    <RelativeLayout
+        android:id="@+id/tv_fragmentPdfReaderBookmarkLvItem_rl"
+        android:layout_width="180dp"
+        android:layout_height="360dp">
+
+        <ImageView
+            android:id="@+id/iv_fragmentPdfReaderBookmarkLvItem_"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/rectangle_stroke_1_d5d5d5_ffff"
+            android:padding="1px"
+            android:scaleType="fitCenter"/>
+
+        <TextView
+            android:id="@+id/tv_fragmentPdfReaderBookmarkLvItem_page"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:background="#99cccccc"
+            android:gravity="center"
+            android:paddingBottom="6dp"
+            android:paddingTop="6dp"
+            android:text="1"
+            android:textColor="@color/black_87"
+            android:textSize="12sp"/>
+    </RelativeLayout>
+
+    <TextView
+        android:id="@+id/tv_fragmentPdfReaderBookmarkLvItem_name"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:ellipsize="start"
+        android:gravity="center_vertical"
+        android:maxLines="6"
+        android:paddingLeft="4dp"
+        android:paddingRight="4dp"
+        android:text="书签"
+        android:textColor="@color/black_87"
+        android:textSize="12sp"/>
+
+</LinearLayout>

+ 46 - 0
reader/src/main/res/layout/item_search.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical" >
+
+    <RelativeLayout
+        android:id="@+id/rl_fragmentPdfReaderSearchLvItem_"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dp"
+        android:layout_marginRight="10dp"
+        android:background="@drawable/rectangle_stroke_1_d5d5d5_ffff"
+        android:orientation="vertical" >
+
+        <TextView
+            android:id="@+id/tv_fragmentPdfReaderSearchLvItem_result"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="2dp"
+            android:maxLines="3"
+            android:minLines="3"
+            android:gravity="center_vertical"
+            android:text="ni hao"
+            android:textColor="#222"
+            android:textSize="12sp" />
+
+        <TextView
+            android:id="@+id/tv_fragmentPdfReaderSearchLvItem_page"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/tv_fragmentPdfReaderSearchLvItem_result"
+            android:background="#ffd5d5d5"
+            android:gravity="center_horizontal"
+            android:text="1"
+            android:textColor="#222"
+            android:textSize="12sp" />
+
+        <View
+            android:id="@+id/view_fragmentPdfReaderSearchLvItem_selected"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_alignBottom="@id/tv_fragmentPdfReaderSearchLvItem_page" />
+    </RelativeLayout>
+
+</LinearLayout>

+ 36 - 0
reader/src/main/res/layout/item_thumbnail.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/id_reader_thumb_fl"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_margin="12dp">
+
+    <ImageView
+        android:id="@+id/iv_fragmentPdfReaderThumbLvItem_"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/rectangle_stroke_1_d5d5d5_ffff"
+        android:padding="1px"
+        android:scaleType="fitCenter"/>
+
+    <TextView
+        android:id="@+id/tv_fragmentPdfReaderThumbLvItem_page"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom"
+        android:background="#99cccccc"
+        android:gravity="center"
+        android:paddingBottom="6dp"
+        android:paddingTop="6dp"
+        android:text="1"
+        android:textColor="@color/black_87"
+        android:textSize="12sp"/>
+
+    <View
+        android:id="@+id/v_pdfThumbGvItem_"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/rectangle_stroke_4dp_33b5e5_0000"
+        android:visibility="gone"/>
+</FrameLayout>

+ 45 - 0
reader/src/main/res/layout/outline_entry.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="4dp"
+    android:paddingRight="4dp">
+
+    <TextView
+        android:id="@+id/tv_outlineEntry_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_toLeftOf="@+id/tv_outlineEntry_page"
+        android:background="#0000"
+        android:ellipsize="end"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
+        android:maxLines="1"
+        android:minLines="1"
+        android:singleLine="true"
+        android:text="大纲选项内容"
+        android:textColor="#222"
+        android:textSize="10sp"/>
+
+    <TextView
+        android:id="@+id/tv_outlineEntry_page"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_centerVertical="true"
+        android:gravity="center_vertical"
+        android:maxLines="1"
+        android:paddingLeft="5dp"
+        android:text="1"
+        android:textColor="#222"
+        android:textSize="8sp"/>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:layout_alignParentBottom="true"
+        android:background="#1a000000"/>
+
+</RelativeLayout>

+ 32 - 0
reader/src/main/res/layout/view_bookmark.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/ll_fragmentPdfReaderBookmark"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center_horizontal"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/tv_fragmentPdfReaderBookmark_"
+        android:layout_width="wrap_content"
+        android:layout_height="30dp"
+        android:drawableLeft="@drawable/ic_pagelist_title_bookmk"
+        android:gravity="center_vertical"
+        android:text="@string/bookmark_title"
+        android:textColor="#afafaf"
+        android:textSize="12sp"/>
+
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:background="#1a000000"/>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/id_km_bookmark_recycler"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:cacheColorHint="@null"
+        android:fadeScrollbars="true"
+        android:scrollbars="vertical"/>
+</LinearLayout>

+ 34 - 0
reader/src/main/res/layout/view_outline.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/ll_viewPdfReaderOutline"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#00000000"
+    android:gravity="center_horizontal"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/textView1"
+        android:layout_width="wrap_content"
+        android:layout_height="30dp"
+        android:drawableLeft="@drawable/ic_pagelist_title_outine"
+        android:gravity="center_vertical"
+        android:text="@string/outline_title"
+        android:textColor="#afafaf"
+        android:textSize="12sp"/>
+
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:background="#1a000000"/>
+
+    <ListView
+        android:id="@+id/lv_viewPdfReaderOutline_"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:divider="#0000"
+        android:dividerHeight="1px"
+        android:listSelector="@drawable/selector_listview_item"/>
+
+</LinearLayout>

+ 88 - 0
reader/src/main/res/layout/view_reading_mode_select.xml

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/tv_readingMode"
+        style="@style/Base.TextAppearance.AppCompat.Body1"
+        android:layout_width="0dp"
+        android:layout_height="48dp"
+        android:layout_marginEnd="16dp"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="8dp"
+        android:text="@string/viewer_setting_page_background_and_display"
+        android:textColor="#030303"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent" />
+
+    <ImageButton
+        android:id="@+id/btn_readingMode_day"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginLeft="16dp"
+        android:layout_marginStart="16dp"
+        android:background="#0000"
+        android:contentDescription="@string/viewer_setting_page_background_and_display"
+        android:src="@drawable/selector_day_mode"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_readingMode" />
+
+    <ImageButton
+        android:id="@+id/btn_readingMode_lilac"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginLeft="24dp"
+        android:layout_marginStart="24dp"
+        android:background="#0000"
+        android:contentDescription="@string/viewer_setting_page_background_and_display"
+        android:src="@drawable/selector_lilac_mode"
+        app:layout_constraintLeft_toRightOf="@+id/btn_readingMode_day"
+        app:layout_constraintTop_toBottomOf="@+id/tv_readingMode" />
+
+    <ImageButton
+        android:id="@+id/btn_readingMode_night"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginLeft="24dp"
+        android:layout_marginStart="24dp"
+        android:background="#0000"
+        android:contentDescription="@string/viewer_setting_page_background_and_display"
+        android:src="@drawable/selector_night_mode"
+        app:layout_constraintLeft_toRightOf="@+id/btn_readingMode_lilac"
+        app:layout_constraintTop_toBottomOf="@+id/tv_readingMode" />
+
+    <ImageView
+        android:id="@+id/iv_readingMode_night_lock"
+        android:layout_width="16dp"
+        android:layout_height="21dp"
+        android:src="@drawable/ic_stat_lock"
+        app:layout_constraintBottom_toBottomOf="@+id/btn_readingMode_night"
+        app:layout_constraintLeft_toLeftOf="@+id/btn_readingMode_night"
+        app:layout_constraintRight_toRightOf="@+id/btn_readingMode_night"
+        app:layout_constraintTop_toTopOf="@+id/btn_readingMode_night" />
+
+    <ImageButton
+        android:id="@+id/btn_readingMode_sefia"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginLeft="24dp"
+        android:layout_marginStart="24dp"
+        android:background="#0000"
+        android:contentDescription="@string/viewer_setting_page_background_and_display"
+        android:src="@drawable/selector_sefia_mode"
+        app:layout_constraintLeft_toRightOf="@+id/btn_readingMode_night"
+        app:layout_constraintTop_toBottomOf="@+id/tv_readingMode" />
+
+    <ImageView
+        android:id="@+id/iv_readingMode_sefia_lock"
+        android:layout_width="16dp"
+        android:layout_height="21dp"
+        android:src="@drawable/ic_stat_lock"
+        app:layout_constraintBottom_toBottomOf="@+id/btn_readingMode_sefia"
+        app:layout_constraintLeft_toLeftOf="@+id/btn_readingMode_sefia"
+        app:layout_constraintRight_toRightOf="@+id/btn_readingMode_sefia"
+        app:layout_constraintTop_toTopOf="@+id/btn_readingMode_sefia" />
+
+</android.support.constraint.ConstraintLayout>

+ 29 - 0
reader/src/main/res/layout/view_row_switch.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/rowSwitchView_text"
+        style="@style/Base.TextAppearance.Widget.AppCompat.Toolbar.Subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="16dp"
+        android:layout_marginStart="16dp"
+        android:textColor="#de000000"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <Switch
+        android:id="@+id/rowSwitchView_switch"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="16dp"
+        android:layout_marginRight="16dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>

+ 27 - 0
reader/src/main/res/layout/view_screen_setting.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/tv_turnPageMode"
+        style="@style/Base.TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="24dp"
+        android:layout_marginLeft="16dp"
+        android:layout_marginStart="16dp"
+        android:text="@string/viewer_setting_screen_setting"
+        android:textColor="#0077fd"
+        app:layout_constraintLeft_toLeftOf="parent" />
+
+    <com.kdanmobile.reader.screen.view.RowSwitchView
+        android:id="@+id/rowSwitchView_lockScreenSleepEnable"
+        android:layout_width="0dp"
+        android:layout_height="48dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_turnPageMode"
+        app:text="@string/viewer_setting_switch_screen_sleep" />
+
+</android.support.constraint.ConstraintLayout>

+ 89 - 0
reader/src/main/res/layout/view_search.xml

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:background="#00000000"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:id="@+id/ll_fragmentPdfReaderSearch"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:orientation="vertical" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="30dp" >
+
+            <TextView
+                android:id="@+id/tv_fragmentPdfReaderSearch_text"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/fragment_search_text"
+                android:textColor="#33b5e5"
+                android:textSize="15sp" />
+
+            <TextView
+                android:id="@+id/tv_fragmentPdfReaderSearch_page"
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/fragment_search_page"
+                android:textColor="#afafaf"
+                android:textSize="15sp" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:layout_marginBottom="2dp"
+            android:background="#1a000000" />
+
+        <EditText
+            android:id="@+id/et_fragmentPdfReaderSearch_"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dp"
+            android:background="@drawable/selector_edittext"
+            android:drawableLeft="@drawable/ic_textfield_search"
+            android:hint="@string/fragment_search_enter_page"
+            android:imeOptions="actionSearch"
+            android:padding="4dp"
+            android:singleLine="true"
+            android:textColor="#222"
+            android:textCursorDrawable="@drawable/icon_line"
+            android:textSize="14sp" >
+
+            <requestFocus />
+        </EditText>
+
+        <View
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:background="#1a000000" />
+
+        <ListView
+            android:id="@+id/lv_fragmentPdfReaderSearch_"
+            android:layout_width="match_parent"
+            android:layout_height="fill_parent"
+            android:divider="#0000"
+            android:dividerHeight="0dp"
+            android:fadeScrollbars="false"
+            android:listSelector="#0000" >
+        </ListView>
+
+        <TextView
+            android:id="@+id/tv_fragmentPdfReaderSearch_tishi"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:gravity="center"
+            android:text="@string/fileManager_no_results"
+            android:textColor="#444"
+            android:visibility="gone"
+            android:textSize="18sp" />
+    </LinearLayout>
+
+</LinearLayout>

+ 35 - 0
reader/src/main/res/layout/view_thumbnail.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/id_km_thumb_title"
+        android:layout_width="wrap_content"
+        android:layout_height="30dp"
+        android:layout_centerHorizontal="true"
+        android:drawableLeft="@drawable/ic_pagelist_title_thumbnail"
+        android:gravity="center_vertical"
+        android:text="@string/thumbnail_title"
+        android:textColor="#afafaf"
+        android:textSize="12sp"/>
+
+    <View
+        android:id="@+id/id_km_thumb_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:layout_below="@+id/id_km_thumb_title"
+        android:background="#1a000000"/>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/id_km_thumb_recycler"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@+id/id_km_thumb_divider"
+        android:layout_centerHorizontal="true"
+        android:layout_margin="10dp"
+        android:cacheColorHint="@null"
+        android:fadeScrollbars="true"
+        android:scrollbars="vertical"/>
+</RelativeLayout>

+ 36 - 0
reader/src/main/res/layout/view_toolbar_setting.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/tv_toolbar_setting"
+        style="@style/Base.TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="24dp"
+        android:layout_marginLeft="16dp"
+        android:layout_marginStart="16dp"
+        android:text="@string/viewer_setting_toolbar_display_setting"
+        android:textColor="#0077fd"
+        app:layout_constraintLeft_toLeftOf="parent" />
+
+    <com.kdanmobile.reader.screen.view.RowSwitchView
+        android:id="@+id/rowSwitchView_show_commentTool"
+        android:layout_width="0dp"
+        android:layout_height="48dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_toolbar_setting"
+        app:text="@string/viewer_setting_toolbar_display_setting_comment" />
+
+    <com.kdanmobile.reader.screen.view.RowSwitchView
+        android:id="@+id/rowSwitchView_show_BOTATool"
+        android:layout_width="0dp"
+        android:layout_height="48dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/rowSwitchView_show_commentTool"
+        app:text="@string/viewer_setting_toolbar_display_setting_bota" />
+
+</android.support.constraint.ConstraintLayout>

+ 52 - 0
reader/src/main/res/layout/view_turn_page_mode_select.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/tv_turnPageMode"
+        style="@style/Base.TextAppearance.AppCompat.Body1"
+        android:layout_width="wrap_content"
+        android:layout_height="24dp"
+        android:layout_marginLeft="16dp"
+        android:layout_marginStart="16dp"
+        android:text="@string/viewer_setting_page_turn_mode"
+        android:textColor="#0077fd"
+        app:layout_constraintLeft_toLeftOf="parent" />
+
+    <RadioGroup
+        android:id="@+id/radioGroup_turnPageMode"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="12dp"
+        android:layout_marginStart="12dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_turnPageMode">
+
+        <RadioButton
+            android:id="@+id/radioBtn_turnPageMode_horizontally"
+            android:layout_width="wrap_content"
+            android:layout_height="48dp"
+            android:text="@string/viewer_setting_page_turn_mode_horizontally"
+            app:layout_constraintLeft_toLeftOf="parent" />
+
+        <RadioButton
+            android:id="@+id/radioBtn_turnPageMode_vertically"
+            android:layout_width="wrap_content"
+            android:layout_height="48dp"
+            android:text="@string/viewer_setting_page_turn_mode_vertically"
+            app:layout_constraintLeft_toLeftOf="parent" />
+
+    </RadioGroup>
+
+    <com.kdanmobile.reader.screen.view.RowSwitchView
+        android:id="@+id/rowSwitchView_showTurnPageBtn"
+        android:layout_width="0dp"
+        android:layout_height="48dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/radioGroup_turnPageMode"
+        app:text="@string/viewer_setting_page_turn_button_visible" />
+
+</android.support.constraint.ConstraintLayout>

+ 6 - 0
reader/src/main/res/menu/reader_more.xml

@@ -1,6 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item
+        android:id="@+id/item_reader_bookmark"
+        android:icon="@drawable/ic_bookmark_border"
+        android:title="@string/reader_more_menu_bookmark"
+        app:showAsAction="ifRoom"
+        />
     <item
         android:id="@+id/item_reader_more_share"
         android:icon="@drawable/ic_share_black_op60_24dp"

+ 25 - 0
reader/src/main/res/values-de/strings.xml

@@ -5,6 +5,31 @@
     <string name="reader_more_menu_share">"Teilen  "</string>
     <string name="reader_more_menu_text_reflow">Text Rückfluss</string>
     <string name="reader_more_menu_print">Drucken</string>
+
     <string name="pdfReader_ppw_thickness">Größe</string>
     <string name="pdfReader_ppw_opacity">Deckkraft</string>
+
+    <string name="reader_more_menu_bookmark">Lesezeichen</string>
+    <string name="reader_alert_dialog_title_add_bookmark">Lesezeichen hinzufügen</string>
+    <string name="reader_alert_dialog_button_confirm">Bestätigen</string>
+    <string name="reader_alert_dialog_button_cancel">Abbrechen</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">Lesezeichen löschen</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">Sind Sie sicher, dass Sie %s löschen wollen?</string>
+
+    <string name="outline_title">Überblick</string>
+    <string name="bookmark_title">Lesezeichen</string>
+    <string name="thumbnail_title">Miniaturansicht</string>
+
+    <string name="fragment_search_page">Seite</string>
+    <string name="fragment_search_text">Text</string>
+    <string name="fragment_search_enter_page">Auf andere Seite springen</string>
+    <string name="fragment_search_enter_text">Textsuche</string>
+
+    <string name="fileManager_no_results">Keine Ergebnisse gefunden</string>
+    <string name="fileManager_thishi_search">Bitte geben Sie mindestens 3 Zeichen ein.</string>
+
+    <string name="dialogAddBookmark_page">Seite</string>
+    <string name="viewer_setting_page_turn_mode">Durch Seiten scrollen</string>
+    <string name="viewer_setting_page_turn_mode_vertically">Vertikal</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">Horizontal</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-es/strings.xml

@@ -7,4 +7,28 @@
     <string name="reader_more_menu_print">Borrar firma</string>
     <string name="pdfReader_ppw_thickness">Tamaño</string>
     <string name="pdfReader_ppw_opacity">Opacidad</string>
+
+    <string name="reader_more_menu_bookmark">Marcador</string>
+    <string name="reader_alert_dialog_title_add_bookmark">Añadir marcador</string>
+    <string name="reader_alert_dialog_button_confirm">Confirmar</string>
+    <string name="reader_alert_dialog_button_cancel">Cancelar</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">Eliminar marcador</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">¿Seguro que deseas eliminar %s ?</string>
+
+    <string name="outline_title">Contorno</string>
+    <string name="bookmark_title">Marcador</string>
+    <string name="thumbnail_title">Miniatura</string>
+
+    <string name="fragment_search_page">Página</string>
+    <string name="fragment_search_text">Texto</string>
+    <string name="fragment_search_enter_page">Ir a la página</string>
+    <string name="fragment_search_enter_text">Búsqueda de texto</string>
+
+    <string name="fileManager_no_results">No se han encontrado resultados</string>
+    <string name="fileManager_thishi_search">Por favor, introduce al menos 3 caracteres.</string>
+
+    <string name="dialogAddBookmark_page">página</string>
+    <string name="viewer_setting_page_turn_mode">Desplace páginas</string>
+    <string name="viewer_setting_page_turn_mode_vertically">Verticalmente</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">Horizontalmente</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-fr/strings.xml

@@ -7,4 +7,28 @@
     <string name="reader_more_menu_print">Imprimer</string>
     <string name="pdfReader_ppw_thickness">Taille</string>
     <string name="pdfReader_ppw_opacity">Opacité</string>
+
+    <string name="reader_more_menu_bookmark">Marquer la page</string>
+    <string name="reader_alert_dialog_title_add_bookmark">Ajouter un marque page</string>
+    <string name="reader_alert_dialog_button_confirm">Confirmer</string>
+    <string name="reader_alert_dialog_button_cancel">Annuler</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">Supprimer un marque page</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">Etes-vous sûre de vouloir supprimer %s ?</string>
+
+    <string name="outline_title">Outline</string>
+    <string name="bookmark_title">Marquer la page</string>
+    <string name="thumbnail_title">Miniatures</string>
+
+    <string name="fragment_search_page">Page</string>
+    <string name="fragment_search_text">Texte</string>
+    <string name="fragment_search_enter_page">Passer à la page</string>
+    <string name="fragment_search_enter_text">Recherche de texte</string>
+
+    <string name="fileManager_no_results">Aucun résultat trouvé</string>
+    <string name="fileManager_thishi_search">Veuillez entrer au moins 3 caractères.</string>
+
+    <string name="dialogAddBookmark_page">Page</string>
+    <string name="viewer_setting_page_turn_mode">Défilement des Pages</string>
+    <string name="viewer_setting_page_turn_mode_vertically">Verticalement</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">Horizontalement</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-it/strings.xml

@@ -7,4 +7,28 @@
     <string name="reader_more_menu_print">Stampa</string>
     <string name="pdfReader_ppw_thickness">Dimensione</string>
     <string name="pdfReader_ppw_opacity">Opacità</string>
+
+    <string name="reader_more_menu_bookmark">Segnalibro</string>
+    <string name="reader_alert_dialog_title_add_bookmark">Aggiungi segnalibro</string>
+    <string name="reader_alert_dialog_button_confirm">Conferma</string>
+    <string name="reader_alert_dialog_button_cancel">Cancella</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">Elimina segnalibro</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">Sei sicuro di voler cancellare %s ?</string>
+
+    <string name="outline_title">Contorno</string>
+    <string name="bookmark_title">Segnalibro</string>
+    <string name="thumbnail_title">Thumbnail</string>
+
+    <string name="fragment_search_page">Pagina</string>
+    <string name="fragment_search_text">Testo</string>
+    <string name="fragment_search_enter_page">Vai alla pagina</string>
+    <string name="fragment_search_enter_text">Ricerca di testo</string>
+
+    <string name="fileManager_no_results">Nessun risultato trovato</string>
+    <string name="fileManager_thishi_search">Si prega di inserire almeno 3 caratteri.</string>
+
+    <string name="dialogAddBookmark_page">Pagina</string>
+    <string name="viewer_setting_page_turn_mode">Pagine di scorrimento</string>
+    <string name="viewer_setting_page_turn_mode_vertically">Verticalmente</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">Orizzontalmente</string>
 </resources>

+ 23 - 0
reader/src/main/res/values-ja/strings.xml

@@ -7,4 +7,27 @@
     <string name="reader_more_menu_user_guide">ユーザーガイド</string>
     <string name="pdfReader_ppw_thickness">サイズ</string>
     <string name="pdfReader_ppw_opacity">透明度</string>
+
+    <string name="reader_more_menu_bookmark">ブックマーク</string>
+    <string name="reader_alert_dialog_title_add_bookmark">ブックマークを作成する</string>
+    <string name="reader_alert_dialog_button_confirm">確定</string>
+    <string name="reader_alert_dialog_button_cancel">キャンセル</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">ブックマークを削除する</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">「%s」のブックマークを削除しますか?</string>
+
+    <string name="outline_title">アウトライン</string>
+    <string name="bookmark_title">ブックマーク</string>
+    <string name="thumbnail_title">サムネイル</string>
+
+    <string name="fragment_search_page">ページ</string>
+    <string name="fragment_search_text">テキスト</string>
+    <string name="fragment_search_enter_page">ページ移動する</string>
+    <string name="fragment_search_enter_text">テキストを検索する</string>
+
+    <string name="fileManager_no_results">見つかりませんでした。</string>
+    <string name="fileManager_thishi_search">少なくとも3文字入力して下さい。</string>
+    <string name="viewer_setting_page_turn_mode">ページをスクロールします</string>
+    <string name="viewer_setting_page_turn_mode_vertically">縦方向</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">横方向</string>
+    <string name="dialogAddBookmark_page">ページ数:</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-ko/strings.xml

@@ -7,4 +7,28 @@
     <string name="reader_more_menu_print">인쇄</string>
     <string name="pdfReader_ppw_thickness">크기</string>
     <string name="pdfReader_ppw_opacity">투명도</string>
+
+    <string name="reader_more_menu_bookmark">북마크</string>
+    <string name="reader_alert_dialog_title_add_bookmark">북마크 추가</string>
+    <string name="reader_alert_dialog_button_confirm">확인</string>
+    <string name="reader_alert_dialog_button_cancel">취소</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">북마크 삭제</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">%s 를 삭제하시겠습니까?</string>
+
+    <string name="outline_title">아웃라인</string>
+    <string name="bookmark_title">북마크</string>
+    <string name="thumbnail_title">썸네일</string>
+
+    <string name="fragment_search_page">페이지</string>
+    <string name="fragment_search_text">텍스트</string>
+    <string name="fragment_search_enter_page">페이지 이동</string>
+    <string name="fragment_search_enter_text">텍스트 검색</string>
+
+    <string name="fileManager_no_results">결과 없음</string>
+    <string name="fileManager_thishi_search">최소 3자 이상 입력해 주십시오.</string>
+
+    <string name="dialogAddBookmark_page">페이지</string>
+    <string name="viewer_setting_page_turn_mode">페이지 스크롤</string>
+    <string name="viewer_setting_page_turn_mode_vertically">세로</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">가로</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-pt/strings.xml

@@ -7,4 +7,28 @@
     <string name="reader_more_menu_print">Imprimir</string>
     <string name="pdfReader_ppw_thickness">Tamanho</string>
     <string name="pdfReader_ppw_opacity">Opacidade</string>
+
+    <string name="reader_more_menu_bookmark">Marcador</string>
+    <string name="reader_alert_dialog_title_add_bookmark">Adicionar marcador</string>
+    <string name="reader_alert_dialog_button_confirm">Confirmar</string>
+    <string name="reader_alert_dialog_button_cancel">Cancelar</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">Apagar marcador</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">Você tem certeza que quer apagar %s ?</string>
+
+    <string name="outline_title">Contorno</string>
+    <string name="bookmark_title">Marcador</string>
+    <string name="thumbnail_title">Miniatura</string>
+
+    <string name="fragment_search_page">Página</string>
+    <string name="fragment_search_text">Texto</string>
+    <string name="fragment_search_enter_page">Avançar para página</string>
+    <string name="fragment_search_enter_text">Busca de texto</string>
+
+    <string name="fileManager_no_results">Não foram encontrados resultados</string>
+    <string name="fileManager_thishi_search">Por favor digite no mínimo 3 caracteres.</string>
+
+    <string name="dialogAddBookmark_page">página</string>
+    <string name="viewer_setting_page_turn_mode">Páginas de rolagem</string>
+    <string name="viewer_setting_page_turn_mode_vertically">Verticalmente</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">Horizontalmente</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-ru/strings.xml

@@ -7,4 +7,28 @@
     <string name="reader_more_menu_print">Печать</string>
     <string name="pdfReader_ppw_thickness">Размер</string>
     <string name="pdfReader_ppw_opacity">Прозрачность</string>
+
+    <string name="reader_more_menu_bookmark">Закладка</string>
+    <string name="reader_alert_dialog_title_add_bookmark">Добавить закладку</string>
+    <string name="reader_alert_dialog_button_confirm">Подтвердить</string>
+    <string name="reader_alert_dialog_button_cancel">Отменить</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">Удалить закладку</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">Вы уверены что хотите удалить %s ?</string>
+
+    <string name="outline_title">Контур</string>
+    <string name="bookmark_title">Закладка</string>
+    <string name="thumbnail_title">Миниатюра</string>
+
+    <string name="fragment_search_page">Страница</string>
+    <string name="fragment_search_text">Текст</string>
+    <string name="fragment_search_enter_page">Перейти на страницу</string>
+    <string name="fragment_search_enter_text">Поиск текста</string>
+
+    <string name="fileManager_no_results">Не найдено</string>
+    <string name="fileManager_thishi_search">Пожалуйста введите минимум 3 символа</string>
+
+    <string name="dialogAddBookmark_page">страница</string>
+    <string name="viewer_setting_page_turn_mode">Прокручивание страниц</string>
+    <string name="viewer_setting_page_turn_mode_vertically">Вертикально</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">Горизонтально</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-zh-rTW/strings.xml

@@ -8,4 +8,28 @@
     <string name="reader_copy_text_success">已複製到剪貼簿中!</string>
     <string name="pdfReader_ppw_thickness">大小</string>
     <string name="pdfReader_ppw_opacity">透明度</string>
+
+    <string name="reader_more_menu_bookmark">書籤</string>
+    <string name="reader_alert_dialog_title_add_bookmark">新增書籤</string>
+    <string name="reader_alert_dialog_button_confirm">確定</string>
+    <string name="reader_alert_dialog_button_cancel">取消</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">刪除書籤</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">確定刪除書籤 %s ?</string>
+
+    <string name="outline_title">大綱</string>
+    <string name="bookmark_title">書籤</string>
+    <string name="thumbnail_title">縮列圖</string>
+
+    <string name="fragment_search_page">頁碼</string>
+    <string name="fragment_search_text">文字</string>
+    <string name="fragment_search_enter_page">輸入頁碼</string>
+    <string name="fragment_search_enter_text">搜尋文字</string>
+
+    <string name="fileManager_no_results">無搜尋結果</string>
+    <string name="fileManager_thishi_search">請至少輸入3個字元</string>
+
+    <string name="dialogAddBookmark_page">頁數</string>
+    <string name="viewer_setting_page_turn_mode">翻頁設定</string>
+    <string name="viewer_setting_page_turn_mode_vertically">垂直滾動</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">水平滾動</string>
 </resources>

+ 24 - 0
reader/src/main/res/values-zh/strings.xml

@@ -8,4 +8,28 @@
     <string name="reader_copy_text_success">已复制到剪切板!</string>
     <string name="pdfReader_ppw_thickness">厚度</string>
     <string name="pdfReader_ppw_opacity">透明度</string>
+
+    <string name="reader_more_menu_bookmark">书签</string>
+    <string name="reader_alert_dialog_title_add_bookmark">添加书签</string>
+    <string name="reader_alert_dialog_button_confirm">确定</string>
+    <string name="reader_alert_dialog_button_cancel">取消</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">删除书签</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">确定删除书签 %s ?</string>
+
+    <string name="outline_title">大纲</string>
+    <string name="bookmark_title">书签</string>
+    <string name="thumbnail_title">缩略图</string>
+
+    <string name="fragment_search_page">页码</string>
+    <string name="fragment_search_text">文字</string>
+    <string name="fragment_search_enter_page">输入页码</string>
+    <string name="fragment_search_enter_text">文本查找</string>
+
+    <string name="fileManager_no_results">无搜索结果</string>
+    <string name="fileManager_thishi_search">请至少输入3个字符</string>
+
+    <string name="dialogAddBookmark_page">页码</string>
+    <string name="viewer_setting_page_turn_mode">翻页设置</string>
+    <string name="viewer_setting_page_turn_mode_vertically">垂直滚动</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">水平滚动</string>
 </resources>

+ 9 - 0
reader/src/main/res/values/attrs.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <declare-styleable name="RowSwitchView">
+        <attr name="text" format="string" />
+        <attr name="isChecked" format="boolean" />
+    </declare-styleable>
+
+</resources>

+ 3 - 1
reader/src/main/res/values/dimens.xml

@@ -5,4 +5,6 @@
 
     <dimen name="reader_color_displayer_width">54dp</dimen>
     <dimen name="reader_color_displayer_height">60dp</dimen>
-</resources>
+
+    <dimen name="reader_left_right_toolbar_icon_width">48dp</dimen>
+</resources>

+ 37 - 0
reader/src/main/res/values/strings.xml

@@ -1,6 +1,7 @@
 <resources>
     <string name="app_name" translatable="false">Reader</string>
 
+    <string name="reader_more_menu_bookmark">Bookmark</string>
     <string name="reader_more_menu_share">Share</string>
     <string name="reader_more_menu_text_reflow">Text Reflow</string>
     <string name="reader_more_menu_print">Print</string>
@@ -10,4 +11,40 @@
 
     <string name="pdfReader_ppw_thickness">Size</string>
     <string name="pdfReader_ppw_opacity">Opacity</string>
+
+    <string name="reader_alert_dialog_title_add_bookmark">Add bookmark</string>
+    <string name="reader_alert_dialog_title_delete_bookmark">Delete bookmark</string>
+    <string name="reader_alert_dialog_message_delete_bookmark">Are you sure you want to delete %s ?</string>
+    <string name="reader_alert_dialog_button_confirm">Confirm</string>
+    <string name="reader_alert_dialog_button_cancel">Cancel</string>
+
+    <string name="null_str" translatable="false">&#160;</string>
+
+    <string name="outline_title">Outline</string>
+    <string name="bookmark_title">Bookmark</string>
+    <string name="thumbnail_title">Thumbnail</string>
+
+    <string name="fragment_search_page">Page</string>
+    <string name="fragment_search_text">Text</string>
+    <string name="fragment_search_enter_page">Jump to page</string>
+    <string name="fragment_search_enter_text">Text search</string>
+
+    <string name="fileManager_no_results">No results found</string>
+    <string name="fileManager_thishi_search">Please enter at least 3 characters.</string>
+
+    <string name="dialogAddBookmark_page">page</string>
+
+    <!--viewer setting-->
+    <string name="viewer_setting_page_background_and_display">Page Background And Display</string>
+    <string name="viewer_setting_switch_smart_crop">Smart Crop Mode</string>
+    <string name="viewer_setting_switch_show_state_bar">Show State Bar</string>
+    <string name="viewer_setting_page_turn_mode">Scroll Pages</string>
+    <string name="viewer_setting_page_turn_mode_horizontally">Horizontally</string>
+    <string name="viewer_setting_page_turn_mode_vertically">Vertically</string>
+    <string name="viewer_setting_page_turn_button_visible">Show turn page button</string>
+    <string name="viewer_setting_screen_setting">Screen Setting</string>
+    <string name="viewer_setting_switch_screen_sleep">Screen Sleep Setting Enable</string>
+    <string name="viewer_setting_toolbar_display_setting">Toolbar Display Setting</string>
+    <string name="viewer_setting_toolbar_display_setting_comment">Display Comment Tool</string>
+    <string name="viewer_setting_toolbar_display_setting_bota">Display BOTA tool</string>
 </resources>