Skip to content

Commit 70b04bc

Browse files
committed
3.1.8 Bionic Reading
1 parent f87615c commit 70b04bc

File tree

8 files changed

+82
-9
lines changed

8 files changed

+82
-9
lines changed

app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ android {
1414
applicationId "com.lagradost.quicknovel"
1515
minSdkVersion 21
1616
targetSdkVersion 34
17-
versionCode 54
18-
versionName "3.1.7"
17+
versionCode 55
18+
versionName "3.1.8"
1919
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
2020
}
2121

app/src/main/java/com/lagradost/quicknovel/DataStore.kt

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const val DOWNLOAD_NORMAL_SORTING_METHOD: String = "download_normal_sorting"
2020
const val DOWNLOAD_SETTINGS: String = "download_settings"
2121
const val EPUB_LOCK_ROTATION: String = "reader_epub_rotation"
2222
const val EPUB_TEXT_SIZE: String = "reader_epub_text_size"
23+
const val EPUB_TEXT_BIONIC: String = "reader_epub_bionic_reading"
2324
const val EPUB_SCROLL_VOL: String = "reader_epub_scroll_volume"
2425
const val EPUB_TTS_LOCK: String = "reader_epub_scroll_lock"
2526
const val EPUB_BG_COLOR: String = "reader_epub_bg_color"

app/src/main/java/com/lagradost/quicknovel/ReadActivity2.kt

+13-2
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,6 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
553553
config.setArgs(binding.loadingText, CONFIG_FONT or CONFIG_COLOR)
554554
config.setArgs(binding.readBattery, CONFIG_FONT or CONFIG_COLOR or CONFIG_FONT_BOLD)
555555
config.setArgs(binding.readTimeClock, CONFIG_FONT or CONFIG_COLOR or CONFIG_FONT_BOLD)
556-
557556
config.setArgs(binding.readLoadingBar)
558557
}
559558

@@ -715,7 +714,8 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
715714
textColor = viewModel.textColor,
716715
textSize = viewModel.textSize,
717716
textFont = viewModel.textFont,
718-
backgroundColor = viewModel.backgroundColor
717+
backgroundColor = viewModel.backgroundColor,
718+
bionicReading = viewModel.bionicReading
719719
).also { config ->
720720
updateOtherTextConfig(config)
721721
}
@@ -754,6 +754,12 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
754754
}
755755
}
756756

757+
observe(viewModel.bionicReadingLive) { color ->
758+
if (textAdapter.changeBionicReading(color)) {
759+
updateTextAdapterConfig()
760+
}
761+
}
762+
757763
observe(viewModel.showBatteryLive) { show ->
758764
binding.readBattery.isVisible = show
759765
binding.readOverlay.isVisible = show && viewModel.showTime
@@ -1266,6 +1272,11 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
12661272
viewModel.scrollWithVolume = isChecked
12671273
}
12681274

