Skip to content

Commit

Permalink
Check icon before saving it
Browse files Browse the repository at this point in the history
  • Loading branch information
jocmp committed Nov 14, 2024
1 parent 42934d1 commit 6911b96
Show file tree
Hide file tree
Showing 21 changed files with 123 additions and 53 deletions.
10 changes: 6 additions & 4 deletions app/src/main/java/com/capyreader/app/CommonModule.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.capyreader.app

import com.jocmp.capy.AccountManager
import com.jocmp.capy.DatabaseProvider
import com.jocmp.capy.PreferenceStoreProvider
import com.capyreader.app.common.AndroidDatabaseProvider
import com.capyreader.app.common.AppFaviconFetcher
import com.capyreader.app.common.AppPreferences
import com.capyreader.app.common.SharedPreferenceStoreProvider
import com.jocmp.capy.AccountManager
import com.jocmp.capy.DatabaseProvider
import com.jocmp.capy.PreferenceStoreProvider
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module

Expand All @@ -17,7 +18,8 @@ internal val common = module {
rootFolder = androidContext().filesDir.toURI(),
databaseProvider = get(),
cacheDirectory = androidContext().cacheDir.toURI(),
preferenceStoreProvider = get()
preferenceStoreProvider = get(),
faviconFetcher = AppFaviconFetcher(get())
)
}
single { AppPreferences(get()) }
Expand Down
24 changes: 23 additions & 1 deletion app/src/main/java/com/capyreader/app/MainApplication.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package com.capyreader.app

import android.app.Application
import android.content.Context
import coil3.ImageLoader
import coil3.SingletonImageLoader
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import com.capyreader.app.common.AppPreferences
import com.google.android.material.color.DynamicColors
import com.jocmp.capy.UserAgentInterceptor
import okhttp3.OkHttpClient
import org.koin.android.ext.android.get
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.workmanager.koin.workManagerFactory
import org.koin.core.context.startKoin

