|
@@ -1,5 +1,9 @@
|
|
|
package com.kdanmobile.reader.additionalpage
|
|
|
|
|
|
+import android.util.SparseBooleanArray
|
|
|
+import androidx.annotation.IntRange
|
|
|
+import kotlin.math.abs
|
|
|
+
|
|
|
/**
|
|
|
* 額外頁面管理員
|
|
|
* 判斷哪些頁面是額外頁面、是否該顯示額外頁面
|
|
@@ -7,13 +11,16 @@ package com.kdanmobile.reader.additionalpage
|
|
|
* <名詞解釋>
|
|
|
* 額外頁面:在原始文件之間插入的空頁面,之後可在其上插入其他內容(例如廣告)
|
|
|
*/
|
|
|
-interface AdditionalPageManager {
|
|
|
-
|
|
|
- // 額外頁面頁碼轉換器
|
|
|
- val pageConverter: AdditionalPageConverter
|
|
|
+class AdditionalPageManager(
|
|
|
+ val pageConverter: AdditionalPageConverter = AdditionalPageConverter(),
|
|
|
+ val displayStrategy: AdditionalPageDisplayStrategy = AdditionalPageDisplayStrategy(),
|
|
|
+ @IntRange(from = 3) private val nextInterval: Int = DEFAULT_NEXT_INTERVAL
|
|
|
+) {
|
|
|
|
|
|
- // 額外頁面顯示策略
|
|
|
- val displayStrategy: AdditionalPageDisplayStrategy
|
|
|
+ companion object {
|
|
|
+ // 當前頁面改變後,前後第N頁該顯示額外頁面
|
|
|
+ const val DEFAULT_NEXT_INTERVAL = 3
|
|
|
+ }
|
|
|
|
|
|
// 額外頁面顯示策略類型
|
|
|
var displayStrategyType: AdditionalPageDisplayStrategyType
|
|
@@ -24,29 +31,97 @@ interface AdditionalPageManager {
|
|
|
displayStrategy.displayStrategyType = value
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 記錄額外頁面頁碼與其是否可見
|
|
|
+ */
|
|
|
+ private val additionalPageVisibleSet = SparseBooleanArray()
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 記錄哪些額外頁面是隱藏不可見
|
|
|
+ */
|
|
|
+ private val hiddenAdditionalPageSet = HashSet<Int>()
|
|
|
+
|
|
|
/**
|
|
|
* 請求額外頁面
|
|
|
*/
|
|
|
- var requestAdditionalPage: (position: Int) -> Unit
|
|
|
+ var requestAdditionalPage: (position: Int) -> Unit = {}
|
|
|
|
|
|
/**
|
|
|
* 判斷額外頁面是否讀取完畢
|
|
|
*/
|
|
|
- var isAdditionalPageLoaded: (position: Int) -> Boolean
|
|
|
+ var isAdditionalPageLoaded: (position: Int) -> Boolean = {
|
|
|
+ false
|
|
|
+ }
|
|
|
+
|
|
|
+ init {
|
|
|
+ pageConverter.isAdditionalPageEnabled = {
|
|
|
+ displayStrategyType != AdditionalPageDisplayStrategyType.HIDE
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 判斷第position頁是否是額外頁面,並且該額外頁面是否可見
|
|
|
*/
|
|
|
- fun isAdditionalPageVisible(position: Int): Boolean
|
|
|
+ fun isAdditionalPageVisible(position: Int): Boolean {
|
|
|
+ return pageConverter.isAdditionalPage(position) && additionalPageVisibleSet[position]
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判斷第position頁是否可顯示額外頁面
|
|
|
+ * 若是滿足以下任意條件則不可顯示額外頁面:
|
|
|
+ * .該頁不是額外頁面
|
|
|
+ * .該頁在可視範圍內(與當前頁差距小於nextInterval頁)
|
|
|
+ * .頁碼超過文件範圍
|
|
|
+ */
|
|
|
+ private fun canDisplayAdditionalPageAt(position: Int): Boolean {
|
|
|
+ return when {
|
|
|
+ !pageConverter.isAdditionalPage(position) -> false
|
|
|
+ abs(position - pageConverter.getCurrentPage()) < nextInterval -> false
|
|
|
+ position < 0 || position >= pageConverter.getPageCount() -> false
|
|
|
+ else -> true
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 當前頁面更新時呼叫此方法
|
|
|
* 判斷哪幾頁應請求/顯示額外頁面
|
|
|
*/
|
|
|
- fun onPageChanged(position: Int)
|
|
|
+ fun onPageChanged(position: Int) {
|
|
|
+ // 若不該顯示額外頁面則停止執行
|
|
|
+ if (!pageConverter.isAdditionalPageEnabled.invoke()) return
|
|
|
+
|
|
|
+ for (dir in -1 .. 1 step 2) {
|
|
|
+ // 判斷position的前後第nextInterval頁
|
|
|
+ val targetPosition = position + nextInterval * dir
|
|
|
+ // 是否可顯示額外頁面
|
|
|
+ val isValid = displayStrategy.canDisplayAdditionalPageAt(additionalPageVisibleSet, targetPosition)
|
|
|
+ val isHidden = hiddenAdditionalPageSet.contains(targetPosition)
|
|
|
+ if (isValid && !isHidden) {
|
|
|
+ // 該額外頁面是否請求成功
|
|
|
+ if (isAdditionalPageLoaded.invoke(targetPosition)) {
|
|
|
+ // 若該位置可顯示額外頁面
|
|
|
+ if (canDisplayAdditionalPageAt(targetPosition)) {
|
|
|
+ // 顯示額外頁面
|
|
|
+ additionalPageVisibleSet.put(targetPosition, true)
|
|
|
+ // 更新最後顯示時間
|
|
|
+ displayStrategy.updateDisplayTime()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ requestAdditionalPage.invoke(targetPosition)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 隱藏額外頁面
|
|
|
*/
|
|
|
- fun tryToHideAdditionalPageAt(position: Int): Boolean
|
|
|
+ fun tryToHideAdditionalPageAt(position: Int): Boolean {
|
|
|
+ if (!pageConverter.isAdditionalPage(position)) return false
|
|
|
+ // 移除該額外頁面
|
|
|
+ additionalPageVisibleSet.put(position, false)
|
|
|
+ // 紀錄為隱藏狀態
|
|
|
+ hiddenAdditionalPageSet.add(position)
|
|
|
+ return true
|
|
|
+ }
|
|
|
}
|