2 Achegas c47d7fbae1 ... 8a69992f45

Autor SHA1 Mensaxe Data
  faterhenry 8a69992f45 Merge branch 'feature-page-editor' %!s(int64=5) %!d(string=hai) anos
  faterhenry fa26dac07f feature page editor %!s(int64=5) %!d(string=hai) anos
Modificáronse 100 ficheiros con 1113 adicións e 1 borrados
  1. 1 0
      app/build.gradle
  2. 4 0
      app/src/main/AndroidManifest.xml
  3. 58 0
      app/src/main/java/com/kdanmobile/pdfreaderviewapp/MyPdfThumbActivity.kt
  4. 5 0
      app/src/main/java/com/kdanmobile/pdfreaderviewapp/MyReaderActivity.kt
  5. 3 1
      reader/src/main/AndroidManifest.xml
  6. 33 0
      reader/src/main/java/com/kdanmobile/reader/ReaderActivity.kt
  7. 6 0
      reader/src/main/java/com/kdanmobile/reader/ReaderViewModel.kt
  8. 9 0
      reader/src/main/java/com/kdanmobile/reader/screen/handler/OperateHandler.kt
  9. 5 0
      reader/src/main/java/com/kdanmobile/reader/screen/handler/PasswordHandler.kt
  10. 2 0
      reader/src/main/java/com/kdanmobile/reader/screen/view/SearchView.kt
  11. 108 0
      reader/src/main/java/com/kdanmobile/reader/thumb/FileUtil.kt
  12. 12 0
      reader/src/main/java/com/kdanmobile/reader/thumb/ItemMoveSwipeListener.kt
  13. 34 0
      reader/src/main/java/com/kdanmobile/reader/thumb/ItemTouchHelpCallback.kt
  14. 309 0
      reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbActivity.kt
  15. 121 0
      reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbAdapter.kt
  16. 246 0
      reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbViewModel.kt
  17. 10 0
      reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbViewModelFactory.kt
  18. 23 0
      reader/src/main/java/com/kdanmobile/reader/thumb/ScreenUtil.kt
  19. 15 0
      reader/src/main/java/com/kdanmobile/reader/thumb/ThumbData.kt
  20. 23 0
      reader/src/main/java/com/kdanmobile/reader/thumb/mode/EditMode.kt
  21. 11 0
      reader/src/main/java/com/kdanmobile/reader/thumb/mode/Mode.kt
  22. 24 0
      reader/src/main/java/com/kdanmobile/reader/thumb/mode/NormalMode.kt
  23. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_arrowback_black_24dp.png
  24. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_arrowback_blue_24dp.png
  25. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_checkbox_off_blue_24dp.png
  26. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_checkbox_on_blue_24dp.png
  27. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_close_black_24dp.png
  28. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_delete_black_24dp.png
  29. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_delete_blue_24dp.png
  30. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_delete_dis_24dp.png
  31. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_deselect_black_24dp.png
  32. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_deselect_blue_24dp.png
  33. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_deselect_dis_24dp.png
  34. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_extract_page_btn_action_bar.webp
  35. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_rotate_black_24dp.png
  36. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_rotate_blue_24dp.png
  37. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_rotate_dis_24dp.png
  38. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_selectall_black_24dp.png
  39. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_selectall_blue_24dp.png
  40. BIN=BIN
      reader/src/main/res/drawable-hdpi/ic_selectall_dis_24dp.png
  41. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_delete_black_24dp.png
  42. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_delete_blue_24dp.png
  43. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_delete_dis_24dp.png
  44. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_deselect_black_24dp.png
  45. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_deselect_blue_24dp.png
  46. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_deselect_dis_24dp.png
  47. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_extract_page_btn_action_bar.webp
  48. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_rotate_black_24dp.png
  49. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_rotate_blue_24dp.png
  50. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_rotate_dis_24dp.png
  51. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_selectall_black_24dp.png
  52. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_selectall_blue_24dp.png
  53. BIN=BIN
      reader/src/main/res/drawable-mdpi/ic_selectall_dis_24dp.png
  54. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_arrowback_black_24dp.png
  55. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_arrowback_blue_24dp.png
  56. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_checkbox_off_blue_24dp.png
  57. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_checkbox_on_blue_24dp.png
  58. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_close_black_24dp.png
  59. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_delete_black_24dp.png
  60. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_delete_blue_24dp.png
  61. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_delete_dis_24dp.png
  62. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_deselect_black_24dp.png
  63. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_deselect_blue_24dp.png
  64. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_deselect_dis_24dp.png
  65. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_extract_page_btn_action_bar.webp
  66. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_rotate_black_24dp.png
  67. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_rotate_blue_24dp.png
  68. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_rotate_dis_24dp.png
  69. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_selectall_black_24dp.png
  70. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_selectall_blue_24dp.png
  71. BIN=BIN
      reader/src/main/res/drawable-xhdpi/ic_selectall_dis_24dp.png
  72. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_arrowback_black_24dp.png
  73. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_arrowback_blue_24dp.png
  74. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_checkbox_off_blue_24dp.png
  75. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_checkbox_on_blue_24dp.png
  76. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_close_black_24dp.png
  77. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_delete_black_24dp.png
  78. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_delete_blue_24dp.png
  79. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_delete_dis_24dp.png
  80. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_deselect_black_24dp.png
  81. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_deselect_blue_24dp.png
  82. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_deselect_dis_24dp.png
  83. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_extract_page_btn_action_bar.webp
  84. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_rotate_black_24dp.png
  85. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_rotate_blue_24dp.png
  86. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_rotate_dis_24dp.png
  87. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_selectall_black_24dp.png
  88. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_selectall_blue_24dp.png
  89. BIN=BIN
      reader/src/main/res/drawable-xxhdpi/ic_selectall_dis_24dp.png
  90. BIN=BIN
      reader/src/main/res/drawable-xxxhdpi/ic_extract_page_btn_action_bar.webp
  91. 4 0
      reader/src/main/res/drawable/ic_close_black_24dp.xml
  92. 4 0
      reader/src/main/res/drawable/ic_close_blue_24dp.xml
  93. 4 0
      reader/src/main/res/drawable/ic_close_dis_24dp.xml
  94. 4 0
      reader/src/main/res/drawable/ic_mode_edit_black_24dp.xml
  95. 4 0
      reader/src/main/res/drawable/ic_mode_edit_blue_24dp.xml
  96. 4 0
      reader/src/main/res/drawable/ic_mode_edit_dis_24dp.xml
  97. 8 0
      reader/src/main/res/drawable/selector_arrowback.xml
  98. 11 0
      reader/src/main/res/drawable/selector_checkbox.xml
  99. 8 0
      reader/src/main/res/drawable/selector_close_btn_navigation.xml
  100. 0 0
      reader/src/main/res/drawable/selector_delete_btn_action_bar.xml

