Add notifications page

This commit is contained in:
Alessio 2024-08-31 23:23:22 -07:00
parent 1f392f5240
commit 665e6a31dd
12 changed files with 136 additions and 10 deletions

View File

@ -118,6 +118,6 @@ func (app *Application) ChangeSession(w http.ResponseWriter, r *http.Request) {
app.error_400_with_message(w, r, fmt.Sprintf("User not in database: %s", form.AccountName))
return
}
data := Notifications{NumMessageNotifications: len(app.Profile.GetUnreadConversations(app.ActiveUser.ID))}
data := NotificationBubbles{NumMessageNotifications: len(app.Profile.GetUnreadConversations(app.ActiveUser.ID))}
app.buffered_render_htmx(w, "nav-sidebar", PageGlobalData{}, data)
}

View File

@ -0,0 +1,11 @@
package webserver
import (
"net/http"
)
func (app *Application) Notifications(w http.ResponseWriter, r *http.Request) {
feed := app.Profile.GetNotificationsForUser(app.ActiveUser.ID, 0)
app.buffered_render_page(w, "tpl/notifications.tpl", PageGlobalData{TweetTrove: feed.TweetTrove}, feed)
}

View File

@ -13,6 +13,6 @@ func (app *Application) NavSidebarPollUpdates(w http.ResponseWriter, r *http.Req
return
}
data := Notifications{NumMessageNotifications: len(app.Profile.GetUnreadConversations(app.ActiveUser.ID))}
data := NotificationBubbles{NumMessageNotifications: len(app.Profile.GetUnreadConversations(app.ActiveUser.ID))}
app.buffered_render_htmx(w, "nav-sidebar", PageGlobalData{}, data)
}

View File

