Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions client/src/main/scala/client/Home.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,29 @@ object Home:
private val feedsObserver =
feedVar.updater[FeedItemList]((xs1, xs2) => (xs1 ++: xs2).distinctBy(_.link))

private val hasMoreObserver = Observer[FeedItemList] { xs =>
hasMoreVar.set(xs.size == pageLimit)
}

private val unreadCountObserver = Observer[Try[Int]] {
case Success(count) => unreadCountVar.set(count)
case Failure(err) => handleError(err)
}

private def bindFeeds(stream: EventStream[Try[FeedItemList]], owner: Owner): Unit =
val data = stream.collectSuccess
val errors = stream.collectFailure
data.addObserver(feedsObserver)(owner)
data.addObserver(hasMoreObserver)(owner)
errors.addObserver(errorObserver)(owner)

def render: Element =
div(
cls := "cards main-content",
cls := "main-content",
div(
onMountBind(ctx =>
refreshFeedsBus --> { page =>
val response = getChannelsAndFeedsRequest(page)
val data = response.collectSuccess
val errors = response.collectFailure
data.addObserver(feedsObserver)(ctx.owner)
errors.addObserver(errorObserver)(ctx.owner)
bindFeeds(getChannelsAndFeedsRequest(page), ctx.owner)
}
),
div(
Expand Down Expand Up @@ -95,22 +102,23 @@ object Home:
_.design := ButtonDesign.Transparent,
_.icon := IconName.download,
"More News",
onClick.mapTo(feedVar.now().size / pageLimit + 1) --> Home.refreshFeedsBus,
hidden <-- feedVar.signal.map(xs => xs.isEmpty)
onClick.mapTo(
(feedVar.now().size + pageLimit - 1) / pageLimit + 1
) --> Home.refreshFeedsBus,
hidden <-- feedSignal.combineWith(hasMoreSignal).map { case (feeds, hasMore) =>
feeds.isEmpty || !hasMore
}
Comment on lines +108 to +110

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This logic correctly hides the 'More News' button. However, there's a related high-severity issue in the pagination logic on the preceding line (103). The current page calculation, onClick.mapTo(feedVar.now().size / pageLimit + 1), can lead to an infinite loop of fetching the same page. This occurs if a new page of feeds contains items that are already loaded, as feedsObserver uses distinctBy(_.link). In this case, feedVar.now().size won't increase by a full page, causing the same page number to be calculated on the next click.

To fix this, the page number calculation should be more robust. For example, using ceiling division:

(feedVar.now().size + pageLimit - 1) / pageLimit + 1

Since this issue is on an unchanged line, I'm adding this comment here for visibility.

)
)
)

private def feeds(): Element =
val response = getChannelsAndFeedsRequest(1)
val data = response.collectSuccess
val errors = response.collectFailure
val stream = getChannelsAndFeedsRequest(1)
val unreadCountResponse = getUnreadCountRequest()
UList(
onMountCallback(ctx => bindFeeds(stream, ctx.owner)),
_.noDataText := "Nothing to read",
children <-- feedSignal.split(_.link)(renderItem),
data --> feedsObserver,
errors --> errorObserver,
unreadCountResponse --> unreadCountObserver
)

Expand Down
2 changes: 2 additions & 0 deletions client/src/main/scala/client/Models.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ final class Model:
val channelVar: Var[ChannelList] = Var(List())
val settingsVar: Var[Option[UserSettings]] = Var(Option.empty)
val unreadCountVar: Var[Int] = Var(0)
val hasMoreVar: Var[Boolean] = Var(true)
val feedSignal: StrictSignal[FeedItemList] = feedVar.signal
val channelSignal: StrictSignal[ChannelList] = channelVar.signal
val settingsSignal: StrictSignal[Option[UserSettings]] = settingsVar.signal
val unreadCountSignal: StrictSignal[Int] = unreadCountVar.signal
val hasMoreSignal: StrictSignal[Boolean] = hasMoreVar.signal