Compare commits

...

2 Commits

4 changed files with 215 additions and 205 deletions

View File

@ -17,6 +17,7 @@ import androidx.appcompat.app.AppCompatActivity
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
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.* import androidx.recyclerview.widget.*
import androidx.work.Constraints import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
@ -34,10 +35,13 @@ import bou.amine.apps.readerforselfossv2.android.utils.Config
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
import bou.amine.apps.readerforselfossv2.dao.ACTION import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.model.SelfossModel import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.* import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.utils.ItemType
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
import bou.amine.apps.readerforselfossv2.utils.getIcon
import bou.amine.apps.readerforselfossv2.utils.longHash
import com.ashokvarma.bottomnavigation.BottomNavigationBar import com.ashokvarma.bottomnavigation.BottomNavigationBar
import com.ashokvarma.bottomnavigation.BottomNavigationItem import com.ashokvarma.bottomnavigation.BottomNavigationItem
import com.ashokvarma.bottomnavigation.TextBadgeItem import com.ashokvarma.bottomnavigation.TextBadgeItem
@ -66,7 +70,6 @@ import org.kodein.di.DIAware
import org.kodein.di.android.closestDI import org.kodein.di.android.closestDI
import org.kodein.di.instance import org.kodein.di.instance
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAware { class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAware {
@ -118,6 +121,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
override val di by closestDI() override val di by closestDI()
private val repository : Repository by instance() private val repository : Repository by instance()
private val viewModel: AppViewModel by instance()
data class DrawerData(val tags: List<SelfossModel.Tag>?, val sources: List<SelfossModel.Source>?) data class DrawerData(val tags: List<SelfossModel.Tag>?, val sources: List<SelfossModel.Source>?)
@ -142,6 +146,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
} }
setContentView(view) setContentView(view)
lifecycleScope.launch {
viewModel.refreshingIndicatorProvider.collect { showRefresh ->
binding.swipeRefreshLayout.isRefreshing = showRefresh
}
}
handleThemeBinding() handleThemeBinding()
@ -153,18 +162,25 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
mDrawerToggle.syncState() mDrawerToggle.syncState()
customTabActivityHelper = CustomTabActivityHelper() customTabActivityHelper = CustomTabActivityHelper()
handleSettings()
lifecycleScope.launch {
viewModel.items.collect { fetchedItems ->
items = fetchedItems
handleListResult()
}
}
handleBottomBar() handleBottomBar()
handleDrawer() handleDrawer()
handleSwipeRefreshLayout() handleSwipeRefreshLayout()
handleSettings()
getElementsAccordingToTab() getElementsAccordingToTab()
handleBadgesContent()
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.IO).launch {
repository.tryToCacheItemsAndGetNewOnes() repository.tryToCacheItemsAndGetNewOnes()
} }
@ -180,10 +196,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
repository.offlineOverride = false repository.offlineOverride = false
lastFetchDone = false lastFetchDone = false
handleDrawerItems() handleDrawerItems()
CoroutineScope(Dispatchers.Main).launch { viewModel.getItems(false, elementsShown)
getElementsAccordingToTab()
binding.swipeRefreshLayout.isRefreshing = false
}
} }
val simpleItemTouchCallback = val simpleItemTouchCallback =
@ -219,8 +232,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
adapter.handleItemAtIndex(position) adapter.handleItemAtIndex(position)
reloadBadgeContent()
val tagHashes = i.tags.map { it.longHash() } val tagHashes = i.tags.map { it.longHash() }
tagsBadge = tagsBadge.map { tagsBadge = tagsBadge.map {
if (tagHashes.contains(it.key)) { if (tagHashes.contains(it.key)) {
@ -252,16 +263,23 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
tabNewBadge = TextBadgeItem() tabNewBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false)
.setBackgroundColor(appColors.colorPrimary) .setBackgroundColor(appColors.colorPrimary)
if (!displayUnreadCount) {
tabNewBadge.hide(false)
}
tabArchiveBadge = TextBadgeItem() tabArchiveBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false)
.setBackgroundColor(appColors.colorPrimary) .setBackgroundColor(appColors.colorPrimary)
tabStarredBadge = TextBadgeItem() tabStarredBadge = TextBadgeItem()
.setText("") .setText("")
.setHideOnSelect(false).hide(false) .setHideOnSelect(false)
.setBackgroundColor(appColors.colorPrimary) .setBackgroundColor(appColors.colorPrimary)
if (!displayAllCount) {
tabArchiveBadge.hide(false)
tabStarredBadge.hide(false)
}
val tabNew = val tabNew =
BottomNavigationItem( BottomNavigationItem(
@ -453,7 +471,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
// TODO: refactor this. // TODO: refactor this.
private fun handleDrawerItems() { private fun handleDrawerItems() {
tagsBadge = emptyMap() tagsBadge = emptyMap()
fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) { fun handleDrawerData(maybeDrawerData: DrawerData?) {
fun createDrawerItem( fun createDrawerItem(
it: SelfossModel.Tag it: SelfossModel.Tag
) { ) {
@ -495,12 +513,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
fun handleTags(maybeTags: List<SelfossModel.Tag>?) { fun handleTags(maybeTags: List<SelfossModel.Tag>?) {
if (maybeTags == null) { if (maybeTags == null) {
if (loadedFromCache) { 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 {
val filteredTags = maybeTags val filteredTags = maybeTags
.filterNot { hiddenTags.contains(it.tag) } .filterNot { hiddenTags.contains(it.tag) }
@ -515,14 +531,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
fun handleHiddenTags(maybeTags: List<SelfossModel.Tag>?) { fun handleHiddenTags(maybeTags: List<SelfossModel.Tag>?) {
if (maybeTags == null) { if (maybeTags == null) {
if (loadedFromCache) { 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_tags isSelectable = false
isSelectable = false }
} )
)
}
} else { } else {
val filteredHiddenTags: List<SelfossModel.Tag> = val filteredHiddenTags: List<SelfossModel.Tag> =
maybeTags.filter { hiddenTags.contains(it.tag) } maybeTags.filter { hiddenTags.contains(it.tag) }
@ -536,14 +550,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
fun handleSources(maybeSources: List<SelfossModel.Source>?) { fun handleSources(maybeSources: List<SelfossModel.Source>?) {
if (maybeSources == null) { if (maybeSources == null) {
if (loadedFromCache) { binding.mainDrawer.itemAdapter.add(
binding.mainDrawer.itemAdapter.add( SecondaryDrawerItem().apply {
SecondaryDrawerItem().apply { nameRes = R.string.drawer_error_loading_sources
nameRes = R.string.drawer_error_loading_sources isSelectable = false
isSelectable = false }
} )
)
}
} else { } else {
for (source in maybeSources) { for (source in maybeSources) {
val item = PrimaryDrawerItem().apply { val item = PrimaryDrawerItem().apply {
@ -632,61 +644,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
} }
) )
if (!loadedFromCache) {
if (maybeDrawerData.tags != null) {
thread {
repository.resetDBTagsWithData(maybeDrawerData.tags)
}
}
if (maybeDrawerData.sources != null) {
thread {
repository.resetDBSourcesWithData(maybeDrawerData.sources)
}
}
}
} else { } else {
if (!loadedFromCache) { binding.mainDrawer.itemAdapter.add(
binding.mainDrawer.itemAdapter.add( PrimaryDrawerItem().apply {
PrimaryDrawerItem().apply { nameRes = R.string.no_tags_loaded
nameRes = R.string.no_tags_loaded identifier = DRAWER_ID_TAGS
identifier = DRAWER_ID_TAGS isSelectable = false
isSelectable = false },
}, PrimaryDrawerItem().apply {
PrimaryDrawerItem().apply { nameRes = R.string.no_sources_loaded
nameRes = R.string.no_sources_loaded identifier = DRAWER_ID_SOURCES
identifier = DRAWER_ID_SOURCES isSelectable = false
isSelectable = false
}
)
}
}
}
fun drawerApiCalls(maybeDrawerData: DrawerData?) {
var tags: List<SelfossModel.Tag>? = null
var sources: List<SelfossModel.Source>?
fun sourcesApiCall() {
CoroutineScope(Dispatchers.Main).launch {
val response = repository.getSources()
if (response != null) {
sources = response
val apiDrawerData = DrawerData(tags, sources)
if ((maybeDrawerData != null && maybeDrawerData != apiDrawerData) || maybeDrawerData == null) {
handleDrawerData(apiDrawerData)
}
} else {
val apiDrawerData = DrawerData(tags, null)
if ((maybeDrawerData != null && maybeDrawerData != apiDrawerData) || maybeDrawerData == null) {
handleDrawerData(apiDrawerData)
}
} }
} )
}
CoroutineScope(Dispatchers.IO).launch {
tags = repository.getTags()
sourcesApiCall()
} }
} }
@ -697,12 +667,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
} }
) )
thread { CoroutineScope(Dispatchers.IO).launch {
val drawerData = DrawerData(repository.getDBTags().map { it.toView() }, val drawerData = DrawerData(repository.getTags(),
repository.getDBSources().map { it.toView() }) repository.getSources())
runOnUiThread { runOnUiThread {
handleDrawerData(drawerData, loadedFromCache = true) handleDrawerData(drawerData)
drawerApiCalls(drawerData)
} }
} }
} }
@ -839,21 +808,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
} }
firstVisible = if (appendResults) firstVisible else 0 firstVisible = if (appendResults) firstVisible else 0
getItems(appendResults, elementsShown) viewModel.getItems(appendResults, elementsShown)
}
private fun getItems(appendResults: Boolean, itemType: ItemType) {
CoroutineScope(Dispatchers.Main).launch {
binding.swipeRefreshLayout.isRefreshing = true
repository.displayedItems = itemType
items = if (appendResults) {
repository.getOlderItems()
} else {
repository.getNewerItems()
}
binding.swipeRefreshLayout.isRefreshing = false
handleListResult()
}
} }
private fun handleListResult(appendResults: Boolean = false) { private fun handleListResult(appendResults: Boolean = false) {
@ -915,26 +870,50 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
private fun reloadBadges() { private fun reloadBadges() {
if (displayUnreadCount || displayAllCount) { if (displayUnreadCount || displayAllCount) {
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.IO).launch {
repository.reloadBadges() repository.reloadBadges()
reloadBadgeContent()
} }
} }
} }
private fun reloadBadgeContent() { private fun handleBadgesContent() {
if (displayUnreadCount) { if (displayUnreadCount) {
tabNewBadge lifecycleScope.launch {
.setText(repository.badgeUnread.toString()) repository.badgeUnread.collect { unreadCount ->
.maybeShow() if (unreadCount > 0) {
tabNewBadge
.setText(unreadCount.toString())
.maybeShow()
} else {
tabNewBadge.removeBadge()
}
}
}
} }
if (displayAllCount) { if (displayAllCount) {
tabArchiveBadge lifecycleScope.launch {
.setText(repository.badgeAll.toString()) repository.badgeAll.collect { itemsCount ->
.maybeShow() if (itemsCount > 0) {
tabStarredBadge tabArchiveBadge
.setText(repository.badgeStarred.toString()) .setText(itemsCount.toString())
.maybeShow() .maybeShow()
} else {
tabArchiveBadge.removeBadge()
}
}
}
lifecycleScope.launch {
repository.badgeStarred.collect { starredCount ->
if (starredCount > 0) {
tabStarredBadge
.setText(starredCount.toString())
.maybeShow()
} else {
tabStarredBadge.removeBadge()
}
}
}
} }
} }
@ -992,56 +971,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
when (item.itemId) { when (item.itemId) {
R.id.refresh -> { R.id.refresh -> {
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) { needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show() viewModel.updateRemote()
// TODO: Use Dispatchers.IO
CoroutineScope(Dispatchers.Main).launch {
val updatedRemote = repository.updateRemote()
if (updatedRemote) {
// TODO: Send toast messages from the repository
Toast.makeText(
this@HomeActivity,
R.string.refresh_success_response, Toast.LENGTH_LONG
)
.show()
} else {
Toast.makeText(
this@HomeActivity,
R.string.refresh_failer_message,
Toast.LENGTH_SHORT
).show()
}
}
} }
return true return true
} }
R.id.readAll -> { R.id.readAll -> {
if (elementsShown == ItemType.UNREAD) { if (elementsShown == ItemType.UNREAD) {
needsConfirmation(R.string.readAll, R.string.markall_dialog_message) { needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
binding.swipeRefreshLayout.isRefreshing = true viewModel.markAllAsRead()
CoroutineScope(Dispatchers.Main).launch {
val success = repository.markAllAsRead(items)
if (success) {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_read,
Toast.LENGTH_SHORT
).show()
tabNewBadge.removeBadge()
handleDrawerItems()
getElementsAccordingToTab()
} else {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_not_read,
Toast.LENGTH_SHORT
).show()
}
handleListResult()
binding.swipeRefreshLayout.isRefreshing = false
}
} }
} }
return true return true
@ -1055,10 +992,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
private fun maxItemNumber(): Int = private fun maxItemNumber(): Int =
when (elementsShown) { when (elementsShown) {
ItemType.UNREAD -> repository.badgeUnread ItemType.UNREAD -> repository.badgeUnread.value
ItemType.ALL -> repository.badgeAll ItemType.ALL -> repository.badgeAll.value
ItemType.STARRED -> repository.badgeStarred ItemType.STARRED -> repository.badgeStarred.value
else -> repository.badgeUnread // if !elementsShown then unread are fetched. else -> repository.badgeUnread.value // if !elementsShown then unread are fetched.
} }
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) { private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
@ -1082,9 +1019,4 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
WorkManager.getInstance(baseContext).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork) WorkManager.getInstance(baseContext).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
} }
} }
private fun handleOfflineActions() {
}
} }