+ 1 - 0
app/build.gradle

@@ -32,6 +32,7 @@ dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
     implementation 'com.android.support:appcompat-v7:28.0.0'
     implementation 'com.android.support.constraint:constraint-layout:1.1.3'
+    implementation 'com.android.support:recyclerview-v7:28.0.0'
     testImplementation 'junit:junit:4.12'
     androidTestImplementation 'com.android.support.test:runner:1.0.2'
     androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

+ 4 - 0
app/src/main/AndroidManifest.xml

@@ -24,6 +24,10 @@
             android:name=".MyReaderActivity"
             android:exported="true"
             android:theme="@style/ReaderActivityNoActionBarNoTitle" />
+        <activity
+            android:name=".MyPdfThumbActivity"
+            android:exported="true"
+            android:theme="@style/ReaderActivityNoActionBarNoTitle" />
     </application>
 
 </manifest>

+ 58 - 0
app/src/main/java/com/kdanmobile/pdfreaderviewapp/MyPdfThumbActivity.kt

@@ -0,0 +1,58 @@
+package com.kdanmobile.pdfreaderviewapp
+
+import android.content.Intent
+import android.os.Bundle
+import com.kdanmobile.reader.thumb.PdfThumbActivity
+import java.io.File
+
+class MyPdfThumbActivity: PdfThumbActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun canDelete() : Boolean{
+        return true
+    }
+
+    override fun canExtract() : Boolean{
+        return true
+    }
+
+    override fun canChangePage() : Boolean{
+        return true
+    }
+    override fun provideIntent() :Intent{
+        return  Intent(this, MyReaderActivity::class.java)
+    }
+
+    override fun getTrialDays(): Long{
+        return 5566
+    }
+
+    override fun getHeight(): Int {
+        return 0
+    }
+
+    override fun getWidth(): Int {
+        return 0
+    }
+
+    override fun getPadding(): Int {
+        return 0
+    }
+
+    override fun getColumns(): Int {
+        return 0
+    }
+
+   override fun getCreateExtractBlankFile(pdfFilename: String, selectPage: String) : File{
+       return File("5566")
+   }
+
+    override fun getSubscribeRunnable(): Runnable{
+        return Runnable {
+            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+        }
+    }
+
+}

+ 5 - 0
app/src/main/java/com/kdanmobile/pdfreaderviewapp/MyReaderActivity.kt

@@ -1,5 +1,6 @@
 package com.kdanmobile.pdfreaderviewapp
 
+import android.content.Intent
 import android.os.Bundle
 import com.kdanmobile.reader.ReaderActivity
 
@@ -24,6 +25,10 @@ class MyReaderActivity : ReaderActivity() {
         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
     }
 
+    override fun transferThumbIntent(): Intent {
+        return Intent(this, MyPdfThumbActivity::class.java)
+    }
+
     companion object {
         val KEY_FILE_ABSOLUTE = ReaderActivity.KEY_FILE_ABSOLUTE
     }

+ 3 - 1
reader/src/main/AndroidManifest.xml

@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.kdanmobile.reader">
-
     <application>
         <activity
             android:name=".ReaderActivity"
@@ -13,6 +12,9 @@
             android:name=".screen.signature.SignatureActivity"
             android:screenOrientation="landscape"
             android:theme="@style/ReaderActivityNoActionBarNoTitle" />
+        <activity
+            android:name=".thumb.PdfThumbActivity"
+            android:theme="@style/ReaderActivityNoActionBarNoTitle" />
     </application>
 
 </manifest>

+ 33 - 0
reader/src/main/java/com/kdanmobile/reader/ReaderActivity.kt

@@ -1,6 +1,7 @@
 package com.kdanmobile.reader
 
 import android.annotation.SuppressLint
+import android.app.Activity
 import android.arch.lifecycle.Observer
 import android.arch.lifecycle.ViewModelProviders
 import android.content.Intent
@@ -43,6 +44,7 @@ import com.kdanmobile.reader.utils.AnimationUtil
 import com.kdanmobile.reader.utils.DensityUtil
 import com.kdanmobile.reader.view.AnnotationAttributeView
 import com.kdanmobile.reader.view.AnnotationAttributeWindow
