Skip to content

Commit

Permalink
Simplify EntriesModel
Browse files Browse the repository at this point in the history
  • Loading branch information
bubelov committed Apr 17, 2022
1 parent 4086ec3 commit a0d20e1
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 104 deletions.
36 changes: 16 additions & 20 deletions app/src/main/kotlin/entries/EntriesFragment.kt
Expand Up @@ -47,7 +47,7 @@ class EntriesFragment : AppFragment(), Scrollable {
EntriesFragmentArgs.fromBundle(requireArguments())
}

private val model: EntriesViewModel by viewModel()
private val model: EntriesModel by viewModel()
private val sharedModel: EntriesSharedViewModel by sharedViewModel()

private var _binding: FragmentEntriesBinding? = null
Expand Down Expand Up @@ -416,11 +416,12 @@ class EntriesFragment : AppFragment(), Scrollable {
setOnRefreshListener {
lifecycleScope.launch {
runCatching {
model.fetchEntriesFromApi()
model.onPullRefresh()
}.onFailure {
binding.swipeRefresh.isRefreshing = false
showErrorDialog(it)
lifecycleScope.launchWhenResumed { showErrorDialog(it) }
}

binding.swipeRefresh.isRefreshing = false
}
}
}
Expand Down Expand Up @@ -459,19 +460,19 @@ class EntriesFragment : AppFragment(), Scrollable {
}.launchIn(viewLifecycleOwner.lifecycleScope)
}

