Migration of Item management to SharedItems (#345)

* Refactor Item addition and deletion

* Metods to filter the items according to read and starred status

* Remove displayed items only if displaying unread items

* Remove unnecessary api calls on tab change and delegate item storage to SharedItems

* Store articles in SharedItems when they get fetched

* Add tag filtering

* Mark items as read

* Disable sorting function

* Add function to get the unread status of an element.

* Fetch items on pull gesture

* Move marking as read logic in SharedItems.

* Delegate item status to SharedItems

* Allow changing unread status of items

* Use full article position reference and not the relative one

* Delegate marking items as unread to SharedItems

* Delegate database addition of Items to SharedItems.

* Function to only provide connectivity information

* Better database management

* Sort items by date

* Provide information about item caching to SharedItems

* Add missing imports

* Update database after fetching articles

* Add missing variable

* Remove unused import

* Use coroutines to access database

* Use coroutines to simultaneously fetch articles.

* Update database after fetching articles.

* Don't block thread when accessing the database

* Prevent crash if connectivity is lost while fetching articles

* Show "Not connected" snackbar if there is no connection or connection is lost during download

* Use coroutines in the background sync

* Added function to get only new items

* Introduced function to filter articles

* Don't execute background sync if the option is disabled

* Improve item filtering

* Apply filters when they are selected on the UI

* Handle infinite scroll

* Incorrect parameters were passed

* Simplify tab selection logic

* Upgrade kotlin jvm to version 1.8

* On tab change fetch new items if the item list is not completely populated

* Remove redundant assignations.

* Fetch articles when changing tag, source or search if the list is not fully populated

* Fetch only the article in the tab selected

* Correct inconsistent position address

* Disable swiping articles only if favorites are selected

* Delegate badge count to SharedItems

* Clear the database when the app starts in order to avoid accumulation and inconsistencies

* Remove unused functions and variables

* Do not overwrite fetched items with old copies from the database

* Display "There's nothing here" only if there are no articles

* Adapt function to read all articles to the new changes

* Use IO Dispatcher for Database and Network computations

* Adapt Background sync to the usage of SharedItems

* Handle refresh gesture appropriately by refreshing the whole items list

* Remove unused imports
This commit is contained in:
2021-09-25 13:45:51 +02:00
committed by GitHub
parent 304b6c3761
commit 46e723a238
14 changed files with 663 additions and 684 deletions
@@ -18,6 +18,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.view.MenuItemCompat
import androidx.core.view.doOnNextLayout
import androidx.recyclerview.widget.*
import androidx.room.Room
import androidx.work.Constraints
@@ -43,7 +44,6 @@ import apps.amine.bou.readerforselfoss.utils.SharedItems
import apps.amine.bou.readerforselfoss.utils.bottombar.maybeShow
import apps.amine.bou.readerforselfoss.utils.bottombar.removeBadge
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.flattenTags
import apps.amine.bou.readerforselfoss.utils.longHash
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
@@ -58,7 +58,6 @@ import com.ashokvarma.bottomnavigation.BottomNavigationItem
import com.ashokvarma.bottomnavigation.TextBadgeItem
import com.bumptech.glide.Glide
import com.ftinc.scoop.Scoop
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder
import com.mikepenz.materialdrawer.Drawer
import com.mikepenz.materialdrawer.holder.BadgeStyle
@@ -66,10 +65,12 @@ import com.mikepenz.materialdrawer.holder.StringHolder
import com.mikepenz.materialdrawer.model.DividerDrawerItem
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.text.SimpleDateFormat
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
@@ -129,10 +130,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private var recyclerAdapter: RecyclerView.Adapter<*>? = null
private var badgeNew: Int = -1
private var badgeAll: Int = -1
private var badgeFavs: Int = -1
private var fromTabShortcut: Boolean = false
private var offlineShortcut: Boolean = false
@@ -213,7 +210,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
allItems = ArrayList()
lastFetchDone = false
handleDrawerItems()
getElementsAccordingToTab()
CoroutineScope(Dispatchers.Main).launch {
refreshFocusedItems(applicationContext, api, db)
getElementsAccordingToTab()
binding.swipeRefreshLayout.isRefreshing = false
}
}
val simpleItemTouchCallback =
@@ -225,7 +226,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int =
if (elementsShown != UNREAD_SHOWN && elementsShown != READ_SHOWN) {
if (elementsShown == FAV_SHOWN) {
0
} else {
super.getSwipeDirs(
@@ -247,16 +248,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
if (i != null) {
val adapter = binding.recyclerView.adapter as ItemsAdapter<*>
val wasItemUnread = adapter.unreadItemStatusAtIndex(position)
adapter.handleItemAtIndex(position)
if (wasItemUnread) {
badgeNew--
} else {
badgeNew++
}
reloadBadgeContent()
val tagHashes = i.tags.tags.split(",").map { it.longHash() }
@@ -392,56 +385,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
private fun getAndStoreAllItems() {
api.allNewItems().enqueue(object : Callback<List<Item>> {
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
}
override fun onResponse(
call: Call<List<Item>>,
response: Response<List<Item>>
) {
enqueueArticles(response, true)
}
})
api.allReadItems().enqueue(object : Callback<List<Item>> {
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
}
override fun onResponse(
call: Call<List<Item>>,
response: Response<List<Item>>
) {
enqueueArticles(response, false)
}
})
api.allStarredItems().enqueue(object : Callback<List<Item>> {
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
}
override fun onResponse(
call: Call<List<Item>>,
response: Response<List<Item>>
) {
enqueueArticles(response, false)
}
})
}
private fun enqueueArticles(response: Response<List<Item>>, clearDatabase: Boolean) {
thread {
if (response.body() != null) {
val apiItems = (response.body() as ArrayList<Item>).filter {
maybeTagFilter != null || filter(it.tags.tags)
} as ArrayList<Item>
if (clearDatabase) {
db.itemsDao().deleteAllItems()
}
db.itemsDao()
.insertAllItems(*(apiItems.map { it.toEntity() }).toTypedArray())
}
}
CoroutineScope(Dispatchers.Main).launch {
binding.swipeRefreshLayout.isRefreshing = true
getAndStoreAllItems(applicationContext ,api, db)
this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout), offlineShortcut)
handleListResult()
binding.swipeRefreshLayout.isRefreshing = false
SharedItems.updateDatabase(db)
}
}
override fun onStop() {
@@ -461,6 +412,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
displayAccountHeader = sharedPref.getBoolean("account_header_displaying", false)
infiniteScroll = sharedPref.getBoolean("infinite_loading", false)
itemsCaching = sharedPref.getBoolean("items_caching", false)
SharedItems.itemsCaching = itemsCaching
updateSources = sharedPref.getBoolean("update_sources", true)
markOnScroll = sharedPref.getBoolean("mark_on_scroll", false)
hiddenTags = if (sharedPref.getString("hidden_tags", "")!!.isNotEmpty()) {
@@ -597,7 +549,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
.withOnDrawerItemClickListener { _, _, _ ->
allItems = ArrayList()
maybeTagFilter = it
SharedItems.tagFilter = it.tag
getElementsAccordingToTab()
fetchOnEmptyList()
false
}
if (it.unread > 0) {
@@ -648,7 +602,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
.withOnDrawerItemClickListener { _, _, _ ->
allItems = ArrayList()
maybeTagFilter = it
SharedItems.tagFilter = it.tag
getElementsAccordingToTab()
fetchOnEmptyList()
false
}
if (it.unread > 0) {
@@ -680,7 +636,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
.withOnDrawerItemClickListener { _, _, _ ->
allItems = ArrayList()
maybeSourceFilter = tag
SharedItems.sourceIDFilter = tag.id.toLong()
SharedItems.sourceFilter = tag.title
getElementsAccordingToTab()
fetchOnEmptyList()
false
}
if (tag.getIcon(this@HomeActivity).isNotBlank()) {
@@ -710,8 +669,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
.withOnDrawerItemClickListener { _, _, _ ->
allItems = ArrayList()
maybeSourceFilter = null
SharedItems.sourceFilter = null
SharedItems.sourceIDFilter = null
maybeTagFilter = null
SharedItems.tagFilter = null
getElementsAccordingToTab()
fetchOnEmptyList()
false
}
)
@@ -900,7 +863,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
binding.recyclerView.layoutManager = layoutManager
}
} else {
}
}
}
@@ -933,69 +895,28 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
offset = 0
lastFetchDone = false
if (itemsCaching) {
elementsShown = position + 1
getElementsAccordingToTab()
binding.recyclerView.scrollToPosition(0)
if (!binding.swipeRefreshLayout.isRefreshing) {
binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = true }
}
thread {
val dbItems = db.itemsDao().items().map { it.toView() }.sortedByDescending {
SimpleDateFormat(Config.dateTimeFormatter).parse(it.datetime)
}
runOnUiThread {
if (dbItems.isNotEmpty()) {
items = when (position) {
0 -> ArrayList(dbItems.filter { it.unread })
1 -> ArrayList(dbItems.filter { !it.unread })
2 -> ArrayList(dbItems.filter { it.starred })
else -> ArrayList(dbItems.filter { it.unread })
}
handleListResult()
when (position) {
0 -> getUnRead()
1 -> getRead()
2 -> getStarred()
else -> Unit
}
} else {
if (this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout), offlineShortcut)) {
when (position) {
0 -> getUnRead()
1 -> getRead()
2 -> getStarred()
else -> Unit
}
getAndStoreAllItems()
}
}
}
}
} else {
when (position) {
0 -> getUnRead()
1 -> getRead()
2 -> getStarred()
else -> Unit
}
}
fetchOnEmptyList()
}
})
}
private fun fetchOnEmptyList() {
binding.recyclerView.doOnNextLayout {
if (SharedItems.focusedItems.size - 1 == getLastVisibleItem()) {
getElementsAccordingToTab(true)
}
}
}
private fun handleInfiniteScroll() {
recyclerViewScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(localRecycler: RecyclerView, dx: Int, dy: Int) {
if (dy > 0) {
val manager = binding.recyclerView.layoutManager
val lastVisibleItem: Int = when (manager) {
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
null
).last()
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
else -> 0
}
val lastVisibleItem = getLastVisibleItem()
if (lastVisibleItem == (items.size - 1) && items.size < maxItemNumber()) {
getElementsAccordingToTab(appendResults = true)
@@ -1008,13 +929,22 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
binding.recyclerView.addOnScrollListener(recyclerViewScrollListener)
}
private fun getLastVisibleItem() : Int {
val manager = binding.recyclerView.layoutManager
return when (manager) {
is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
null
).last()
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
else -> 0
}
}
private fun mayBeEmpty() =
if (items.isEmpty()) {
binding.emptyText.visibility = View.VISIBLE
binding.recyclerView.visibility = View.GONE
} else {
binding.emptyText.visibility = View.GONE
binding.recyclerView.visibility = View.VISIBLE
}
private fun getElementsAccordingToTab(
@@ -1030,155 +960,52 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
}
offset = if (appendResults && offsetOverride === null) {
(offset + itemsNumber)
offset = if (appendResults) {
SharedItems.focusedItems.size - 1
} else {
offsetOverride ?: 0
0
}
firstVisible = if (appendResults) firstVisible else 0
if (itemsCaching) {
if (!binding.swipeRefreshLayout.isRefreshing) {
binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = true }
}
thread {
val dbItems = db.itemsDao().items().map { it.toView() }.sortedByDescending {
SimpleDateFormat(Config.dateTimeFormatter).parse(it.datetime)
}
runOnUiThread {
if (dbItems.isNotEmpty()) {
items = when (elementsShown) {
UNREAD_SHOWN -> ArrayList(dbItems.filter { it.unread })
READ_SHOWN -> ArrayList(dbItems.filter { !it.unread })
FAV_SHOWN -> ArrayList(dbItems.filter { it.starred })
else -> ArrayList(dbItems.filter { it.unread })
}
handleListResult()
doGetAccordingToTab()
} else {
if (this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout), offlineShortcut)) {
doGetAccordingToTab()
getAndStoreAllItems()
}
}
}
}
} else {
doGetAccordingToTab()
}
}
private fun filter(tags: String): Boolean {
val tagsList = tags.replace("\\s".toRegex(), "").split(",")
return tagsList.intersect(hiddenTags).isEmpty()
}
private fun doCallTo(
appendResults: Boolean,
toastMessage: Int,
call: (String?, Long?, String?) -> Call<List<Item>>
) {
fun handleItemsResponse(response: Response<List<Item>>) {
val shouldUpdate = (response.body()?.toSet() != items.toSet())
if (response.body() != null) {
if (shouldUpdate) {
getAndStoreAllItems()
items = response.body() as ArrayList<Item>
items = items.filter {
maybeTagFilter != null || filter(it.tags.tags)
} as ArrayList<Item>
if (allItems.isEmpty()) {
allItems = items
} else {
items.forEach {
if (!allItems.contains(it)) allItems.add(it)
}
}
SharedItems.focusedItems = items
SharedItems.items = allItems
}
} else {
if (!appendResults) {
items = ArrayList()
allItems = ArrayList()
}
}
handleListResult(appendResults)
if (!appendResults) mayBeEmpty()
binding.swipeRefreshLayout.isRefreshing = false
}
if (!binding.swipeRefreshLayout.isRefreshing) {
binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = true }
}
if (this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout), offlineShortcut)) {
call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter)
.enqueue(object : Callback<List<Item>> {
override fun onResponse(
call: Call<List<Item>>,
response: Response<List<Item>>
) {
handleItemsResponse(response)
}
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
binding.swipeRefreshLayout.isRefreshing = false
Toast.makeText(
this@HomeActivity,
toastMessage,
Toast.LENGTH_SHORT
).show()
}
})
} else {
binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = false }
}
doGetAccordingToTab()
}
private fun getUnRead(appendResults: Boolean = false) {
elementsShown = UNREAD_SHOWN
doCallTo(appendResults, R.string.cant_get_new_elements) { t, id, f ->
api.newItems(
t,
id,
f,
itemsNumber,
offset
)
CoroutineScope(Dispatchers.Main).launch {
if (appendResults || !SharedItems.fetchedUnread) {
binding.swipeRefreshLayout.isRefreshing = true
getUnreadItems(applicationContext, api, db, offset)
binding.swipeRefreshLayout.isRefreshing = false
}
SharedItems.getUnRead()
items = SharedItems.focusedItems
handleListResult()
}
}
private fun getRead(appendResults: Boolean = false) {
elementsShown = READ_SHOWN
doCallTo(appendResults, R.string.cant_get_read) { t, id, f ->
api.readItems(
t,
id,
f,
itemsNumber,
offset
)
CoroutineScope(Dispatchers.Main).launch {
if (appendResults || !SharedItems.fetchedAll) {
binding.swipeRefreshLayout.isRefreshing = true
getReadItems(applicationContext, api, db, offset)
binding.swipeRefreshLayout.isRefreshing = false
}
SharedItems.getAll()
items = SharedItems.focusedItems
handleListResult()
}
}
private fun getStarred(appendResults: Boolean = false) {
elementsShown = FAV_SHOWN
doCallTo(appendResults, R.string.cant_get_favs) { t, id, f ->
api.starredItems(
t,
id,
f,
itemsNumber,
offset
)
CoroutineScope(Dispatchers.Main).launch {
if (appendResults || !SharedItems.fetchedStarred) {
binding.swipeRefreshLayout.isRefreshing = true
getStarredItems(applicationContext, api, db, offset)
binding.swipeRefreshLayout.isRefreshing = false
}
SharedItems.getStarred()
items = SharedItems.focusedItems
handleListResult()
}
}
@@ -1238,59 +1065,35 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
binding.recyclerView.adapter = recyclerAdapter
} else {
if (!appendResults) {
(recyclerAdapter as ItemsAdapter<*>).updateAllItems()
} else {
(recyclerAdapter as ItemsAdapter<*>).addItemsAtEnd(items)
}
}
reloadBadges()
mayBeEmpty()
}
private fun reloadBadges() {
if (this@HomeActivity.isNetworkAccessible(null, offlineShortcut) && (displayUnreadCount || displayAllCount)) {
api.stats.enqueue(object : Callback<Stats> {
override fun onResponse(call: Call<Stats>, response: Response<Stats>) {
if (response.body() != null) {
badgeNew = response.body()!!.unread
badgeAll = response.body()!!.total
badgeFavs = response.body()!!.starred
reloadBadgeContent()
}
}
override fun onFailure(call: Call<Stats>, t: Throwable) {
}
})
} else {
reloadBadgeContent(succeeded = false)
if (displayUnreadCount || displayAllCount) {
CoroutineScope(Dispatchers.Main).launch {
reloadBadges(applicationContext, api)
reloadBadgeContent()
}
}
}
private fun reloadBadgeContent(succeeded: Boolean = true) {
if (succeeded) {
if (displayUnreadCount) {
tabNewBadge
.setText(badgeNew.toString())
.maybeShow()
}
if (displayAllCount) {
tabArchiveBadge
.setText(badgeAll.toString())
.maybeShow()
tabStarredBadge
.setText(badgeFavs.toString())
.maybeShow()
} else {
tabArchiveBadge.removeBadge()
tabStarredBadge.removeBadge()
}
} else {
tabNewBadge.removeBadge()
tabArchiveBadge.removeBadge()
tabStarredBadge.removeBadge()
private fun reloadBadgeContent() {
if (displayUnreadCount) {
tabNewBadge
.setText(SharedItems.badgeUnread.toString())
.maybeShow()
}
if (displayAllCount) {
tabArchiveBadge
.setText(SharedItems.badgeAll.toString())
.maybeShow()
tabStarredBadge
.setText(SharedItems.badgeStarred.toString())
.maybeShow()
}
}
@@ -1310,14 +1113,18 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
override fun onQueryTextChange(p0: String?): Boolean {
if (p0.isNullOrBlank()) {
maybeSearchFilter = null
SharedItems.searchFilter = null
getElementsAccordingToTab()
fetchOnEmptyList()
}
return false
}
override fun onQueryTextSubmit(p0: String?): Boolean {
maybeSearchFilter = p0
SharedItems.searchFilter = p0
getElementsAccordingToTab()
fetchOnEmptyList()
return false
}
@@ -1387,64 +1194,33 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
R.id.readAll -> {
if (elementsShown == UNREAD_SHOWN) {
needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
binding.swipeRefreshLayout.isRefreshing = false
val ids = allItems.map { it.id }
val itemsByTag: Map<Long, Int> =
allItems.flattenTags()
.groupBy { it.tags.tags.longHash() }
.map { it.key to it.value.size }
.toMap()
binding.swipeRefreshLayout.isRefreshing = true
if (ids.isNotEmpty() && this@HomeActivity.isNetworkAccessible(null, offlineShortcut)) {
api.readAll(ids).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
if (response.body() != null && response.body()!!.isSuccess) {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_read,
Toast.LENGTH_SHORT
).show()
tabNewBadge.removeBadge()
if (this@HomeActivity.isNetworkAccessible(null, offlineShortcut)) {
CoroutineScope(Dispatchers.Main).launch {
val success = readAll(applicationContext, api, db)
if (success) {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_read,
Toast.LENGTH_SHORT
).show()
tabNewBadge.removeBadge()
handleDrawerItems()
handleDrawerItems()
getElementsAccordingToTab()
} else {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_not_read,
Toast.LENGTH_SHORT
).show()
}
binding.swipeRefreshLayout.isRefreshing = false
}
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
getElementsAccordingToTab()
} else {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_not_read,
Toast.LENGTH_SHORT
).show()
binding.swipeRefreshLayout.isRefreshing = false
}
})
items = ArrayList()
allItems = ArrayList()
handleListResult()
binding.swipeRefreshLayout.isRefreshing = false
}
}
if (items.isEmpty()) {
Toast.makeText(
this@HomeActivity,
R.string.nothing_here,
Toast.LENGTH_SHORT
).show()
}
handleListResult()
}
}
return true
@@ -1458,10 +1234,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private fun maxItemNumber(): Int =
when (elementsShown) {
UNREAD_SHOWN -> badgeNew
READ_SHOWN -> badgeAll
FAV_SHOWN -> badgeFavs
else -> badgeNew // if !elementsShown then unread are fetched.
UNREAD_SHOWN -> SharedItems.badgeUnread
READ_SHOWN -> SharedItems.badgeAll
FAV_SHOWN -> SharedItems.badgeStarred
else -> SharedItems.badgeUnread // if !elementsShown then unread are fetched.
}
private fun updateItems(adapterItems: ArrayList<Item>) {
@@ -1505,7 +1281,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
if (this@HomeActivity.isNetworkAccessible(null, offlineShortcut)) {
thread {
CoroutineScope(Dispatchers.Main).launch {
val actions = db.actionsDao().actions()
actions.forEach { action ->
Internal Server Error - Amine's git
500 Internal Server Error

Gitea Version: 1.28.0+dev-210-gd87d26d735