+import com.kdanmobile.reader.thumb.PdfThumbActivity
 import kotlinx.android.synthetic.main.activity_reader.*
 
 abstract class ReaderActivity : AppCompatActivity() {
@@ -52,9 +54,11 @@ abstract class ReaderActivity : AppCompatActivity() {
     abstract fun onClickFileInfo()
     abstract fun onClickPrint()
     abstract fun onClickUserGuide()
+    abstract fun transferThumbIntent(): Intent
 
     companion object {
         const val KEY_FILE_ABSOLUTE = "file_absolutepath"
+        const val THUMB = 221
     }
 
     private lateinit var viewModel: ReaderViewModel
@@ -518,6 +522,10 @@ abstract class ReaderActivity : AppCompatActivity() {
 
     private fun setupBottomToolbar() {
         ib_readerActivity_bottomToolbarMediaBox.setOnClickListener { mediaBoxView.show() }
+        ib_readerActivity_bottomToolbarViewAll.setOnClickListener {
+            onClickBottomThumb1()
+            viewModel.transferKmpdfCore()
+        }
     }
 
     private fun setupMediaBoxView() {
@@ -776,6 +784,7 @@ abstract class ReaderActivity : AppCompatActivity() {
         }
     }
 
+
     private fun updateLeftToolbarIcons() {
         iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_left_toolbar_thumbnails)
         iv_readerActivity_bookmark.setImageResource(R.drawable.ic_left_toolbar_bookmarks)
@@ -791,4 +800,28 @@ abstract class ReaderActivity : AppCompatActivity() {
             }
         }
     }
+
+    private fun onClickBottomThumb1() {
+        var intent = transferThumbIntent()
+        startActivityForResult(intent,THUMB)
+    }
+
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        if (resultCode == Activity.RESULT_OK){
+            when (requestCode){
+                THUMB -> {
+                    val mode = data?.getIntExtra("operate", -1)
+                    when (mode) {
+                        PdfThumbActivity.THUMB_NORMAL -> {
+                            val pageIndex = data.getIntExtra("result", 0)
+                            viewModel.pdfInfoHandler.setCurrentPage(pageIndex)
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
 }

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

@@ -31,6 +31,7 @@ import com.kdanmobile.reader.screen.data.SignatureAttribute
 import com.kdanmobile.reader.screen.data.StampAttribute
 import com.kdanmobile.reader.screen.data.TextBoxAttribute
 import com.kdanmobile.reader.screen.handler.*
+import com.kdanmobile.reader.thumb.PdfThumbViewModel
 
 class ReaderViewModel(private val pdfSdkLicense: String, private val pdfSdkRsaMsg: String) : ViewModel() {
 
@@ -428,6 +429,11 @@ class ReaderViewModel(private val pdfSdkLicense: String, private val pdfSdkRsaMs
         }
     }
 
+    fun transferKmpdfCore(){
+        PdfThumbViewModel.tempKmpdfFactory = kmpdfFactory
+        PdfThumbViewModel.tempkmpdfDocumentController = kmpdfDocumentController
+    }
+
     private fun verifyLicense(context: Context): Boolean {
         val errorCode = KMPDFFactory.verifyLicense(context, pdfSdkLicense, pdfSdkRsaMsg)
         return errorCode == 0

+ 9 - 0
reader/src/main/java/com/kdanmobile/reader/screen/handler/OperateHandler.kt

@@ -0,0 +1,9 @@
+package com.kdanmobile.reader.screen.handler
+
+interface OperateHandler {
+
+    fun save(): Boolean
+    fun deletePages(pages: IntArray): Boolean
+    fun reorderPage(fromPage: Int, toPage: Int): Boolean
+    fun splitPDFWithPages(path: String, selectPage: IntArray): Boolean
+}

+ 5 - 0
reader/src/main/java/com/kdanmobile/reader/screen/handler/PasswordHandler.kt

@@ -0,0 +1,5 @@
+package com.kdanmobile.reader.screen.handler
+
+interface PasswordHandler {
+    fun isNeedPassword(): Boolean
+}

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

@@ -1,6 +1,7 @@
 package com.kdanmobile.reader.screen.view
 
 import android.content.Context
+import android.content.Intent
 import android.graphics.RectF
 import android.os.Handler
 import android.os.Message
@@ -19,6 +20,7 @@ import com.kdanmobile.reader.screen.handler.PdfInfoHandler
 import com.kdanmobile.reader.screen.handler.SearchHandler
 import com.kdanmobile.reader.screen.model.SearchResultInfo
 import com.kdanmobile.reader.screen.model.SimpleTextWatcher
+import com.kdanmobile.reader.thumb.PdfThumbActivity
 import com.kdanmobile.reader.utils.DensityUtil
 import io.reactivex.Completable
 import io.reactivex.android.schedulers.AndroidSchedulers

+ 108 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/FileUtil.kt

@@ -0,0 +1,108 @@
+package com.kdanmobile.reader.thumb
+
+import android.os.Environment
+import java.io.File
+import kotlin.collections.ArrayList
+
+object FileUtil {
+    val myFolder = "KdanPDFReader"
+    val EXTENSION_SEPARATOR = '.'
+    private val UNIX_SEPARATOR = '/'
+    private val NOT_FOUND = -1
+    private val WINDOWS_SEPARATOR = '\\'
+
+    fun generateSelectedPagesString(selectPage: ArrayList<Int>): String {
+        val pages = StringBuffer()
+        for (n in selectPage) {
+            val position = n + 1
+            pages.append(position).append(",")
+        }
+        pages.deleteCharAt(pages.length - 1)
+        return pages.toString()
+    }
+
+    fun createExtractBlankFile(fileName: String, pages: String, folder: File?): File {
+        val ext = getExtension(fileName)
+        val name = removeExtension(fileName) + String.format("(page-%s)", pages)
+        var file = File(folder, String.format("%s.%s", name, ext))
+        var i = 2
+        while (file.exists()) {
+            file = File(folder, String.format("%s(%d).%s", name, i, ext))
+            i++
+        }
+        return file
+    }
+
+    @Synchronized
+    fun getMyFile(): File? {
+        var myFile: File? = null
+        if (myFile == null) {
+            myFile = File(getSdCardFile(), myFolder)
+        }
+        if (myFile.exists()) {
+            myFile.mkdirs()
+        }
+        return myFile
+    }
+
+    private fun getSdCardFile(): File? {
+        var sdcardFile: File? = null
+        if (sdcardFile == null) {
+            sdcardFile = Environment.getExternalStorageDirectory()
+        }
+        return sdcardFile
+    }
+
+    fun getExtension(filename: String?): String? {
+        if (filename == null) {
+            return null
+        }
+        val index = indexOfExtension(filename)
+        return if (index == NOT_FOUND) {
+            ""
+        } else {
+            filename.substring(index + 1)
+        }
+    }
+
+    fun indexOfExtension(filename: String?): Int {
+        if (filename == null) {
+            return NOT_FOUND
+        }
+        val extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR)
+        val lastSeparator = indexOfLastSeparator(filename)
+        return if (lastSeparator > extensionPos) NOT_FOUND else extensionPos
+    }
+
+    fun indexOfLastSeparator(filename: String?): Int {
+        if (filename == null) {
+            return NOT_FOUND
+        }
+        val lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR)
+        val lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR)
+        return Math.max(lastUnixPos, lastWindowsPos)
+    }
+
+     private fun removeExtension(filename: String?): String? {
+        if (filename == null) {
+            return null
+        }
+        failIfNullBytePresent(filename)
+
+        val index = indexOfExtension(filename)
+        return if (index == NOT_FOUND) {
+            filename
+        } else {
+            filename.substring(0, index)
+        }
+    }
+
+    private fun failIfNullBytePresent(path: String) {
+        val len = path.length
+        for (i in 0 until len) {
+            if (path[i].toInt() == 0) {
+                throw IllegalArgumentException("Null byte present in file/path name. There are no " + "known legitimate use cases for such data, but several injection attacks may use it")
+            }
+        }
+    }
+}

+ 12 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/ItemMoveSwipeListener.kt

@@ -0,0 +1,12 @@
+package com.kdanmobile.reader.thumb
+
+import android.support.v7.widget.RecyclerView
+
+interface ItemMoveSwipeListener {
+    fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int
+    fun isLongPressDragEnabled(): Boolean
+    fun onItemMove(fromPosition: Int, toPosition: Int): Boolean
+    fun onItemSwipe(position: Int)
+    fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int)
+    fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder)
+}

+ 34 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/ItemTouchHelpCallback.kt

@@ -0,0 +1,34 @@
+package com.kdanmobile.reader.thumb
+
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.helper.ItemTouchHelper
+
+
+class ItemTouchHelpCallback (private val itemMoveSwipeListener: ItemMoveSwipeListener) : ItemTouchHelper.Callback() {
+
+    override fun isLongPressDragEnabled(): Boolean {
+        return itemMoveSwipeListener.isLongPressDragEnabled()
+    }
+
+    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
+        return itemMoveSwipeListener.getMovementFlags(recyclerView,viewHolder)
+    }
+
+    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
+        return itemMoveSwipeListener.onItemMove(viewHolder.adapterPosition, target.adapterPosition)
+    }
+    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
+        itemMoveSwipeListener.onItemSwipe(viewHolder.adapterPosition)
+    }
+
+    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
+        itemMoveSwipeListener.clearView(recyclerView,viewHolder)
+        super.clearView(recyclerView, viewHolder)
+    }
+
+    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
+        itemMoveSwipeListener.onSelectedChanged(viewHolder, actionState)
+        super.onSelectedChanged(viewHolder, actionState)
+    }
+
+}

