Compare commits

..

13 Commits

Author SHA1 Message Date
Amine Louveau
023a30c008 Merge pull request 'Simplify sources and tags handling' (#70) from davidoskky/ReaderForSelfoss-multiplatform:drawer_data into master
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/70
2022-10-04 18:52:39 +00:00
Amine Louveau
a2862a2587 Merge pull request 'Correct mechanism of mark and unmark snackbars' (#74) from davidoskky/ReaderForSelfoss-multiplatform:snackbar-mark into master
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/74
2022-10-04 18:43:44 +00:00
Amine Louveau
054e936657 Merge pull request 'Correct boolean serialization' (#73) from davidoskky/ReaderForSelfoss-multiplatform:swiping into master
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/73
2022-10-04 18:40:14 +00:00
1d2e5069b8 Avoid double snackbar generation 2022-10-04 16:47:13 +02:00
a147646743 Correct mechanism of mark and unmark snackbars 2022-10-04 16:43:21 +02:00
32e7fc0038 Correct boolean serialization 2022-10-04 15:01:22 +02:00
c15bf44032 Adjust repository tests 2022-10-02 01:01:39 +02:00
0bcd55bd4e Add translated strings 2022-10-01 22:51:09 +02:00
ebef0b3511 Start monitoring connectivity status when the repository is initiated. 2022-10-01 22:43:48 +02:00
713ceb05bf Remove unnecessary data class 2022-09-30 15:07:17 +02:00
dc8381b661 Add missing string 2022-09-30 15:00:25 +02:00
b5b820c64b Remove database access from the Home 2022-09-30 15:00:01 +02:00
f7055626d9 Start monitoring the connectivity before loading the Repository 2022-09-30 14:56:10 +02:00
23 changed files with 52 additions and 50 deletions

View File

@ -15,9 +15,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.view.doOnNextLayout import androidx.core.view.doOnNextLayout
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
@ -98,8 +95,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
private val repository : Repository by instance() private val repository : Repository by instance()
private val appSettingsService : AppSettingsService by instance() private val appSettingsService : AppSettingsService by instance()
data class DrawerData(val tags: List<SelfossModel.Tag>?, val sources: List<SelfossModel.Source>?)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater) binding = ActivityHomeBinding.inflate(layoutInflater)
@ -352,28 +347,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
) )
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
val drawerData = DrawerData(repository.getDBTags().map { it.toView() }, val tags = repository.getTags()
repository.getDBSources().map { it.toView() }) val sources = repository.getSources()
runOnUiThread { runOnUiThread {
// TODO: All this logic should be handled by the repository, simplify and remove direct DB access handleDrawerData(tags, sources)
// Only refresh if there is no data in the DB, or if the `UpdateSources` setting is enabled
if (drawerData.sources?.isEmpty() == true || appSettingsService.isUpdateSourcesEnabled()) {
drawerApiCalls(drawerData)
} else {
handleDrawerData(drawerData, loadedFromCache = true)
}
} }
} }
} }
private fun drawerApiCalls(drawerData: DrawerData) { private fun handleDrawerData(tags: List<SelfossModel.Tag>, sources: List<SelfossModel.Source>) {
CoroutineScope(Dispatchers.Main).launch {
val apiDrawerData = DrawerData(repository.getTags(), repository.getSources())
handleDrawerData(if (drawerData != apiDrawerData) apiDrawerData else drawerData)
}
}
private fun handleDrawerData(drawerData: DrawerData, loadedFromCache: Boolean = false) {
binding.mainDrawer.itemAdapter.clear() binding.mainDrawer.itemAdapter.clear()
// Filters title with clear action // Filters title with clear action
@ -387,24 +369,24 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
} }
// Hidden tags // Hidden tags
if (drawerData.tags != null && drawerData.tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) { if (tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) {
secondaryItem( secondaryItem(
withDivider = true, withDivider = true,
R.string.drawer_item_hidden_tags, R.string.drawer_item_hidden_tags,
DRAWER_ID_HIDDEN_TAGS DRAWER_ID_HIDDEN_TAGS
) )
handleHiddenTags(drawerData.tags) handleHiddenTags(tags)
} }
// Tags // Tags
secondaryItem(withDivider = true, R.string.drawer_item_tags, DRAWER_ID_TAGS) secondaryItem(withDivider = true, R.string.drawer_item_tags, DRAWER_ID_TAGS)
if (drawerData.tags == null && !loadedFromCache) { if (tags.isEmpty()) {
binding.mainDrawer.itemAdapter.add( binding.mainDrawer.itemAdapter.add(
SecondaryDrawerItem() SecondaryDrawerItem()
.apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false } .apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false }
) )
} else { } else {
handleTags(drawerData.tags!!) handleTags(tags)
} }
// Sources // Sources
@ -412,15 +394,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
startActivity(Intent(v!!.context, SourcesActivity::class.java)) startActivity(Intent(v!!.context, SourcesActivity::class.java))
false false
} }
if (drawerData.sources == null && !loadedFromCache) { if (sources.isEmpty()) {
binding.mainDrawer.itemAdapter.add( binding.mainDrawer.itemAdapter.add(
SecondaryDrawerItem().apply { SecondaryDrawerItem().apply {
nameRes = R.string.drawer_error_loading_tags nameRes = R.string.drawer_error_loading_sources
isSelectable = false isSelectable = false
} }
) )
} else { } else {
handleSources(drawerData.sources!!) handleSources(sources)
} }
// About action // About action