class MainApplication : Application() {
class MainApplication : Application(), SingletonImageLoader.Factory {
override fun onCreate() {
super.onCreate()
DynamicColors.applyToActivitiesIfAvailable(this)
Expand All @@ -23,4 +29,20 @@ class MainApplication : Application() {
loadAccountModules()
}
}

override fun newImageLoader(context: Context): ImageLoader {
return ImageLoader.Builder(context)
.components {
add(
OkHttpNetworkFetcherFactory(
callFactory = {
OkHttpClient.Builder()
.addInterceptor(UserAgentInterceptor())
.build()
}
)
)
}
.build()
}
}
21 changes: 21 additions & 0 deletions app/src/main/java/com/capyreader/app/common/AppFaviconFetcher.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.capyreader.app.common

import android.content.Context
import coil3.imageLoader
import coil3.request.ImageRequest
import com.jocmp.capy.accounts.FaviconFetcher

class AppFaviconFetcher(private val context: Context) : FaviconFetcher {
override suspend fun isValid(url: String?): Boolean {
url ?: return false

val result = context.imageLoader
.execute(
ImageRequest.Builder(context)
.data(url)
.build()
)

return result.image != null
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil3.compose.AsyncImage
import com.capyreader.app.R
import com.capyreader.app.common.ImagePreview
import com.capyreader.app.ui.articles.list.ArticleActionMenu
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil3.compose.AsyncImage
import com.capyreader.app.R
import com.capyreader.app.common.ThemeOption
import com.capyreader.app.ui.theme.CapyTheme
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import coil.request.ImageRequest
import com.capyreader.app.common.supportGifs
import coil3.request.ImageRequest
import com.capyreader.app.ui.components.LoadingView
import com.capyreader.app.ui.components.Swiper
import com.capyreader.app.ui.components.rememberSwiperState
Expand Down Expand Up @@ -67,7 +66,6 @@ fun ArticleMediaView(
ZoomableAsyncImage(
model = ImageRequest.Builder(LocalContext.current)
.data(url)
.supportGifs()
.listener(
onError = { _, _ ->
if (url != null) {
Expand Down
15 changes: 10 additions & 5 deletions app/src/main/java/com/capyreader/app/ui/components/WebView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toBitmapOrNull
import androidx.webkit.WebViewAssetLoader
import androidx.webkit.WebViewAssetLoader.AssetsPathHandler
import androidx.webkit.WebViewAssetLoader.DEFAULT_DOMAIN
import androidx.webkit.WebViewAssetLoader.ResourcesPathHandler
import coil.executeBlocking
import coil.imageLoader
import coil.request.ImageRequest
import coil3.asDrawable
import coil3.executeBlocking
import coil3.imageLoader
import coil3.request.ImageRequest
import com.capyreader.app.common.AppPreferences
import com.capyreader.app.common.WebViewInterface
import com.capyreader.app.common.openLink
Expand Down Expand Up @@ -107,7 +108,11 @@ class AccompanistWebViewClient(
.data(request.url)
.build()
val bitmap =
view.context.imageLoader.executeBlocking(imageRequest).drawable?.toBitmap()
view.context.imageLoader
.executeBlocking(imageRequest)
.image
?.asDrawable(view.resources)
?.toBitmapOrNull()

if (bitmap != null) {
return WebResourceResponse(
Expand Down
3 changes: 3 additions & 0 deletions capy/src/main/java/com/jocmp/capy/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.jocmp.capy

import com.jocmp.capy.accounts.AddFeedResult
import com.jocmp.capy.accounts.AutoDelete
import com.jocmp.capy.accounts.FaviconFetcher
import com.jocmp.capy.accounts.LocalAccountDelegate
import com.jocmp.capy.accounts.LocalOkHttpClient
import com.jocmp.capy.accounts.Source
Expand Down Expand Up @@ -33,10 +34,12 @@ data class Account(
val database: Database,
val preferences: AccountPreferences,
val source: Source = Source.LOCAL,
val faviconFetcher: FaviconFetcher,
val delegate: AccountDelegate = when (source) {
Source.LOCAL -> LocalAccountDelegate(
database = database,
httpClient = LocalOkHttpClient.forAccount(path = cacheDirectory),
faviconFetcher = faviconFetcher,
)

Source.FEEDBIN -> FeedbinAccountDelegate(
Expand Down
8 changes: 6 additions & 2 deletions capy/src/main/java/com/jocmp/capy/AccountManager.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jocmp.capy

import com.jocmp.capy.accounts.FaviconFetcher
import com.jocmp.capy.accounts.Source
import com.jocmp.capy.db.Database
import java.io.File
Expand All @@ -12,14 +13,15 @@ class AccountManager(
private val cacheDirectory: URI,
private val databaseProvider: DatabaseProvider,
private val preferenceStoreProvider: PreferenceStoreProvider,
private val faviconFetcher: FaviconFetcher,
) {
fun findByID(
id: String,
database: Database = databaseProvider.build(id)
database: Database = databaseProvider.build(id),
): Account? {
val existingAccount = findAccountFile(id) ?: return null

return buildAccount(existingAccount, database)
return buildAccount(existingAccount, database, faviconFetcher)
}

fun createAccount(
Expand Down Expand Up @@ -72,6 +74,7 @@ class AccountManager(
private fun buildAccount(
path: File,
database: Database,
faviconFetcher: FaviconFetcher,
preferences: AccountPreferences = preferenceStoreProvider.build(path.name)
): Account {
val id = path.name
Expand All @@ -85,6 +88,7 @@ class AccountManager(
database = database,
source = preferences.source.get(),
preferences = preferences,
faviconFetcher = faviconFetcher,
)
}

Expand Down
5 changes: 5 additions & 0 deletions capy/src/main/java/com/jocmp/capy/accounts/FaviconFetcher.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.jocmp.capy.accounts

interface FaviconFetcher {
suspend fun isValid(url: String?): Boolean
}
10 changes: 10 additions & 0 deletions capy/src/main/java/com/jocmp/capy/accounts/LocalAccountDelegate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.jocmp.feedfinder.parser.Feed as ParserFeed
class LocalAccountDelegate(
private val database: Database,
private val httpClient: OkHttpClient,
private val faviconFetcher: FaviconFetcher,
private val feedFinder: FeedFinder = DefaultFeedFinder(httpClient),
) : AccountDelegate {
private val articleContent = ArticleContent(httpClient)
Expand Down Expand Up @@ -59,6 +60,7 @@ class LocalAccountDelegate(
val feed = feedRecords.findBy(id = resultFeed.feedURL.toString())

return if (feed != null) {
verifyFavicon(feed)
upsertFolders(feed, folderTitles)
saveArticles(resultFeed.items, cutoffDate = null, feed = feed)

Expand Down Expand Up @@ -221,6 +223,14 @@ class LocalAccountDelegate(
)
}
}

private suspend fun verifyFavicon(feed: Feed) {
if (faviconFetcher.isValid(feed.faviconURL)) {
return
}

feedRecords.clearFavicon(feed.id)
}
}

internal val RssItem.contentHTML: String?
Expand Down
4 changes: 4 additions & 0 deletions capy/src/main/java/com/jocmp/capy/persistence/FeedRecords.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ internal class FeedRecords(private val database: Database) {
)
}

fun clearFavicon(feedID: String) {
database.feedsQueries.updateFavicon(faviconURL = null, feedID = feedID)
}

fun updateStickyFullContent(feedID: String, enabled: Boolean) {
database.feedsQueries.updateStickyFullContent(
enabled = enabled,
Expand Down
4 changes: 4 additions & 0 deletions capy/src/main/sqldelight/com/jocmp/capy/db/feeds.sq
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ update:
UPDATE feeds SET
title = :title WHERE feeds.id = :feedID;

updateFavicon:
UPDATE feeds SET
favicon_url = :faviconURL WHERE feeds.id = :feedID;

updateStickyFullContent:
UPDATE feeds SET enable_sticky_full_content = :enabled WHERE feeds.id = :feedID;

Expand Down
2 changes: 2 additions & 0 deletions capy/src/test/java/com/jocmp/capy/AccountManagerTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jocmp.capy

import com.jocmp.capy.accounts.FakeFaviconFetcher
import com.jocmp.capy.accounts.Source
import kotlinx.coroutines.runBlocking
import org.junit.Rule
Expand All @@ -20,6 +21,7 @@ class AccountManagerTest {
preferenceStoreProvider = InMemoryPreferencesProvider(),
cacheDirectory = rootFolder.newFolder().toURI(),
databaseProvider = InMemoryDatabaseProvider,
faviconFetcher = FakeFaviconFetcher
)
}

Expand Down
4 changes: 3 additions & 1 deletion capy/src/test/java/com/jocmp/capy/OPMLFileTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jocmp.capy

import com.jocmp.capy.accounts.FakeFaviconFetcher
import com.jocmp.capy.accounts.LocalAccountDelegate
import com.jocmp.capy.db.Database
import com.jocmp.capy.fixtures.AccountFixture
Expand Down Expand Up @@ -35,7 +36,8 @@ class OPMLFileTest {
val delegate = LocalAccountDelegate(
database = database,
httpClient = httpClient,
feedFinder = MockFeedFinder()
feedFinder = MockFeedFinder(),
faviconFetcher = FakeFaviconFetcher
)

account = AccountFixture.create(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.jocmp.capy.accounts

object FakeFaviconFetcher : FaviconFetcher {
override suspend fun isValid(url: String?) = true
}
Loading

0 comments on commit 6911b96

Please sign in to comment.