Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Imeplementation the search function #40

Merged
merged 11 commits into from
Feb 13, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.github.whitescent.mastify.extensions.buildHtmlText
import com.github.whitescent.mastify.network.model.account.Account
import com.github.whitescent.mastify.network.model.emoji.Emoji
import com.github.whitescent.mastify.network.model.status.Card
import com.github.whitescent.mastify.network.model.status.Hashtag
import com.github.whitescent.mastify.network.model.status.Mention
import com.github.whitescent.mastify.network.model.status.Poll
import com.github.whitescent.mastify.network.model.status.Status
Expand All @@ -45,6 +46,7 @@ data class StatusUiData(
val content: String,
val accountEmojis: ImmutableList<Emoji>,
val emojis: ImmutableList<Emoji>,
val tags: ImmutableList<Hashtag>,
val mentions: ImmutableList<Mention>,
val attachments: ImmutableList<Status.Attachment>,
val actionable: Status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ import com.github.whitescent.mastify.network.MastodonApi
import com.github.whitescent.mastify.network.model.search.SearchResult
import javax.inject.Inject

class ExploreRepository @Inject constructor(
private val api: MastodonApi
) {
suspend fun getPreviewResultsForSearch(keyword: String): NetworkResult<SearchResult?> {
class ExploreRepository @Inject constructor(private val api: MastodonApi) {

suspend fun getPreviewResultsForSearch(
keyword: String,
limit: Int? = null,
offset: Int? = null
): NetworkResult<SearchResult?> {
if (keyword.isBlank()) return NetworkResult.success(null)
return api.searchSync(query = keyword, limit = 10).fold(
return api.searchSync(query = keyword, limit = limit, offset = offset).fold(
{
NetworkResult.success(it)
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2024 WhiteScent
*
* This file is a part of Mastify.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mastify is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mastify; if not,
* see <http://www.gnu.org/licenses>.
*/

package com.github.whitescent.mastify.data.repository

import at.connyduck.calladapter.networkresult.getOrThrow
import com.github.whitescent.mastify.network.MastodonApi
import com.github.whitescent.mastify.network.model.search.SearchResult
import javax.inject.Inject

class SearchRepository @Inject constructor(
private val api: MastodonApi
) {
suspend fun fetchSearchResult(
keyword: String,
type: String,
resolve: Boolean? = false,
limit: Int? = null,
offset: Int? = null
): SearchResult = api.searchSync(
query = keyword,
limit = limit,
offset = offset,
type = type,
resolve = resolve
).getOrThrow()
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.github.whitescent.mastify.network.model.status.NewPoll
import com.github.whitescent.mastify.network.model.status.NewStatus
import com.github.whitescent.mastify.network.model.status.Status
import com.github.whitescent.mastify.network.model.status.StatusContext
import com.github.whitescent.mastify.utils.getOrThrow
import com.github.whitescent.mastify.utils.getServerErrorMessage
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2024 WhiteScent
*
* This file is a part of Mastify.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mastify is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mastify; if not,
* see <http://www.gnu.org/licenses>.
*/

package com.github.whitescent.mastify.data.repository

import at.connyduck.calladapter.networkresult.getOrThrow
import com.github.whitescent.mastify.network.MastodonApi
import kotlinx.coroutines.flow.flow
import javax.inject.Inject

class TagRepository @Inject constructor(
private val api: MastodonApi
) {
suspend fun fetchHashtagTimeline(
hashtag: String,
any: List<String>? = null,
maxId: String? = null,
limit: Int? = null
) = api.hashtagTimeline(
hashtag = hashtag,
any = any,
local = false,
maxId = maxId,
sinceId = null,
limit = limit
)

suspend fun fetchHashtagInfo(name: String) = flow {
emit(api.tag(name).getOrThrow())
}

suspend fun followHashtag(name: String, follow: Boolean) = flow {
emit((if (follow) api.followTag(name) else api.unfollowTag(name)).getOrThrow())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fun Status.toUiData(): StatusUiData = StatusUiData(
accountEmojis = (reblog?.account?.emojis ?: account.emojis).toImmutableList(),
emojis = (reblog?.emojis ?: emojis).toImmutableList(),
mentions = (reblog?.mentions ?: mentions).toImmutableList(),
tags = (reblog?.tags ?: tags).toImmutableList(),
card = (reblog?.card ?: card)?.let {
it.copy(
title = it.title.trim(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.github.whitescent.mastify.network.model.emoji.Emoji
import com.github.whitescent.mastify.network.model.instance.AppCredentials
import com.github.whitescent.mastify.network.model.instance.InstanceInfo
import com.github.whitescent.mastify.network.model.search.SearchResult
import com.github.whitescent.mastify.network.model.status.Hashtag
import com.github.whitescent.mastify.network.model.status.MediaUploadResult
import com.github.whitescent.mastify.network.model.status.NewStatus
import com.github.whitescent.mastify.network.model.status.Poll
Expand Down Expand Up @@ -147,7 +148,7 @@ interface MastodonApi {
@GET("api/v1/statuses/{id}/context")
suspend fun statusContext(
@Path("id") statusId: String
): NetworkResult<StatusContext>
): Response<StatusContext>

@GET("api/v1/accounts/{id}")
suspend fun account(
Expand Down Expand Up @@ -228,4 +229,23 @@ interface MastodonApi {
@Part description: MultipartBody.Part? = null,
@Part focus: MultipartBody.Part? = null
): Response<MediaUploadResult>

@GET("api/v1/tags/{name}")
suspend fun tag(@Path("name") name: String): NetworkResult<Hashtag>

@GET("api/v1/timelines/tag/{hashtag}")
suspend fun hashtagTimeline(
@Path("hashtag") hashtag: String,
@Query("any[]") any: List<String>?,
@Query("local") local: Boolean?,
@Query("max_id") maxId: String?,
@Query("since_id") sinceId: String?,
@Query("limit") limit: Int?
): Response<List<Status>>

@POST("api/v1/tags/{name}/follow")
suspend fun followTag(@Path("name") name: String): NetworkResult<Hashtag>

@POST("api/v1/tags/{name}/unfollow")
suspend fun unfollowTag(@Path("name") name: String): NetworkResult<Hashtag>
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ data class Account(
val emojis: List<Emoji>
) {

val noteWithEmoji = generateHtmlContentWithEmoji(note, emojis)
val noteWithEmoji = generateHtmlContentWithEmoji(note, emojis).trim()
val fieldsWithEmoji = fields.map {
it.copy(
name = generateHtmlContentWithEmoji(it.name, emojis),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ data class Hashtag(
val url: String,
val following: Boolean?,
val history: List<History>?
)
) {
val todayPost get() = history?.firstOrNull()?.uses?.toInt() ?: 0
val posts get() = history?.sumOf { it.uses.toInt() } ?: 0
val participants get() = history?.sumOf { it.accounts.toInt() } ?: 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import com.github.whitescent.mastify.paging.PageLoadState.NotLoading
import com.github.whitescent.mastify.paging.PageLoadState.Refresh
import com.github.whitescent.mastify.ui.component.StatusAppendingIndicator
import com.github.whitescent.mastify.ui.component.StatusEndIndicator
import com.github.whitescent.mastify.ui.component.drawVerticalScrollbar
import com.github.whitescent.mastify.ui.component.status.paging.EmptyStatusListPlaceholder
import com.github.whitescent.mastify.ui.component.status.paging.PagePlaceholderType
import com.github.whitescent.mastify.ui.component.status.paging.StatusListLoadError
Expand All @@ -66,8 +67,9 @@ import kotlinx.coroutines.launch
fun <T : Any> LazyPagingList(
paginator: Paginator,
modifier: Modifier = Modifier,
paginatorUiState: PaginatorUiState,
paginatorUiState: PaginatorUiState = rememberPaginatorUiState(paginator),
list: ImmutableList<T>,
showScrollbar: Boolean = true,
lazyListState: LazyListState = rememberLazyListState(),
contentPadding: PaddingValues = PaddingValues(0.dp),
pagePlaceholderType: PagePlaceholderType,
Expand Down Expand Up @@ -133,7 +135,10 @@ fun <T : Any> LazyPagingList(
}
LazyColumn(
state = lazyListState,
modifier = modifier,
modifier = modifier
.let {
if (showScrollbar) it.drawVerticalScrollbar(lazyListState) else it
},
contentPadding = contentPadding,
reverseLayout = reverseLayout,
verticalArrangement = verticalArrangement,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2024 WhiteScent
*
* This file is a part of Mastify.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mastify is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mastify; if not,
* see <http://www.gnu.org/licenses>.
*/

package com.github.whitescent.mastify.paging.factory

import com.github.whitescent.mastify.data.repository.SearchRepository
import com.github.whitescent.mastify.paging.LoadResult
import com.github.whitescent.mastify.paging.PagingFactory
import com.github.whitescent.mastify.viewModel.SearchType
import kotlinx.coroutines.flow.MutableStateFlow

@Suppress("UNCHECKED_CAST")
class SearchPagingFactory<T> (
private val keyword: String,
private val repository: SearchRepository,
private val type: SearchType,
) : PagingFactory() {

val list = MutableStateFlow(emptyList<T>())

override suspend fun append(pageSize: Int): LoadResult {
val searchResult = repository.fetchSearchResult(
keyword = keyword,
offset = list.value.size,
limit = pageSize,
type = type.toString()
)
val typeList = when (type) {
SearchType.Status -> searchResult.statuses as List<T>
SearchType.Account -> searchResult.accounts as List<T>
SearchType.Hashtag -> searchResult.hashtags as List<T>
}
list.emit(list.value + typeList)
return LoadResult.Page(typeList.isEmpty())
}

override suspend fun refresh(pageSize: Int): LoadResult {
val searchResult = repository.fetchSearchResult(
keyword = keyword,
limit = pageSize,
type = type.toString(),
resolve = true
)
val typeList = when (type) {
SearchType.Status -> searchResult.statuses as List<T>
SearchType.Account -> searchResult.accounts as List<T>
SearchType.Hashtag -> searchResult.hashtags as List<T>
}
list.emit(typeList)
return LoadResult.Page(typeList.isEmpty() || typeList.size < pageSize)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2024 WhiteScent
*
* This file is a part of Mastify.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mastify is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mastify; if not,
* see <http://www.gnu.org/licenses>.
*/

package com.github.whitescent.mastify.paging.factory

import com.github.whitescent.mastify.data.repository.TagRepository
import com.github.whitescent.mastify.network.model.status.Status
import com.github.whitescent.mastify.paging.LoadResult
import com.github.whitescent.mastify.paging.PagingFactory
import com.github.whitescent.mastify.utils.getOrThrow
import kotlinx.coroutines.flow.MutableStateFlow

class TagPagingFactory(
private val hashtag: String,
private val repository: TagRepository
) : PagingFactory() {

val list = MutableStateFlow(emptyList<Status>())

override suspend fun append(pageSize: Int): LoadResult {
val response = repository.fetchHashtagTimeline(
hashtag = hashtag,
limit = pageSize,
maxId = list.value.lastOrNull()?.id
).getOrThrow()
list.emit(list.value + response)
return LoadResult.Page(endReached = response.isEmpty())
}

override suspend fun refresh(pageSize: Int): LoadResult {
val response = repository.fetchHashtagTimeline(hashtag, limit = pageSize).getOrThrow()
list.emit(response)
return LoadResult.Page(endReached = response.isEmpty() || response.size < pageSize)
}
}
Loading