Implement the different Source types through an interface
This commit is contained in:
parent
6ace50c306
commit
c127271ede
@ -49,7 +49,7 @@ class SourcesActivity : AppCompatActivity(), DIAware {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
|
||||||
var items: ArrayList<SelfossModel.Source>
|
var items: ArrayList<SelfossModel.SourceDetail>
|
||||||
|
|
||||||
binding.recyclerView.setHasFixedSize(true)
|
binding.recyclerView.setHasFixedSize(true)
|
||||||
binding.recyclerView.layoutManager = mLayoutManager
|
binding.recyclerView.layoutManager = mLayoutManager
|
||||||
|
@ -24,7 +24,7 @@ import org.kodein.di.instance
|
|||||||
|
|
||||||
class UpsertSourceActivity : AppCompatActivity(), DIAware {
|
class UpsertSourceActivity : AppCompatActivity(), DIAware {
|
||||||
|
|
||||||
private var existingSource: SelfossModel.Source? = null
|
private var existingSource: SelfossModel.SourceDetail? = null
|
||||||
private var mSpoutsValue: String? = null
|
private var mSpoutsValue: String? = null
|
||||||
|
|
||||||
private lateinit var binding: ActivityUpsertSourceBinding
|
private lateinit var binding: ActivityUpsertSourceBinding
|
||||||
|
@ -31,7 +31,7 @@ import org.kodein.di.instance
|
|||||||
|
|
||||||
class SourcesListAdapter(
|
class SourcesListAdapter(
|
||||||
private val app: Activity,
|
private val app: Activity,
|
||||||
private val items: ArrayList<SelfossModel.Source>
|
private val items: ArrayList<SelfossModel.SourceDetail>
|
||||||
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), DIAware {
|
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), DIAware {
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
|
@ -84,7 +84,7 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
|
|||||||
) {
|
) {
|
||||||
val sourceGroup = binding.sourcesGroup
|
val sourceGroup = binding.sourcesGroup
|
||||||
|
|
||||||
repository.getSourcesStats().forEach { source ->
|
repository.getSourcesDetailsOrStats().forEach { source ->
|
||||||
val c = Chip(context)
|
val c = Chip(context)
|
||||||
c.ellipsize = TextUtils.TruncateAt.END
|
c.ellipsize = TextUtils.TruncateAt.END
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package bou.amine.apps.readerforselfossv2.model
|
package bou.amine.apps.readerforselfossv2.model
|
||||||
|
|
||||||
|
import bou.amine.apps.readerforselfossv2.dao.SOURCE
|
||||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
|
import bou.amine.apps.readerforselfossv2.utils.DateUtils
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
@ -63,70 +64,113 @@ class SelfossModel {
|
|||||||
fun isPublicModeEnabled() = publicMode ?: false
|
fun isPublicModeEnabled() = publicMode ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Source(
|
interface Source {
|
||||||
val id: Int,
|
val id: Int
|
||||||
val title: String,
|
var title: String
|
||||||
var unread: Int?,
|
var unread: Int?
|
||||||
var tags: List<String>?,
|
var error: String?
|
||||||
var spout: String?,
|
var icon: String?
|
||||||
var error: String?,
|
|
||||||
var icon: String?,
|
|
||||||
var params: SourceParams?
|
|
||||||
) {
|
|
||||||
|
|
||||||
constructor(sourceDetail: SourceDetail) : this(
|
fun checkSameSource(source: Source): Boolean {
|
||||||
id = sourceDetail.id,
|
return this.id != source.id || this.title != source.title
|
||||||
title = sourceDetail.title,
|
}
|
||||||
unread = null,
|
|
||||||
tags = sourceDetail.tags,
|
|
||||||
spout = sourceDetail.spout,
|
|
||||||
error = sourceDetail.error,
|
|
||||||
icon = sourceDetail.icon,
|
|
||||||
params = sourceDetail.params
|
|
||||||
)
|
|
||||||
|
|
||||||
constructor(sourceStat: SourceStats) : this(
|
|
||||||
id = sourceStat.id,
|
|
||||||
title = sourceStat.title,
|
|
||||||
unread = sourceStat.unread,
|
|
||||||
tags = null,
|
|
||||||
spout = null,
|
|
||||||
error = null,
|
|
||||||
icon = null,
|
|
||||||
params = null
|
|
||||||
)
|
|
||||||
|
|
||||||
fun update(source: Source) {
|
fun update(source: Source) {
|
||||||
if (this.id != source.id || this.title != source.title) {
|
if (source is SourceDetail) {
|
||||||
|
source.update(source)
|
||||||
|
} else if (source is SourceStats) {
|
||||||
|
source.update(source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun update(source: SourceStats)
|
||||||
|
|
||||||
|
fun update(source: SourceDetail)
|
||||||
|
|
||||||
|
fun toEntity(): SOURCE
|
||||||
|
|
||||||
|
operator fun component1(): Int { return id }
|
||||||
|
operator fun component2(): String { return title }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SourceStats(
|
||||||
|
override val id: Int,
|
||||||
|
override var title: String,
|
||||||
|
override var unread: Int?,
|
||||||
|
override var error: String? = null,
|
||||||
|
override var icon: String? = null
|
||||||
|
) : Source {
|
||||||
|
override fun update(source: SourceStats) {
|
||||||
|
if (checkSameSource(source)) {
|
||||||
throw Exception()
|
throw Exception()
|
||||||
}
|
}
|
||||||
this.unread = source.unread
|
this.unread = source.unread
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(source: SourceDetail) {
|
||||||
|
if (checkSameSource(source)) {
|
||||||
|
throw Exception()
|
||||||
|
}
|
||||||
|
this.error = source.error
|
||||||
|
this.icon = source.icon
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toEntity(): SOURCE {
|
||||||
|
return SOURCE(
|
||||||
|
this.id.toString(),
|
||||||
|
this.title.getHtmlDecoded(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
this.error,
|
||||||
|
this.icon,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SourceDetail(
|
||||||
|
override val id: Int,
|
||||||
|
override var title: String,
|
||||||
|
override var unread: Int? = null,
|
||||||
|
@Serializable(with = TagsListSerializer::class)
|
||||||
|
var tags: List<String>?,
|
||||||
|
var spout: String?,
|
||||||
|
override var error: String?,
|
||||||
|
override var icon: String?,
|
||||||
|
var params: SourceParams?
|
||||||
|
) : Source {
|
||||||
|
override fun update(source: SourceStats) {
|
||||||
|
if (checkSameSource(source)) {
|
||||||
|
throw Exception()
|
||||||
|
}
|
||||||
|
this.unread = source.unread
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(source: SourceDetail) {
|
||||||
|
if (checkSameSource(source)) {
|
||||||
|
throw Exception()
|
||||||
|
}
|
||||||
this.tags = source.tags
|
this.tags = source.tags
|
||||||
this.spout = source.spout
|
this.spout = source.spout
|
||||||
this.error = source.error
|
this.error = source.error
|
||||||
this.icon = source.icon
|
this.icon = source.icon
|
||||||
this.params = source.params
|
this.params = source.params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toEntity(): SOURCE {
|
||||||
|
return SOURCE(
|
||||||
|
this.id.toString(),
|
||||||
|
this.title.getHtmlDecoded(),
|
||||||
|
this.tags?.joinToString(","),
|
||||||
|
this.spout,
|
||||||
|
this.error,
|
||||||
|
this.icon.orEmpty(),
|
||||||
|
this.params?.url
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class SourceStats(
|
|
||||||
val id: Int,
|
|
||||||
val title: String,
|
|
||||||
val unread: Int
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class SourceDetail(
|
|
||||||
val id: Int,
|
|
||||||
val title: String,
|
|
||||||
@Serializable(with = TagsListSerializer::class)
|
|
||||||
val tags: List<String>,
|
|
||||||
val spout: String,
|
|
||||||
val error: String,
|
|
||||||
val icon: String?,
|
|
||||||
val params: SourceParams?
|
|
||||||
)
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SourceParams(
|
data class SourceParams(
|
||||||
val url: String
|
val url: String
|
||||||
|
@ -44,12 +44,11 @@ class Repository(
|
|||||||
private val _badgeStarred = MutableStateFlow(0)
|
private val _badgeStarred = MutableStateFlow(0)
|
||||||
val badgeStarred = _badgeStarred.asStateFlow()
|
val badgeStarred = _badgeStarred.asStateFlow()
|
||||||
|
|
||||||
private var sources = ArrayList<SelfossModel.Source>()
|
|
||||||
|
|
||||||
private var fetchedTags = false
|
private var fetchedTags = false
|
||||||
|
private var fetchedSources = false
|
||||||
|
|
||||||
private var _readerItems = ArrayList<SelfossModel.Item>()
|
private var _readerItems = ArrayList<SelfossModel.Item>()
|
||||||
private var _selectedSource: SelfossModel.Source? = null
|
private var _selectedSource: SelfossModel.SourceDetail? = null
|
||||||
|
|
||||||
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
||||||
var fetchedItems: StatusAndData<List<SelfossModel.Item>> = StatusAndData.error()
|
var fetchedItems: StatusAndData<List<SelfossModel.Item>> = StatusAndData.error()
|
||||||
@ -181,47 +180,60 @@ class Repository(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSources(newSources: ArrayList<SelfossModel.Source>) {
|
private fun updateSources(newSources: List<SelfossModel.Source>): List<SelfossModel.Source> {
|
||||||
val isDatabaseEnabled =
|
val isDatabaseEnabled =
|
||||||
appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
||||||
val newIds = newSources.map {it.id}
|
return if (isDatabaseEnabled) {
|
||||||
val filteredSources = sources.filterNot { it.id in newIds }
|
var sources = getDBSources().map { it.toView() }
|
||||||
for (source in filteredSources) {
|
for (source in sources) {
|
||||||
val newSource = newSources.find { it.id == source.id }
|
val newSource = newSources.find { it.id == source.id }
|
||||||
source.update(newSource!!)
|
if (newSource != null) {
|
||||||
|
source.update(newSource)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sources = (filteredSources + newSources).distinctBy { it.id } as ArrayList<SelfossModel.Source>
|
|
||||||
|
|
||||||
if (isDatabaseEnabled) {
|
sources = (sources + newSources).distinctBy { it.id }
|
||||||
|
|
||||||
resetDBSourcesWithData(sources)
|
resetDBSourcesWithData(sources)
|
||||||
|
sources
|
||||||
|
} else {
|
||||||
|
newSources
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getSourcesStats(): ArrayList<SelfossModel.Source> {
|
suspend fun getSourcesDetailsOrStats(): ArrayList<SelfossModel.Source> {
|
||||||
|
var sources = ArrayList<SelfossModel.Source>()
|
||||||
val isDatabaseEnabled =
|
val isDatabaseEnabled =
|
||||||
appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
||||||
if (isNetworkAvailable() && sources.none { it.unread != null }) {
|
val shouldFetch = if (appSettingsService.isUpdateSourcesEnabled()) !fetchedSources else true
|
||||||
|
if (shouldFetch && isNetworkAvailable()) {
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
val apiSources = api.sourcesStats()
|
val apiSources = api.sourcesStats()
|
||||||
if (apiSources.success && apiSources.data != null) {
|
if (apiSources.success && apiSources.data != null) {
|
||||||
updateSources(apiSources.data.map { SelfossModel.Source(it) } as ArrayList)
|
sources = updateSources(apiSources.data) as ArrayList<SelfossModel.Source>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sources = getSourcesDetails() as ArrayList<SelfossModel.Source>
|
||||||
}
|
}
|
||||||
} else if (isDatabaseEnabled) {
|
} else if (isDatabaseEnabled) {
|
||||||
updateSources(getDBSources().map { it.toView() } as ArrayList)
|
sources = getDBSources().map { it.toView() } as ArrayList<SelfossModel.Source>
|
||||||
}
|
}
|
||||||
|
|
||||||
return sources
|
return sources
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getSourcesDetails(): ArrayList<SelfossModel.Source> {
|
suspend fun getSourcesDetails(): ArrayList<SelfossModel.SourceDetail> {
|
||||||
|
var sources = ArrayList<SelfossModel.SourceDetail>()
|
||||||
val isDatabaseEnabled =
|
val isDatabaseEnabled =
|
||||||
appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
|
||||||
if (isNetworkAvailable() && sources.none { it.spout != null }) {
|
val shouldFetch = if (appSettingsService.isUpdateSourcesEnabled()) !fetchedSources else true
|
||||||
|
if (shouldFetch && isNetworkAvailable()) {
|
||||||
val apiSources = api.sourcesDetailed()
|
val apiSources = api.sourcesDetailed()
|
||||||
if (apiSources.success && apiSources.data != null) {
|
if (apiSources.success && apiSources.data != null) {
|
||||||
updateSources(apiSources.data.map { SelfossModel.Source(it) } as ArrayList)
|
sources = updateSources(apiSources.data) as ArrayList<SelfossModel.SourceDetail>
|
||||||
}
|
}
|
||||||
} else if (isDatabaseEnabled) {
|
} else if (isDatabaseEnabled) {
|
||||||
updateSources(getDBSources().map { it.toView() } as ArrayList)
|
sources = getDBSources().map { it.toView() } as ArrayList<SelfossModel.SourceDetail>
|
||||||
}
|
}
|
||||||
return sources
|
return sources
|
||||||
}
|
}
|
||||||
@ -400,7 +412,6 @@ class Repository(
|
|||||||
items = ArrayList(items.filter { it.sourcetitle != title })
|
items = ArrayList(items.filter { it.sourcetitle != title })
|
||||||
setReaderItems(items)
|
setReaderItems(items)
|
||||||
db.itemsQueries.deleteItemsWhereSource(title)
|
db.itemsQueries.deleteItemsWhereSource(title)
|
||||||
sources.removeAll { it.id == id }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return success
|
return success
|
||||||
@ -620,7 +631,7 @@ class Repository(
|
|||||||
ReaderForSelfossDB.Schema.migrate(driverFactory.createDriver(), 0, 1)
|
ReaderForSelfossDB.Schema.migrate(driverFactory.createDriver(), 0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSelectedSource(source: SelfossModel.Source) {
|
fun setSelectedSource(source: SelfossModel.SourceDetail) {
|
||||||
_selectedSource = source
|
_selectedSource = source
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,7 +639,7 @@ class Repository(
|
|||||||
_selectedSource = null
|
_selectedSource = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSelectedSource(): SelfossModel.Source? {
|
fun getSelectedSource(): SelfossModel.SourceDetail? {
|
||||||
return _selectedSource
|
return _selectedSource
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,10 +13,10 @@ fun TAG.toView(): SelfossModel.Tag =
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun SOURCE.toView(): SelfossModel.Source =
|
fun SOURCE.toView(): SelfossModel.Source =
|
||||||
SelfossModel.Source(
|
SelfossModel.SourceDetail(
|
||||||
this.id.toInt(),
|
this.id.toInt(),
|
||||||
this.title,
|
this.title,
|
||||||
this.unread?.toInt(),
|
null,
|
||||||
this.tags?.split(","),
|
this.tags?.split(","),
|
||||||
this.spout,
|
this.spout,
|
||||||
this.error,
|
this.error,
|
||||||
@ -24,18 +24,6 @@ fun SOURCE.toView(): SelfossModel.Source =
|
|||||||
if (this.url != null) SelfossModel.SourceParams(this.url) else null
|
if (this.url != null) SelfossModel.SourceParams(this.url) else null
|
||||||
)
|
)
|
||||||
|
|
||||||
fun SelfossModel.Source.toEntity(): SOURCE =
|
|
||||||
SOURCE(
|
|
||||||
this.id.toString(),
|
|
||||||
this.title.getHtmlDecoded(),
|
|
||||||
this.unread?.toLong(),
|
|
||||||
this.tags?.joinToString(","),
|
|
||||||
this.spout,
|
|
||||||
this.error,
|
|
||||||
this.icon.orEmpty(),
|
|
||||||
this.params?.url
|
|
||||||
)
|
|
||||||
|
|
||||||
fun SelfossModel.Tag.toEntity(): TAG =
|
fun SelfossModel.Tag.toEntity(): TAG =
|
||||||
TAG(
|
TAG(
|
||||||
this.tag,
|
this.tag,
|
||||||
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE SOURCE ADD COLUMN `unread` INTEGER;
|
|
@ -1,7 +1,6 @@
|
|||||||
CREATE TABLE SOURCE (
|
CREATE TABLE SOURCE (
|
||||||
`id` TEXT NOT NULL,
|
`id` TEXT NOT NULL,
|
||||||
`title` TEXT NOT NULL,
|
`title` TEXT NOT NULL,
|
||||||
`unread` INTEGER,
|
|
||||||
`tags` TEXT,
|
`tags` TEXT,
|
||||||
`spout` TEXT,
|
`spout` TEXT,
|
||||||
`error` TEXT,
|
`error` TEXT,
|
||||||
|
Loading…
Reference in New Issue
Block a user