@ -15,7 +15,7 @@ import (
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
)
type Notifications struct {
type NotificationBubbles struct {
NumMessageNotifications int
}
@ -24,8 +24,8 @@ type PageGlobalData struct {
scraper.TweetTrove
SearchText string
FocusedTweetID scraper.TweetID
Notifications
Toasts []Toast
Toasts []Toast
NotificationBubbles
}
func (d PageGlobalData) Tweet(id scraper.TweetID) scraper.Tweet {
@ -40,6 +40,9 @@ func (d PageGlobalData) Retweet(id scraper.TweetID) scraper.Retweet {
func (d PageGlobalData) Space(id scraper.SpaceID) scraper.Space {
return d.Spaces[id]
}
func (d PageGlobalData) Notification(id scraper.NotificationID) scraper.Notification {
return d.Notifications[id]
}
func (d PageGlobalData) Message(id scraper.DMMessageID) scraper.DMMessage {
return d.Messages[id]
}
@ -95,7 +98,7 @@ func (r renderer) BufferedRender(w io.Writer) {
func (app *Application) buffered_render_page(w http.ResponseWriter, tpl_file string, global_data PageGlobalData, tpl_data interface{}) {
partials := append(glob("tpl/includes/*.tpl"), glob("tpl/tweet_page_includes/*.tpl")...)
global_data.Notifications.NumMessageNotifications = len(app.Profile.GetUnreadConversations(app.ActiveUser.ID))
global_data.NotificationBubbles.NumMessageNotifications = len(app.Profile.GetUnreadConversations(app.ActiveUser.ID))
r := renderer{
Funcs: app.make_funcmap(global_data),
@ -127,6 +130,7 @@ func (app *Application) make_funcmap(global_data PageGlobalData) template.FuncMa
"user": global_data.User,
"retweet": global_data.Retweet,
"space": global_data.Space,
"notification": global_data.Notification,
"dm_message": global_data.Message,
"chat_room": global_data.ChatRoom,
"focused_tweet_id": global_data.GetFocusedTweetID,

View File

@ -132,6 +132,8 @@ func (app *Application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.StripPrefix("/lists", http.HandlerFunc(app.Lists)).ServeHTTP(w, r)
case "bookmarks":
app.Bookmarks(w, r)
case "notifications":
app.Notifications(w, r)
case "messages":
http.StripPrefix("/messages", http.HandlerFunc(app.Messages)).ServeHTTP(w, r)
case "nav-sidebar-poll-updates":

View File

@ -888,3 +888,22 @@ func TestMessagesPaginate(t *testing.T) {
require.NoError(err)
assert.Len(cascadia.QueryAll(root, selector(".dm-message")), 2)
}
func TestNotifications(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
// Boilerplate for setting an active user
app := webserver.NewApp(profile)
app.IsScrapingDisabled = true
app.ActiveUser = scraper.User{ID: 1488963321701171204, Handle: "Offline_Twatter"} // Simulate a login
// Notifications page
recorder := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/notifications", nil)
app.ServeHTTP(recorder, req)
resp := recorder.Result()
root, err := html.Parse(resp.Body)
require.NoError(err)
assert.Len(cascadia.QueryAll(root, selector(".notification")), 6)
}

View File

@ -543,7 +543,7 @@ main {
/**
* Tweet module
*/
.tweet {
.tweet, .notification {
padding: 0 1.5em;
position: relative;
z-index: 0; /* Dunno why, but without it, hovering a tweet with a Poll hides the poll fill bars */
@ -940,6 +940,21 @@ main {
}
}
/******************************************************
* Notifications
******************************************************/
/**
* Notifications module
*/
.notification {
.notification__users {
font-size: 0.8em; /* Make the profile images smaller */
}
}
/******************************************************
* Navigation and base page
******************************************************/

View File

@ -35,7 +35,7 @@
/>
</form>
</header>
{{template "nav-sidebar" (global_data).Notifications}}
{{template "nav-sidebar" (global_data).NotificationBubbles}}
<main>
{{template "main" .}}
</main>

View File

@ -20,7 +20,7 @@
</li>
</a>
{{if (not (eq (active_user).Handle "[nobody]"))}}
<a href="#">
<a href="/notifications">
<li class="button labelled-icon">
<img class="svg-icon" src="/static/icons/notifications.svg" width="24" height="24" />
<label class="nav-sidebar__button-label">Notifications</label>

View File

@ -0,0 +1,11 @@
{{define "title"}}Notifications{{end}}
{{define "main"}}
<div class="notifications-header">
<h2>Notifications</h2>
</div>
<div class="timeline">
{{template "timeline" .}}
</div>
{{end}}

View File

@ -0,0 +1,60 @@
{{define "notification"}}
{{$notification := (notification .NotificationID)}}
<div class="notification">
<div class="notification__header">
{{if (not (eq $notification.ActionUserID 0))}}
<div class="notification__users">
{{template "circle-profile-img" (user $notification.ActionUserID)}}
{{/*template "author-info" (user $notification.ActionUserID)*/}}
{{if (gt (len $notification.UserIDs) 1)}}
{{$max_display_users := 10}}
{{range $i, $user_id := $notification.UserIDs}}
{{if (ne $user_id $notification.ActionUserID)}} {{/* don't duplicate main user */}}
{{/* Only render the first 10-ish users */}}
{{if (lt $i $max_display_users)}}
{{template "circle-profile-img" (user $user_id)}}
{{end}}
{{end}}
{{end}}
{{if (gt (len $notification.UserIDs) (add $max_display_users 1))}}
<span class="ellipsis">...</span>
{{end}}
{{end}}
</div>
{{end}}
<div class="notification__text">
{{if (eq $notification.Type 1)}} {{/* LIKE */}}
<b>{{(user $notification.ActionUserID).DisplayName}} liked your tweet</b>
{{else if (eq $notification.Type 2)}} {{/* RETWEET */}}
<b>{{(user $notification.ActionUserID).DisplayName}} retweeted you</b>
{{else if (eq $notification.Type 3)}} {{/* QUOTE_TWEET */}}
<b>{{(user $notification.ActionUserID).DisplayName}} quote-tweeted you</b>
{{else if (eq $notification.Type 4)}} {{/* REPLY */}}
<b>{{(user $notification.ActionUserID).DisplayName}} replied to you</b>
{{else if (eq $notification.Type 5)}} {{/* FOLLOW */}}
<b>{{(user $notification.ActionUserID).DisplayName}} followed you!</b>
{{else if (eq $notification.Type 6)}} {{/* MENTION */}}
<b>{{(user $notification.ActionUserID).DisplayName}} mentioned you</b>
{{else if (eq $notification.Type 7)}} {{/* USER_IS_LIVE */}}
<b>{{(user $notification.ActionUserID).DisplayName}} is live</b>
{{else if (eq $notification.Type 8)}} {{/* POLL_ENDED */}}
<b>Poll ended.</b>
{{else if (eq $notification.Type 9)}} {{/* LOGIN */}}
<b>New login on your account.</b>
{{else if (eq $notification.Type 10)}} {{/* COMMUNITY_PINNED_POST */}}
<b>{{(user $notification.ActionUserID).DisplayName}} posted in community</b>
{{else if (eq $notification.Type 11)}} {{/* RECOMMENDED_POST */}}
<b>You've been recommended a post from {{(user $notification.ActionUserID).DisplayName}}</b>
{{else}}
<b>{{"<<UNKNOWN ID>>: "}}{{$notification.Type}}</b>
{{end}}
</div>
</div>
{{if (ne .TweetID 0)}}
{{template "tweet" .}}
{{end}}
</div>
{{end}}

View File

@ -1,6 +1,10 @@
{{define "timeline"}}
{{range .Items}}
{{template "tweet" .}}
{{if .NotificationID}}
{{template "notification" .}}
{{else}}
{{template "tweet" .}}
{{end}}
{{end}}
<div class="show-more">