1275+
readSettingsShowBionic.isChecked = viewModel.bionicReading
1276+
readSettingsShowBionic.setOnCheckedChangeListener { _, isChecked ->
1277+
viewModel.bionicReading = isChecked
1278+
}
1279+
12691280
readSettingsLockTts.isChecked = viewModel.ttsLock
12701281
readSettingsLockTts.setOnCheckedChangeListener { _, isChecked ->
12711282
viewModel.ttsLock = isChecked

app/src/main/java/com/lagradost/quicknovel/ReadActivityViewModel.kt

+8
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,14 @@ class ReadActivityViewModel : ViewModel() {
12021202
textSizeLive
12031203
)
12041204

1205+
val bionicReadingLive: MutableLiveData<Boolean> = MutableLiveData(null)
1206+
var bionicReading by PreferenceDelegateLiveView(
1207+
EPUB_TEXT_BIONIC,
1208+
false,
1209+
Boolean::class,
1210+
bionicReadingLive
1211+
)
1212+
12051213
val orientationLive: MutableLiveData<Int> = MutableLiveData(null)
12061214
var orientation by PreferenceDelegateLiveView(
12071215
EPUB_LOCK_ROTATION,

app/src/main/java/com/lagradost/quicknovel/TTSHelper.kt

+32-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.ComponentName
44
import android.content.Context
55
import android.content.Intent
66
import android.content.IntentFilter
7+
import android.graphics.Typeface
78
import android.media.AudioAttributes
89
import android.media.AudioFocusRequest
910
import android.media.AudioManager
@@ -12,21 +13,26 @@ import android.speech.tts.TextToSpeech
1213
import android.speech.tts.UtteranceProgressListener
1314
import android.speech.tts.Voice
1415
import android.support.v4.media.session.MediaSessionCompat
16+
import android.text.Spannable
17+
import android.text.SpannableString
1518
import android.text.Spanned
19+
import android.text.style.StyleSpan
1620
import android.view.KeyEvent
1721
import androidx.media.session.MediaButtonReceiver
18-
import com.lagradost.quicknovel.ui.UiText
19-
import com.lagradost.quicknovel.ui.txt
2022
import com.lagradost.quicknovel.BaseApplication.Companion.removeKey
2123
import com.lagradost.quicknovel.BaseApplication.Companion.setKey
2224
import com.lagradost.quicknovel.mvvm.debugAssert
2325
import com.lagradost.quicknovel.receivers.BecomingNoisyReceiver
26+
import com.lagradost.quicknovel.ui.UiText
27+
import com.lagradost.quicknovel.ui.txt
2428
import com.lagradost.quicknovel.util.UIHelper.requestAudioFocus
2529
import io.noties.markwon.Markwon
2630
import kotlinx.coroutines.delay
2731
import org.jsoup.Jsoup
2832
import java.util.Locale
2933
import java.util.Stack
34+
import kotlin.math.roundToInt
35+
3036

3137
class TTSSession(val context: Context, event: (TTSHelper.TTSActionType) -> Boolean) {
3238
private val intentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
@@ -266,6 +272,30 @@ data class TextSpan(
266272
override val index: Int,
267273
override var innerIndex: Int,
268274
) : SpanDisplay() {
275+
val bionicText : Spanned by lazy {
276+
val wordToSpan: Spannable = SpannableString(text)
277+
val length = wordToSpan.length
278+
Regex("([a-zà-ýA-ZÀ-ÝåäöÅÄÖ].*?)[^a-zà-ýA-ZÀ-ÝåäöÅÄÖ'’]").findAll(text).forEach { match ->
279+
val range = match.groups[1]!!.range
280+
// https://github.com/gBloxy/Bionic-Reader/blob/main/bionic-reader.py#L167
281+
val correctLength = when (val rangeLength = range.last + 1 - range.first) {
282+
0 -> return@forEach // this should never happened
283+
1, 2, 3 -> 1
284+
4 -> 2
285+
else -> {
286+
(rangeLength.toFloat() * 0.4).roundToInt()
287+
}
288+
}
289+
wordToSpan.setSpan(
290+
StyleSpan(Typeface.BOLD),
291+
minOf(maxOf(match.range.first, 0), length),
292+
minOf(maxOf(match.range.first + correctLength, 0), length),
293+
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
294+
)
295+
}
296+
297+
wordToSpan
298+
}
269299
override fun id(): Long {
270300
return generateId(0, index, start, end)
271301
}

app/src/main/java/com/lagradost/quicknovel/ui/TextAdapter.kt

+14-3
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ data class TextConfig(
174174
val textFont: String,
175175
val defaultFont: Typeface,
176176
val backgroundColor : Int,
177+
val bionicReading : Boolean
177178
) {
178179
private val fontFile: File? by lazy {
179180
if (textFont == "") null else systemFonts.firstOrNull { it.name == textFont }
@@ -251,6 +252,12 @@ class TextAdapter(private val viewModel: ReadActivityViewModel, var config: Text
251252
return true
252253
}
253254

255+
fun changeBionicReading(to : Boolean) : Boolean {
256+
if (config.bionicReading == to) return false
257+
config = config.copy(bionicReading = to)
258+
return true
259+
}
260+
254261
fun changeColor(color: Int): Boolean {
255262
if (config.textColor == color) return false
256263
config = config.copy(textColor = color)
@@ -547,7 +554,7 @@ class TextAdapter(private val viewModel: ReadActivityViewModel, var config: Text
547554
UIHelper.bindImage(binding.root, img)
548555
}
549556

550-
private fun bindText(obj: TextSpan) {
557+
private fun bindText(obj: TextSpan, config: TextConfig) {
551558
when (binding) {
552559
is SingleImageBinding -> {
553560
val img = obj.text.getSpans<AsyncDrawableSpan>(0, obj.text.length)[0]
@@ -586,7 +593,11 @@ class TextAdapter(private val viewModel: ReadActivityViewModel, var config: Text
586593
binding.root.apply {
587594
// this is set to fix the nonclick https://stackoverflow.com/questions/8641343/android-clickablespan-not-calling-onclick
588595
movementMethod = LinkMovementMethod.getInstance()
589-
text = obj.text
596+
text = if (config.bionicReading) {
597+
obj.bionicText
598+
} else {
599+
obj.text
600+
}
590601

591602
//val links = obj.text.getSpans<io.noties.markwon.core.spans.LinkSpan>()
592603
//if (links.isNotEmpty()) {
@@ -671,7 +682,7 @@ class TextAdapter(private val viewModel: ReadActivityViewModel, var config: Text
671682
span = obj
672683
when (obj) {
673684
is TextSpan -> {
674-
this.bindText(obj)
685+
this.bindText(obj, config)
675686
// because we bind text here we know that it will be cleared and thus
676687
// we do not have to update it with null
677688
if (ttsLine != null)

app/src/main/res/layout/read_bottom_settings.xml

+11
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,17 @@
9999
android:layout_width="match_parent"
100100
android:layout_height="wrap_content" />
101101

102+
<com.google.android.material.checkbox.MaterialCheckBox
103+
android:textSize="16sp"
104+
android:paddingStart="5dp"
105+
android:paddingEnd="5dp"
106+
android:text="@string/bionic_reading"
107+
android:id="@+id/read_settings_show_bionic"
108+
android:textColor="?attr/textColor"
109+
app:buttonTint="?attr/colorOnPrimary"
110+
android:layout_width="match_parent"
111+
android:layout_height="wrap_content" />
112+
102113
<com.google.android.material.checkbox.MaterialCheckBox
103114
android:textSize="16sp"
104115
android:paddingStart="5dp"

app/src/main/res/values/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,5 @@
207207
<string name="more_info">More Info</string>
208208
<string name="download_path_key">download_path_key</string>
209209
<string name="download_path_pref">Download path</string>
210+
<string name="bionic_reading">Bionic Reading</string>
210211
</resources>

0 commit comments

Comments
 (0)