Skip to content

Commit

Permalink
seek to
Browse files Browse the repository at this point in the history
  • Loading branch information
LagradOst committed Jul 8, 2023
1 parent d37c141 commit e5ebb95
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 43 deletions.
78 changes: 58 additions & 20 deletions app/src/main/java/com/lagradost/quicknovel/ReadActivity2.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import android.view.WindowManager
import android.widget.AbsListView
import android.widget.ArrayAdapter
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.doOnEnd
import androidx.core.app.NotificationManagerCompat
Expand Down Expand Up @@ -198,10 +201,10 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
private lateinit var textAdapter: TextAdapter
private lateinit var textLayoutManager: LinearLayoutManager

private fun transformIndexToScrollVisibilityItem(index: Int): ScrollVisibilityItem {
private fun transformIndexToScrollVisibilityItem(adapterPosition: Int): ScrollVisibilityItem {
return ScrollVisibilityItem(
index = index,
viewHolder = binding.realText.findViewHolderForAdapterPosition(index),
adapterPosition = adapterPosition,
viewHolder = binding.realText.findViewHolderForAdapterPosition(adapterPosition),
)
}

Expand Down Expand Up @@ -260,24 +263,21 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
private var cachedChapter: List<SpanDisplay> = emptyList()
private fun scrollToDesired() {
val desired = viewModel.desiredIndex
val index =
val adapterPosition =
cachedChapter.indexOfFirst { display -> display.index == desired.index && display.innerIndex == desired.innerIndex }
if (index > 0) {
textLayoutManager.scrollToPositionWithOffset(index, 0)

if (adapterPosition > 0) {
textLayoutManager.scrollToPositionWithOffset(adapterPosition, 0)
desired.firstVisibleChar?.let { visible ->
binding.realText.post {
binding.realText.scrollBy(
0,
(textAdapter.getViewOffset(
transformIndexToScrollVisibilityItem(index),
transformIndexToScrollVisibilityItem(adapterPosition),
visible
) ?: 0) + 7.toPx
)
}
}

binding.realText.findViewHolderForAdapterPosition(index)
}
}

Expand All @@ -299,6 +299,11 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
}
}

/*fun setRot(org: OrientationType) {
orientationType = org.prefValue
requestedOrientation = org.flag
binding.readActionRotate.setImageResource(org.iconRes)
}*/
override fun onCreate(savedInstanceState: Bundle?) {
CommonActivity.loadThemes(this)
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -347,14 +352,51 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
}

observe(viewModel.chaptersTitles) { titles ->
binding.readActionChapters.setOnClickListener {
val builderSingle: AlertDialog.Builder = AlertDialog.Builder(this)
//builderSingle.setIcon(R.drawable.ic_launcher)
val currentChapter = viewModel.desiredIndex.index
// cant be too safe here
val validChapter = currentChapter >= 0 && currentChapter < titles.size
if (validChapter) {
builderSingle.setTitle(titles[currentChapter]) // "Select Chapter"
} else {
builderSingle.setTitle("Select Chapter")
}

val arrayAdapter = ArrayAdapter<String>(this, R.layout.chapter_select_dialog)

arrayAdapter.addAll(titles)

builderSingle.setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }

builderSingle.setAdapter(arrayAdapter) { _, which ->
viewModel.seekToChapter(which)
}

val dialog = builderSingle.create()
dialog.show()

dialog.listView.choiceMode = AbsListView.CHOICE_MODE_SINGLE
if (validChapter) {
dialog.listView.setSelection(currentChapter)
dialog.listView.setItemChecked(currentChapter, true)
}
}
}

observe(viewModel.ttsStatus) { status ->
val isTTSRunning = status != TTSHelper.TTSStatus.IsStopped

binding.readerBottomView.isGone = isTTSRunning
binding.readerBottomViewTts.isVisible = isTTSRunning
binding.ttsActionPausePlay.setImageResource(
when (status) {
TTSHelper.TTSStatus.IsPaused -> R.drawable.ic_baseline_play_arrow_24
TTSHelper.TTSStatus.IsRunning -> R.drawable.ic_baseline_pause_24
TTSHelper.TTSStatus.IsStopped -> R.drawable.ic_baseline_play_arrow_24
}
)
}

