mirror of https://github.com/readrops/Readrops.git
Add adapter for jsonfeed items
This commit is contained in:
parent
592fa4603a
commit
ca29c4acb0
|
@ -13,7 +13,11 @@
|
|||
"title": "Acorn and 10.13",
|
||||
"content_html": "<p>Happy Mac OS High Sierra release day everyone.</p>\n<p>I'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'm also working on some 10.13 goodies for Acorn 6 folks later this year. I can't wait to share that with you, but you'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",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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'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'm also working on some 10.13 goodies for Acorn 6 folks later this year. I can't wait to share that with you, but you'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'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's going to start getting brighter for you though).</p>\n<p>Today I'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'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'll be a focus- as well as Dark Mode for Acorn and one other major thing I've got planned. Retrobatch will probably also get the Dark Mode treatment, but not until I've done it for Acorn first.</p>\n<p>So it's going to be a busy summer, but I'm looking forward to it.</p>\n",
|
||||
"url": "http://flyingmeat.com/blog/archives/2018/6/a_pair_of_updates.html"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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] }
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue