Show loading animation while loading elements
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / core / DefaultElementLoader.kt
diff --git a/src/main/kotlin/net/pterodactylus/sone/core/DefaultElementLoader.kt b/src/main/kotlin/net/pterodactylus/sone/core/DefaultElementLoader.kt
new file mode 100644 (file)
index 0000000..eabfed8
--- /dev/null
@@ -0,0 +1,56 @@
+package net.pterodactylus.sone.core
+
+import com.google.common.cache.CacheBuilder
+import freenet.keys.FreenetURI
+import java.io.ByteArrayInputStream
+import javax.imageio.ImageIO
+import javax.inject.Inject
+
+/**
+ * [ElementLoader] implementation that uses a simple Guava [com.google.common.cache.Cache].
+ */
+class DefaultElementLoader @Inject constructor(private val freenetInterface: FreenetInterface) : ElementLoader {
+
+       private val loadingLinks = CacheBuilder.newBuilder().build<String, Boolean>()
+       private val imageCache = CacheBuilder.newBuilder().build<String, LinkedImage>()
+       private val callback = object : FreenetInterface.BackgroundFetchCallback {
+               override fun loaded(uri: FreenetURI, mimeType: String, data: ByteArray) {
+                       if (!mimeType.startsWith("image/")) {
+                               return
+                       }
+                       ByteArrayInputStream(data).use {
+                               ImageIO.read(it)
+                       }?.let {
+                               imageCache.get(uri.toString()) { LinkedImage(uri.toString()) }
+                       }
+                       removeLoadingLink(uri)
+               }
+
+               override fun failed(uri: FreenetURI) {
+                       removeLoadingLink(uri)
+               }
+
+               private fun removeLoadingLink(uri: FreenetURI) {
+                       synchronized(loadingLinks) {
+                               loadingLinks.invalidate(uri.toString())
+                       }
+               }
+       }
+
+       override fun loadElement(link: String): LinkedElement {
+               synchronized(loadingLinks) {
+                       imageCache.getIfPresent(link)?.run {
+                               return this
+                       }
+                       if (loadingLinks.getIfPresent(link) == null) {
+                               loadingLinks.put(link, true)
+                               freenetInterface.startFetch(FreenetURI(link), callback)
+                       }
+               }
+               return object : LinkedElement {
+                       override val link = link
+                       override val loading = true
+               }
+       }
+
+}