/*val touchListener = View.OnTouchListener { _, event ->
Expand Down Expand Up @@ -436,16 +478,12 @@ class ReadActivity2 : AppCompatActivity(), ColorPickerDialogListener {
})
}

var firstAppend = true
observe(viewModel.chapter) { text ->
cachedChapter = text
textAdapter.submitList(text)
if (firstAppend) {
firstAppend = false
scrollToDesired()
}

binding.realText.post {
observe(viewModel.chapter) { chapter ->
cachedChapter = chapter.data
textAdapter.submitList(chapter.data) {
if (chapter.seekToDesired) {
scrollToDesired()
}
onScroll()
}
}
Expand Down
71 changes: 52 additions & 19 deletions app/src/main/java/com/lagradost/quicknovel/ReadActivityViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ data class LiveChapterData(
val ttsLines: List<TTSHelper.TTSLine>
)

data class ChapterUpdate(
val data: ArrayList<SpanDisplay>,
val seekToDesired: Boolean
)

class ReadActivityViewModel : ViewModel() {
private lateinit var book: AbstractBook
private lateinit var markwon: Markwon
Expand All @@ -212,9 +217,9 @@ class ReadActivityViewModel : ViewModel() {
}


private val _chapterData: MutableLiveData<ArrayList<SpanDisplay>> =
MutableLiveData<ArrayList<SpanDisplay>>(null)
val chapter: LiveData<ArrayList<SpanDisplay>> = _chapterData
private val _chapterData: MutableLiveData<ChapterUpdate> =
MutableLiveData<ChapterUpdate>(null)
val chapter: LiveData<ChapterUpdate> = _chapterData

// we use bool as we cant construct Nothing, does not represent anything
private val _loadingStatus: MutableLiveData<Resource<Boolean>> =
Expand All @@ -241,7 +246,6 @@ class ReadActivityViewModel : ViewModel() {
MutableLiveData<TTSHelper.TTSStatus>(TTSHelper.TTSStatus.IsStopped)
val ttsStatus: LiveData<TTSHelper.TTSStatus> = _ttsStatus


private val _ttsLine: MutableLiveData<TTSHelper.TTSLine?> =
MutableLiveData<TTSHelper.TTSLine?>(null)
val ttsLine: LiveData<TTSHelper.TTSLine?> = _ttsLine
Expand Down Expand Up @@ -304,7 +308,7 @@ class ReadActivityViewModel : ViewModel() {
}
}

private fun updateReadArea() {
private fun updateReadArea(seekToDesired: Boolean = false) {
val cIndex = currentIndex
val chapters = ArrayList<SpanDisplay>()
for (idx in cIndex - chapterPaddingBottom..cIndex + chapterPaddingTop) {
Expand All @@ -330,13 +334,13 @@ class ReadActivityViewModel : ViewModel() {
chapters.add(ChapterStartSpanned(idx, 0, chaptersTitlesInternal[idx]))
chapters.addAll(append)
}
_chapterData.postValue(chapters)
_chapterData.postValue(ChapterUpdate(data = chapters, seekToDesired = seekToDesired))
}

private fun notifyChapterUpdate(index: Int) {
private fun notifyChapterUpdate(index: Int, seekToDesired: Boolean = false) {
val cIndex = currentIndex
if (cIndex - chapterPaddingBottom <= index && index <= cIndex + chapterPaddingTop) {
updateReadArea()
updateReadArea(seekToDesired)
}
}

Expand Down Expand Up @@ -483,7 +487,7 @@ class ReadActivityViewModel : ViewModel() {
changeIndex(ScrollIndex(currentIndex, innerIndex), updateArea = false)

// notify once because initial load is 3 chapters I don't care about 10 notifications when the user cant see it
notifyChapterUpdate(index = loadedChapter)
updateReadArea(seekToDesired = true)

_loadingStatus.postValue(
Resource.Success(true)
Expand Down Expand Up @@ -576,10 +580,6 @@ class ReadActivityViewModel : ViewModel() {
set(value) {
if (_CurrentTTSStatus == TTSHelper.TTSStatus.IsStopped && value == TTSHelper.TTSStatus.IsRunning) {
startTTSThread()
} else if (_CurrentTTSStatus == TTSHelper.TTSStatus.IsRunning && value == TTSHelper.TTSStatus.IsStopped) {
ioSafe {
ttsSession.interruptTTS()
}
}

_ttsStatus.postValue(value)
Expand Down Expand Up @@ -609,13 +609,12 @@ class ReadActivityViewModel : ViewModel() {
fun pausePlayTTS() {
if (CurrentTTSStatus == TTSHelper.TTSStatus.IsRunning) {
CurrentTTSStatus = TTSHelper.TTSStatus.IsPaused
}
if (CurrentTTSStatus == TTSHelper.TTSStatus.IsPaused) {
} else if (CurrentTTSStatus == TTSHelper.TTSStatus.IsPaused) {
CurrentTTSStatus = TTSHelper.TTSStatus.IsRunning
}
}

fun isTTSRunning() : Boolean {
fun isTTSRunning(): Boolean {
return CurrentTTSStatus == TTSHelper.TTSStatus.IsRunning
}

Expand Down Expand Up @@ -675,7 +674,7 @@ class ReadActivityViewModel : ViewModel() {

// this is because if you go back one line you will be on the previous chapter with
// a negative innerIndex, this makes the wrapping good
if(innerIndex < 0) {
if (innerIndex < 0) {
innerIndex += lines.size
}

Expand All @@ -693,10 +692,18 @@ class ReadActivityViewModel : ViewModel() {
CurrentTTSStatus != TTSHelper.TTSStatus.IsRunning || pendingTTSSkip != 0
}

var isPauseDuration = 0
while (CurrentTTSStatus == TTSHelper.TTSStatus.IsPaused) {
isPauseDuration++
delay(100)
}

// if we pause then we resume on the same line
if (isPauseDuration > 0) {
pendingTTSSkip = 0
continue
}

if (pendingTTSSkip != 0) {
innerIndex += pendingTTSSkip
pendingTTSSkip = 0
Expand All @@ -706,7 +713,7 @@ class ReadActivityViewModel : ViewModel() {
}
if (CurrentTTSStatus == TTSHelper.TTSStatus.IsStopped) break

if(innerIndex > 0) {
if (innerIndex > 0) {
// goto next chapter and set inner to 0
index++
innerIndex = 0
Expand All @@ -733,7 +740,7 @@ class ReadActivityViewModel : ViewModel() {
return false
}

when(input) {
when (input) {
TTSHelper.TTSActionType.Pause -> pauseTTS()
TTSHelper.TTSActionType.Resume -> startTTS()
TTSHelper.TTSActionType.Stop -> stopTTS()
Expand Down Expand Up @@ -773,6 +780,32 @@ class ReadActivityViewModel : ViewModel() {
}
}

fun seekToChapter(index: Int) = ioSafe {
// sanity check
if(index < 0 || index >= book.size()) return@ioSafe

// set loading
_loadingStatus.postValue(Resource.Loading())

// load the chapters
updateIndexAsync(index, notify = false)

// set the keys
setKey(EPUB_CURRENT_POSITION, book.title(), index)
setKey(EPUB_CURRENT_POSITION_SCROLL_CHAR, book.title(), 0)

// set the state
desiredIndex = ScrollIndex(index, 0, 0, 0)
currentIndex = index

// push the update
updateReadArea(seekToDesired = true)

// update the view
_chapterTile.postValue(chaptersTitlesInternal[index])
_loadingStatus.postValue(Resource.Success(true))
}

private fun changeIndex(index: Int, updateArea: Boolean = true) {
val realNewIndex = minOf(index, book.size() - 1)
if (currentIndex == realNewIndex) return
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/java/com/lagradost/quicknovel/ui/TextAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const val DRAW_CHAPTER = 4


data class ScrollVisibilityItem(
val index: Int,
val adapterPosition: Int,
val viewHolder: RecyclerView.ViewHolder?,
)

Expand Down Expand Up @@ -121,7 +121,7 @@ class TextAdapter(private val viewModel: ReadActivityViewModel) :
}

fun getViewOffset(scrollVisibility: ScrollVisibilityItem, char: Int): Int? {
if (scrollVisibility.index < 0 || scrollVisibility.index >= itemCount) return null
if (scrollVisibility.adapterPosition < 0 || scrollVisibility.adapterPosition >= itemCount) return null
//val item = getItem(scrollVisibility.index)
val viewHolder = scrollVisibility.viewHolder
if (viewHolder !is TextAdapterHolder) return null
Expand All @@ -148,8 +148,8 @@ class TextAdapter(private val viewModel: ReadActivityViewModel) :
screenTop: Int,
screenBottom: Int
): ScrollIndex? {
if (scrollVisibility.index < 0 || scrollVisibility.index >= itemCount) return null
val item = getItem(scrollVisibility.index)
if (scrollVisibility.adapterPosition < 0 || scrollVisibility.adapterPosition >= itemCount) return null
val item = getItem(scrollVisibility.adapterPosition)
val viewHolder = scrollVisibility.viewHolder

var firstVisibleChar: Int? = null
Expand Down

0 comments on commit e5ebb95

Please sign in to comment.