-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Expand file tree
/
Copy pathCommentsViewModel.kt
More file actions
92 lines (86 loc) · 3.48 KB
/
CommentsViewModel.kt
File metadata and controls
92 lines (86 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package org.schabi.newpipe.viewmodels
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.cachedIn
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.schabi.newpipe.extractor.NewPipe
import org.schabi.newpipe.extractor.comments.CommentsInfo
import org.schabi.newpipe.extractor.comments.CommentsInfoItem
import org.schabi.newpipe.paging.CommentsSource
import org.schabi.newpipe.ui.components.video.comment.CommentInfo
import org.schabi.newpipe.util.KEY_URL
import org.schabi.newpipe.viewmodels.util.Resource
class CommentsViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
val uiState = savedStateHandle.getStateFlow(KEY_URL, "")
.map {
try {
val info = CommentsInfo.getInfo(it)
Resource.Success(CommentInfo(info))
} catch (e: Exception) {
Resource.Error(e)
}
}
.flowOn(Dispatchers.IO)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), Resource.Loading)
// Separate flow for live chat items (not using Paging 3)
private val _liveChatItems = MutableStateFlow<List<CommentsInfoItem>>(emptyList())
val liveChatItems: StateFlow<List<CommentsInfoItem>> = _liveChatItems
@OptIn(ExperimentalCoroutinesApi::class)
val comments: Flow<PagingData<CommentsInfoItem>> = uiState
.filterIsInstance<Resource.Success<CommentInfo>>()
.flatMapLatest {
val info = it.data
if (info.isLiveChat) {
_liveChatItems.value = info.comments
startLiveChatPolling(info)
// Return empty PagingData for live chat (items come from liveChatItems flow)
kotlinx.coroutines.flow.flowOf(androidx.paging.PagingData.empty())
} else {
Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) {
CommentsSource(info)
}.flow
}
}
.cachedIn(viewModelScope)
private fun startLiveChatPolling(info: CommentInfo) {
var nextPage = info.nextPage
viewModelScope.launch(Dispatchers.IO) {
while (isActive) {
delay(3000)
if (nextPage == null) {
continue
}
try {
val result = CommentsInfo.getMoreItems(
NewPipe.getService(info.serviceId),
info.url,
nextPage
)
if (result.items.isNotEmpty()) {
_liveChatItems.value = result.items + _liveChatItems.value
}
nextPage = result.nextPage
} catch (e: Exception) {
// Silently ignore polling errors
}
}
}
}
}