+ 309 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbActivity.kt

@@ -0,0 +1,309 @@
+package com.kdanmobile.reader.thumb
+
+import android.app.Activity
+import android.app.AlertDialog
+import android.arch.lifecycle.ViewModelProviders
+import android.content.Intent
+import android.content.res.Configuration
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.GridLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.helper.ItemTouchHelper
+import android.view.*
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.ReaderActivity
+import com.kdanmobile.reader.thumb.mode.EditMode
+import com.kdanmobile.reader.thumb.mode.NormalMode
+import com.kdanmobile.reader.widget.drag.OnRecyclerItemClickListener
+import kotlinx.android.synthetic.main.layout_toolbar.*
+import kotlinx.android.synthetic.main.pdf_thumb.*
+import java.io.File
+
+abstract class PdfThumbActivity: AppCompatActivity(), PdfThumbAdapter.PageMoveHandler {
+
+    abstract fun provideIntent():Intent
+    abstract fun canDelete(): Boolean
+    abstract fun canExtract() : Boolean
+    abstract fun canChangePage() : Boolean
+    abstract fun getTrialDays(): Long
+    abstract fun getSubscribeRunnable(): Runnable
+    abstract fun getHeight(): Int
+    abstract fun getWidth(): Int
+    abstract fun getPadding(): Int
+    abstract fun getColumns(): Int
+    abstract fun getCreateExtractBlankFile(pdfFilename: String, selectPage: String): File
+
+    companion object {
+        const val THUMB_NORMAL = 0
+    }
+    private lateinit var viewModel: PdfThumbViewModel
+    private lateinit var pdfThumbAdapter: PdfThumbAdapter
+    private lateinit var thumbData: ThumbData
+    private var editMode = EditMode()
+    private var normalMode = NormalMode()
+    private var columns = 0
+    private var height = 0
+    private var width = 0
+    private var padding = 0
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+        setContentView(R.layout.pdf_thumb)
+        setSupportActionBar(toolbar)
+        val factory = PdfThumbViewModelFactory()
+        viewModel = ViewModelProviders.of(this, factory).get(PdfThumbViewModel::class.java)
+        initView()
+        initToolBar()
+    }
+
+    private fun initView() {
+        id_recyclerview.setHasFixedSize(true)
+        setViewSize()
+        thumbData = ThumbData().apply {
+            this.viewHeight = height
+            this.viewWidth = width
+            this.viewPadding = padding
+            this.isEditMode = viewModel.isEditMode
+            this.currentPage = viewModel.pdfInfoHandler.getCurrentPage()
+            this.pageSelect = viewModel.mapSelect
+            this.pages = viewModel.getAllPdfBitmap()
+            this.hasBookMarks = viewModel.hasBookMark()
+        }
+        pdfThumbAdapter = PdfThumbAdapter(thumbData,this)
+        viewModel.kmpdfDocumentController?.currentPageNum
+        id_recyclerview.adapter = pdfThumbAdapter
+        id_recyclerview.layoutManager = GridLayoutManager(this, columns)
+        id_recyclerview.addOnItemTouchListener(object : OnRecyclerItemClickListener(id_recyclerview) {
+            override fun onItemClick(vh: RecyclerView.ViewHolder) {
+                viewModel.mode.onPageItemClick(this@PdfThumbActivity, vh.adapterPosition, THUMB_NORMAL, viewModel.mapSelect, pdfThumbAdapter)
+            }
+            override fun onItemLongClick(vh: RecyclerView.ViewHolder) {}
+        })
+        id_recyclerview.scrollToPosition(viewModel.pdfInfoHandler.getCurrentPage())
+        var itemTouchHelperCallBack = ItemTouchHelpCallback(pdfThumbAdapter)
+        var itemTouchHelper = ItemTouchHelper(itemTouchHelperCallBack)
+        itemTouchHelper.attachToRecyclerView(id_recyclerview)
+    }
+
+    private fun initToolBar(){
+        viewModel.isEditMode.let {
+            if (it){
+                toolbar.setNavigationIcon(R.drawable.selector_close_btn_navigation)
+                supportActionBar?.title = resources.getString(R.string.pdf_thumb_title_edit_mode)
+            } else {
+                toolbar.setNavigationIcon(R.drawable.selector_arrowback)
+                supportActionBar?.title = resources.getString(R.string.thumbnail)
+            }
+        }
+        toolbar.setNavigationOnClickListener(this::onClickToolBarNavigation)
+    }
+
+    private fun setViewSize() {
+        if (resources.configuration.orientation === Configuration.ORIENTATION_LANDSCAPE) {
+            if (ScreenUtil.getXDp(this) >= 720) {
+                columns = 6
+                width = (ScreenUtil.getScreenWidth(this) / 6.6).toInt()
+            } else {
+                columns = 5
+                width = (ScreenUtil.getScreenWidth(this) / 5.5).toInt()
+            }
+        } else {
+            if (ScreenUtil.getXDp(this) >= 720) {
+                columns = 4
+                width = (ScreenUtil.getScreenWidth(this) / 4.4).toInt()
+            } else {
+                columns = 3
+                width = (ScreenUtil.getScreenWidth(this) / 3.3).toInt()
+            }
+        }
+        padding = (ScreenUtil.getScreenWidth(this) - width * columns) / 2 * (columns + 1)
+        height = 234 * width / 180
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu): Boolean {
+        if (!viewModel.passwordHandler.isNeedPassword()) menuInflater.inflate(R.menu.menu_thumb, menu)
+        return true
+    }
+
+    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
+        if (!viewModel.passwordHandler.isNeedPassword()) {
+            when (viewModel.isEditMode) {
+                true -> {
+                    val isExtractEnable = viewModel.hasSelectItem()
+                    val isRotateEnable = viewModel.hasSelectItem()
+                    val isDeleteEnable = viewModel.hasSelectItem() && !viewModel.isAllItemSelect()
+                    val visible = viewModel.isPdf
+                    menu.findItem(R.id.item_action_edit_thumb).isVisible = false
+                    menu.findItem(R.id.item_action_select_all_thumb)
+                            .setVisible(visible)
+                            .setIcon(if (viewModel.isAllItemSelect()) R.drawable.selector_deselect_all_btn_action_bar else R.drawable.selector_select_all_btn_action_bar)
+                    menu.findItem(R.id.item_action_extract_thumb)
+                            .setVisible(visible).isEnabled = isExtractEnable
+                    menu.findItem(R.id.item_action_rorate_thumb)
+                            .setVisible(visible).isEnabled = isRotateEnable
+                    menu.findItem(R.id.item_action_delete_thumb)
+                            .setVisible(visible).isEnabled = isDeleteEnable
+                }
+                false -> {
+                    val visible = viewModel.isPdf
+                    menu.findItem(R.id.item_action_edit_thumb).isVisible = visible
+                    menu.findItem(R.id.item_action_select_all_thumb).isVisible = false
+                    menu.findItem(R.id.item_action_extract_thumb).isVisible = false
+                    menu.findItem(R.id.item_action_rorate_thumb).isVisible = false
+                    menu.findItem(R.id.item_action_delete_thumb).isVisible = false
+                }
+            }
+        }
+        return super.onPrepareOptionsMenu(menu)
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        when (item.itemId) {
+            R.id.item_action_edit_thumb -> switchToEditMode()
+            R.id.item_action_select_all_thumb -> onClickSelectAllBtn()
+            R.id.item_action_rorate_thumb -> onClickRotateBtn()
+            R.id.item_action_delete_thumb -> onClickDeleteBtn()
+            R.id.item_action_extract_thumb -> onClickExtractBtn()
+        }
+        return super.onOptionsItemSelected(item)
+    }
+
+    override fun onBackPressed() {
+        val data = Intent()
+        data.putExtra("result", viewModel.pdfInfoHandler.getCurrentPage())
+        data.putExtra("operate", THUMB_NORMAL)
+        setResult(Activity.RESULT_OK, data)
+        finish()
+        super.onBackPressed()
+    }
+
+    private fun onClickToolBarNavigation(v: View){
+        when(viewModel.isEditMode){
+            true -> {
+                switchToNormalMode()
+                invalidateOptionsMenu()
+                onModeSwitched()
+            }
+            false -> {
+                onBackPressed()
+            }
+        }
+    }
+    private fun switchToEditMode() {
+        viewModel.mode = editMode
+        viewModel.isEditMode = true
+        thumbData.isEditMode = true
+        pdfThumbAdapter.setThumbData(thumbData)
+        onModeSwitched()
+    }
+
+    private fun switchToNormalMode() {
+        viewModel.mode = normalMode
+        viewModel.isEditMode = false
+        thumbData.isEditMode = false
+        pdfThumbAdapter.setThumbData(thumbData)
+        onModeSwitched()
+    }
+
+    private fun onModeSwitched() {
+        updateToolbar()
+    }
+
+    fun updateToolbar() {
+        invalidateOptionsMenu()
+        when(viewModel.isEditMode){
+            true -> {
+                supportActionBar?.setTitle(R.string.pdf_thumb_title_edit_mode)
+                toolbar.setNavigationIcon(R.drawable.selector_close_btn_navigation)
+            }
+            false -> {
+                supportActionBar?.setTitle(R.string.thumbnail)
+                toolbar.setNavigationIcon(R.drawable.selector_arrowback)
+            }
+        }
+    }
+
+    private fun onClickSelectAllBtn() {
+        if (!viewModel.isAllItemSelect()) {
+            viewModel.setAllSelect()
+        } else {
+            viewModel.setAllUnSelect()
+        }
+        pdfThumbAdapter.notifyDataSetChanged()
+        updateToolbar()
+    }
+
+    private fun onClickRotateBtn() {
+        val runnable = Runnable {
+            thumbData.pages = viewModel.getAllPdfBitmap()
+            pdfThumbAdapter.notifyDataSetChanged()
+        }
+        viewModel.pageRotate(runnable)
+    }
+
+    private fun onClickExtractBtn(){
+        if (!canExtract()) {
+            getSubscribeRunnable().run()
+        } else {
+            val pagesForFile = FileUtil.generateSelectedPagesString(viewModel.getSelectPage())
+            val dst = FileUtil.createExtractBlankFile(viewModel.pdfInfoHandler.getOpenPdfFilename(), pagesForFile, FileUtil.getMyFile())
+            val runnable = Runnable {
+                val filePath = String.format("/%s/%s", dst.getParentFile().getName(), dst.getName())
+                val msg = getString(R.string.pdf_thumb_extract_page_suc_dialog_msg, filePath)
+                AlertDialog.Builder(this)
+                        .setTitle(R.string.pdf_thumb_extract_page_suc_dialog_title)
+                        .setMessage(msg)
+                        .setPositiveButton(R.string.pdf_thumb_extract_page_suc_dialog_positive_btn) { _, _ ->
+                            val intent = provideIntent()
+                            intent.putExtra(ReaderActivity.KEY_FILE_ABSOLUTE, dst.absolutePath)
+                            startActivity(intent)
+                        }
+                        .show()
+            }
+            val runnableForFail = Runnable {
+                AlertDialog.Builder(this)
+                        .setTitle(R.string.pdf_thumb_extract_page_failed_dialog_title)
+                        .setMessage(R.string.pdf_thumb_extract_page_failed_dialog_msg)
+                        .show()
+            }
+            viewModel.pageExtract(dst, runnable, runnableForFail)
+        }
+    }
+
+    private fun onClickDeleteBtn(){
+        if (!canDelete()) {
+            getSubscribeRunnable().run()
+        } else {
+            var builder = AlertDialog.Builder(this)
+            builder.setMessage(R.string.pdf_thumb_delete_check_dialog_msg)
+            builder.setNegativeButton(R.string.common_cancel) { dialog, _ -> dialog.dismiss() }
+            builder.setPositiveButton(R.string.common_okay) { _, _ ->
+                    viewModel.pageDelete(Runnable {
+                    viewModel.setAllUnSelect()
+                    thumbData.pages = viewModel.getAllPdfBitmap()
+                    pdfThumbAdapter.notifyDataSetChanged() }) }
+            builder.create().show()
+        }
+    }
+
+
+    override fun onPageMove(fromPage: Int, toPage: Int) {
+        if(!canChangePage()) {
+            getSubscribeRunnable().run()
+        } else {
+            val runnable = Runnable {
+                thumbData.hasBookMarks?.let { it ->
+                    it[fromPage] = it[toPage]
+                }
+                thumbData.pages?.let { it ->
+                    var tempPage = it[fromPage]
+                    it.removeAt(fromPage)
+                    it.add(toPage, tempPage)
+                }
+            }
+            viewModel.reorderPage(fromPage, toPage, runnable)
+        }
+    }
+}

