Skip to content

Commit

Permalink
feat: お気に入り一覧処理の取得処理をRepositoryに移動した
Browse files Browse the repository at this point in the history
  • Loading branch information
pantasystem committed May 19, 2024
1 parent 5459cd2 commit 20c0cd2
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import net.pantasystem.milktea.data.infrastructure.note.impl.ThreadContextApiAda
import net.pantasystem.milktea.data.infrastructure.note.impl.sqlite.SQLiteNoteDataSource
import net.pantasystem.milktea.data.infrastructure.note.renote.RenotesPagingServiceImpl
import net.pantasystem.milktea.data.infrastructure.note.timeline.TimelineRepositoryImpl
import net.pantasystem.milktea.data.infrastructure.note.timeline.favorite.FavoriteTimelineRepositoryImpl
import net.pantasystem.milktea.model.note.NoteDataSource
import net.pantasystem.milktea.model.note.NoteRepository
import net.pantasystem.milktea.model.note.NoteStreaming
Expand All @@ -34,6 +35,7 @@ import net.pantasystem.milktea.model.note.draft.DraftNoteRepository
import net.pantasystem.milktea.model.note.draft.DraftNoteService
import net.pantasystem.milktea.model.note.repost.RenotesPagingService
import net.pantasystem.milktea.model.note.timeline.TimelineRepository
import net.pantasystem.milktea.model.note.timeline.favorite.FavoriteTimelineRepository
import javax.inject.Singleton

@Module
Expand Down Expand Up @@ -82,6 +84,10 @@ abstract class NoteBindModule{
@Singleton
internal abstract fun bindTimelineRepository(impl: TimelineRepositoryImpl): TimelineRepository

@Binds
@Singleton
internal abstract fun bindFavoriteTimelineRepository(impl: FavoriteTimelineRepositoryImpl): FavoriteTimelineRepository

}

@Module
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package net.pantasystem.milktea.data.infrastructure.note

import android.util.Log
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.sync.Mutex
import net.pantasystem.milktea.api.mastodon.status.TootStatusDTO
import net.pantasystem.milktea.api.misskey.favorite.Favorite
import net.pantasystem.milktea.api.misskey.notes.NoteRequest
import net.pantasystem.milktea.common.MastodonLinkHeaderDecoder
import net.pantasystem.milktea.common.PageableState
import net.pantasystem.milktea.common.StateContent
import net.pantasystem.milktea.common.paginator.EntityConverter
Expand All @@ -15,28 +14,19 @@ import net.pantasystem.milktea.common.paginator.IdGetter
import net.pantasystem.milktea.common.paginator.PreviousLoader
import net.pantasystem.milktea.common.paginator.StateLocker
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common.throwIfHasError
import net.pantasystem.milktea.data.api.mastodon.MastodonAPIProvider
import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.account.page.Pageable
import net.pantasystem.milktea.model.note.Note

import net.pantasystem.milktea.model.note.timeline.favorite.FavoriteTimelineRepository


