From 63b69b2822ce7e486c4d375e273b1bd8582558cb Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 7 Feb 2023 20:40:22 +0100 Subject: [PATCH 1/9] Add support for the /sources/stats api endpoint --- .../amine/apps/readerforselfossv2/rest/SelfossApi.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt index 4d10b3b..3870852 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/rest/SelfossApi.kt @@ -183,7 +183,15 @@ class SelfossApi(private val appSettingsService: AppSettingsService) { } }) - suspend fun sources(): StatusAndData> = + suspend fun sourcesStats(): StatusAndData> = + bodyOrFailure(client.tryToGet(url("/sources/stats")) { + if (!shouldHavePostLogin()) { + parameter("username", appSettingsService.getUserName()) + parameter("password", appSettingsService.getPassword()) + } + }) + + suspend fun sourcesDetailed(): StatusAndData> = bodyOrFailure(client.tryToGet(url("/sources/list")) { if (!shouldHavePostLogin()) { parameter("username", appSettingsService.getUserName()) -- 2.34.1 From a286d0c5cf47c953c1c78cd29b3514ca53658969 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 7 Feb 2023 20:41:38 +0100 Subject: [PATCH 2/9] Add a data model to contain information from both sources stats and details --- .../readerforselfossv2/model/SelfossModel.kt | 73 ++++++++++++++++++- .../readerforselfossv2/utils/EntityUtils.kt | 6 +- .../amine/apps/readerforselfossv2/dao/3.sqm | 1 + .../apps/readerforselfossv2/dao/Sources.sq | 9 ++- 4 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt index 8fdf5e8..673b316 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt @@ -63,8 +63,79 @@ class SelfossModel { fun isPublicModeEnabled() = publicMode ?: false } - @Serializable data class Source( + val id: Int, + val title: String, + var unread: Int?, + var tags: List?, + var spout: String?, + var error: String?, + var icon: String?, + var params: SourceParams? + ) { + + constructor(sourceDetail: SourceDetail) : this( + id = sourceDetail.id, + 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(sourceStat: SourceStats) { + if (this.id != sourceStat.id || this.title != sourceStat.title) { + throw Exception() + } + this.unread = sourceStat.unread + } + + fun update(sourceDetail: SourceDetail) { + if (this.id != sourceDetail.id || this.title != sourceDetail.title) { + throw Exception() + } + this.tags = sourceDetail.tags + this.spout = sourceDetail.spout + this.error = sourceDetail.error + this.icon = sourceDetail.icon + this.params = sourceDetail.params + } + + fun update(source: Source) { + if (this.id != source.id || this.title != source.title) { + throw Exception() + } + this.unread = source.unread + this.tags = source.tags + this.spout = source.spout + this.error = source.error + this.icon = source.icon + this.params = source.params + } + } + + @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) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt index 875da49..8b932ae 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt @@ -16,7 +16,8 @@ fun SOURCE.toView(): SelfossModel.Source = SelfossModel.Source( this.id.toInt(), this.title, - this.tags.split(","), + this.unread?.toInt(), + this.tags?.split(","), this.spout, this.error, this.icon, @@ -27,7 +28,8 @@ fun SelfossModel.Source.toEntity(): SOURCE = SOURCE( this.id.toString(), this.title.getHtmlDecoded(), - this.tags.joinToString(","), + this.unread?.toLong(), + this.tags?.joinToString(","), this.spout, this.error, this.icon.orEmpty(), diff --git a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm new file mode 100644 index 0000000..fc42709 --- /dev/null +++ b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm @@ -0,0 +1 @@ +ALTER TABLE SOURCE ADD COLUMN `unread` INTEGER; \ No newline at end of file diff --git a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq index 9dd5082..249a86d 100644 --- a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq +++ b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq @@ -1,10 +1,11 @@ CREATE TABLE SOURCE ( `id` TEXT NOT NULL, `title` TEXT NOT NULL, - `tags` TEXT NOT NULL, - `spout` TEXT NOT NULL, - `error` TEXT NOT NULL, - `icon` TEXT NOT NULL, + `unread` INTEGER, + `tags` TEXT, + `spout` TEXT, + `error` TEXT, + `icon` TEXT, `url` TEXT, PRIMARY KEY(`id`) ); -- 2.34.1 From 772b5535b913b2f8a3666fc62077434433b815ec Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 7 Feb 2023 20:44:17 +0100 Subject: [PATCH 3/9] Support both sources endpoints in the repository --- .../repository/RepositoryImpl.kt | 58 ++++++++++++++----- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 1bcf35e..078d842 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -44,7 +44,8 @@ class Repository( private val _badgeStarred = MutableStateFlow(0) val badgeStarred = _badgeStarred.asStateFlow() - private var fetchedSources = false + private var sources = ArrayList() + private var fetchedTags = false private var _readerItems = ArrayList() @@ -180,23 +181,49 @@ class Repository( } } - suspend fun getSources(): ArrayList { + private fun updateSources(newSources: ArrayList) { val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() - return if (isNetworkAvailable() && !fetchedSources) { - val apiSources = api.sources() - if (apiSources.success && apiSources.data != null && isDatabaseEnabled) { - resetDBSourcesWithData(apiSources.data) - if (!appSettingsService.isUpdateSourcesEnabled()) { - fetchedSources = true - } - } - apiSources.data ?: ArrayList() - } else if (isDatabaseEnabled) { - ArrayList(getDBSources().map { it.toView() }) - } else { - ArrayList() + val newIds = newSources.map {it.id} + val filteredSources = sources.filterNot { it.id in newIds } + for (source in filteredSources) { + val newSource = newSources.find { it.id == source.id } + source.update(newSource!!) } + sources = (filteredSources + newSources).distinctBy { it.id } as ArrayList + + if (isDatabaseEnabled) { + resetDBSourcesWithData(sources) + } + } + + suspend fun getSourcesStats(): ArrayList { + val isDatabaseEnabled = + appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() + if (isNetworkAvailable() && sources.none { it.unread != null }) { + val apiSources = api.sourcesStats() + if (apiSources.success && apiSources.data != null) { + updateSources(apiSources.data.map { SelfossModel.Source(it) } as ArrayList) + } + } else if (isDatabaseEnabled) { + updateSources(getDBSources().map { it.toView() } as ArrayList) + } + + return sources + } + + suspend fun getSourcesDetails(): ArrayList { + val isDatabaseEnabled = + appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() + if (isNetworkAvailable() && sources.none { it.spout != null }) { + val apiSources = api.sourcesDetailed() + if (apiSources.success && apiSources.data != null) { + updateSources(apiSources.data.map { SelfossModel.Source(it) } as ArrayList) + } + } else if (isDatabaseEnabled) { + updateSources(getDBSources().map { it.toView() } as ArrayList) + } + return sources } suspend fun markAsRead(item: SelfossModel.Item): Boolean { @@ -373,6 +400,7 @@ class Repository( items = ArrayList(items.filter { it.sourcetitle != title }) setReaderItems(items) db.itemsQueries.deleteItemsWhereSource(title) + sources.removeAll { it.id == id } } return success -- 2.34.1 From bb45820ae8e5431b0dd3f85ea63487e20dc411fe Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 7 Feb 2023 20:44:34 +0100 Subject: [PATCH 4/9] Fix tests --- androidApp/src/test/kotlin/RepositoryTest.kt | 68 +++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/androidApp/src/test/kotlin/RepositoryTest.kt b/androidApp/src/test/kotlin/RepositoryTest.kt index ec307b9..af41ab5 100644 --- a/androidApp/src/test/kotlin/RepositoryTest.kt +++ b/androidApp/src/test/kotlin/RepositoryTest.kt @@ -303,6 +303,7 @@ class RepositoryTest { repository.setSourceFilter(SelfossModel.Source( 1, "Test", + 0, listOf("tags"), SPOUT, "", @@ -609,19 +610,19 @@ class RepositoryTest { fun get_sources() { val (sources, sourcesDB) = prepareSources() initializeRepository() - var testSources: List? + var testSources: List runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } - assertSame(sources, testSources) + assertEquals(sources.map { SelfossModel.Source(it) }, testSources) assertNotEquals(sourcesDB.map { it.toView() }, testSources) - coVerify(exactly = 1) { api.sources() } + coVerify(exactly = 1) { api.sourcesDetailed() } } - private fun prepareSources(): Pair, List> { + private fun prepareSources(): Pair, List> { val sources = arrayListOf( - SelfossModel.Source( + SelfossModel.SourceDetail( 1, "First source", listOf("Test", "second"), @@ -630,7 +631,7 @@ class RepositoryTest { IMAGE_URL_2, SelfossModel.SourceParams("url") ), - SelfossModel.Source( + SelfossModel.SourceDetail( 2, "Second source", listOf("second"), @@ -644,6 +645,7 @@ class RepositoryTest { SOURCE( "1", "First DB source", + 3, "Test,second", SPOUT, "", @@ -653,6 +655,7 @@ class RepositoryTest { SOURCE( "2", "Second source", + null, "second", SPOUT, "", @@ -661,7 +664,7 @@ class RepositoryTest { ) ) - coEvery { api.sources() } returns StatusAndData(success = true, data = sources) + coEvery { api.sourcesDetailed() } returns StatusAndData(success = true, data = sources) every { db.sourcesQueries.sources().executeAsList() } returns sourcesDB return Pair(sources, sourcesDB) } @@ -675,13 +678,13 @@ class RepositoryTest { initializeRepository() var testSources: List? runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() // Sources will be fetched from the database on the second call, thus testSources != sources - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } - coVerify(exactly = 1) { api.sources() } - assertNotSame(sources, testSources) + coVerify(exactly = 1) { api.sourcesDetailed() } + assertNotEquals(sources.map { SelfossModel.Source(it) }, testSources) assertEquals(sourcesDB.map { it.toView() }, testSources) verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @@ -693,13 +696,13 @@ class RepositoryTest { every { appSettingsService.isUpdateSourcesEnabled() } returns true every { appSettingsService.isItemCachingEnabled() } returns false initializeRepository() - var testSources: List? + var testSources: List runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } - assertSame(sources, testSources) - coVerify(exactly = 1) { api.sources() } + assertEquals(sources.map { SelfossModel.Source(it) }, testSources) + coVerify(exactly = 1) { api.sourcesDetailed() } verify(exactly = 0) { db.sourcesQueries } } @@ -710,13 +713,13 @@ class RepositoryTest { every { appSettingsService.isUpdateSourcesEnabled() } returns false every { appSettingsService.isItemCachingEnabled() } returns false initializeRepository() - var testSources: List? + var testSources: List runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } - assertSame(sources, testSources) - coVerify(exactly = 1) { api.sources() } + assertEquals(sources.map { SelfossModel.Source(it) }, testSources) + coVerify(exactly = 1) { api.sourcesDetailed() } verify(atLeast = 1) { db.sourcesQueries } } @@ -724,13 +727,13 @@ class RepositoryTest { fun get_sources_without_connection() { val (_, sourcesDB) = prepareSources() initializeRepository(MutableStateFlow(false)) - var testSources: List? + var testSources: List runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } assertEquals(sourcesDB.map { it.toView() }, testSources) - coVerify(exactly = 0) { api.sources() } + coVerify(exactly = 0) { api.sourcesDetailed() } verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @@ -741,13 +744,13 @@ class RepositoryTest { every { appSettingsService.isItemCachingEnabled() } returns false every { appSettingsService.isUpdateSourcesEnabled() } returns true initializeRepository(MutableStateFlow(false)) - var testSources: List? + var testSources: List runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } assertEquals(emptyList(), testSources) - coVerify(exactly = 0) { api.sources() } + coVerify(exactly = 0) { api.sourcesDetailed() } verify(exactly = 0) { db.sourcesQueries.sources().executeAsList() } } @@ -758,13 +761,13 @@ class RepositoryTest { every { appSettingsService.isItemCachingEnabled() } returns true every { appSettingsService.isUpdateSourcesEnabled() } returns false initializeRepository(MutableStateFlow(false)) - var testSources: List? + var testSources: List runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } assertEquals(sourcesDB.map { it.toView() }, testSources) - coVerify(exactly = 0) { api.sources() } + coVerify(exactly = 0) { api.sourcesDetailed() } verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @@ -775,13 +778,13 @@ class RepositoryTest { every { appSettingsService.isItemCachingEnabled() } returns false every { appSettingsService.isUpdateSourcesEnabled() } returns false initializeRepository(MutableStateFlow(false)) - var testSources: List? + var testSources: List runBlocking { - testSources = repository.getSources() + testSources = repository.getSourcesDetails() } assertEquals(sourcesDB.map { it.toView() }, testSources) - coVerify(exactly = 0) { api.sources() } + coVerify(exactly = 0) { api.sourcesDetailed() } verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @@ -1105,6 +1108,7 @@ class RepositoryTest { SelfossModel.Source( 1, "First source", + 5, listOf("Test", "second"), SPOUT, "", -- 2.34.1 From 97793a7fc81952f08dd8ac308210b0aba1a58837 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 7 Feb 2023 20:45:41 +0100 Subject: [PATCH 5/9] Use source stats in the home to filter since it is available in public mode --- .../apps/readerforselfossv2/android/SourcesActivity.kt | 2 +- .../apps/readerforselfossv2/android/UpsertSourceActivity.kt | 2 +- .../android/adapters/SourcesListAdapter.kt | 2 +- .../android/fragments/FilterSheetFragment.kt | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt index d8019a0..c677952 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt @@ -55,7 +55,7 @@ class SourcesActivity : AppCompatActivity(), DIAware { binding.recyclerView.layoutManager = mLayoutManager CoroutineScope(Dispatchers.Main).launch { - val response = repository.getSources() + val response = repository.getSourcesDetails() if (response.isNotEmpty()) { items = response val mAdapter = SourcesListAdapter( diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt index 882ff1b..d166d90 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt @@ -68,7 +68,7 @@ class UpsertSourceActivity : AppCompatActivity(), DIAware { private fun initFields(items: Map) { binding.nameInput.setText(existingSource!!.title) - binding.tags.setText(existingSource!!.tags.joinToString(", ")) + binding.tags.setText(existingSource!!.tags?.joinToString(", ")) binding.sourceUri.setText(existingSource!!.params?.url) binding.spoutsSpinner.setSelection(items.keys.indexOf(existingSource!!.spout)) binding.progress.visibility = View.GONE diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt index 4bf3436..49e3a3c 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt @@ -61,7 +61,7 @@ class SourcesListAdapter( c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.itemImage) } - if (itm.error.isNotBlank()) { + if (itm.error.isNullOrBlank()) { binding.errorText.visibility = View.VISIBLE binding.errorText.text = itm.error } else { diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt index 2831031..832906b 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt @@ -84,7 +84,7 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware { ) { val sourceGroup = binding.sourcesGroup - repository.getSources().forEach { source -> + repository.getSourcesStats().forEach { source -> val c = Chip(context) c.ellipsize = TextUtils.TruncateAt.END @@ -141,9 +141,9 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware { selectedChip = c } - c.isEnabled = source.error.isBlank() + c.isEnabled = source.error.isNullOrBlank() - if (source.error.isNotBlank() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!source.error.isNullOrBlank() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { c.tooltipText = source.error } -- 2.34.1 From 6ace50c3069c9c4cea579a5db79b2b35e710bf5e Mon Sep 17 00:00:00 2001 From: davidoskky Date: Tue, 7 Feb 2023 21:45:51 +0100 Subject: [PATCH 6/9] Review --- .../android/adapters/SourcesListAdapter.kt | 2 +- .../readerforselfossv2/model/SelfossModel.kt | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt index 49e3a3c..65ae592 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt @@ -61,7 +61,7 @@ class SourcesListAdapter( c.circularBitmapDrawable(itm.getIcon(repository.baseUrl), binding.itemImage) } - if (itm.error.isNullOrBlank()) { + if (!itm.error.isNullOrBlank()) { binding.errorText.visibility = View.VISIBLE binding.errorText.text = itm.error } else { diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt index 673b316..e0733f1 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt @@ -96,24 +96,6 @@ class SelfossModel { params = null ) - fun update(sourceStat: SourceStats) { - if (this.id != sourceStat.id || this.title != sourceStat.title) { - throw Exception() - } - this.unread = sourceStat.unread - } - - fun update(sourceDetail: SourceDetail) { - if (this.id != sourceDetail.id || this.title != sourceDetail.title) { - throw Exception() - } - this.tags = sourceDetail.tags - this.spout = sourceDetail.spout - this.error = sourceDetail.error - this.icon = sourceDetail.icon - this.params = sourceDetail.params - } - fun update(source: Source) { if (this.id != source.id || this.title != source.title) { throw Exception() -- 2.34.1 From 0c942f7a80240c58248aa750c4591977849d48fb Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sun, 12 Mar 2023 16:53:17 +0100 Subject: [PATCH 7/9] Implement the different Source types through an interface --- .../android/SourcesActivity.kt | 2 +- .../android/UpsertSourceActivity.kt | 2 +- .../android/adapters/SourcesListAdapter.kt | 2 +- .../android/fragments/FilterSheetFragment.kt | 2 +- .../readerforselfossv2/model/SelfossModel.kt | 148 ++++++++++++------ .../repository/RepositoryImpl.kt | 63 +++++--- .../readerforselfossv2/utils/EntityUtils.kt | 16 +- .../amine/apps/readerforselfossv2/dao/3.sqm | 1 - .../apps/readerforselfossv2/dao/Sources.sq | 1 - 9 files changed, 142 insertions(+), 95 deletions(-) delete mode 100644 shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt index c677952..ca47080 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/SourcesActivity.kt @@ -49,7 +49,7 @@ class SourcesActivity : AppCompatActivity(), DIAware { super.onResume() val mLayoutManager = LinearLayoutManager(this) - var items: ArrayList + var items: ArrayList binding.recyclerView.setHasFixedSize(true) binding.recyclerView.layoutManager = mLayoutManager diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt index d166d90..c24babe 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/UpsertSourceActivity.kt @@ -24,7 +24,7 @@ import org.kodein.di.instance class UpsertSourceActivity : AppCompatActivity(), DIAware { - private var existingSource: SelfossModel.Source? = null + private var existingSource: SelfossModel.SourceDetail? = null private var mSpoutsValue: String? = null private lateinit var binding: ActivityUpsertSourceBinding diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt index 65ae592..2eba4c1 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/adapters/SourcesListAdapter.kt @@ -31,7 +31,7 @@ import org.kodein.di.instance class SourcesListAdapter( private val app: Activity, - private val items: ArrayList + private val items: ArrayList ) : RecyclerView.Adapter(), DIAware { private val c: Context = app.baseContext private val generator: ColorGenerator = ColorGenerator.MATERIAL diff --git a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt index 832906b..53b5932 100644 --- a/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt +++ b/androidApp/src/main/java/bou/amine/apps/readerforselfossv2/android/fragments/FilterSheetFragment.kt @@ -84,7 +84,7 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware { ) { val sourceGroup = binding.sourcesGroup - repository.getSourcesStats().forEach { source -> + repository.getSourcesDetailsOrStats().forEach { source -> val c = Chip(context) c.ellipsize = TextUtils.TruncateAt.END diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt index e0733f1..be6eb13 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt @@ -1,5 +1,6 @@ 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.getHtmlDecoded import kotlinx.serialization.KSerializer @@ -63,70 +64,117 @@ class SelfossModel { fun isPublicModeEnabled() = publicMode ?: false } - data class Source( - val id: Int, - val title: String, - var unread: Int?, - var tags: List?, - var spout: String?, - var error: String?, - var icon: String?, - var params: SourceParams? - ) { + interface Source { + val id: Int + var title: String + var unread: Int? + var error: String? + var icon: String? - constructor(sourceDetail: SourceDetail) : this( - id = sourceDetail.id, - 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 checkSameSource(source: Source): Boolean { + return this.id != source.id + } fun update(source: Source) { - if (this.id != source.id || this.title != source.title) { + if (source is SourceDetail) { + this.update(source) + } else if (source is SourceStats) { + this.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() } + this.title = source.title this.unread = source.unread + } + + override fun update(source: SourceDetail) { + if (checkSameSource(source)) { + throw Exception() + } + this.title = source.title + 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?, + 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.title = source.title + this.unread = source.unread + } + + override fun update(source: SourceDetail) { + if (checkSameSource(source)) { + throw Exception() + } + this.title = source.title this.tags = source.tags this.spout = source.spout this.error = source.error this.icon = source.icon 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, - val spout: String, - val error: String, - val icon: String?, - val params: SourceParams? - ) @Serializable data class SourceParams( val url: String diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index 078d842..b1ad6e3 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -44,12 +44,11 @@ class Repository( private val _badgeStarred = MutableStateFlow(0) val badgeStarred = _badgeStarred.asStateFlow() - private var sources = ArrayList() - private var fetchedTags = false + private var fetchedSources = false private var _readerItems = ArrayList() - private var _selectedSource: SelfossModel.Source? = null + private var _selectedSource: SelfossModel.SourceDetail? = null suspend fun getNewerItems(): ArrayList { var fetchedItems: StatusAndData> = StatusAndData.error() @@ -181,47 +180,62 @@ class Repository( } } - private fun updateSources(newSources: ArrayList) { + private fun updateSources(newSources: List): List { val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() - val newIds = newSources.map {it.id} - val filteredSources = sources.filterNot { it.id in newIds } - for (source in filteredSources) { - val newSource = newSources.find { it.id == source.id } - source.update(newSource!!) - } - sources = (filteredSources + newSources).distinctBy { it.id } as ArrayList + return if (isDatabaseEnabled) { + var sources = getDBSources().map { it.toView() } + for (source in sources) { + val newSource = newSources.find { it.id == source.id } + if (newSource != null) { + source.update(newSource) + } + } + + sources = (sources + newSources).distinctBy { it.id } - if (isDatabaseEnabled) { resetDBSourcesWithData(sources) + sources + } else { + newSources } } - suspend fun getSourcesStats(): ArrayList { + suspend fun getSourcesDetailsOrStats(): ArrayList { + var sources = ArrayList() val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() - if (isNetworkAvailable() && sources.none { it.unread != null }) { - val apiSources = api.sourcesStats() - if (apiSources.success && apiSources.data != null) { - updateSources(apiSources.data.map { SelfossModel.Source(it) } as ArrayList) + val shouldFetch = if (!appSettingsService.isUpdateSourcesEnabled()) !fetchedSources else true + if (shouldFetch && isNetworkAvailable()) { + if (appSettingsService.getPublicAccess()) { + val apiSources = api.sourcesStats() + if (apiSources.success && apiSources.data != null) { + fetchedSources = true + sources = updateSources(apiSources.data) as ArrayList + } + } else { + sources = getSourcesDetails() as ArrayList } } else if (isDatabaseEnabled) { - updateSources(getDBSources().map { it.toView() } as ArrayList) + sources = getDBSources().map { it.toView() } as ArrayList } return sources } - suspend fun getSourcesDetails(): ArrayList { + suspend fun getSourcesDetails(): ArrayList { + var sources = ArrayList() val isDatabaseEnabled = 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() if (apiSources.success && apiSources.data != null) { - updateSources(apiSources.data.map { SelfossModel.Source(it) } as ArrayList) + fetchedSources = true + sources = updateSources(apiSources.data) as ArrayList } } else if (isDatabaseEnabled) { - updateSources(getDBSources().map { it.toView() } as ArrayList) + sources = getDBSources().map { it.toView() } as ArrayList } return sources } @@ -400,7 +414,6 @@ class Repository( items = ArrayList(items.filter { it.sourcetitle != title }) setReaderItems(items) db.itemsQueries.deleteItemsWhereSource(title) - sources.removeAll { it.id == id } } return success @@ -620,7 +633,7 @@ class Repository( ReaderForSelfossDB.Schema.migrate(driverFactory.createDriver(), 0, 1) } - fun setSelectedSource(source: SelfossModel.Source) { + fun setSelectedSource(source: SelfossModel.SourceDetail) { _selectedSource = source } @@ -628,7 +641,7 @@ class Repository( _selectedSource = null } - fun getSelectedSource(): SelfossModel.Source? { + fun getSelectedSource(): SelfossModel.SourceDetail? { return _selectedSource } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt index 8b932ae..05e0b60 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt @@ -13,10 +13,10 @@ fun TAG.toView(): SelfossModel.Tag = ) fun SOURCE.toView(): SelfossModel.Source = - SelfossModel.Source( + SelfossModel.SourceDetail( this.id.toInt(), this.title, - this.unread?.toInt(), + null, this.tags?.split(","), this.spout, this.error, @@ -24,18 +24,6 @@ fun SOURCE.toView(): SelfossModel.Source = 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 = TAG( this.tag, diff --git a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm deleted file mode 100644 index fc42709..0000000 --- a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/3.sqm +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE SOURCE ADD COLUMN `unread` INTEGER; \ No newline at end of file diff --git a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq index 249a86d..b5332d8 100644 --- a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq +++ b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq @@ -1,7 +1,6 @@ CREATE TABLE SOURCE ( `id` TEXT NOT NULL, `title` TEXT NOT NULL, - `unread` INTEGER, `tags` TEXT, `spout` TEXT, `error` TEXT, -- 2.34.1 From 4966fb704e211ff1870a040f90d9b06700df6f99 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sun, 12 Mar 2023 17:26:28 +0100 Subject: [PATCH 8/9] Fix sources tests --- androidApp/src/test/kotlin/RepositoryTest.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/androidApp/src/test/kotlin/RepositoryTest.kt b/androidApp/src/test/kotlin/RepositoryTest.kt index af41ab5..78b6ca9 100644 --- a/androidApp/src/test/kotlin/RepositoryTest.kt +++ b/androidApp/src/test/kotlin/RepositoryTest.kt @@ -300,10 +300,10 @@ class RepositoryTest { every { appSettingsService.isItemCachingEnabled() } returns true initializeRepository(MutableStateFlow(false)) - repository.setSourceFilter(SelfossModel.Source( + repository.setSourceFilter(SelfossModel.SourceDetail( 1, "Test", - 0, + null, listOf("tags"), SPOUT, "", @@ -615,7 +615,7 @@ class RepositoryTest { testSources = repository.getSourcesDetails() } - assertEquals(sources.map { SelfossModel.Source(it) }, testSources) + assertEquals(sources, testSources) assertNotEquals(sourcesDB.map { it.toView() }, testSources) coVerify(exactly = 1) { api.sourcesDetailed() } } @@ -625,6 +625,7 @@ class RepositoryTest { SelfossModel.SourceDetail( 1, "First source", + null, listOf("Test", "second"), SPOUT, "", @@ -634,6 +635,7 @@ class RepositoryTest { SelfossModel.SourceDetail( 2, "Second source", + null, listOf("second"), SPOUT, "", @@ -645,7 +647,6 @@ class RepositoryTest { SOURCE( "1", "First DB source", - 3, "Test,second", SPOUT, "", @@ -655,7 +656,6 @@ class RepositoryTest { SOURCE( "2", "Second source", - null, "second", SPOUT, "", @@ -684,7 +684,7 @@ class RepositoryTest { } coVerify(exactly = 1) { api.sourcesDetailed() } - assertNotEquals(sources.map { SelfossModel.Source(it) }, testSources) + assertNotEquals(sources, testSources) assertEquals(sourcesDB.map { it.toView() }, testSources) verify(atLeast = 1) { db.sourcesQueries.sources().executeAsList() } } @@ -701,7 +701,7 @@ class RepositoryTest { testSources = repository.getSourcesDetails() } - assertEquals(sources.map { SelfossModel.Source(it) }, testSources) + assertEquals(sources, testSources) coVerify(exactly = 1) { api.sourcesDetailed() } verify(exactly = 0) { db.sourcesQueries } } @@ -718,7 +718,7 @@ class RepositoryTest { testSources = repository.getSourcesDetails() } - assertEquals(sources.map { SelfossModel.Source(it) }, testSources) + assertEquals(sources, testSources) coVerify(exactly = 1) { api.sourcesDetailed() } verify(atLeast = 1) { db.sourcesQueries } } @@ -1105,7 +1105,7 @@ class RepositoryTest { private fun prepareSearch() { repository.setTagFilter(SelfossModel.Tag("Tag", "read", 0)) repository.setSourceFilter( - SelfossModel.Source( + SelfossModel.SourceDetail( 1, "First source", 5, -- 2.34.1 From 2ae32794be5bb59d8081e5a6b9622b948eee8cb8 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Sun, 12 Mar 2023 21:06:17 +0100 Subject: [PATCH 9/9] Cleanup --- .../readerforselfossv2/model/SelfossModel.kt | 86 +------------------ .../repository/RepositoryImpl.kt | 30 ++----- .../readerforselfossv2/utils/EntityUtils.kt | 13 ++- .../apps/readerforselfossv2/dao/Sources.sq | 8 +- 4 files changed, 24 insertions(+), 113 deletions(-) diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt index be6eb13..71e5d65 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/model/SelfossModel.kt @@ -1,6 +1,5 @@ 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.getHtmlDecoded import kotlinx.serialization.KSerializer @@ -70,26 +69,6 @@ class SelfossModel { var unread: Int? var error: String? var icon: String? - - fun checkSameSource(source: Source): Boolean { - return this.id != source.id - } - - fun update(source: Source) { - if (source is SourceDetail) { - this.update(source) - } else if (source is SourceStats) { - this.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 @@ -99,36 +78,7 @@ class SelfossModel { 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() - } - this.title = source.title - this.unread = source.unread - } - - override fun update(source: SourceDetail) { - if (checkSameSource(source)) { - throw Exception() - } - this.title = source.title - 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 - ) - } - } + ) : Source @Serializable data class SourceDetail( @@ -141,39 +91,7 @@ class SelfossModel { override var error: String?, override var icon: String?, var params: SourceParams? - ) : Source { - override fun update(source: SourceStats) { - if (checkSameSource(source)) { - throw Exception() - } - this.title = source.title - this.unread = source.unread - } - - override fun update(source: SourceDetail) { - if (checkSameSource(source)) { - throw Exception() - } - this.title = source.title - this.tags = source.tags - this.spout = source.spout - this.error = source.error - this.icon = source.icon - 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 - ) - } - } + ) : Source @Serializable data class SourceParams( diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt index b1ad6e3..f59a367 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/repository/RepositoryImpl.kt @@ -180,27 +180,6 @@ class Repository( } } - private fun updateSources(newSources: List): List { - val isDatabaseEnabled = - appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled() - return if (isDatabaseEnabled) { - var sources = getDBSources().map { it.toView() } - for (source in sources) { - val newSource = newSources.find { it.id == source.id } - if (newSource != null) { - source.update(newSource) - } - } - - sources = (sources + newSources).distinctBy { it.id } - - resetDBSourcesWithData(sources) - sources - } else { - newSources - } - } - suspend fun getSourcesDetailsOrStats(): ArrayList { var sources = ArrayList() val isDatabaseEnabled = @@ -211,7 +190,7 @@ class Repository( val apiSources = api.sourcesStats() if (apiSources.success && apiSources.data != null) { fetchedSources = true - sources = updateSources(apiSources.data) as ArrayList + sources = apiSources.data as ArrayList } } else { sources = getSourcesDetails() as ArrayList @@ -232,7 +211,10 @@ class Repository( val apiSources = api.sourcesDetailed() if (apiSources.success && apiSources.data != null) { fetchedSources = true - sources = updateSources(apiSources.data) as ArrayList + sources = apiSources.data + if (isDatabaseEnabled) { + resetDBSourcesWithData(sources) + } } } else if (isDatabaseEnabled) { sources = getDBSources().map { it.toView() } as ArrayList @@ -523,7 +505,7 @@ class Repository( } } - private fun resetDBSourcesWithData(sources: List) { + private fun resetDBSourcesWithData(sources: List) { db.sourcesQueries.deleteAllSources() db.sourcesQueries.transaction { diff --git a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt index 05e0b60..7c1c1af 100644 --- a/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt +++ b/shared/src/commonMain/kotlin/bou/amine/apps/readerforselfossv2/utils/EntityUtils.kt @@ -12,7 +12,7 @@ fun TAG.toView(): SelfossModel.Tag = this.unread.toInt() ) -fun SOURCE.toView(): SelfossModel.Source = +fun SOURCE.toView(): SelfossModel.SourceDetail = SelfossModel.SourceDetail( this.id.toInt(), this.title, @@ -24,6 +24,17 @@ fun SOURCE.toView(): SelfossModel.Source = if (this.url != null) SelfossModel.SourceParams(this.url) else null ) +fun SelfossModel.SourceDetail.toEntity(): SOURCE = + SOURCE( + this.id.toString(), + this.title.getHtmlDecoded(), + this.tags?.joinToString(",").orEmpty(), + this.spout.orEmpty(), + this.error.orEmpty(), + this.icon.orEmpty(), + this.params?.url + ) + fun SelfossModel.Tag.toEntity(): TAG = TAG( this.tag, diff --git a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq index b5332d8..9dd5082 100644 --- a/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq +++ b/shared/src/commonMain/sqldelight/bou/amine/apps/readerforselfossv2/dao/Sources.sq @@ -1,10 +1,10 @@ CREATE TABLE SOURCE ( `id` TEXT NOT NULL, `title` TEXT NOT NULL, - `tags` TEXT, - `spout` TEXT, - `error` TEXT, - `icon` TEXT, + `tags` TEXT NOT NULL, + `spout` TEXT NOT NULL, + `error` TEXT NOT NULL, + `icon` TEXT NOT NULL, `url` TEXT, PRIMARY KEY(`id`) ); -- 2.34.1