+ 121 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbAdapter.kt

@@ -0,0 +1,121 @@
+package com.kdanmobile.reader.thumb
+
+import android.graphics.Bitmap
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.helper.ItemTouchHelper
+import android.support.v7.widget.helper.ItemTouchHelper.Callback.makeMovementFlags
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import com.kdanmobile.reader.R
+import kotlinx.android.synthetic.main.pdf_thumb_gv_item.view.*
+
+class PdfThumbAdapter(thumbData: ThumbData, pageMoveHandler: PageMoveHandler): RecyclerView.Adapter<PdfThumbAdapter.ViewHolder>(), ItemMoveSwipeListener {
+    var data = thumbData
+    var handler = pageMoveHandler
+
+    override fun getItemCount(): Int {
+        var size = 0
+        data.pages?.let {
+            size = it.size
+        }
+        return size
+    }
+
+    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+        holder.bind(data, position)
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val v1 = LayoutInflater.from(parent.context).inflate(R.layout.pdf_thumb_gv_item, parent, false)
+        var holder = ViewHolder(v1)
+        holder?.setSize(data.viewWidth, data.viewHeight, data.viewPadding, ScreenUtil.getDensity(parent.context))
+        return ViewHolder(v1)
+    }
+
+    class ViewHolder (view : View) : RecyclerView.ViewHolder(view) {
+        fun bind(thumbData: ThumbData, position: Int) {
+            var pages = thumbData.pages as List<Bitmap>
+            itemView.iv_pdfThumbGvItem_.setImageBitmap(pages[position])
+            itemView.tv_pdfThumbGvItem_page.text = (position + 1).toString()
+            itemView.cb_pdfThumbGvItem_.isChecked = thumbData.pageSelect[position] as Boolean
+            thumbData.hasBookMarks?.let {
+                when (it[position]){
+                    true -> {
+                        itemView.iv_pdfThumbGvItem_bookmark.visibility = View.VISIBLE
+                    }
+                    false -> {
+                        itemView.iv_pdfThumbGvItem_bookmark.visibility = View.GONE
+                    }
+                }
+            }
+            when(thumbData.currentPage == position) {
+                true -> {
+                    itemView.view_pdfThumbGvItem_.visibility = View.VISIBLE
+                }
+                false -> {
+                    itemView.view_pdfThumbGvItem_.visibility = View.GONE
+                }
+            }
+            when(thumbData.isEditMode){
+                true -> {
+                    itemView.cb_pdfThumbGvItem_.visibility = View.VISIBLE
+                }
+                false -> {
+                    itemView.cb_pdfThumbGvItem_.visibility = View.GONE
+                }
+            }
+        }
+
+        fun setSize(width: Int, height: Int, padding: Int, density: Float) {
+            if (width != itemView.rl_pdfThumbGvItem_.getWidth()) {
+                val params = LinearLayout.LayoutParams(width, height)
+                params.topMargin = (density * 4).toInt()
+                params.leftMargin = padding
+                params.rightMargin = padding
+                itemView.rl_pdfThumbGvItem_.layoutParams = params
+                itemView.iv_pdfThumbGvItem_.setPadding(1, 1, 1, 1)
+            }
+        }
+    }
+
+    fun setThumbData(thumbData: ThumbData){
+        data = thumbData
+        notifyDataSetChanged()
+    }
+
+    override fun isLongPressDragEnabled(): Boolean {
+        return data.isEditMode
+    }
+    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
+        val dragFlags = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
+        val swipeFlags = 0
+        return makeMovementFlags(dragFlags, swipeFlags)
+    }
+    override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
+        notifyItemMoved(fromPosition, toPosition)
+        handler.onPageMove(fromPosition,toPosition)
+        return true
+    }
+
+    override fun onItemSwipe(position: Int) {
+    }
+
+    override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
+        viewHolder.itemView.scaleX = 1.0f
+        viewHolder.itemView.scaleY = 1.0f
+        notifyDataSetChanged()
+    }
+
+    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
+        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && null != viewHolder) {
+            viewHolder.itemView.scaleX = 0.7f
+            viewHolder.itemView.scaleY = 0.7f
+        }
+    }
+
+    interface PageMoveHandler{
+        fun onPageMove(fromPage: Int, toPage: Int)
+    }
+}