View File

@ -84,6 +84,15 @@ class MyApp : MultiDexApplication(), DIAware {
).show() ).show()
} }
} }
CoroutineScope(Dispatchers.Main).launch {
viewModel.toastMessageProvider.collect { toastMessage ->
Toast.makeText(
applicationContext,
toastMessage,
Toast.LENGTH_SHORT
).show()
}
}
} }

View File

@ -3,16 +3,29 @@ package bou.amine.apps.readerforselfossv2.android.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import bou.amine.apps.readerforselfossv2.android.R import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.repository.Repository import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.utils.ItemType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class AppViewModel(private val repository: Repository) : ViewModel() { class AppViewModel(private val repository: Repository) : ViewModel() {
private val _networkAvailableProvider = MutableSharedFlow<Boolean>() private val _networkAvailableProvider = MutableSharedFlow<Boolean>()
val networkAvailableProvider = _networkAvailableProvider.asSharedFlow() val networkAvailableProvider = _networkAvailableProvider.asSharedFlow()
private val _refreshingIndicatorProvider = MutableSharedFlow<Boolean>()
val refreshingIndicatorProvider = _refreshingIndicatorProvider.asSharedFlow()
private val _toastMessageProvider = MutableSharedFlow<Int>()
val toastMessageProvider = _toastMessageProvider.asSharedFlow()
private var wasConnected = true private var wasConnected = true
private val _items = MutableStateFlow(ArrayList<SelfossModel.Item>())
val items = _items.asStateFlow()
init { init {
viewModelScope.launch { viewModelScope.launch {
repository.isConnectionAvailable.collect { isConnected -> repository.isConnectionAvailable.collect { isConnected ->
@ -28,4 +41,43 @@ class AppViewModel(private val repository: Repository) : ViewModel() {
} }
} }
} }
fun updateRemote() {
CoroutineScope(Dispatchers.IO).launch {
_toastMessageProvider.emit(R.string.refresh_in_progress)
val updatedRemote = repository.updateRemote()
if (updatedRemote) {
_toastMessageProvider.emit(R.string.refresh_success_response)
} else {
_toastMessageProvider.emit(R.string.refresh_failer_message)
}
}
}
fun getItems(appendResults: Boolean, itemType: ItemType) {
CoroutineScope(Dispatchers.Main).launch {
_refreshingIndicatorProvider.emit(true)
repository.displayedItems = itemType
val items = if (appendResults) {
repository.getOlderItems()
} else {
repository.getNewerItems()
}
_items.emit(items)
_refreshingIndicatorProvider.emit(false)
}
}
fun markAllAsRead() {
CoroutineScope(Dispatchers.IO).launch {
_refreshingIndicatorProvider.emit(true)
val success = repository.markAllAsRead(items.value)
if (success) {
_toastMessageProvider.emit(R.string.all_posts_read)
} else {
_toastMessageProvider.emit(R.string.all_posts_not_read)
}
_refreshingIndicatorProvider.emit(false)
}
}
} }

View File

@ -11,6 +11,8 @@ import com.russhwolf.settings.Settings
import io.github.aakira.napier.Napier import io.github.aakira.napier.Napier
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class Repository(private val api: SelfossApi, private val apiDetails: ApiDetailsService, private val connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) { class Repository(private val api: SelfossApi, private val apiDetails: ApiDetailsService, private val connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) {
@ -33,18 +35,23 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
var offlineOverride = false var offlineOverride = false
var apiMajorVersion = 0 var apiMajorVersion = 0
var badgeUnread = 0 private val _badgeUnread = MutableStateFlow(0)
set(value) {field = if (value < 0) { 0 } else { value } } val badgeUnread = _badgeUnread.asStateFlow()
var badgeAll = 0 private val _badgeAll = MutableStateFlow(0)
set(value) {field = if (value < 0) { 0 } else { value } } val badgeAll = _badgeAll.asStateFlow()
var badgeStarred = 0 private val _badgeStarred = MutableStateFlow(0)
set(value) {field = if (value < 0) { 0 } else { value } } val badgeStarred = _badgeStarred.asStateFlow()
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
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
updateApiVersion() updateApiVersion()
reloadBadges() isConnectionAvailable.collect { connectionAvailable ->
if (connectionAvailable) {
updateApiVersion()
reloadBadges()
}
}
} }
} }
@ -125,27 +132,31 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
if (isNetworkAvailable()) { if (isNetworkAvailable()) {
val response = api.stats() val response = api.stats()
if (response != null) { if (response != null) {
badgeUnread = response.unread _badgeUnread.value = response.unread
badgeAll = response.total _badgeAll.value = response.total
badgeStarred = response.starred _badgeStarred.value = response.starred
success = true success = true
} }
} else { } else if (itemsCaching) {
// TODO: do this differently, because it's not efficient // TODO: do this differently, because it's not efficient
val dbItems = getDBItems() val dbItems = getDBItems()
badgeUnread = dbItems.filter { item -> item.unread }.size _badgeUnread.value = dbItems.filter { item -> item.unread }.size
badgeStarred = dbItems.filter { item -> item.starred }.size _badgeStarred.value = dbItems.filter { item -> item.starred }.size
badgeAll = items.size _badgeAll.value = dbItems.size
} }
return success return success
} }
suspend fun getTags(): List<SelfossModel.Tag>? { suspend fun getTags(): List<SelfossModel.Tag>? {
return if (isNetworkAvailable()) { val tags = if (isNetworkAvailable()) {
api.tags() api.tags()
} else { } else {
getDBTags().map { it.toView() } getDBTags().map { it.toView() }
} }
if (tags != null) {
resetDBTagsWithData(tags)
}
return tags
} }
suspend fun getSpouts(): Map<String, SelfossModel.Spout>? { suspend fun getSpouts(): Map<String, SelfossModel.Spout>? {
@ -157,12 +168,15 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
} }
suspend fun getSources(): ArrayList<SelfossModel.Source>? { suspend fun getSources(): ArrayList<SelfossModel.Source>? {
val sources = if (isNetworkAvailable()) {
return if (isNetworkAvailable()) {
api.sources() api.sources()
} else { } else {
ArrayList(getDBSources().map { it.toView() }) ArrayList(getDBSources().map { it.toView() })
} }
if (sources != null) {
resetDBSourcesWithData(sources)
}
return sources
} }
suspend fun markAsRead(item: SelfossModel.Item): Boolean { suspend fun markAsRead(item: SelfossModel.Item): Boolean {
@ -253,7 +267,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
private fun markAsReadLocally(item: SelfossModel.Item) { private fun markAsReadLocally(item: SelfossModel.Item) {
if (item.unread) { if (item.unread) {
item.unread = false item.unread = false
badgeUnread -= 1 _badgeUnread.value -= 1
} }
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
@ -264,7 +278,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
private fun unmarkAsReadLocally(item: SelfossModel.Item) { private fun unmarkAsReadLocally(item: SelfossModel.Item) {
if (!item.unread) { if (!item.unread) {
item.unread = true item.unread = true
badgeUnread += 1 _badgeUnread.value += 1
} }
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
@ -275,7 +289,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
private fun starrLocally(item: SelfossModel.Item) { private fun starrLocally(item: SelfossModel.Item) {
if (!item.starred) { if (!item.starred) {
item.starred = true item.starred = true
badgeStarred += 1 _badgeStarred.value += 1
} }
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
@ -286,7 +300,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
private fun unstarrLocally(item: SelfossModel.Item) { private fun unstarrLocally(item: SelfossModel.Item) {
if (item.starred) { if (item.starred) {
item.starred = false item.starred = false
badgeStarred -= 1 _badgeStarred.value -= 1
} }
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
@ -428,13 +442,16 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item>? { suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item>? {
try { if (itemsCaching) {
val newItems = getMaxItemsForBackground(ItemType.UNREAD) try {
val allItems = getMaxItemsForBackground(ItemType.ALL) val newItems = getMaxItemsForBackground(ItemType.UNREAD)
val starredItems = getMaxItemsForBackground(ItemType.STARRED) val allItems = getMaxItemsForBackground(ItemType.ALL)
insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty()) val starredItems = getMaxItemsForBackground(ItemType.STARRED)
return newItems insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty())
} catch (e: Throwable) {} return newItems
} catch (e: Throwable) {
}
}
return emptyList() return emptyList()
} }