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: Add Explore Page #8

Merged
merged 5 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ android {
applicationId = "com.github.whitescent.mastify"
minSdk = 21
targetSdk = 34
versionCode = 8
versionName = "1.1.4-pre-alpha"
versionCode = 9
versionName = "1.2.0-pre-alpha"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class MastifyApp : Application(), ImageLoaderFactory {
add(VideoFrameDecoder.Factory())
}
.placeholder(R.drawable.image_placeholder)
.crossfade(true)
.build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ data class StatusUiData(
val emojis: ImmutableList<Emoji>,
val attachments: ImmutableList<Status.Attachment>,
val actionable: Status,
val actionableId: String,
val reblogDisplayName: String,
val fullname: String,
val createdAt: String,
Expand All @@ -57,6 +56,8 @@ data class StatusUiData(
val hasUnloadedStatus: Boolean,
) {

val actionableId inline get() = reblog?.id ?: id

val parsedContent: String = Jsoup.parse(content).body().text()
val isInReplyTo inline get() = inReplyToId != null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,61 +17,28 @@

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

import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import at.connyduck.calladapter.networkresult.NetworkResult
import at.connyduck.calladapter.networkresult.fold
import com.github.whitescent.mastify.data.model.ui.StatusUiData
import com.github.whitescent.mastify.network.MastodonApi
import com.github.whitescent.mastify.network.model.search.SearchResult
import com.github.whitescent.mastify.paging.PublicTimelinePagingSource
import com.github.whitescent.mastify.paging.TrendingPagingSource
import kotlinx.coroutines.flow.Flow
import com.github.whitescent.mastify.network.model.trends.News
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ExploreRepository @Inject constructor(
private val api: MastodonApi
) {

suspend fun getPreviewResultsForSearch(keyword: String): SearchPreviewResult {
if (keyword.isBlank()) return SearchPreviewResult.Success(null)
suspend fun getPreviewResultsForSearch(keyword: String): NetworkResult<SearchResult?> {
if (keyword.isBlank()) return NetworkResult.success(null)
return api.searchSync(query = keyword, limit = 10).fold(
{
SearchPreviewResult.Success(it)
NetworkResult.success(it)
},
{
it.printStackTrace()
SearchPreviewResult.Failure(it)
NetworkResult.failure(it)
}
)
}

fun getTrendingStatusPager(): Flow<PagingData<StatusUiData>> =
Pager(
config = PagingConfig(
pageSize = 20,
enablePlaceholders = false,
),
pagingSourceFactory = {
TrendingPagingSource(api = api)
},
).flow

fun getPublicTimelinePager(): Flow<PagingData<StatusUiData>> =
Pager(
config = PagingConfig(
pageSize = 20,
enablePlaceholders = false,
),
pagingSourceFactory = {
PublicTimelinePagingSource(api = api)
},
).flow
}

sealed interface SearchPreviewResult {
data class Success(val response: SearchResult?) : SearchPreviewResult
data class Failure(val exception: Throwable) : SearchPreviewResult
suspend fun getNews(): NetworkResult<List<News>> = api.trendingNews(10)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.github.whitescent.mastify.domain

import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import com.github.whitescent.mastify.network.MastodonApi
import com.github.whitescent.mastify.ui.component.status.StatusSnackbarType
Expand All @@ -33,8 +34,7 @@ class StatusActionHandler(private val api: MastodonApi) {
val snackBarFlow = snackBarChanel.receiveAsFlow()

suspend fun onStatusAction(action: StatusAction, context: Context) {
val clipManager =
context.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
val clipManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
when (action) {
is StatusAction.Favorite -> {
if (action.favorite) api.favouriteStatus(action.id) else api.unfavouriteStatus(action.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ fun Status.toUiData(): StatusUiData = StatusUiData(
favouritesCount = reblog?.favouritesCount ?: favouritesCount,
favorited = reblog?.favorited ?: favorited,
inReplyToId = reblog?.inReplyToId ?: inReplyToId,
// NOTE: make sure that you need to do a conversion whenever you use this property,
// otherwise it may cause inconsistencies between StatusUiData and StatusUiData.actionable
actionable = actionableStatus,
actionableId = actionableStatus.id,
hasUnloadedStatus = hasUnloadedStatus
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class InstanceSwitchAuthInterceptor(private val db: AppDatabase) : Interceptor {
} else {
runBlocking {
val currentAccount = db.accountDao().getActiveAccount()
logcat { "currentAccount $currentAccount" }
if (currentAccount != null) {
val accessToken = currentAccount.accessToken
if (accessToken.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.github.whitescent.mastify.network.model.search.SearchResult
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.network.model.trends.News
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Field
Expand Down Expand Up @@ -96,6 +97,12 @@ interface MastodonApi {
@Query("offset") offset: Int = 0
): Response<List<Status>>

@GET("api/v1/trends/links")
suspend fun trendingNews(
@Query("limit") limit: Int? = null,
@Query("offset") offset: Int = 0
): NetworkResult<List<News>>

@POST("api/v1/statuses/{id}/bookmark")
suspend fun bookmarkStatus(
@Path("id") statusId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ package com.github.whitescent.mastify.network.model.status
import kotlinx.serialization.Serializable

@Serializable
data class Hashtag(val name: String, val url: String, val following: Boolean? = null)
data class Hashtag(
val name: String,
val url: String,
val following: Boolean?,
val history: List<History>?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2023 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.network.model.status

import kotlinx.serialization.Serializable

@Serializable
data class History(
val day: String,
val uses: String,
val accounts: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2023 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.network.model.trends

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class News(
val url: String,
val title: String,
val description: String,
@SerialName("author_name") val authorname: String,
@SerialName("provider_name") val providername: String,
@SerialName("published_at") val publishedAt: String?,
val image: String,
val blurhash: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

package com.github.whitescent.mastify.paging

import com.github.whitescent.mastify.paging.LoadState.Error
import com.github.whitescent.mastify.paging.LoadState.NotLoading

class Paginator<Key, Item>(
private val refreshKey: Key,
private inline val getAppendKey: suspend () -> Key,
Expand All @@ -25,7 +28,12 @@ class Paginator<Key, Item>(
private inline val onRequest: suspend (Key) -> Result<List<Item>>,
private inline val onSuccess: suspend (loadState: LoadState, items: List<Item>) -> Unit,
) : PaginatorInterface<Key, Item> {
private var loadState = LoadState.NotLoading

var loadState = NotLoading
private set

var endReached: Boolean = false
private set

override suspend fun append() {
if (loadState == LoadState.Append) return
Expand All @@ -35,16 +43,17 @@ class Paginator<Key, Item>(
val appendKey = getAppendKey()
val result = onRequest(appendKey).getOrElse {
onError(it)
loadState = LoadState.Error
loadState = Error
onLoadUpdated(loadState)
return
}
if (result.isEmpty()) endReached = true
onSuccess(loadState, result)
loadState = LoadState.NotLoading
loadState = NotLoading
onLoadUpdated(loadState)
} catch (e: Exception) {
onError(e)
loadState = LoadState.Error
loadState = Error
onLoadUpdated(loadState)
return
}
Expand All @@ -57,16 +66,17 @@ class Paginator<Key, Item>(
try {
val result = onRequest(refreshKey).getOrElse {
onError(it)
loadState = LoadState.Error
loadState = Error
onLoadUpdated(loadState)
return
}
if (result.isEmpty()) endReached = true
onSuccess(loadState, result)
loadState = LoadState.NotLoading
loadState = NotLoading
onLoadUpdated(loadState)
} catch (e: Exception) {
onError(e)
loadState = LoadState.Error
loadState = Error
onLoadUpdated(loadState)
return
}
Expand Down
Loading