+ 246 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbViewModel.kt

@@ -0,0 +1,246 @@
+package com.kdanmobile.reader.thumb
+
+import android.app.AlertDialog
+import android.arch.lifecycle.ViewModel
+import android.graphics.Bitmap
+import com.kdanmobile.kmpdfkit.manager.KMPDFFactory
+import com.kdanmobile.kmpdfkit.manager.controller.KMPDFDocumentController
+import com.kdanmobile.kmpdfkit.pdfcommon.Bookmark
+import com.kdanmobile.kmpdfkit.pdfcommon.TextWord
+import com.kdanmobile.reader.R
+import com.kdanmobile.reader.ReaderActivity
+import com.kdanmobile.reader.screen.handler.*
+import com.kdanmobile.reader.thumb.mode.Mode
+import com.kdanmobile.reader.thumb.mode.NormalMode
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+import java.io.File
+import java.util.HashMap
+
+class PdfThumbViewModel: ViewModel() {
+    companion object {
+        var tempKmpdfFactory: KMPDFFactory? = null
+        var tempkmpdfDocumentController: KMPDFDocumentController? = null
+    }
+
+    private var pageCount = 0
+    private var normalMode = NormalMode()
+    private var disposable: Disposable? = null
+    var kmpdfFactory: KMPDFFactory? = null
+    var kmpdfDocumentController: KMPDFDocumentController? = null
+    val mapSelect: MutableMap<Int, Boolean> = HashMap()
+    var mode: Mode
+    var isEditMode = false
+    var isPdf = true
+
+    init {
+        kmpdfFactory = tempKmpdfFactory
+        kmpdfDocumentController = tempkmpdfDocumentController
+        tempKmpdfFactory = null
+        tempkmpdfDocumentController = null
+        pageCount = kmpdfDocumentController?.getDocumentPageCount(false) ?: 0
+        for (i in 0 until pageCount){
+            mapSelect[i] = false
+        }
+        mode = normalMode
+    }
+
+    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()
+        }
+    }
+
+    private 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)
+        }
+    }
+
+    private val bookmarkHandler = object : BookmarkHandler {
+        override fun getBookmarks(): Array<Bookmark> {
+            return kmpdfDocumentController?.bookmarks ?: arrayOf()
+        }
+    }
+
+    val operateHandler = object : OperateHandler {
+        override fun deletePages(pages: IntArray): Boolean {
+            return kmpdfDocumentController?.deletePages(pages) ?: false
+        }
+        override fun save(): Boolean {
+            return kmpdfDocumentController?.save() ?: false
+        }
+
+        override fun reorderPage(fromPage: Int, toPage: Int): Boolean {
+            return kmpdfDocumentController?.reorderPages(fromPage,toPage) ?: false
+        }
+
+        override fun splitPDFWithPages(path: String, selectPage: IntArray): Boolean {
+            return kmpdfDocumentController?.splitPDFWithPages(path, selectPage) ?: false
+        }
+    }
+
+    val passwordHandler = object : PasswordHandler {
+        override fun isNeedPassword(): Boolean {
+            return tempKmpdfFactory?.needPassWord() ?: false
+        }
+    }
+
+    fun getAllPdfBitmap(): ArrayList<Bitmap>{
+        var pdfBitmaps = ArrayList<Bitmap>()
+        var pageCount: Int = kmpdfDocumentController?.getDocumentPageCount(true) ?: 0
+        for(i in 0 until pageCount) {
+            pdfBitmaps.add(thumbnailHandler.getPdfBitmap(i, 180, ThumbnailHandler.MODE_DAY, true))
+        }
+        return pdfBitmaps
+    }
+
+    fun isAllItemSelect(): Boolean{
+        var count = 0
+        for (i in 0 until pageCount){
+            mapSelect[i]?.let {
+                if(it) count ++
+            }
+        }
+        return (count == pageCount)
+    }
+
+    fun setAllSelect(){
+        for (i in 0 until pageCount) {
+            mapSelect.let {
+                it[i] = true
+            }
+        }
+    }
+
+    fun setAllUnSelect(){
+        for (i in 0 until pageCount) {
+            mapSelect.let {
+                it[i] = false
+            }
+        }
+    }
+
+    fun getSelectPage(): ArrayList<Int>{
+        var list = ArrayList<Int>()
+        for (i in 0 until pageCount){
+            mapSelect[i]?.let {
+                if(it) list.add(i)
+            }
+        }
+        return list
+    }
+
+    fun hasSelectItem(): Boolean{
+        var count = 0
+        for (i in 0 until pageCount){
+            mapSelect[i]?.let {
+                if(it) count ++
+            }
+        }
+        return (count > 0)
+    }
+
+    fun hasBookMark() : Array<Boolean>{
+        var hasBookMark = Array(pageCount) { false }
+        for (bookmark in bookmarkHandler.getBookmarks()){
+            hasBookMark[bookmark.pageNum] = true
+        }
+        return hasBookMark
+    }
+
+    fun pageRotate(runnable: Runnable){
+        val isRotate = kmpdfDocumentController?.rotatePages(getSelectPage().toIntArray(), KMPDFDocumentController.RotationalDirection.CLOCK_WISE)
+        when(isRotate){
+            true -> {
+                runnable.run()
+            }
+        }
+    }
+
+    fun pageDelete(runnable: Runnable){
+        disposable = Observable.create<Boolean> { emitter ->
+            val flag = operateHandler.deletePages(getSelectPage().toIntArray())
+            emitter.onNext(flag)
+            emitter.onComplete()
+        }
+                .subscribeOn(Schedulers.computation())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    when(it){
+                        true -> {
+                            runnable.run()
+                        }
+                    }
+                }, {
+                    it.printStackTrace()
+                })
+    }
+
+    fun pageExtract(dst: File, runnableForSuc: Runnable, runnableForFail: Runnable) {
+        disposable = Observable.create<Boolean> { emitter ->
+            val b = operateHandler.splitPDFWithPages(dst.absolutePath, getSelectPage().toIntArray())
+            emitter.onNext(b)
+            emitter.onComplete()
+            }
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    when (it) {
+                        true -> {
+                            runnableForSuc.run()
+                        }
+                        false -> {
+                            runnableForFail.run()
+                        }
+                    }
+                }, {
+                    it.printStackTrace()
+                })
+    }
+
+    fun reorderPage(fromPage: Int, toPage: Int, runnable: Runnable){
+        disposable = Observable.create<Boolean> { emitter ->
+            val flag = operateHandler.reorderPage(fromPage, toPage)
+            emitter.onNext(flag)
+            emitter.onComplete()
+        }
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe({
+                    when(it){
+                        true -> {
+                            runnable.run()
+                        }
+                    }
+                }, {
+                    it.printStackTrace()
+                })
+    }
+
+    override fun onCleared() {
+        if (null != disposable && !disposable!!.isDisposed) {
+            disposable?.dispose()
+            disposable = null
+        }
+        super.onCleared()
+    }
+}