private suspend fun displayState(state: EntriesViewModel.State?) = binding.apply {
private suspend fun displayState(state: EntriesModel.State?) = binding.apply {
Timber.d("Displaying state ${state?.javaClass?.simpleName}")

when (state) {
null -> {
swipeRefresh.isRefreshing = false
list.hide()
progress.show(animate = true)
progress.hide()
message.hide()
retry.hide()
}

is EntriesViewModel.State.PerformingInitialSync -> {
is EntriesModel.State.PerformingInitialSync -> {
swipeRefresh.isRefreshing = false
list.hide()
progress.show(animate = true)
Expand All @@ -480,7 +481,7 @@ class EntriesFragment : AppFragment(), Scrollable {
retry.hide()
}

is EntriesViewModel.State.FailedToSync -> {
is EntriesModel.State.FailedToSync -> {
swipeRefresh.isRefreshing = false
list.hide()
progress.hide()
Expand All @@ -491,22 +492,21 @@ class EntriesFragment : AppFragment(), Scrollable {
model.onRetry(sharedModel)
}
}
showErrorDialog(state.error)
showErrorDialog(state.cause)
}

EntriesViewModel.State.LoadingEntries -> {
EntriesModel.State.LoadingEntries -> {
swipeRefresh.isRefreshing = false
list.hide()
progress.show(animate = true)
message.hide()
retry.hide()
}

is EntriesViewModel.State.ShowingEntries -> {
is EntriesModel.State.ShowingEntries -> {
Timber.d(
"Showing entries (count = %s, includes_unread = %s, show_background_progress = %s)",
"Showing entries (count = %s, show_background_progress = %s)",
state.entries.count(),
state.includesUnread,
state.showBackgroundProgress,
)

Expand All @@ -515,7 +515,7 @@ class EntriesFragment : AppFragment(), Scrollable {
progress.hide()

if (state.entries.isEmpty()) {
message.text = getEmptyMessage(state.includesUnread)
message.text = getEmptyMessage()
message.show(animate = true)
} else {
message.hide()
Expand All @@ -536,14 +536,10 @@ class EntriesFragment : AppFragment(), Scrollable {
}
}

private fun getEmptyMessage(includesUnread: Boolean): String {
private fun getEmptyMessage(): String {
return when (args.filter) {
is EntriesFilter.Bookmarked -> getString(R.string.you_have_no_bookmarks)
else -> if (includesUnread) {
getString(R.string.news_list_is_empty)
} else {
getString(R.string.you_have_no_unread_news)
}
else -> getString(R.string.news_list_is_empty)
}
}

Expand Down
Expand Up @@ -25,7 +25,7 @@ import timber.log.Timber
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle

class EntriesViewModel(
class EntriesModel(
private val feedsRepository: FeedsRepository,
private val entriesRepository: EntriesRepository,
private val entriesSupportingTextRepository: EntriesSupportingTextRepository,
Expand All @@ -43,13 +43,11 @@ class EntriesViewModel(
init {
viewModelScope.launch {
entriesImagesRepository.selectAll().collectLatest {
val currentState = state.value

if (currentState is State.ShowingEntries) {
state.compareAndSet(
currentState,
currentState.copy(entries = getCachedEntries(getConf().first())),
)
state.update { state ->
when (state) {
is State.ShowingEntries -> state.copy(entries = getCachedEntries())
else -> state
}
}
}
}
Expand All @@ -68,27 +66,42 @@ class EntriesViewModel(
) {
sharedModel.syncedOnStartup = true

if (networkMonitor.online) {
state.value = State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
showBackgroundProgress = true,
)
state.update { State.LoadingEntries }

fetchEntriesFromApi()
} else {
state.value = State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
state.update {
State.ShowingEntries(
entries = getCachedEntries(),
showBackgroundProgress = false,
)
}

if (networkMonitor.online) {
state.update {
when (it) {
is State.ShowingEntries -> it.copy(showBackgroundProgress = true)
else -> it
}
}

val syncResult = newsApiSync.sync()
if (syncResult is SyncResult.Err) throw syncResult.e

state.update {
State.ShowingEntries(
entries = getCachedEntries(),
showBackgroundProgress = false,
)
}
}
} else {
state.value = State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
showBackgroundProgress = false,
)
state.update { State.LoadingEntries }

state.update {
State.ShowingEntries(
entries = getCachedEntries(),
showBackgroundProgress = false,
)
}
}
} else {
sharedModel.syncedOnStartup = true
Expand All @@ -100,8 +113,7 @@ class EntriesViewModel(

state.update {
State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
entries = getCachedEntries(),
showBackgroundProgress = false,
)
}
Expand All @@ -110,28 +122,23 @@ class EntriesViewModel(
}
}
} else {
if (state.value is State.ShowingEntries) {
runCatching {
val conf = getConf().first()

state.value = State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
showBackgroundProgress = false,
)
}.onFailure {
state.value = State.FailedToSync(it)
}
state.update {
State.ShowingEntries(
entries = getCachedEntries(),
showBackgroundProgress = false,
)
}
}
}

suspend fun onRetry(sharedModel: EntriesSharedViewModel) {
state.value = null
state.update { null }
onViewCreated(filter, sharedModel)
}

private suspend fun getCachedEntries(conf: Conf): List<EntriesAdapterItem> {
private suspend fun getCachedEntries(): List<EntriesAdapterItem> {
val conf = getConf().first()

val unsortedEntries = when (val filter = filter) {
is EntriesFilter.NotBookmarked -> {
if (conf.showReadEntries) {
Expand Down Expand Up @@ -170,22 +177,15 @@ class EntriesViewModel(
}
}

suspend fun fetchEntriesFromApi() {
when (val res = newsApiSync.sync()) {
is SyncResult.Ok -> {
if (state.value is State.ShowingEntries) {
val conf = getConf().first()

state.value = State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
showBackgroundProgress = false,
)
}
}
is SyncResult.Err -> {
throw res.e
}
suspend fun onPullRefresh() {
val syncResult = newsApiSync.sync()
if (syncResult is SyncResult.Err) throw syncResult.e

state.update {
State.ShowingEntries(
entries = getCachedEntries(),
showBackgroundProgress = false,
)
}
}

Expand All @@ -194,12 +194,11 @@ class EntriesViewModel(
suspend fun saveConf(conf: Conf) {
this.confRepo.upsert(conf)

if (state.value is State.ShowingEntries) {
state.value = State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
showBackgroundProgress = false,
)
state.update { state ->
when (state) {
is State.ShowingEntries -> state.copy(entries = getCachedEntries())
else -> state
}
}
}

Expand Down Expand Up @@ -251,22 +250,25 @@ class EntriesViewModel(
}

fun show(entry: EntriesAdapterItem, entryIndex: Int) {
val state = state.value

if (state is State.ShowingEntries) {
this.state.value = state.copy(
entries = state.entries.toMutableList().apply { add(entryIndex, entry) }
)
state.update { state ->
when (state) {
is State.ShowingEntries -> state.copy(
entries = state.entries.toMutableList().apply { add(entryIndex, entry) }
)
else -> state
}
}
}

fun hide(entry: EntriesAdapterItem) {
val state = state.value
state.update { state ->
when (state) {
is State.ShowingEntries -> state.copy(
entries = state.entries.toMutableList().apply { removeAll { it == entry } }
)

if (state is State.ShowingEntries) {
this.state.value = state.copy(
entries = state.entries.toMutableList().apply { removeAll { it == entry } }
)
else -> state
}
}
}

Expand Down Expand Up @@ -295,13 +297,12 @@ class EntriesViewModel(
}

if (state.value is State.ShowingEntries) {
val conf = getConf().first()

state.value = State.ShowingEntries(
entries = getCachedEntries(conf),
includesUnread = conf.showReadEntries || filter is EntriesFilter.Bookmarked,
showBackgroundProgress = false,
)
state.update {
State.ShowingEntries(
entries = getCachedEntries(),
showBackgroundProgress = false,
)
}
}

viewModelScope.launch {
Expand Down Expand Up @@ -347,13 +348,12 @@ class EntriesViewModel(

data class PerformingInitialSync(val message: String) : State()

data class FailedToSync(val error: Throwable) : State()
data class FailedToSync(val cause: Throwable) : State()

object LoadingEntries : State()

data class ShowingEntries(
val entries: List<EntriesAdapterItem>,
val includesUnread: Boolean,
val showBackgroundProgress: Boolean,
) : State()
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/kotlin/injections/AppModule.kt
Expand Up @@ -18,7 +18,7 @@ import common.AppViewModel
import common.ConfRepository
import sync.NewsApiSync
import feeds.FeedsRepository
import entries.EntriesViewModel
import entries.EntriesModel
import entries.EntriesRepository
import entry.EntryViewModel
import entriesimages.EntriesImagesRepository
Expand Down Expand Up @@ -72,7 +72,7 @@ val appModule = module {

viewModelOf(::AppViewModel)
viewModelOf(::AuthViewModel)
viewModelOf(::EntriesViewModel)
viewModelOf(::EntriesModel)
viewModelOf(::EntriesSharedViewModel)
viewModelOf(::EntryViewModel)
viewModelOf(::SettingsViewModel)
Expand Down

0 comments on commit a0d20e1

Please sign in to comment.