internal class FavoriteNoteTimelinePagingStoreImpl(
val pageableTimeline: Pageable.Favorite,
val noteAdder: NoteDataSourceAdder,
val getAccount: suspend () -> Account,
val misskeyAPIProvider: MisskeyAPIProvider,
val mastodonAPIProvider: MastodonAPIProvider,
) : EntityConverter<FavoriteType, Note.Id>, PreviousLoader<FavoriteType>, FutureLoader<FavoriteType>,
private val favoriteTimelineRepository: FavoriteTimelineRepository,
) : EntityConverter<Note.Id, Note.Id>, PreviousLoader<Note.Id>, FutureLoader<Note.Id>,
IdGetter<String>, StateLocker, TimelinePagingBase {

private var favoriteIdAndNoteIdMap = mutableMapOf<Note.Id, String>()

private var mastodonUntilId: String? = null
private var mastodonSinceId: String? = null
private var untilId: String? = null
private var sinceId: String? = null

private val _state =
MutableStateFlow<PageableState<List<Note.Id>>>(PageableState.Loading.Init())
Expand All @@ -45,111 +35,48 @@ internal class FavoriteNoteTimelinePagingStoreImpl(

override val mutex: Mutex = Mutex()

override suspend fun convertAll(list: List<FavoriteType>): List<Note.Id> {
val account = getAccount.invoke()

val fabIdAndNoteId = list.map {
when(it) {
is FavoriteType.Mastodon -> {
noteAdder.addTootStatusDtoIntoDataSource(account, it.status).id to it.status.id
}
is FavoriteType.Misskey -> {
noteAdder.addNoteDtoToDataSource(account, it.favorite.note).id to it.favorite.id
}
}
}
favoriteIdAndNoteIdMap.putAll(fabIdAndNoteId.toMap())
return fabIdAndNoteId.map {
it.first
}
override suspend fun convertAll(list: List<Note.Id>): List<Note.Id> {
return list
}

override suspend fun getSinceId(): String? {
if (mastodonSinceId != null) {
return mastodonSinceId
}

if (getAccount().instanceType == Account.InstanceType.MASTODON) {
return null
}

return (getState().content as? StateContent.Exist)?.rawContent?.firstOrNull()?.let {
favoriteIdAndNoteIdMap[it]
}
return sinceId
}

override suspend fun getUntilId(): String? {
if (mastodonUntilId != null) {
return mastodonUntilId
}
if (getAccount().instanceType == Account.InstanceType.MASTODON) {
return null
}
return (getState().content as? StateContent.Exist)?.rawContent?.lastOrNull()?.let {
favoriteIdAndNoteIdMap[it]
}
return untilId
}

override suspend fun loadFuture(): Result<List<FavoriteType>> {
override suspend fun loadFuture(): Result<List<Note.Id>> {
val ac = getAccount.invoke()
return runCancellableCatching {
when(ac.instanceType) {
Account.InstanceType.MISSKEY, Account.InstanceType.FIREFISH -> {
misskeyAPIProvider.get(getAccount.invoke()).favorites(
NoteRequest.Builder(pageableTimeline, ac.token, limit = LIMIT)
.build(NoteRequest.Conditions(sinceId = getSinceId()))
).throwIfHasError().body()!!.map {
FavoriteType.Misskey(it)
}
}
Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
// NOTE: ページが末端であるかをチェックしている
if (getSinceId() == null && !isEmpty()) {
return@runCancellableCatching emptyList()
}

val res = mastodonAPIProvider.get(getAccount()).getFavouriteStatuses(
minId = getSinceId()
)
val linkHeader = res.headers()["link"]
mastodonSinceId = MastodonLinkHeaderDecoder(linkHeader).getMinId()
res.throwIfHasError().body()!!.map {
FavoriteType.Mastodon(it)
}
}

val res = favoriteTimelineRepository.findLaterTimeline(
ac.accountId,
sinceId = getSinceId(),
limit = LIMIT
).getOrThrow()
if (!isEmpty() && res.timelineItems.isEmpty()) {
return@runCancellableCatching emptyList()
}
sinceId = res.sinceId
res.timelineItems
}
}

override suspend fun loadPrevious(): Result<List<FavoriteType>> {
override suspend fun loadPrevious(): Result<List<Note.Id>> {
return runCancellableCatching {
val ac = getAccount.invoke()
when(ac.instanceType) {
Account.InstanceType.MISSKEY, Account.InstanceType.FIREFISH -> {
misskeyAPIProvider.get(getAccount.invoke()).favorites(
NoteRequest.Builder(pageableTimeline, ac.token, limit = LIMIT)
.build(NoteRequest.Conditions(untilId = getUntilId()))
).throwIfHasError().body()!!.map {
FavoriteType.Misskey(it)
}
}
Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
// NOTE: ページが末端であるかをチェックしている
if (getUntilId() == null && !isEmpty()) {
return@runCancellableCatching emptyList()
}

val res = mastodonAPIProvider.get(getAccount()).getFavouriteStatuses(
maxId = getUntilId()
)
val linkHeader = res.headers()["link"]
mastodonUntilId = MastodonLinkHeaderDecoder(linkHeader).getMaxId()
res.throwIfHasError().body()!!.map {
FavoriteType.Mastodon(it)
}
}
val res = favoriteTimelineRepository.findPreviousTimeline(
ac.accountId,
untilId = getUntilId(),
limit = LIMIT
).getOrThrow()
if (!isEmpty() && res.timelineItems.isEmpty()) {
return@runCancellableCatching emptyList()
}

untilId = res.untilId
res.timelineItems
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import net.pantasystem.milktea.model.nodeinfo.NodeInfoRepository
import net.pantasystem.milktea.model.note.Note
import net.pantasystem.milktea.model.note.timeline.TimelineRepository
import net.pantasystem.milktea.model.note.timeline.TimelineType
import net.pantasystem.milktea.model.note.timeline.favorite.FavoriteTimelineRepository
import javax.inject.Inject


Expand All @@ -44,6 +45,7 @@ class TimelineStoreImpl(
private val nodeInfoRepository: NodeInfoRepository,
private val instanceInfoService: InstanceInfoService,
private val timelineRepository: TimelineRepository,
private val favoriteTimelineRepository: FavoriteTimelineRepository,
) : TimelineStore {

class Factory @Inject constructor(
Expand All @@ -53,6 +55,7 @@ class TimelineStoreImpl(
private val nodeInfoRepository: NodeInfoRepository,
private val instanceInfoService: InstanceInfoService,
private val timelineRepository: TimelineRepository,
private val favoriteTimelineRepository: FavoriteTimelineRepository,
) : TimelineStore.Factory {
override fun create(
pageable: Pageable,
Expand All @@ -70,7 +73,8 @@ class TimelineStoreImpl(
mastodonAPIProvider,
nodeInfoRepository = nodeInfoRepository,
instanceInfoService = instanceInfoService,
timelineRepository = timelineRepository
timelineRepository = timelineRepository,
favoriteTimelineRepository = favoriteTimelineRepository,
)
}
}
Expand All @@ -90,7 +94,8 @@ class TimelineStoreImpl(
when (pageableTimeline) {
is Pageable.Favorite -> {
FavoriteNoteTimelinePagingStoreImpl(
pageableTimeline, noteAdder, getAccount, misskeyAPIProvider, mastodonAPIProvider
getAccount,
favoriteTimelineRepository,
)
}
is Pageable.Mastodon -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package net.pantasystem.milktea.data.infrastructure.note.timeline.favorite

import net.pantasystem.milktea.api.misskey.notes.NoteRequest
import net.pantasystem.milktea.common.MastodonLinkHeaderDecoder
import net.pantasystem.milktea.common.runCancellableCatching
import net.pantasystem.milktea.common.throwIfHasError
import net.pantasystem.milktea.data.api.mastodon.MastodonAPIProvider
import net.pantasystem.milktea.data.api.misskey.MisskeyAPIProvider
import net.pantasystem.milktea.data.infrastructure.note.NoteDataSourceAdder
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.account.AccountRepository
import net.pantasystem.milktea.model.note.timeline.favorite.FavoriteTimelineRepository
import net.pantasystem.milktea.model.note.timeline.favorite.FavoriteTimelineResponse
import javax.inject.Inject

class FavoriteTimelineRepositoryImpl @Inject constructor(
private val accountRepository: AccountRepository,
private val misskeyAPIProvider: MisskeyAPIProvider,
private val mastodonAPIProvider: MastodonAPIProvider,
private val noteDataSourceAdder: NoteDataSourceAdder,
): FavoriteTimelineRepository {
override suspend fun findPreviousTimeline(
accountId: Long,
untilId: String?,
untilDate: Long?,
limit: Int
): Result<FavoriteTimelineResponse> = runCancellableCatching {
val account = accountRepository.get(accountId).getOrThrow()
when(account.instanceType) {
Account.InstanceType.MISSKEY, Account.InstanceType.FIREFISH -> {
val res = misskeyAPIProvider.get(account).favorites(
NoteRequest(
i = account.token,
limit = limit,
untilId = untilId,
untilDate = untilDate
)
).throwIfHasError()
val nextSinceId = res.body()?.firstOrNull()?.id
val nextUntilId = res.body()?.lastOrNull()?.id
val ids = noteDataSourceAdder.addNoteDtoListToDataSource(
account,
requireNotNull(res.body()).map { it.note }
)
FavoriteTimelineResponse(
timelineItems = ids,
sinceId = nextSinceId,
untilId = nextUntilId
)
}
Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val res = mastodonAPIProvider.get(account).getFavouriteStatuses(
maxId = untilId,
).throwIfHasError()
val decoder = MastodonLinkHeaderDecoder(res.headers()["Link"])
val maxId = decoder.getMaxId()
val minId = decoder.getMinId()
val ids = noteDataSourceAdder.addTootStatusDtoListIntoDataSource(
account,
requireNotNull(res.body())
)
FavoriteTimelineResponse(
timelineItems = ids,
sinceId = maxId,
untilId = minId
)
}
}
}

override suspend fun findLaterTimeline(
accountId: Long,
sinceId: String?,
sinceDate: Long?,
limit: Int
): Result<FavoriteTimelineResponse> = runCancellableCatching {
val account = accountRepository.get(accountId).getOrThrow()
when(account.instanceType) {
Account.InstanceType.MISSKEY, Account.InstanceType.FIREFISH -> {
val res = misskeyAPIProvider.get(account).favorites(
NoteRequest(
i = account.token,
limit = limit,
sinceId = sinceId,
sinceDate = sinceDate
)
).throwIfHasError()
val nextSinceId = res.body()?.firstOrNull()?.id
val nextUntilId = res.body()?.lastOrNull()?.id
val ids = noteDataSourceAdder.addNoteDtoListToDataSource(
account,
requireNotNull(res.body()).map { it.note }
)
FavoriteTimelineResponse(
timelineItems = ids,
sinceId = nextSinceId,
untilId = nextUntilId
)
}
Account.InstanceType.MASTODON, Account.InstanceType.PLEROMA -> {
val res = mastodonAPIProvider.get(account).getFavouriteStatuses(
minId = sinceId,
).throwIfHasError()
val decoder = MastodonLinkHeaderDecoder(res.headers()["Link"])
val maxId = decoder.getMaxId()
val minId = decoder.getMinId()
val ids = noteDataSourceAdder.addTootStatusDtoListIntoDataSource(
account,
requireNotNull(res.body())
)
FavoriteTimelineResponse(
timelineItems = ids,
sinceId = maxId,
untilId = minId
)
}
}
}
}
Loading

0 comments on commit 20c0cd2

Please sign in to comment.