+ 10 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/PdfThumbViewModelFactory.kt

@@ -0,0 +1,10 @@
+package com.kdanmobile.reader.thumb
+
+import android.arch.lifecycle.ViewModel
+import android.arch.lifecycle.ViewModelProvider
+
+class PdfThumbViewModelFactory: ViewModelProvider.Factory {
+    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
+        return PdfThumbViewModel() as T
+    }
+}

+ 23 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/ScreenUtil.kt

@@ -0,0 +1,23 @@
+package com.kdanmobile.reader.thumb
+
+import android.content.Context
+import android.util.DisplayMetrics
+
+object ScreenUtil {
+
+    private fun getDisPlayMetrics(context: Context): DisplayMetrics {
+        return context.resources.displayMetrics
+    }
+
+    fun getScreenWidth(context: Context): Int {
+        return getDisPlayMetrics(context).widthPixels
+    }
+
+    fun getDensity(context: Context): Float {
+        return getDisPlayMetrics(context).density
+    }
+
+    fun getXDp(context: Context): Double {
+        return (getScreenWidth(context) / getDensity(context)).toDouble()
+    }
+}

+ 15 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/ThumbData.kt

@@ -0,0 +1,15 @@
+package com.kdanmobile.reader.thumb
+
+import android.graphics.Bitmap
+import java.util.HashMap
+
+class ThumbData {
+    var viewHeight = 0
+    var viewWidth = 0
+    var viewPadding = 0
+    var currentPage = 0
+    var isEditMode = false
+    var pages: ArrayList<Bitmap>? = null
+    var pageSelect: MutableMap<Int, Boolean> = HashMap()
+    var hasBookMarks: Array<Boolean>? = null
+}

