Compare commits
3 Commits
master
...
dispatcher
Author | SHA1 | Date | |
---|---|---|---|
ac0156748b | |||
8c817b5938 | |||
4857a3d0ac |
@ -17,6 +17,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.*
|
||||
import androidx.work.Constraints
|
||||
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.removeBadge
|
||||
import bou.amine.apps.readerforselfossv2.android.utils.customtabs.CustomTabActivityHelper
|
||||
import bou.amine.apps.readerforselfossv2.dao.ACTION
|
||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
|
||||
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.BottomNavigationItem
|
||||
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||
@ -66,7 +70,6 @@ import org.kodein.di.DIAware
|
||||
import org.kodein.di.android.closestDI
|
||||
import org.kodein.di.instance
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAware {
|
||||
|
||||
@ -118,6 +121,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
override val di by closestDI()
|
||||
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>?)
|
||||
|
||||
@ -142,6 +146,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
|
||||
setContentView(view)
|
||||
lifecycleScope.launch {
|
||||
viewModel.refreshingIndicatorProvider.collect { showRefresh ->
|
||||
binding.swipeRefreshLayout.isRefreshing = showRefresh
|
||||
}
|
||||
}
|
||||
|
||||
handleThemeBinding()
|
||||
|
||||
@ -153,18 +162,25 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
mDrawerToggle.syncState()
|
||||
|
||||
customTabActivityHelper = CustomTabActivityHelper()
|
||||
handleSettings()
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.items.collect { fetchedItems ->
|
||||
items = fetchedItems
|
||||
handleListResult()
|
||||
}
|
||||
}
|
||||
|
||||
handleBottomBar()
|
||||
handleDrawer()
|
||||
|
||||
handleSwipeRefreshLayout()
|
||||
|
||||
handleSettings()
|
||||
|
||||
getElementsAccordingToTab()
|
||||
|
||||
handleBadgesContent()
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.tryToCacheItemsAndGetNewOnes()
|
||||
}
|
||||
|
||||
@ -180,10 +196,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
repository.offlineOverride = false
|
||||
lastFetchDone = false
|
||||
handleDrawerItems()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
getElementsAccordingToTab()
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
viewModel.getItems(false, elementsShown)
|
||||
}
|
||||
|
||||
val simpleItemTouchCallback =
|
||||
@ -219,8 +232,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
adapter.handleItemAtIndex(position)
|
||||
|
||||
reloadBadgeContent()
|
||||
|
||||
val tagHashes = i.tags.map { it.longHash() }
|
||||
tagsBadge = tagsBadge.map {
|
||||
if (tagHashes.contains(it.key)) {
|
||||
@ -252,16 +263,23 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
tabNewBadge = TextBadgeItem()
|
||||
.setText("")
|
||||
.setHideOnSelect(false).hide(false)
|
||||
.setHideOnSelect(false)
|
||||
.setBackgroundColor(appColors.colorPrimary)
|
||||
if (!displayUnreadCount) {
|
||||
tabNewBadge.hide(false)
|
||||
}
|
||||
tabArchiveBadge = TextBadgeItem()
|
||||
.setText("")
|
||||
.setHideOnSelect(false).hide(false)
|
||||
.setHideOnSelect(false)
|
||||
.setBackgroundColor(appColors.colorPrimary)
|
||||
tabStarredBadge = TextBadgeItem()
|
||||
.setText("")
|
||||
.setHideOnSelect(false).hide(false)
|
||||
.setHideOnSelect(false)
|
||||
.setBackgroundColor(appColors.colorPrimary)
|
||||
if (!displayAllCount) {
|
||||
tabArchiveBadge.hide(false)
|
||||
tabStarredBadge.hide(false)
|
||||
}
|
||||
|
||||
val tabNew =
|
||||
BottomNavigationItem(
|
||||
@ -318,7 +336,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
handleRecurringTask()
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.handleDBActions()
|
||||
}
|
||||
|
||||
@ -453,7 +471,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
// TODO: refactor this.
|
||||
private fun handleDrawerItems() {
|
||||
tagsBadge = emptyMap()
|
||||
fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) {
|
||||
fun handleDrawerData(maybeDrawerData: DrawerData?) {
|
||||
fun createDrawerItem(
|
||||
it: SelfossModel.Tag
|
||||
) {
|
||||
@ -495,12 +513,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
fun handleTags(maybeTags: List<SelfossModel.Tag>?) {
|
||||
if (maybeTags == null) {
|
||||
if (loadedFromCache) {
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem()
|
||||
.apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false }
|
||||
)
|
||||
}
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem()
|
||||
.apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false }
|
||||
)
|
||||
} else {
|
||||
val filteredTags = maybeTags
|
||||
.filterNot { hiddenTags.contains(it.tag) }
|
||||
@ -515,14 +531,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
fun handleHiddenTags(maybeTags: List<SelfossModel.Tag>?) {
|
||||
if (maybeTags == null) {
|
||||
if (loadedFromCache) {
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem().apply {
|
||||
nameRes = R.string.drawer_error_loading_tags
|
||||
isSelectable = false
|
||||
}
|
||||
)
|
||||
}
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem().apply {
|
||||
nameRes = R.string.drawer_error_loading_tags
|
||||
isSelectable = false
|
||||
}
|
||||
)
|
||||
} else {
|
||||
val filteredHiddenTags: List<SelfossModel.Tag> =
|
||||
maybeTags.filter { hiddenTags.contains(it.tag) }
|
||||
@ -536,14 +550,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
fun handleSources(maybeSources: List<SelfossModel.Source>?) {
|
||||
if (maybeSources == null) {
|
||||
if (loadedFromCache) {
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem().apply {
|
||||
nameRes = R.string.drawer_error_loading_sources
|
||||
isSelectable = false
|
||||
}
|
||||
)
|
||||
}
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
SecondaryDrawerItem().apply {
|
||||
nameRes = R.string.drawer_error_loading_sources
|
||||
isSelectable = false
|
||||
}
|
||||
)
|
||||
} else {
|
||||
for (source in maybeSources) {
|
||||
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 {
|
||||
if (!loadedFromCache) {
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
PrimaryDrawerItem().apply {
|
||||
nameRes = R.string.no_tags_loaded
|
||||
identifier = DRAWER_ID_TAGS
|
||||
isSelectable = false
|
||||
},
|
||||
PrimaryDrawerItem().apply {
|
||||
nameRes = R.string.no_sources_loaded
|
||||
identifier = DRAWER_ID_SOURCES
|
||||
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)
|
||||
}
|
||||
binding.mainDrawer.itemAdapter.add(
|
||||
PrimaryDrawerItem().apply {
|
||||
nameRes = R.string.no_tags_loaded
|
||||
identifier = DRAWER_ID_TAGS
|
||||
isSelectable = false
|
||||
},
|
||||
PrimaryDrawerItem().apply {
|
||||
nameRes = R.string.no_sources_loaded
|
||||
identifier = DRAWER_ID_SOURCES
|
||||
isSelectable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
tags = repository.getTags()
|
||||
sourcesApiCall()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,12 +667,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
)
|
||||
|
||||
thread {
|
||||
val drawerData = DrawerData(repository.getDBTags().map { it.toView() },
|
||||
repository.getDBSources().map { it.toView() })
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val drawerData = DrawerData(repository.getTags(),
|
||||
repository.getSources())
|
||||
runOnUiThread {
|
||||
handleDrawerData(drawerData, loadedFromCache = true)
|
||||
drawerApiCalls(drawerData)
|
||||
handleDrawerData(drawerData)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -839,21 +808,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
}
|
||||
firstVisible = if (appendResults) firstVisible else 0
|
||||
|
||||
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()
|
||||
}
|
||||
viewModel.getItems(appendResults, elementsShown)
|
||||
}
|
||||
|
||||
private fun handleListResult(appendResults: Boolean = false) {
|
||||
@ -915,26 +870,50 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
private fun reloadBadges() {
|
||||
if (displayUnreadCount || displayAllCount) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.reloadBadges()
|
||||
reloadBadgeContent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadBadgeContent() {
|
||||
private fun handleBadgesContent() {
|
||||
if (displayUnreadCount) {
|
||||
tabNewBadge
|
||||
.setText(repository.badgeUnread.toString())
|
||||
.maybeShow()
|
||||
lifecycleScope.launch {
|
||||
repository.badgeUnread.collect { unreadCount ->
|
||||
if (unreadCount > 0) {
|
||||
tabNewBadge
|
||||
.setText(unreadCount.toString())
|
||||
.maybeShow()
|
||||
} else {
|
||||
tabNewBadge.removeBadge()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displayAllCount) {
|
||||
tabArchiveBadge
|
||||
.setText(repository.badgeAll.toString())
|
||||
.maybeShow()
|
||||
tabStarredBadge
|
||||
.setText(repository.badgeStarred.toString())
|
||||
.maybeShow()
|
||||
lifecycleScope.launch {
|
||||
repository.badgeAll.collect { itemsCount ->
|
||||
if (itemsCount > 0) {
|
||||
tabArchiveBadge
|
||||
.setText(itemsCount.toString())
|
||||
.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) {
|
||||
R.id.refresh -> {
|
||||
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
|
||||
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
viewModel.updateRemote()
|
||||
}
|
||||
return true
|
||||
}
|
||||
R.id.readAll -> {
|
||||
if (elementsShown == ItemType.UNREAD) {
|
||||
needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
|
||||
binding.swipeRefreshLayout.isRefreshing = true
|
||||
|
||||
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
|
||||
}
|
||||
viewModel.markAllAsRead()
|
||||
}
|
||||
}
|
||||
return true
|
||||
@ -1055,10 +992,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
private fun maxItemNumber(): Int =
|
||||
when (elementsShown) {
|
||||
ItemType.UNREAD -> repository.badgeUnread
|
||||
ItemType.ALL -> repository.badgeAll
|
||||
ItemType.STARRED -> repository.badgeStarred
|
||||
else -> repository.badgeUnread // if !elementsShown then unread are fetched.
|
||||
ItemType.UNREAD -> repository.badgeUnread.value
|
||||
ItemType.ALL -> repository.badgeAll.value
|
||||
ItemType.STARRED -> repository.badgeStarred.value
|
||||
else -> repository.badgeUnread.value // if !elementsShown then unread are fetched.
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleOfflineActions() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,15 @@ class MyApp : MultiDexApplication(), DIAware {
|
||||
).show()
|
||||
}
|
||||
}
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
viewModel.toastMessageProvider.collect { toastMessage ->
|
||||
Toast.makeText(
|
||||
applicationContext,
|
||||
toastMessage,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,29 @@ package bou.amine.apps.readerforselfossv2.android.viewmodel
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
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.utils.ItemType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class AppViewModel(private val repository: Repository) : ViewModel() {
|
||||
private val _networkAvailableProvider = MutableSharedFlow<Boolean>()
|
||||
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 val _items = MutableStateFlow(ArrayList<SelfossModel.Item>())
|
||||
val items = _items.asStateFlow()
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
repository.isConnectionAvailable.collect { isConnected ->
|
||||
@ -28,4 +41,44 @@ 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) {
|
||||
// TODO: Find a way to use Dispatchers.IO without creating conflicts
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,8 @@ import com.russhwolf.settings.Settings
|
||||
import io.github.aakira.napier.Napier
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
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 apiMajorVersion = 0
|
||||
var badgeUnread = 0
|
||||
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||
var badgeAll = 0
|
||||
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||
var badgeStarred = 0
|
||||
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||
private val _badgeUnread = MutableStateFlow(0)
|
||||
val badgeUnread = _badgeUnread.asStateFlow()
|
||||
private val _badgeAll = MutableStateFlow(0)
|
||||
val badgeAll = _badgeAll.asStateFlow()
|
||||
private val _badgeStarred = MutableStateFlow(0)
|
||||
val badgeStarred = _badgeStarred.asStateFlow()
|
||||
|
||||
init {
|
||||
// TODO: Dispatchers.IO not available in KMM, an alternative solution should be found
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
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()) {
|
||||
val response = api.stats()
|
||||
if (response != null) {
|
||||
badgeUnread = response.unread
|
||||
badgeAll = response.total
|
||||
badgeStarred = response.starred
|
||||
_badgeUnread.value = response.unread
|
||||
_badgeAll.value = response.total
|
||||
_badgeStarred.value = response.starred
|
||||
success = true
|
||||
}
|
||||
} else {
|
||||
} else if (itemsCaching) {
|
||||
// TODO: do this differently, because it's not efficient
|
||||
val dbItems = getDBItems()
|
||||
badgeUnread = dbItems.filter { item -> item.unread }.size
|
||||
badgeStarred = dbItems.filter { item -> item.starred }.size
|
||||
badgeAll = items.size
|
||||
_badgeUnread.value = dbItems.filter { item -> item.unread }.size
|
||||
_badgeStarred.value = dbItems.filter { item -> item.starred }.size
|
||||
_badgeAll.value = dbItems.size
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun getTags(): List<SelfossModel.Tag>? {
|
||||
return if (isNetworkAvailable()) {
|
||||
val tags = if (isNetworkAvailable()) {
|
||||
api.tags()
|
||||
} else {
|
||||
getDBTags().map { it.toView() }
|
||||
}
|
||||
if (tags != null) {
|
||||
resetDBTagsWithData(tags)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
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>? {
|
||||
|
||||
return if (isNetworkAvailable()) {
|
||||
val sources = if (isNetworkAvailable()) {
|
||||
api.sources()
|
||||
} else {
|
||||
ArrayList(getDBSources().map { it.toView() })
|
||||
}
|
||||
if (sources != null) {
|
||||
resetDBSourcesWithData(sources)
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
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) {
|
||||
if (item.unread) {
|
||||
item.unread = false
|
||||
badgeUnread -= 1
|
||||
_badgeUnread.value -= 1
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
@ -264,7 +278,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
|
||||
private fun unmarkAsReadLocally(item: SelfossModel.Item) {
|
||||
if (!item.unread) {
|
||||
item.unread = true
|
||||
badgeUnread += 1
|
||||
_badgeUnread.value += 1
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
@ -275,7 +289,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
|
||||
private fun starrLocally(item: SelfossModel.Item) {
|
||||
if (!item.starred) {
|
||||
item.starred = true
|
||||
badgeStarred += 1
|
||||
_badgeStarred.value += 1
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
@ -286,7 +300,7 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
|
||||
private fun unstarrLocally(item: SelfossModel.Item) {
|
||||
if (item.starred) {
|
||||
item.starred = false
|
||||
badgeStarred -= 1
|
||||
_badgeStarred.value -= 1
|
||||
}
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
@ -428,13 +442,16 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
|
||||
|
||||
|
||||
suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item>? {
|
||||
try {
|
||||
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
||||
val allItems = getMaxItemsForBackground(ItemType.ALL)
|
||||
val starredItems = getMaxItemsForBackground(ItemType.STARRED)
|
||||
insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty())
|
||||
return newItems
|
||||
} catch (e: Throwable) {}
|
||||
if (itemsCaching) {
|
||||
try {
|
||||
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
||||
val allItems = getMaxItemsForBackground(ItemType.ALL)
|
||||
val starredItems = getMaxItemsForBackground(ItemType.STARRED)
|
||||
insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty())
|
||||
return newItems
|
||||
} catch (e: Throwable) {
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user