Implement fever favicon (#496)

This commit is contained in:
kid1412621 2023-12-23 18:08:27 +08:00 committed by GitHub
parent ed893c3810
commit 4d5d9ef3da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 7 deletions

View File

@ -92,10 +92,9 @@ class FeverRssService @Inject constructor(
* obtained is 0 or their quantity exceeds 250, at which point the pulling process stops. * obtained is 0 or their quantity exceeds 250, at which point the pulling process stops.
* *
* 1. Fetch the Fever groups * 1. Fetch the Fever groups
* 2. Fetch the Fever feeds * 2. Fetch the Fever feeds (including favicons)
* 3. Fetch the Fever articles * 3. Fetch the Fever articles
* 4. Synchronize read/unread and starred/un-starred items * 4. Synchronize read/unread and starred/un-starred items
* 5. TODO: Fetch the Fever favicons
*/ */
override suspend fun sync(coroutineWorker: CoroutineWorker): ListenableWorker.Result = supervisorScope { override suspend fun sync(coroutineWorker: CoroutineWorker): ListenableWorker.Result = supervisorScope {
coroutineWorker.setProgress(SyncWorker.setIsSyncing(true)) coroutineWorker.setProgress(SyncWorker.setIsSyncing(true))
@ -127,6 +126,9 @@ class FeverRssService @Inject constructor(
} }
} }
} }
// Fetch the Fever favicons
val faviconsById = feverAPI.getFavicons().favicons?.associateBy { it.id } ?: emptyMap()
feedDao.insertOrUpdate( feedDao.insertOrUpdate(
feedsBody.feeds?.map { feedsBody.feeds?.map {
Feed( Feed(
@ -135,6 +137,7 @@ class FeverRssService @Inject constructor(
url = it.url!!, url = it.url!!,
groupId = accountId.spacerDollar(feedsGroupsMap[it.id.toString()]!!), groupId = accountId.spacerDollar(feedsGroupsMap[it.id.toString()]!!),
accountId = accountId, accountId = accountId,
icon = faviconsById[it.favicon_id]?.data
) )
} ?: emptyList() } ?: emptyList()
) )
@ -191,7 +194,6 @@ class FeverRssService @Inject constructor(
} }
} }
// TODO: 5. Fetch the Fever favicons
Log.i("RLog", "onCompletion: ${System.currentTimeMillis() - preTime}") Log.i("RLog", "onCompletion: ${System.currentTimeMillis() - preTime}")
accountDao.update(account.apply { accountDao.update(account.apply {

View File

@ -101,12 +101,12 @@ object FeverDTO {
val api_version: Int?, val api_version: Int?,
val auth: Int?, val auth: Int?,
val last_refreshed_on_time: Long?, val last_refreshed_on_time: Long?,
val favicons: Map<String, Favicon>, val favicons: List<Favicon>?,
) )
data class Favicon( data class Favicon(
val mime_type: String, val id: Int,
val data: String, val data: String?,
) )
/** /**

View File

@ -15,6 +15,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import me.ash.reader.ui.component.base.Base64Image
import me.ash.reader.ui.component.base.RYAsyncImage import me.ash.reader.ui.component.base.RYAsyncImage
@Composable @Composable
@ -26,7 +27,7 @@ fun FeedIcon(
if (iconUrl == null) { if (iconUrl == null) {
Box( Box(
modifier = Modifier modifier = Modifier
.size(20.dp) .size(size)
.clip(CircleShape) .clip(CircleShape)
.background(MaterialTheme.colorScheme.primary), .background(MaterialTheme.colorScheme.primary),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
@ -38,6 +39,14 @@ fun FeedIcon(
fontSize = 10.sp, fontSize = 10.sp,
) )
} }
}
// e.g. image/gif;base64,R0lGODlh...
else if ("^image/.*;base64,.*".toRegex().matches(iconUrl)) {
Base64Image(
modifier = Modifier
.size(size)
.clip(CircleShape),
base64Uri = iconUrl)
} else { } else {
RYAsyncImage( RYAsyncImage(
modifier = Modifier modifier = Modifier

View File

@ -0,0 +1,30 @@
package me.ash.reader.ui.component.base
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Base64
import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
@Composable
fun Base64Image(
modifier: Modifier = Modifier,
base64Uri: String
) {
val bitmap = base64ToBitmap(base64Uri)
val imageBitmap = bitmap.asImageBitmap()
Image(
bitmap = imageBitmap,
modifier = modifier,
contentDescription = null
)
}
fun base64ToBitmap(base64String: String): Bitmap {
val base64Data = base64String.substringAfter("base64,")
val imageBytes = Base64.decode(base64Data, Base64.DEFAULT)
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
}