Skip to content

Commit d0e8d3a

Browse files
committed
Pin and unpin feeds
1 parent e4a492c commit d0e8d3a

File tree

2 files changed

+115
-10
lines changed

2 files changed

+115
-10
lines changed

lib/ex_rss_web/feed_live/index.ex

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ defmodule ExRssWeb.FeedLive.Index do
2222
join: e in Entry,
2323
on: f.id == e.feed_id,
2424
group_by: f.id,
25+
order_by: [desc_nulls_last: f.position],
2526
select: %{
2627
f
2728
| unread_entries_count: filter(count(e.id), e.read == false),
@@ -101,6 +102,94 @@ defmodule ExRssWeb.FeedLive.Index do
101102
end
102103
end
103104

105+
def handle_event("pin_feed", %{"feed-id" => feed_id}, socket) do
106+
update_feed_position(feed_id, 0, socket)
107+
end
108+
109+
def handle_event("unpin_feed", %{"feed-id" => feed_id}, socket) do
110+
update_feed_position(feed_id, nil, socket)
111+
end
112+
113+
def update_feed_position(feed_id, position, socket) do
114+
changeset =
115+
Repo.get!(User, socket.assigns.current_user.id)
116+
|> Ecto.assoc(:feeds)
117+
|> Repo.get!(feed_id)
118+
|> Feed.changeset(%{"position" => position})
119+
120+
case Repo.update(changeset) do
121+
{:ok, feed} ->
122+
current_user = Repo.get!(User, socket.assigns.current_user.id)
123+
124+
feeds_of_current_user = current_user |> Ecto.assoc(:feeds)
125+
126+
feeds_with_counts =
127+
from(
128+
f in feeds_of_current_user,
129+
join: e in Entry,
130+
on: f.id == e.feed_id,
131+
group_by: f.id,
132+
order_by: [desc_nulls_last: f.position],
133+
select: %{
134+
f
135+
| unread_entries_count: filter(count(e.id), e.read == false),
136+
read_entries_count: filter(count(e.id), e.read == true),
137+
has_error: f.retries > 0
138+
}
139+
)
140+
141+
feeds =
142+
feeds_with_counts
143+
|> Repo.all()
144+
|> Repo.preload(
145+
entries: from(e in Entry, where: e.read == false, order_by: [desc: e.posted_at])
146+
)
147+
148+
feed_with_counts_query =
149+
from(
150+
f in Feed,
151+
join: e in Entry,
152+
on: f.id == e.feed_id,
153+
group_by: f.id,
154+
select: %{
155+
f
156+
| unread_entries_count: filter(count(e.id), e.read == false),
157+
read_entries_count: filter(count(e.id), e.read == true),
158+
has_error: f.retries > 0
159+
}
160+
)
161+
162+
updated_feed =
163+
Repo.get!(feed_with_counts_query, feed.id)
164+
|> Repo.preload(
165+
entries: from(e in Entry, where: e.read == false, order_by: [desc: e.posted_at])
166+
)
167+
168+
update_broadcaster =
169+
Application.get_env(:ex_rss, :update_broadcaster, ExRss.Crawler.UpdateBroadcaster)
170+
171+
Task.Supervisor.start_child(
172+
ExRss.TaskSupervisor,
173+
update_broadcaster,
174+
:broadcast_update,
175+
[updated_feed]
176+
)
177+
178+
oldest_unread_entry =
179+
User.oldest_unread_entry(socket.assigns.current_user.id)
180+
181+
socket =
182+
socket
183+
|> assign(:oldest_unread_entry, oldest_unread_entry)
184+
|> stream(:feeds, feeds, reset: true)
185+
186+
{:noreply, socket}
187+
188+
_ ->
189+
{:noreply, socket}
190+
end
191+
end
192+
104193
# 2024-12-03
105194
# This `use` is needed for `content_tag` to be available in `elm_module`.
106195
use Phoenix.HTML

lib/ex_rss_web/feed_live/index.html.heex

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,33 @@
1010

1111
<ul id="live-feeds" phx-update="stream">
1212
<li :for={{dom_id, feed} <- @streams.feeds} id={dom_id}>
13-
<h1 class="mb-2 font-bold"><%= feed.title %></h1>
13+
<div class="flex">
14+
<div>
15+
<h1 class="mb-2 font-bold"><%= feed.title %></h1>
1416

15-
<ul class="mb-4">
16-
<li class="inline-block mr-2">
17-
<%= feed.read_entries_count + feed.unread_entries_count %> entries
18-
</li>
19-
<li class="inline-block mr-2"><%= feed.unread_entries_count %> unread</li>
20-
<li class="inline-block mr-2">
21-
last successful update at <%= feed.last_successful_update_at %>
22-
</li>
23-
</ul>
17+
<ul class="mb-4">
18+
<li class="inline-block mr-2">
19+
<%= feed.read_entries_count + feed.unread_entries_count %> entries
20+
</li>
21+
<li class="inline-block mr-2"><%= feed.unread_entries_count %> unread</li>
22+
<li class="inline-block mr-2">
23+
last successful update at <%= feed.last_successful_update_at %>
24+
</li>
25+
</ul>
26+
</div>
27+
28+
<div class="md:shrink-0 flex self-start justify-end mt-1 ml-auto space-x-4">
29+
<%= if is_nil(feed.position) do %>
30+
<button aria-label="Pin feed" phx-click="pin_feed" phx-value-feed-id={feed.id}>
31+
<.icon name="hero-bookmark-solid" />
32+
</button>
33+
<% else %>
34+
<button aria-label="Unpin feed" phx-click="unpin_feed" phx-value-feed-id={feed.id}>
35+
<.icon name="hero-bookmark-slash-solid" />
36+
</button>
37+
<% end %>
38+
</div>
39+
</div>
2440

2541
<.entries entries={feed.entries} />
2642
</li>

0 commit comments

Comments
 (0)