fix: Disable page curl on affected devices
Some checks are pending
Build / build (push) Waiting to run

The Play crash report named the TECNO-KJ5 and IIIF150 Air1_Ultra.
This change routed page drags on those devices through the reader's
standard page turn and kept the curl on other devices.
This commit is contained in:
Chmouel Boudjnah 2026-10-14 23:40:28 +02:00
parent 044fcc4c8f
commit dd6892bbf9
4 changed files with 128 additions and 1 deletions

View file

@ -3,6 +3,7 @@ package com.chmouel.liseur.reader
import android.app.Activity
import android.graphics.BitmapFactory
import android.graphics.Rect
import android.os.Build
import android.util.Log
import android.view.WindowManager
import androidx.activity.compose.BackHandler
@ -190,6 +191,7 @@ import com.chmouel.liseur.reader.chrome.AutoScrollTicker
import com.chmouel.liseur.reader.chrome.autoScrollControlsShown
import com.chmouel.liseur.reader.chrome.JumpBackPill
import com.chmouel.liseur.reader.chrome.PageCurl
import com.chmouel.liseur.reader.chrome.isPageCurlSupportedOnDevice
import com.chmouel.liseur.reader.chrome.PageCurlOverlay
import com.chmouel.liseur.reader.chrome.PageCurlState
import com.chmouel.liseur.reader.chrome.PageTurnDrag
@ -1145,6 +1147,14 @@ fun ReaderScreen(
val eInk = LocalEInk.current
val eInkNow by rememberUpdatedState(eInk)
val pageCurlSupportedOnDevice = remember {
isPageCurlSupportedOnDevice(
manufacturer = Build.MANUFACTURER.orEmpty(),
brand = Build.BRAND.orEmpty(),
model = Build.MODEL.orEmpty(),
device = Build.DEVICE.orEmpty(),
)
}
var showingEnd by remember { mutableStateOf(false) }
chromeTransition.targetState = chromeVisible && !showingEnd
val showingEndNow by rememberUpdatedState(showingEnd)
@ -1245,7 +1255,7 @@ fun ReaderScreen(
tappedSelection == null &&
viewedImageNow == null && !openingImageNow
},
interactive = { !eInkNow },
interactive = { !eInkNow && pageCurlSupportedOnDevice },
isRtl = {
navigatorNow?.overflow?.value?.readingProgression == ReadingProgression.RTL
},

View file

@ -0,0 +1,28 @@
package com.chmouel.liseur.reader.chrome
import java.util.Locale
private val DEVICE_NAME_SEPARATORS = Regex("[^a-z0-9]+")
/**
* Whether the custom page curl should be used on this device.
*/
internal fun isPageCurlSupportedOnDevice(
manufacturer: String,
brand: String,
model: String,
device: String,
): Boolean {
val names = listOf(manufacturer, brand, model, device)
.map { it.lowercase(Locale.ROOT).replace(DEVICE_NAME_SEPARATORS, " ").trim() }
val isTecnoKj5 =
names.any { it.hasToken("tecno") } &&
names.any { it == "kj5" || it.endsWith(" kj5") }
val isAir1Ultra = names.any { it == "air1 ultra" || it.endsWith(" air1 ultra") }
return !(isTecnoKj5 || isAir1Ultra)
}
private fun String.hasToken(token: String): Boolean =
split(' ').any { it == token }

View file

@ -0,0 +1,72 @@
package com.chmouel.liseur.reader.chrome
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class PageCurlCompatibilityTest {
@Test
fun `TECNO KJ5 is kept off the custom curl`() {
assertFalse(
isPageCurlSupportedOnDevice(
manufacturer = "TECNO",
brand = "TECNO",
model = "TECNO-KJ5",
device = "KJ5",
),
)
}
@Test
fun `the TECNO Spark 20 sample is matched by its KJ5 device code`() {
assertFalse(
isPageCurlSupportedOnDevice(
manufacturer = "TECNO",
brand = "TECNO",
model = "TECNO SPARK 20",
device = "KJ5",
),
)
}
@Test
fun `IIIF150 Air1 Ultra is kept off the custom curl`() {
assertFalse(
isPageCurlSupportedOnDevice(
manufacturer = "Unknown",
brand = "Unknown",
model = "Air1_Ultra",
device = "Air1_Ultra",
),
)
}
@Test
fun `unreported models keep the custom curl`() {
assertTrue(
isPageCurlSupportedOnDevice(
manufacturer = "TECNO",
brand = "TECNO",
model = "TECNO-KJ50",
device = "KJ50",
),
)
assertTrue(
isPageCurlSupportedOnDevice(
manufacturer = "IIIF150",
brand = "IIIF150",
model = "Air1",
device = "Air1",
),
)
assertTrue(
isPageCurlSupportedOnDevice(
manufacturer = "Google",
brand = "Google",
model = "Pixel 10",
device = "generic",
),
)
}
}

View file

@ -125,6 +125,23 @@ class PageTurnDragTest {
assertTrue(h.curl.log.isEmpty())
}
@Test
fun `a reported device leaves the horizontal drag to the navigator`() {
val h = Harness(
interactive = isPageCurlSupportedOnDevice(
manufacturer = "TECNO",
brand = "TECNO",
model = "TECNO-KJ5",
device = "KJ5",
),
)
assertFalse(h.drag.offer(pointers = 1, dx = -200f, dy = 4f))
assertFalse(h.drag.release())
assertTrue(h.turns.isEmpty())
assertTrue(h.curl.log.isEmpty())
}
// Curls.
@Test