View File

@ -75,7 +75,6 @@ class MyApp : MultiDexApplication(), DIAware {
).show() ).show()
} }
} }
} }
private fun handleNotificationChannels() { private fun handleNotificationChannels() {

View File

@ -28,7 +28,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
updateItems(this.items) updateItems(this.items)
} }
private fun unmarkSnackbar(position: Int) { private fun unmarkSnackbar(item: SelfossModel.Item, position: Int) {
val s = Snackbar val s = Snackbar
.make( .make(
app.findViewById(R.id.coordLayout), app.findViewById(R.id.coordLayout),
@ -37,7 +37,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
) )
.setAction(R.string.undo_string) { .setAction(R.string.undo_string) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
unreadItemAtIndex(position, false) unreadItemAtIndex(item, position, false)
} }
} }
@ -47,7 +47,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
s.show() s.show()
} }
private fun markSnackbar(position: Int) { private fun markSnackbar(item: SelfossModel.Item, position: Int) {
val s = Snackbar val s = Snackbar
.make( .make(
app.findViewById(R.id.coordLayout), app.findViewById(R.id.coordLayout),
@ -55,7 +55,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
Snackbar.LENGTH_LONG Snackbar.LENGTH_LONG
) )
.setAction(R.string.undo_string) { .setAction(R.string.undo_string) {
readItemAtIndex(position) readItemAtIndex(item, position, false)
} }
val view = s.view val view = s.view
@ -66,37 +66,36 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
fun handleItemAtIndex(position: Int) { fun handleItemAtIndex(position: Int) {
if (items[position].unread) { if (items[position].unread) {
readItemAtIndex(position) readItemAtIndex(items[position], position)
} else { } else {
unreadItemAtIndex(position) unreadItemAtIndex(items[position], position)
} }
} }
private fun readItemAtIndex(position: Int, showSnackbar: Boolean = true) { private fun readItemAtIndex(item: SelfossModel.Item, position: Int, showSnackbar: Boolean = true) {
val i = items[position]
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
repository.markAsRead(i) repository.markAsRead(item)
} }
if (repository.displayedItems == ItemType.UNREAD) { if (repository.displayedItems == ItemType.UNREAD) {
items.remove(i) items.remove(item)
notifyItemRemoved(position) notifyItemRemoved(position)
updateItems(items) updateItems(items)
} else { } else {
notifyItemChanged(position) notifyItemChanged(position)
} }
if (showSnackbar) { if (showSnackbar) {
unmarkSnackbar(position) unmarkSnackbar(item, position)
} }
} }
private fun unreadItemAtIndex(position: Int, showSnackbar: Boolean = true) { private fun unreadItemAtIndex(item: SelfossModel.Item, position: Int, showSnackbar: Boolean = true) {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
repository.unmarkAsRead(items[position]) repository.unmarkAsRead(item)
} }
notifyItemChanged(position) notifyItemChanged(position)
if (showSnackbar) { if (showSnackbar) {
markSnackbar(position) markSnackbar(item, position)
} }
} }

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Thème sombre</string> <string name="mode_dark">Thème sombre</string>
<string name="mode_system">Utiliser les paramètres système</string> <string name="mode_system">Utiliser les paramètres système</string>
<string name="mode_light">Thème clair</string> <string name="mode_light">Thème clair</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">深色模式</string> <string name="mode_dark">深色模式</string>
<string name="mode_system">遵循系统设置</string> <string name="mode_system">遵循系统设置</string>
<string name="mode_light">浅色模式</string> <string name="mode_light">浅色模式</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string> <string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string> <string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string> <string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources> </resources>