+ 23 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/mode/EditMode.kt

@@ -0,0 +1,23 @@
+package com.kdanmobile.reader.thumb.mode
+
+import android.app.Activity
+import com.kdanmobile.reader.thumb.PdfThumbActivity
+import com.kdanmobile.reader.thumb.PdfThumbAdapter
+
+class EditMode: Mode() {
+    override fun onClickToolBarNavigation() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun updateToolbar() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun onPageItemClick(activity: Activity, integer: Int, operate: Int, selectMap: MutableMap<Int,Boolean>, pdfThumbAdapter: PdfThumbAdapter){
+        selectMap[integer]?.let {
+            selectMap[integer] = !it
+        }
+        pdfThumbAdapter.notifyDataSetChanged()
+        (activity as PdfThumbActivity).updateToolbar()
+    }
+}

+ 11 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/mode/Mode.kt

@@ -0,0 +1,11 @@
+package com.kdanmobile.reader.thumb.mode
+
+import android.app.Activity
+import com.kdanmobile.reader.thumb.PdfThumbAdapter
+
+abstract class Mode {
+    abstract fun onPageItemClick(activity: Activity, integer: Int, operate: Int, selectMap: MutableMap<Int,Boolean>, pdfThumbAdapter: PdfThumbAdapter)
+    abstract fun onClickToolBarNavigation()
+    abstract fun updateToolbar()
+
+}

+ 24 - 0
reader/src/main/java/com/kdanmobile/reader/thumb/mode/NormalMode.kt

@@ -0,0 +1,24 @@
+package com.kdanmobile.reader.thumb.mode
+
+import android.app.Activity
+import android.app.Activity.RESULT_OK
+import android.content.Intent
+import com.kdanmobile.reader.thumb.PdfThumbAdapter
+
+class NormalMode: Mode() {
+    override fun onClickToolBarNavigation() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun updateToolbar() {
+        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    }
+
+    override fun onPageItemClick(activity: Activity, integer: Int, operate: Int,selectMap: MutableMap<Int,Boolean>, pdfThumbAdapter: PdfThumbAdapter) {
+        val data = Intent()
+        data.putExtra("result", integer)
+        data.putExtra("operate", operate)
+        activity.setResult(RESULT_OK, data)
+        activity.finish()
+    }
+}

BIN=BIN
reader/src/main/res/drawable-hdpi/ic_arrowback_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_arrowback_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_checkbox_off_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_checkbox_on_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_close_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_delete_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_delete_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_delete_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_deselect_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_deselect_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_deselect_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_extract_page_btn_action_bar.webp


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_rotate_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_rotate_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_rotate_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_selectall_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_selectall_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-hdpi/ic_selectall_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_delete_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_delete_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_delete_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_deselect_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_deselect_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_deselect_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_extract_page_btn_action_bar.webp


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_rotate_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_rotate_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_rotate_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_selectall_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_selectall_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-mdpi/ic_selectall_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_arrowback_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_arrowback_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_checkbox_off_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_checkbox_on_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_close_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_delete_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_delete_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_delete_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_deselect_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_deselect_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_deselect_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_extract_page_btn_action_bar.webp


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_rotate_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_rotate_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_rotate_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_selectall_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_selectall_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xhdpi/ic_selectall_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_arrowback_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_arrowback_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_checkbox_off_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_checkbox_on_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_close_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_delete_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_delete_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_delete_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_deselect_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_deselect_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_deselect_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_extract_page_btn_action_bar.webp


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_rotate_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_rotate_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_rotate_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_selectall_black_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_selectall_blue_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxhdpi/ic_selectall_dis_24dp.png


BIN=BIN
reader/src/main/res/drawable-xxxhdpi/ic_extract_page_btn_action_bar.webp


+ 4 - 0
reader/src/main/res/drawable/ic_close_black_24dp.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
+    <path android:fillColor="#000000" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+</vector>

+ 4 - 0
reader/src/main/res/drawable/ic_close_blue_24dp.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
+    <path android:fillColor="#2196f3" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+</vector>

+ 4 - 0
reader/src/main/res/drawable/ic_close_dis_24dp.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
+    <path android:fillColor="#BDBDBD" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+</vector>

+ 4 - 0
reader/src/main/res/drawable/ic_mode_edit_black_24dp.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
+    <path android:fillColor="#000000" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>

+ 4 - 0
reader/src/main/res/drawable/ic_mode_edit_blue_24dp.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
+    <path android:fillColor="#2196f3" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>

+ 4 - 0
reader/src/main/res/drawable/ic_mode_edit_dis_24dp.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
+    <path android:fillColor="#BDBDBD" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>

+ 8 - 0
reader/src/main/res/drawable/selector_arrowback.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/ic_arrowback_blue_24dp" android:state_pressed="true"/>
+    <item android:drawable="@drawable/ic_arrowback_blue_24dp" android:state_enabled="true" android:state_focused="true"/>
+    <item android:drawable="@drawable/ic_arrowback_black_24dp"/>
+
+</selector>

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

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- <item android:drawable="@drawable/rect_1a7dd7_corners_bl5_br5" android:state_pressed="true"/> -->
+    <!-- <item android:drawable="@drawable/rect_1a7dd7_corners_bl5_br5" android:state_enabled="true" android:state_focused="true"/> -->
+    <!-- <item android:drawable="@drawable/rect_white_corners_bl5_br5"/> -->
+
+    <item android:drawable="@drawable/ic_checkbox_on_blue_24dp" android:state_checked="true" android:state_enabled="true" />
+    <item android:drawable="@drawable/ic_checkbox_off_blue_24dp"/>
+
+</selector>

+ 8 - 0
reader/src/main/res/drawable/selector_close_btn_navigation.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/ic_close_blue_24dp" android:state_enabled="true" android:state_pressed="true"/>
+    <item android:drawable="@drawable/ic_close_dis_24dp" android:state_enabled="false"/>
+    <item android:drawable="@drawable/ic_close_black_24dp" android:state_enabled="true"/>
+
+</selector>

+ 0 - 0
reader/src/main/res/drawable/selector_delete_btn_action_bar.xml


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio