Add adapter for jsonfeed items

This commit is contained in:
Shinokuni 2020-09-15 23:30:56 +02:00
parent 592fa4603a
commit ca29c4acb0
5 changed files with 248 additions and 1 deletions

View File

@ -13,7 +13,11 @@
"title": "Acorn and 10.13",
"content_html": "<p>Happy Mac OS High Sierra release day everyone.</p>\n<p>I&#39;m happy to say that there are no known issues with <a href=\"https://flyingmeat.com/acorn/\">Acorn</a> 6.0.3 or Acorn 5.6.6 when running on Mac OS 10.13 High Sierra. In fact, you might even notice that some things are actually faster and it can now open HEIF images. How awesome is that?</p>\n<p>I&#39;m also working on some 10.13 goodies for Acorn 6 folks later this year. I can&#39;t wait to share that with you, but you&#39;ll have to wait just a little bit.</p>\n",
"date_published": "2017-09-25T14:27:27-07:00",
"url": "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html"
"url": "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html",
"author": {
"url": "this is an url",
"name": "Author 1"
}
},
{
"id": "http://flyingmeat.com/blog/archives/2018/2/acorn_6.1_is_out.html",

View File

@ -0,0 +1,28 @@
{
"items": [
{
"id": "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html",
"title": "Acorn and 10.13",
"summary": "This is a summary",
"content_html": "content_html",
"content_text": "content_text",
"date_published": "2017-09-25T14:27:27-07:00",
"url": "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html",
"image": "https://image.com",
"authors": [
{
"url": "url 1",
"name": "Author 1"
},
{
"url": "url 2",
"name": "Author 2"
},
{
"url": "url 3",
"name": "Author 3"
}
]
}
]
}

View File

@ -0,0 +1,22 @@
{
"items": [
{
"id": "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html",
"content_html": "<p>Happy Mac OS High Sierra release day everyone.</p>\n<p>I&#39;m happy to say that there are no known issues with <a href=\"https://flyingmeat.com/acorn/\">Acorn</a> 6.0.3 or Acorn 5.6.6 when running on Mac OS 10.13 High Sierra. In fact, you might even notice that some things are actually faster and it can now open HEIF images. How awesome is that?</p>\n<p>I&#39;m also working on some 10.13 goodies for Acorn 6 folks later this year. I can&#39;t wait to share that with you, but you&#39;ll have to wait just a little bit.</p>\n",
"date_published": "2017-09-25T14:27:27-07:00",
"url": "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html"
},
{
"id": "http://flyingmeat.com/blog/archives/2018/2/acorn_6.1_is_out.html",
"title": "Acorn 6.1 Is Out",
"content_html": "<p><a href=\"https://flyingmeat.com/acorn/\">Acorn 6.1 has been released</a>.</p>\n<p>You can <a href=\"http://shapeof.com/archives/2018/2/acorn_6.1_is_out.html\">read a longer post about it</a> over on Gus&#39;s blog, but the short of it is: Better, faster, smoother, stronger. And now with Metal 2 support.</p>\n",
"date_published": "2018-02-16T09:59:11-08:00",
},
{
"id": "http://flyingmeat.com/blog/archives/2018/6/a_pair_of_updates.html",
"title": "A Pair of Updates",
"content_html": "<p>Happy summer solstice everybody! (at least for folks in the northern hemisphere, and for folks in the south… sorry. It&#39;s going to start getting brighter for you though).</p>\n<p>Today I&#39;ve got a pair of minor app updates to annouce for you.</p>\n<p>First up is <a href=\"https://flyingmeat.com/acorn/\">Acorn 6.1.3</a>, which <a href=\"https://flyingmeat.com/acorn/releasenotes.html\">fixes a number of bugs</a> including one that stemmed from trying to use QuickLook on a file that was created with Acorn 1.0. For the one or two of you that this was affecting, hurray!</p>\n<p>Next up is <a href=\"https://flyingmeat.com/retrobatch/\">Retrobatch</a>, which also <a href=\"https://flyingmeat.com/retrobatch/releasenotes.html\">includes some bug fixes</a>, the beginnings of Voice Over support, performance improvements, and more.</p>\n<p>What&#39;s next for these apps? Work on Acorn 6.2 will begin shortly, as will Retrobatch 1.1. WWDC introduced some great new APIs that I want to take advantage of (cool new machine learning things), so that&#39;ll be a focus- as well as Dark Mode for Acorn and one other major thing I&#39;ve got planned. Retrobatch will probably also get the Dark Mode treatment, but not until I&#39;ve done it for Acorn first.</p>\n<p>So it&#39;s going to be a busy summer, but I&#39;m looking forward to it.</p>\n",
"url": "http://flyingmeat.com/blog/archives/2018/6/a_pair_of_updates.html"
}
]
}

View File

@ -0,0 +1,77 @@
package com.readrops.api.localfeed.json
import android.content.Context
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.readrops.api.utils.DateUtils
import com.readrops.api.utils.ParseException
import com.readrops.db.entities.Item
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNotNull
import okio.Buffer
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class JSONItemsAdapterTest {
private val context: Context = InstrumentationRegistry.getInstrumentation().context
private val adapter = Moshi.Builder()
.add(Types.newParameterizedType(List::class.java, Item::class.java), JSONItemsAdapter())
.build()
.adapter<List<Item>>(Types.newParameterizedType(List::class.java, Item::class.java))
@Test
fun normalCasesTest() {
val stream = context.resources.assets.open("localfeed/json/json_feed.json")
val items = adapter.fromJson(Buffer().readFrom(stream))!!
val item = items[0]
assertEquals(items.size, 10)
assertEquals(item.guid, "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html")
assertEquals(item.title, "Acorn and 10.13")
assertEquals(item.link, "http://flyingmeat.com/blog/archives/2017/9/acorn_and_10.13.html")
assertEquals(item.pubDate, DateUtils.stringToLocalDateTime("2017-09-25T14:27:27-07:00"))
assertEquals(item.author, "Author 1")
assertNotNull(item.content)
}
@Test
fun otherCasesTest() {
val stream = context.resources.assets.open("localfeed/json/json_items_other_cases.json")
val item = adapter.fromJson(Buffer().readFrom(stream))!![0]
assertEquals(item.description, "This is a summary")
assertEquals(item.content, "content_html")
assertEquals(item.imageLink, "https://image.com")
assertEquals(item.author, "Author 1")
}
@Test
fun nullTitleTest() {
val stream = context.resources.assets.open("localfeed/json/json_items_required_elements.json")
Assert.assertThrows("Item title is required", ParseException::class.java) { adapter.fromJson(Buffer().readFrom(stream))!![0] }
}
@Test
fun nullLinkTest() {
val stream = context.resources.assets.open("localfeed/json/json_items_required_elements.json")
Assert.assertThrows("Item link is required", ParseException::class.java) { adapter.fromJson(Buffer().readFrom(stream))!![1] }
}
@Test
fun nullDateTest() {
val stream = context.resources.assets.open("localfeed/json/json_items_required_elements.json")
Assert.assertThrows("Item date is required", ParseException::class.java) { adapter.fromJson(Buffer().readFrom(stream))!![2] }
}
}

View File

@ -0,0 +1,116 @@
package com.readrops.api.localfeed.json
import com.readrops.api.utils.DateUtils
import com.readrops.api.utils.ParseException
import com.readrops.api.utils.nextNullableString
import com.readrops.db.entities.Item
import com.squareup.moshi.FromJson
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
class JSONItemsAdapter : JsonAdapter<List<Item>>() {
override fun toJson(writer: JsonWriter, value: List<Item>?) {
// not useful
}
@FromJson
override fun fromJson(reader: JsonReader): List<Item> {
try {
val items = arrayListOf<Item>()
reader.beginObject()
while (reader.hasNext()) {
when (reader.nextName()) {
"items" -> parseItems(reader, items)
else -> reader.skipValue()
}
}
return items
} catch (e: Exception) {
throw ParseException(e.message)
}
}
private fun parseItems(reader: JsonReader, items: MutableList<Item>) {
reader.beginArray()
while (reader.hasNext()) {
reader.beginObject()
val item = Item()
var contentText: String? = null
var contentHtml: String? = null
while (reader.hasNext()) {
with(item) {
when (reader.selectName(names)) {
0 -> guid = reader.nextString()
1 -> link = reader.nextString()
2 -> title = reader.nextString()
3 -> contentHtml = reader.nextNullableString()
4 -> contentText = reader.nextNullableString()
5 -> description = reader.nextNullableString()
6 -> imageLink = reader.nextNullableString()
7 -> pubDate = DateUtils.stringToLocalDateTime(reader.nextString())
8 -> author = parseAuthor(reader) // jsonfeed 1.0
9 -> author = parseAuthors(reader) // jsonfeed 1.1
}
}
}
validateItem(item)
item.content = if (contentHtml != null) contentHtml else contentText
reader.endObject()
items += item
}
reader.endArray()
}
private fun parseAuthor(reader: JsonReader): String? {
var author: String? = null
reader.beginObject()
while (reader.hasNext()) {
when (reader.nextName()) {
"name" -> author = reader.nextNullableString()
else -> reader.skipValue()
}
}
reader.endObject()
return author
}
/**
* Returns the first author of the array
*/
private fun parseAuthors(reader: JsonReader): String? {
val authors = arrayListOf<String?>()
reader.beginArray()
while (reader.hasNext()) {
authors.add(parseAuthor(reader))
}
reader.endArray()
return if (authors.filterNotNull().isNotEmpty()) authors.filterNotNull().first() else null
}
private fun validateItem(item: Item) {
when {
item.title == null -> throw ParseException("Item title is required")
item.link == null -> throw ParseException("Item link is required")
item.pubDate == null -> throw ParseException("Item date id required")
}
}
companion object {
val names: JsonReader.Options = JsonReader.Options.of("id", "url", "title", "content_html", "content_text",
"summary", "image", "date_published", "author", "authors")
}
}