View File

@ -63,6 +63,7 @@
<string name="card_height_off">Card height will be fixed</string> <string name="card_height_off">Card height will be fixed</string>
<string name="source_code">Source code</string> <string name="source_code">Source code</string>
<string name="drawer_error_loading_tags">Error loading tags…</string> <string name="drawer_error_loading_tags">Error loading tags…</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
<string name="drawer_item_filters">Filters</string> <string name="drawer_item_filters">Filters</string>
<string name="drawer_action_clear">clear</string> <string name="drawer_action_clear">clear</string>
<string name="drawer_item_tags">Tags</string> <string name="drawer_item_tags">Tags</string>
@ -109,7 +110,7 @@
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string> <string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string> <string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string> <string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
<string name="loading_notification_title">Loading ...</string> <string name="loading_notification_title">Loading </string>
<string name="loading_notification_text">Selfoss is syncing your articles</string> <string name="loading_notification_text">Selfoss is syncing your articles</string>
<string name="notification_channel_sync">Sync notification</string> <string name="notification_channel_sync">Sync notification</string>
<string name="new_items_channel_sync">New items notification</string> <string name="new_items_channel_sync">New items notification</string>

View File

@ -138,7 +138,11 @@ class SelfossModel {
object BooleanSerializer : KSerializer<Boolean> { object BooleanSerializer : KSerializer<Boolean> {
override fun deserialize(decoder: Decoder): Boolean { override fun deserialize(decoder: Decoder): Boolean {
val json = ((decoder as JsonDecoder).decodeJsonElement()).jsonPrimitive val json = ((decoder as JsonDecoder).decodeJsonElement()).jsonPrimitive
return json.booleanOrNull ?: json.int == 1 return if (json.booleanOrNull != null) {
json.boolean
} else {
json.int == 1
}
} }
override val descriptor: SerialDescriptor override val descriptor: SerialDescriptor

View File

@ -42,6 +42,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
init { init {
// TODO: Dispatchers.IO not available in KMM, an alternative solution should be found // TODO: Dispatchers.IO not available in KMM, an alternative solution should be found
connectivityStatus.start()
runBlocking { runBlocking {
updateApiVersion() updateApiVersion()
dateUtils = DateUtils(appSettingsService) dateUtils = DateUtils(appSettingsService)
@ -410,11 +411,9 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
private fun deleteDBAction(action: ACTION) = private fun deleteDBAction(action: ACTION) =
db.actionsQueries.deleteAction(action.id) db.actionsQueries.deleteAction(action.id)
// TODO: This function should be private private fun getDBTags(): List<TAG> = db.tagsQueries.tags().executeAsList()
fun getDBTags(): List<TAG> = db.tagsQueries.tags().executeAsList()
// TODO: This function should be private private fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
private fun resetDBTagsWithData(tagEntities: List<SelfossModel.Tag>) { private fun resetDBTagsWithData(tagEntities: List<SelfossModel.Tag>) {
db.tagsQueries.deleteAllTags() db.tagsQueries.deleteAllTags()

View File

@ -42,6 +42,8 @@ class RepositoryTest() {
every { db.tagsQueries.deleteAllTags() } returns Unit every { db.tagsQueries.deleteAllTags() } returns Unit
every { db.tagsQueries.transaction(any(), any()) } returns Unit every { db.tagsQueries.transaction(any(), any()) } returns Unit
every { db.tagsQueries.insertTag(any()) } returns Unit every { db.tagsQueries.insertTag(any()) } returns Unit
every { connectivityStatus.start() } returns Unit
} }
@Test @Test