Skip to content

Commit

Permalink
add search support for vvo
Browse files Browse the repository at this point in the history
  • Loading branch information
Tlaster committed May 26, 2024
1 parent 4504cf2 commit cbd67fa
Show file tree
Hide file tree
Showing 15 changed files with 428 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ internal class DefaultStatusEvent(
scope.launch {
val account =
accountRepository.get(data.accountKey) as? UiAccount.VVo ?: return@launch
// account.dataSource.like(data)
account.dataSource.like(data)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import com.ramcosta.composedestinations.generated.destinations.ProfileRouteDesti
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import dev.dimension.flare.R
import dev.dimension.flare.common.LazyPagingItemsProxy
import dev.dimension.flare.common.isLoading
import dev.dimension.flare.common.isRefreshing
import dev.dimension.flare.common.onLoading
import dev.dimension.flare.common.onNotEmptyOrLoading
import dev.dimension.flare.common.onSuccess
Expand All @@ -55,6 +55,7 @@ import dev.dimension.flare.ui.component.status.LazyStatusVerticalStaggeredGrid
import dev.dimension.flare.ui.component.status.StatusEvent
import dev.dimension.flare.ui.component.status.mastodon.UserPlaceholder
import dev.dimension.flare.ui.component.status.status
import dev.dimension.flare.ui.model.UiHashtag
import dev.dimension.flare.ui.model.UiState
import dev.dimension.flare.ui.model.UiStatus
import dev.dimension.flare.ui.model.UiUser
Expand Down Expand Up @@ -235,7 +236,11 @@ private fun DiscoverScreen(
Modifier
.width(192.dp),
onClick = {
state.commitSearch("#${hashtag?.hashtag}")
hashtag?.searchContent?.let { it1 ->
state.commitSearch(
it1,
)
}
},
) {
Box(
Expand Down Expand Up @@ -305,6 +310,7 @@ private fun discoverPresenter(
accountType: AccountType,
statusEvent: StatusEvent = koinInject(),
) = run {
val scope = rememberCoroutineScope()
val state = remember(accountType) { DiscoverPresenter(accountType = accountType) }.invoke()
val searchBarState = searchBarPresenter(accountType = accountType)
val searchState =
Expand All @@ -318,18 +324,37 @@ private fun discoverPresenter(
val isInSearchMode = query.isNotEmpty()
val refreshing =
if (!isInSearchMode) {
false
state.users is UiState.Loading || state.status is UiState.Loading ||
state.hashtags is UiState.Loading ||
state.users is UiState.Success &&
(state.users as UiState.Success<LazyPagingItemsProxy<UiUser>>).data.isRefreshing ||
state.status is UiState.Success &&
(state.status as UiState.Success<LazyPagingItemsProxy<UiStatus>>).data.isRefreshing ||
state.hashtags is UiState.Success &&
(state.hashtags as UiState.Success<LazyPagingItemsProxy<UiHashtag>>).data.isRefreshing
} else {
searchState.users is UiState.Loading || searchState.status is UiState.Loading ||
searchState.users is UiState.Success &&
(searchState.users as UiState.Success<LazyPagingItemsProxy<UiUser>>).data.isLoading ||
(searchState.users as UiState.Success<LazyPagingItemsProxy<UiUser>>).data.isRefreshing ||
searchState.status is UiState.Success &&
(searchState.status as UiState.Success<LazyPagingItemsProxy<UiStatus>>).data.isLoading
(searchState.status as UiState.Success<LazyPagingItemsProxy<UiStatus>>).data.isRefreshing
}

fun refresh() {
if (isInSearchMode) {
searchState.search(query)
} else {
scope.launch {
state.users.onSuccess {
it.refreshSuspend()
}
state.status.onSuccess {
it.refreshSuspend()
}
state.hashtags.onSuccess {
it.refreshSuspend()
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ inline fun <reified T : Any> LazyPagingItemsProxy<T>.onLoading(block: () -> Unit
val <T : Any> LazyPagingItemsProxy<T>.isLoading: Boolean
get() = loadState.refresh is LoadState.Loading && itemCount == 0

val <T : Any> LazyPagingItemsProxy<T>.isRefreshing: Boolean
get() = loadState.refresh is LoadState.Loading

inline fun <reified T : Any> LazyPagingItemsProxy<T>.onError(block: (Throwable) -> Unit): LazyPagingItemsProxy<T> {
if (loadState.refresh is LoadState.Error && itemCount == 0) {
block((loadState.refresh as LoadState.Error).error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal class TrendHashtagPagingSource(
UiHashtag(
hashtag = it.name ?: "",
description = null,
searchContent = "#${it.name}",
)
}.let {
return LoadResult.Page(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal class TrendHashtagPagingSource(
UiHashtag(
hashtag = it.tag,
description = null,
searchContent = "#${it.tag}",
)
}.let {
return LoadResult.Page(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package dev.dimension.flare.data.datasource.vvo

import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import dev.dimension.flare.data.cache.DbPagingTimelineWithStatusView
import dev.dimension.flare.data.database.cache.CacheDatabase
import dev.dimension.flare.data.database.cache.mapper.VVO
import dev.dimension.flare.data.network.vvo.VVOService
import dev.dimension.flare.model.MicroBlogKey

@OptIn(ExperimentalPagingApi::class)
internal class DiscoverStatusRemoteMediator(
private val service: VVOService,
private val database: CacheDatabase,
private val accountKey: MicroBlogKey,
private val pagingKey: String,
) : RemoteMediator<Int, DbPagingTimelineWithStatusView>() {
private var page = 0
private val containerId = "102803"

override suspend fun load(
loadType: LoadType,
state: PagingState<Int, DbPagingTimelineWithStatusView>,
): MediatorResult {
return try {
val response =
when (loadType) {
LoadType.REFRESH -> {
page = 0
service.getContainerIndex(containerId = containerId).also {
database.transaction {
database.dbPagingTimelineQueries.deletePaging(accountKey, pagingKey)
}
}
}

LoadType.PREPEND -> {
return MediatorResult.Success(
endOfPaginationReached = true,
)
}
LoadType.APPEND -> {
page++
service.getContainerIndex(containerId = containerId, sinceId = page.toString())
}
}

val status = response.data?.cards?.mapNotNull { it.mblog }.orEmpty()

VVO.save(
database = database,
accountKey = accountKey,
pagingKey = pagingKey,
statuses = status,
sortIdProvider = {
val index = status.indexOf(it)
-(index + page * state.config.pageSize).toLong()
},
)

MediatorResult.Success(
endOfPaginationReached = status.isEmpty(),
)
} catch (e: Throwable) {
MediatorResult.Error(e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package dev.dimension.flare.data.datasource.vvo

import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import dev.dimension.flare.data.cache.DbPagingTimelineWithStatusView
import dev.dimension.flare.data.database.cache.CacheDatabase
import dev.dimension.flare.data.database.cache.mapper.VVO
import dev.dimension.flare.data.network.vvo.VVOService
import dev.dimension.flare.model.MicroBlogKey
import kotlinx.serialization.Required
import kotlinx.serialization.Serializable

@OptIn(ExperimentalPagingApi::class)
internal class SearchStatusRemoteMediator(
private val service: VVOService,
private val database: CacheDatabase,
private val accountKey: MicroBlogKey,
private val pagingKey: String,
private val query: String,
) : RemoteMediator<Int, DbPagingTimelineWithStatusView>() {
private var page = 1
private val containerId by lazy {
"100103type=1&q=$query&t="
}

override suspend fun load(
loadType: LoadType,
state: PagingState<Int, DbPagingTimelineWithStatusView>,
): MediatorResult {
return try {
val response =
when (loadType) {
LoadType.REFRESH -> {
page = 1
service.getContainerIndex(
containerId = containerId,
pageType = "searchall",
).also {
database.transaction {
database.dbPagingTimelineQueries.deletePaging(accountKey, pagingKey)
}
}
}
LoadType.PREPEND -> {
return MediatorResult.Success(
endOfPaginationReached = true,
)
}

LoadType.APPEND -> {
page++
service.getContainerIndex(
containerId = containerId,
pageType = "searchall",
page = page,
)
}
}
val status = response.data?.cards?.mapNotNull { it.mblog }.orEmpty()

VVO.save(
accountKey = accountKey,
pagingKey = pagingKey,
database = database,
statuses = status,
sortIdProvider = {
val index = status.indexOf(it)
-(index + page * state.config.pageSize).toLong()
},
)

MediatorResult.Success(
endOfPaginationReached = status.isEmpty(),
)
} catch (e: Throwable) {
e.printStackTrace()
MediatorResult.Error(e)
}
}
}

@Serializable
data class SearchRequest(
val rawQuery: String? = null,
val count: Long? = null,
val cursor: String? = null,
@Required
val querySource: String = "typed_query",
@Required
val product: String = "Top",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dev.dimension.flare.data.datasource.vvo

import androidx.paging.PagingSource
import androidx.paging.PagingState
import dev.dimension.flare.data.network.vvo.VVOService
import dev.dimension.flare.model.MicroBlogKey
import dev.dimension.flare.ui.model.UiUser
import dev.dimension.flare.ui.model.mapper.toUi

internal class SearchUserPagingSource(
private val service: VVOService,
private val accountKey: MicroBlogKey,
private val query: String,
) : PagingSource<Int, UiUser>() {
private val containerId by lazy {
"100103type=3&q=$query&t="
}

override fun getRefreshKey(state: PagingState<Int, UiUser>): Int? {
return null
}

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, UiUser> {
try {
val response =
service.getContainerIndex(
containerId = containerId,
pageType = "searchall",
page = params.key,
)
val users =
response.data?.cards?.flatMap {
it.cardGroup.orEmpty()
}?.mapNotNull {
it.user
}.orEmpty()
return LoadResult.Page(
data = users.map { it.toUi(accountKey = accountKey) },
prevKey = null,
nextKey = if (users.isEmpty()) null else params.key?.plus(1),
)
} catch (e: Throwable) {
return LoadResult.Error(e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package dev.dimension.flare.data.datasource.vvo

import androidx.paging.PagingSource
import androidx.paging.PagingState
import dev.dimension.flare.data.network.vvo.VVOService
import dev.dimension.flare.ui.model.UiHashtag

internal class TrendHashtagPagingSource(
private val service: VVOService,
) : PagingSource<Int, UiHashtag>() {
private val containerId = "106003type=25&filter_type=realtimehot"

override fun getRefreshKey(state: PagingState<Int, UiHashtag>): Int? {
return null
}

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, UiHashtag> {
try {
service.getContainerIndex(containerId = containerId)
.data
?.cards
?.flatMap {
it.cardGroup.orEmpty()
}
?.mapNotNull {
it.desc
}
?.map {
UiHashtag(
hashtag = it,
description = null,
searchContent = "#$it#",
)
}
?.toList()
.orEmpty()
.let {
return LoadResult.Page(
data = it,
prevKey = null,
nextKey = null,
)
}
} catch (e: Throwable) {
e.printStackTrace()
return LoadResult.Error(e)
}
}
}
Loading

0 comments on commit cbd67fa

Please sign in to comment.