Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/FiltersDataExtensions.kt

213 lines
7.9 KiB
Kotlin

package org.mariotaku.twidere.extension.model
import android.content.ContentResolver
import android.net.Uri
import org.mariotaku.ktextension.addAllEnhanced
import org.mariotaku.ktextension.isNullOrEmpty
import org.mariotaku.ktextension.map
import org.mariotaku.library.objectcursor.ObjectCursor
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.model.FiltersData
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
import org.mariotaku.twidere.util.content.ContentResolverUtils
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlSerializer
import java.io.IOException
import java.util.*
/**
* Created by mariotaku on 2016/12/28.
*/
fun FiltersData.read(cr: ContentResolver, loadSubscription: Boolean = false) {
fun readBaseItems(uri: Uri): List<FiltersData.BaseItem>? {
val where = if (loadSubscription) null else Expression.lesserThan(Filters.SOURCE, 0).sql
val c = cr.query(uri, Filters.COLUMNS, where, null, null) ?: return null
@Suppress("ConvertTryFinallyToUseCall")
try {
val indices = ObjectCursor.indicesFrom(c, FiltersData.BaseItem::class.java)
return c.map(indices)
} finally {
c.close()
}
}
this.users = run {
val where = if (loadSubscription) null else Expression.lesserThan(Filters.Users.SOURCE, 0).sql
val c = cr.query(Filters.Users.CONTENT_URI, Filters.Users.COLUMNS, where, null, null) ?: return@run null
@Suppress("ConvertTryFinallyToUseCall")
try {
val indices = ObjectCursor.indicesFrom(c, FiltersData.UserItem::class.java)
return@run c.map(indices)
} finally {
c.close()
}
}
this.keywords = readBaseItems(Filters.Keywords.CONTENT_URI)
this.sources = readBaseItems(Filters.Sources.CONTENT_URI)
this.links = readBaseItems(Filters.Links.CONTENT_URI)
}
fun FiltersData.write(cr: ContentResolver, deleteOld: Boolean = true) {
val baseCreator = ObjectCursor.valuesCreatorFrom(FiltersData.BaseItem::class.java)
val userCreator = ObjectCursor.valuesCreatorFrom(FiltersData.UserItem::class.java)
if (users != null) {
if (deleteOld) {
cr.delete(Filters.Users.CONTENT_URI, null, null)
}
ContentResolverUtils.bulkInsert(cr, Filters.Users.CONTENT_URI, users.map(userCreator::create))
}
if (keywords != null) {
if (deleteOld) {
cr.delete(Filters.Keywords.CONTENT_URI, null, null)
}
ContentResolverUtils.bulkInsert(cr, Filters.Keywords.CONTENT_URI, keywords.map(baseCreator::create))
}
if (sources != null) {
if (deleteOld) {
cr.delete(Filters.Sources.CONTENT_URI, null, null)
}
ContentResolverUtils.bulkInsert(cr, Filters.Sources.CONTENT_URI, sources.map(baseCreator::create))
}
if (links != null) {
if (deleteOld) {
cr.delete(Filters.Links.CONTENT_URI, null, null)
}
ContentResolverUtils.bulkInsert(cr, Filters.Links.CONTENT_URI, links.map(baseCreator::create))
}
}
private const val TAG_FILTERS = "filters"
private const val TAG_KEYWORD = "keyword"
private const val TAG_SOURCE = "source"
private const val TAG_LINK = "link"
private const val TAG_USER = "user"
private const val ATTR_SCREEN_NAME = "screenName"
private const val ATTR_NAME = "name"
private const val ATTR_KEY = "key"
@Throws(IOException::class)
fun FiltersData.serialize(serializer: XmlSerializer) {
@Throws(IOException::class)
fun FiltersData.BaseItem.serialize(name: String, writer: XmlSerializer) {
writer.startTag(null, name)
writer.text(value)
writer.endTag(null, name)
}
serializer.startDocument("utf-8", true)
serializer.startTag(null, TAG_FILTERS)
this.users?.forEach { user ->
serializer.startTag(null, TAG_USER)
serializer.attribute(null, ATTR_KEY, user.userKey.toString())
serializer.attribute(null, ATTR_NAME, user.name)
serializer.attribute(null, ATTR_SCREEN_NAME, user.screenName)
serializer.endTag(null, TAG_USER)
}
this.keywords?.forEach { it.serialize(TAG_KEYWORD, serializer) }
this.sources?.forEach { it.serialize(TAG_SOURCE, serializer) }
this.links?.forEach { it.serialize(TAG_LINK, serializer) }
serializer.endTag(null, TAG_FILTERS)
serializer.endDocument()
}
@Throws(IOException::class)
fun FiltersData.parse(parser: XmlPullParser) {
fun parseUserItem(parser: XmlPullParser): FiltersData.UserItem? {
val item = FiltersData.UserItem()
item.name = parser.getAttributeValue(null, ATTR_NAME) ?: return null
item.screenName = parser.getAttributeValue(null, ATTR_SCREEN_NAME) ?: return null
item.userKey = parser.getAttributeValue(null, ATTR_KEY)?.let(UserKey::valueOf) ?: return null
return item
}
val stack = Stack<Any?>()
var event = parser.eventType
while (event != XmlPullParser.END_DOCUMENT) {
when (event) {
XmlPullParser.START_DOCUMENT -> {
initFields()
}
XmlPullParser.START_TAG -> {
stack.push(when (parser.name) {
TAG_USER -> parseUserItem(parser)
TAG_KEYWORD, TAG_SOURCE, TAG_LINK -> FiltersData.BaseItem()
else -> null
})
}
XmlPullParser.END_TAG -> {
val obj = stack.pop()
when (parser.name) {
TAG_USER -> (obj as? FiltersData.UserItem)?.let { users.add(it) }
TAG_KEYWORD -> (obj as? FiltersData.BaseItem)?.let { keywords.add(it) }
TAG_SOURCE -> (obj as? FiltersData.BaseItem)?.let { sources.add(it) }
TAG_LINK -> (obj as? FiltersData.BaseItem)?.let { links.add(it) }
}
}
XmlPullParser.TEXT -> {
stack.push(run {
val obj = stack.pop()
when (obj) {
is FiltersData.BaseItem -> {
obj.value = parser.text ?: return@run null
}
}
return@run obj
})
}
}
event = parser.next()
}
}
fun FiltersData.addAll(data: FiltersData, ignoreDuplicates: Boolean = false): Boolean {
var changed: Boolean = false
initFields()
if (data.users != null) {
changed = changed or this.users.addAllEnhanced(collection = data.users, ignoreDuplicates = ignoreDuplicates)
}
if (data.keywords != null) {
changed = changed or this.keywords.addAllEnhanced(collection = data.keywords, ignoreDuplicates = ignoreDuplicates)
}
if (data.sources != null) {
changed = changed or this.sources.addAllEnhanced(collection = data.sources, ignoreDuplicates = ignoreDuplicates)
}
if (data.links != null) {
changed = changed or this.links.addAllEnhanced(collection = data.links, ignoreDuplicates = ignoreDuplicates)
}
return changed
}
fun FiltersData.removeAll(data: FiltersData): Boolean {
var changed: Boolean = false
changed = changed or (data.users?.let { this.users?.removeAll(it) } ?: false)
changed = changed or (data.keywords?.let { this.keywords?.removeAll(it) } ?: false)
changed = changed or (data.sources?.let { this.sources?.removeAll(it) } ?: false)
changed = changed or (data.links?.let { this.links?.removeAll(it) } ?: false)
return changed
}
fun FiltersData.isEmpty(): Boolean {
return users.isNullOrEmpty() && keywords.isNullOrEmpty() && sources.isNullOrEmpty()
&& links.isNullOrEmpty()
}
fun FiltersData.initFields() {
if (users == null) {
users = ArrayList()
}
if (keywords == null) {
keywords = ArrayList()
}
if (sources == null) {
sources = ArrayList()
}
if (links == null) {
links = ArrayList()
}
}