Compare commits
No commits in common. "8c817b59383ce5016b35590c7cb666012f7d361d" and "fbcb428e96d66e9384b74f7b38a0bc22d88bc991" have entirely different histories.
8c817b5938
...
fbcb428e96
@ -17,7 +17,6 @@ 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
|
||||||
@ -35,13 +34,10 @@ 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.android.viewmodel.AppViewModel
|
import bou.amine.apps.readerforselfossv2.dao.ACTION
|
||||||
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 bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.*
|
||||||
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
|
||||||
@ -70,6 +66,7 @@ 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 {
|
||||||
|
|
||||||
@ -121,7 +118,6 @@ 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>?)
|
||||||
|
|
||||||
@ -146,11 +142,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
lifecycleScope.launch {
|
|
||||||
viewModel.refreshingIndicatorProvider.collect { showRefresh ->
|
|
||||||
binding.swipeRefreshLayout.isRefreshing = showRefresh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleThemeBinding()
|
handleThemeBinding()
|
||||||
|
|
||||||
@ -162,25 +153,18 @@ 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.IO).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.tryToCacheItemsAndGetNewOnes()
|
repository.tryToCacheItemsAndGetNewOnes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +180,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
repository.offlineOverride = false
|
repository.offlineOverride = false
|
||||||
lastFetchDone = false
|
lastFetchDone = false
|
||||||
handleDrawerItems()
|
handleDrawerItems()
|
||||||
viewModel.getItems(false, elementsShown)
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
getElementsAccordingToTab()
|
||||||
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val simpleItemTouchCallback =
|
val simpleItemTouchCallback =
|
||||||
@ -232,6 +219,8 @@ 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)) {
|
||||||
@ -263,23 +252,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
tabNewBadge = TextBadgeItem()
|
tabNewBadge = TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
.setBackgroundColor(appColors.colorPrimary)
|
||||||
if (!displayUnreadCount) {
|
|
||||||
tabNewBadge.hide(false)
|
|
||||||
}
|
|
||||||
tabArchiveBadge = TextBadgeItem()
|
tabArchiveBadge = TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
.setBackgroundColor(appColors.colorPrimary)
|
||||||
tabStarredBadge = TextBadgeItem()
|
tabStarredBadge = TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
.setBackgroundColor(appColors.colorPrimary)
|
||||||
if (!displayAllCount) {
|
|
||||||
tabArchiveBadge.hide(false)
|
|
||||||
tabStarredBadge.hide(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val tabNew =
|
val tabNew =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
@ -471,7 +453,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?) {
|
fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) {
|
||||||
fun createDrawerItem(
|
fun createDrawerItem(
|
||||||
it: SelfossModel.Tag
|
it: SelfossModel.Tag
|
||||||
) {
|
) {
|
||||||
@ -513,10 +495,12 @@ 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) }
|
||||||
@ -531,12 +515,14 @@ 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) }
|
||||||
@ -550,12 +536,14 @@ 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 {
|
||||||
@ -644,7 +632,20 @@ 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
|
||||||
@ -659,6 +660,35 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.mainDrawer.itemAdapter.add(
|
binding.mainDrawer.itemAdapter.add(
|
||||||
PrimaryDrawerItem().apply {
|
PrimaryDrawerItem().apply {
|
||||||
@ -667,11 +697,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
thread {
|
||||||
val drawerData = DrawerData(repository.getTags(),
|
val drawerData = DrawerData(repository.getDBTags().map { it.toView() },
|
||||||
repository.getSources())
|
repository.getDBSources().map { it.toView() })
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
handleDrawerData(drawerData)
|
handleDrawerData(drawerData, loadedFromCache = true)
|
||||||
|
drawerApiCalls(drawerData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -808,7 +839,21 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
firstVisible = if (appendResults) firstVisible else 0
|
firstVisible = if (appendResults) firstVisible else 0
|
||||||
|
|
||||||
viewModel.getItems(appendResults, elementsShown)
|
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) {
|
||||||
@ -870,50 +915,26 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun reloadBadges() {
|
private fun reloadBadges() {
|
||||||
if (displayUnreadCount || displayAllCount) {
|
if (displayUnreadCount || displayAllCount) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.reloadBadges()
|
repository.reloadBadges()
|
||||||
|
reloadBadgeContent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleBadgesContent() {
|
private fun reloadBadgeContent() {
|
||||||
if (displayUnreadCount) {
|
if (displayUnreadCount) {
|
||||||
lifecycleScope.launch {
|
|
||||||
repository.badgeUnread.collect { unreadCount ->
|
|
||||||
if (unreadCount > 0) {
|
|
||||||
tabNewBadge
|
tabNewBadge
|
||||||
.setText(unreadCount.toString())
|
.setText(repository.badgeUnread.toString())
|
||||||
.maybeShow()
|
.maybeShow()
|
||||||
} else {
|
|
||||||
tabNewBadge.removeBadge()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displayAllCount) {
|
if (displayAllCount) {
|
||||||
lifecycleScope.launch {
|
|
||||||
repository.badgeAll.collect { itemsCount ->
|
|
||||||
if (itemsCount > 0) {
|
|
||||||
tabArchiveBadge
|
tabArchiveBadge
|
||||||
.setText(itemsCount.toString())
|
.setText(repository.badgeAll.toString())
|
||||||
.maybeShow()
|
.maybeShow()
|
||||||
} else {
|
|
||||||
tabArchiveBadge.removeBadge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lifecycleScope.launch {
|
|
||||||
repository.badgeStarred.collect { starredCount ->
|
|
||||||
if (starredCount > 0) {
|
|
||||||
tabStarredBadge
|
tabStarredBadge
|
||||||
.setText(starredCount.toString())
|
.setText(repository.badgeStarred.toString())
|
||||||
.maybeShow()
|
.maybeShow()
|
||||||
} else {
|
|
||||||
tabStarredBadge.removeBadge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,14 +992,56 @@ 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) {
|
||||||
viewModel.updateRemote()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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) {
|
||||||
viewModel.markAllAsRead()
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -992,10 +1055,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun maxItemNumber(): Int =
|
private fun maxItemNumber(): Int =
|
||||||
when (elementsShown) {
|
when (elementsShown) {
|
||||||
ItemType.UNREAD -> repository.badgeUnread.value
|
ItemType.UNREAD -> repository.badgeUnread
|
||||||
ItemType.ALL -> repository.badgeAll.value
|
ItemType.ALL -> repository.badgeAll
|
||||||
ItemType.STARRED -> repository.badgeStarred.value
|
ItemType.STARRED -> repository.badgeStarred
|
||||||
else -> repository.badgeUnread.value // if !elementsShown then unread are fetched.
|
else -> repository.badgeUnread // if !elementsShown then unread are fetched.
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
||||||
@ -1019,4 +1082,9 @@ 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() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,15 +84,6 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
viewModel.toastMessageProvider.collect { toastMessage ->
|
|
||||||
Toast.makeText(
|
|
||||||
applicationContext,
|
|
||||||
toastMessage,
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,29 +3,16 @@ 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 ->
|
||||||
@ -41,43 +28,4 @@ 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -11,8 +11,6 @@ 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) {
|
||||||
@ -35,25 +33,20 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
|
|||||||
var offlineOverride = false
|
var offlineOverride = false
|
||||||
|
|
||||||
var apiMajorVersion = 0
|
var apiMajorVersion = 0
|
||||||
private val _badgeUnread = MutableStateFlow(0)
|
var badgeUnread = 0
|
||||||
val badgeUnread = _badgeUnread.asStateFlow()
|
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||||
private val _badgeAll = MutableStateFlow(0)
|
var badgeAll = 0
|
||||||
val badgeAll = _badgeAll.asStateFlow()
|
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||||
private val _badgeStarred = MutableStateFlow(0)
|
var badgeStarred = 0
|
||||||
val badgeStarred = _badgeStarred.asStateFlow()
|
set(value) {field = if (value < 0) { 0 } else { value } }
|
||||||
|
|
||||||
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()
|
|
||||||
isConnectionAvailable.collect { connectionAvailable ->
|
|
||||||
if (connectionAvailable) {
|
|
||||||
updateApiVersion()
|
updateApiVersion()
|
||||||
reloadBadges()
|
reloadBadges()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
||||||
// TODO: Use the updatedSince parameter
|
// TODO: Use the updatedSince parameter
|
||||||
@ -132,31 +125,27 @@ 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.value = response.unread
|
badgeUnread = response.unread
|
||||||
_badgeAll.value = response.total
|
badgeAll = response.total
|
||||||
_badgeStarred.value = response.starred
|
badgeStarred = response.starred
|
||||||
success = true
|
success = true
|
||||||
}
|
}
|
||||||
} else if (itemsCaching) {
|
} else {
|
||||||
// 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.value = dbItems.filter { item -> item.unread }.size
|
badgeUnread = dbItems.filter { item -> item.unread }.size
|
||||||
_badgeStarred.value = dbItems.filter { item -> item.starred }.size
|
badgeStarred = dbItems.filter { item -> item.starred }.size
|
||||||
_badgeAll.value = dbItems.size
|
badgeAll = items.size
|
||||||
}
|
}
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getTags(): List<SelfossModel.Tag>? {
|
suspend fun getTags(): List<SelfossModel.Tag>? {
|
||||||
val tags = if (isNetworkAvailable()) {
|
return 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>? {
|
||||||
@ -168,15 +157,12 @@ 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 {
|
||||||
@ -267,7 +253,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.value -= 1
|
badgeUnread -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -278,7 +264,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.value += 1
|
badgeUnread += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -289,7 +275,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.value += 1
|
badgeStarred += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -300,7 +286,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.value -= 1
|
badgeStarred -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@ -442,16 +428,13 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
|
|||||||
|
|
||||||
|
|
||||||
suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item>? {
|
suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item>? {
|
||||||
if (itemsCaching) {
|
|
||||||
try {
|
try {
|
||||||
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
||||||
val allItems = getMaxItemsForBackground(ItemType.ALL)
|
val allItems = getMaxItemsForBackground(ItemType.ALL)
|
||||||
val starredItems = getMaxItemsForBackground(ItemType.STARRED)
|
val starredItems = getMaxItemsForBackground(ItemType.STARRED)
|
||||||
insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty())
|
insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty())
|
||||||
return newItems
|
return newItems
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {}
|
||||||
}
|
|
||||||
}
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user