Skip to content

Commit

Permalink
add favourite timeline for misskey
Browse files Browse the repository at this point in the history
  • Loading branch information
Tlaster committed Feb 1, 2025
1 parent 8ea1237 commit a56a6a4
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
22 changes: 22 additions & 0 deletions app/src/main/java/dev/dimension/flare/data/model/TabSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,14 @@ sealed interface TimelineTabItem : TabItem {

private fun defaultMisskeySecondaryItems(accountKey: MicroBlogKey) =
persistentListOf(
Misskey.FavouriteTimelineTabItem(
account = AccountType.Specific(accountKey),
metaData =
TabMetaData(
title = TitleType.Localized(TitleType.Localized.LocalizedKey.Favourite),
icon = IconType.Mixed(IconType.Material.MaterialIcon.Heart, accountKey),
),
),
Misskey.LocalTimelineTabItem(
account = AccountType.Specific(accountKey),
metaData =
Expand Down Expand Up @@ -711,6 +719,20 @@ object Misskey {

override fun update(metaData: TabMetaData): TabItem = copy(metaData = metaData)
}

@Serializable
data class FavouriteTimelineTabItem(
override val account: AccountType,
override val metaData: TabMetaData,
) : TimelineTabItem {
override val key: String = "favourite_$account"

override fun createPresenter(): TimelinePresenter =
dev.dimension.flare.ui.presenter.home.misskey
.MisskeyFavouriteTimelinePresenter(account)

override fun update(metaData: TabMetaData): TabItem = copy(metaData = metaData)
}
}

object XQT {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package dev.dimension.flare.data.datasource.misskey

import androidx.paging.ExperimentalPagingApi
import androidx.paging.LoadType
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import dev.dimension.flare.data.database.cache.CacheDatabase
import dev.dimension.flare.data.database.cache.mapper.Misskey
import dev.dimension.flare.data.database.cache.model.DbPagingTimelineWithStatus
import dev.dimension.flare.data.network.misskey.MisskeyService
import dev.dimension.flare.data.network.misskey.api.model.AdminAdListRequest
import dev.dimension.flare.model.MicroBlogKey
import kotlinx.datetime.Instant

@OptIn(ExperimentalPagingApi::class)
internal class FavouriteTimelineRemoteMediator(
private val accountKey: MicroBlogKey,
private val service: MisskeyService,
private val database: CacheDatabase,
private val pagingKey: String,
) : RemoteMediator<Int, DbPagingTimelineWithStatus>() {
override suspend fun load(
loadType: LoadType,
state: PagingState<Int, DbPagingTimelineWithStatus>,
): MediatorResult {
return try {
val response =
when (loadType) {
LoadType.PREPEND -> return MediatorResult.Success(
endOfPaginationReached = true,
)

LoadType.REFRESH -> {
service.iFavorites(
AdminAdListRequest(
limit = state.config.pageSize,
),
)
}

LoadType.APPEND -> {
val lastItem =
database.pagingTimelineDao().getLastPagingTimeline(pagingKey)
?: return MediatorResult.Success(
endOfPaginationReached = true,
)
service.iFavorites(
AdminAdListRequest(
limit = state.config.pageSize,
untilId = lastItem.timeline.statusKey.id,
),
)
}
}.body() ?: return MediatorResult.Success(
endOfPaginationReached = true,
)
if (loadType == LoadType.REFRESH) {
database.pagingTimelineDao().delete(pagingKey = pagingKey, accountKey = accountKey)
}

Misskey.save(
database = database,
accountKey = accountKey,
pagingKey = pagingKey,
data = response.map { it.note },
sortIdProvider = {
response.find { note -> note.noteId == it.id }?.createdAt?.let {
Instant.parse(it).toEpochMilliseconds()
} ?: 0
},
)

MediatorResult.Success(
endOfPaginationReached = response.isEmpty(),
)
} catch (e: Throwable) {
MediatorResult.Error(e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -946,4 +946,25 @@ internal class MisskeyDataSource(
),
ProfileTab.Media,
).toPersistentList()

fun favouriteTimeline(
pageSize: Int = 20,
pagingKey: String = "favourite_$accountKey",
scope: CoroutineScope,
): Flow<PagingData<UiTimeline>> =
timelinePager(
pageSize = pageSize,
pagingKey = pagingKey,
accountKey = accountKey,
database = database,
filterFlow = localFilterRepository.getFlow(forTimeline = true),
scope = scope,
mediator =
FavouriteTimelineRemoteMediator(
service = service,
database = database,
accountKey = accountKey,
pagingKey = pagingKey,
),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.dimension.flare.ui.presenter.home.misskey

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.paging.compose.collectAsLazyPagingItems
import dev.dimension.flare.common.PagingState
import dev.dimension.flare.common.toPagingState
import dev.dimension.flare.data.datasource.misskey.MisskeyDataSource
import dev.dimension.flare.data.repository.AccountRepository
import dev.dimension.flare.data.repository.accountServiceProvider
import dev.dimension.flare.model.AccountType
import dev.dimension.flare.ui.model.UiTimeline
import dev.dimension.flare.ui.model.map
import dev.dimension.flare.ui.presenter.home.TimelinePresenter
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import kotlin.getValue

public class MisskeyFavouriteTimelinePresenter(
private val accountType: AccountType,
) : TimelinePresenter(),
KoinComponent {
private val accountRepository: AccountRepository by inject()

@Composable
override fun listState(): PagingState<UiTimeline> {
val scope = rememberCoroutineScope()
val serviceState = accountServiceProvider(accountType = accountType, repository = accountRepository)
return serviceState
.map { service ->
remember(service) {
require(service is MisskeyDataSource)
service.favouriteTimeline(scope = scope)
}.collectAsLazyPagingItems()
}.toPagingState()
}
}

0 comments on commit a56a6a4

Please sign in to comment.