Skip to content

Commit 66201db

Browse files
authored
Fix spotlight image cache (#2031)
* Update changelog * Fix image caching bug
1 parent 004d817 commit 66201db

2 files changed

Lines changed: 27 additions & 28 deletions

File tree

app/src/main/java/com/capyreader/app/ui/widget/SpotlightWidget.kt

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import android.content.Context
44
import android.graphics.Bitmap
55
import android.graphics.BitmapFactory
66
import androidx.compose.runtime.Composable
7-
import androidx.compose.runtime.collectAsState
8-
import androidx.compose.runtime.getValue
97
import androidx.compose.ui.unit.DpSize
108
import androidx.compose.ui.unit.dp
119
import androidx.datastore.preferences.core.Preferences
@@ -47,16 +45,20 @@ class SpotlightWidget : GlanceAppWidget() {
4745
private val viewModel by lazy { SpotlightViewModel() }
4846

4947
override suspend fun provideGlance(context: Context, id: GlanceId) {
50-
if (viewModel.isLoggedIn) {
51-
cacheImages(context)
48+
val entries = if (viewModel.isLoggedIn) {
49+
val articles = viewModel.fetchArticles()
50+
cacheImages(context, articles)
51+
articles.map { it.toSpotlightEntry() }
52+
} else {
53+
emptyList()
5254
}
5355

5456
provideContent {
5557
GlanceTheme {
5658
if (!viewModel.isLoggedIn) {
5759
LoggedOutContent()
5860
} else {
59-
Content()
61+
Content(entries)
6062
}
6163
}
6264
}
@@ -84,16 +86,14 @@ class SpotlightWidget : GlanceAppWidget() {
8486
}
8587

8688
@Composable
87-
private fun Content() {
89+
private fun Content(entries: List<SpotlightEntry>) {
8890
val context = LocalContext.current
8991
val prefs = currentState<Preferences>()
90-
val articles by viewModel.articles.collectAsState(emptyList())
91-
val entries = articles.map { it.toSpotlightEntry() }
9292
val manualOffset = prefs[CURRENT_INDEX_KEY] ?: 0
9393
val currentIndex =
9494
if (entries.isEmpty()) 0 else (lcgIndex(entries.size) + manualOffset).mod(entries.size)
9595
val entry = entries.getOrNull(currentIndex)
96-
val imageBitmap = entry?.let { readCachedImage(context, currentIndex) }
96+
val imageBitmap = entry?.let { readCachedImage(context, it.id) }
9797

9898
SpotlightLayout(
9999
entry = entry,
@@ -122,10 +122,6 @@ class SpotlightWidget : GlanceAppWidget() {
122122
val CURRENT_INDEX_KEY = intPreferencesKey("spotlight_current_index")
123123

124124
suspend fun refresh(context: Context, glanceId: GlanceId) {
125-
try {
126-
cacheImages(context)
127-
} catch (_: Exception) {
128-
}
129125
SpotlightWidget().update(context, glanceId)
130126
}
131127

@@ -137,26 +133,26 @@ class SpotlightWidget : GlanceAppWidget() {
137133
SpotlightWidget().update(context, glanceId)
138134
}
139135

140-
private suspend fun cacheImages(context: Context) {
141-
val viewModel = SpotlightViewModel()
142-
val articles = viewModel.fetchArticles()
143-
136+
private suspend fun cacheImages(context: Context, articles: List<Article>) {
144137
clearImageCache(context)
145138

146-
articles.forEachIndexed { index, article ->
139+
articles.forEach { article ->
147140
article.imageURL?.let { url ->
148-
cacheImage(context, url, index)
141+
cacheImage(context, url, article.id)
149142
}
150143
}
151144
}
152145

153146
private fun imageDir(context: Context): File =
154147
File(context.cacheDir, "spotlight_images").apply { mkdirs() }
155148

156-
private fun imageFile(context: Context, index: Int): File =
157-
File(imageDir(context), "spotlight_$index.jpg")
149+
private fun imageFile(context: Context, id: String): File =
150+
File(imageDir(context), "spotlight_${safeFileName(id)}.jpg")
158151

159-
private suspend fun cacheImage(context: Context, url: String, index: Int) {
152+
private fun safeFileName(id: String): String =
153+
id.hashCode().toUInt().toString(16)
154+
155+
private suspend fun cacheImage(context: Context, url: String, id: String) {
160156
try {
161157
val request = ImageRequest.Builder(context)
162158
.data(url)
@@ -166,15 +162,15 @@ class SpotlightWidget : GlanceAppWidget() {
166162
val result = context.imageLoader.execute(request)
167163
val image = result.image ?: return
168164
val bitmap = image.toBitmap()
169-
imageFile(context, index).outputStream().use { out ->
165+
imageFile(context, id).outputStream().use { out ->
170166
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out)
171167
}
172168
} catch (_: Exception) {
173169
}
174170
}
175171

176-
fun readCachedImage(context: Context, index: Int): Bitmap? {
177-
val file = imageFile(context, index)
172+
fun readCachedImage(context: Context, id: String): Bitmap? {
173+
val file = imageFile(context, id)
178174
if (!file.exists()) return null
179175
return BitmapFactory.decodeFile(file.absolutePath)
180176
}
@@ -192,9 +188,6 @@ private class SpotlightViewModel : KoinComponent {
192188
val isLoggedIn
193189
get() = appPreferences.isLoggedIn
194190

195-
val articles
196-
get() = account.latestArticles(limit = 10)
197-
198191
suspend fun fetchArticles() =
199192
account.latestArticles(limit = 10).first()
200193
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
• Add Spotlight widget for quick access to latest unread articles
2+
• Add "Read Later" feature for local feed
3+
- You can access this via the "Add Link" share sheet action in other apps
4+
• Rework "mark read on scroll" to address some long standing bugs
5+
• Improve folder picker for Google Reader accounts
6+
• Update translations thanks to volunteers!

0 commit comments

Comments
 (0)