Add user setting for marking entry as read on view

This commit is contained in:
xl 2023-03-17 21:56:17 +08:00 committed by Frédéric Guillot
parent 6046a74a64
commit 356d32c6fe
35 changed files with 84 additions and 29 deletions

View file

@ -40,6 +40,7 @@ type User struct {
CJKReadingSpeed int `json:"cjk_reading_speed"` CJKReadingSpeed int `json:"cjk_reading_speed"`
DefaultHomePage string `json:"default_home_page"` DefaultHomePage string `json:"default_home_page"`
CategoriesSortingOrder string `json:"categories_sorting_order"` CategoriesSortingOrder string `json:"categories_sorting_order"`
MarkReadOnView bool `json:"mark_read_on_view"`
} }
func (u User) String() string { func (u User) String() string {
@ -78,6 +79,7 @@ type UserModificationRequest struct {
CJKReadingSpeed *int `json:"cjk_reading_speed"` CJKReadingSpeed *int `json:"cjk_reading_speed"`
DefaultHomePage *string `json:"default_home_page"` DefaultHomePage *string `json:"default_home_page"`
CategoriesSortingOrder *string `json:"categories_sorting_order"` CategoriesSortingOrder *string `json:"categories_sorting_order"`
MarkReadOnView *bool `json:"mark_read_on_view"`
} }
// Users represents a list of users. // Users represents a list of users.

View file

@ -702,4 +702,9 @@ var migrations = []func(tx *sql.Tx) error{
return nil return nil
}, },
func(tx *sql.Tx) (err error) {
sql := `ALTER TABLE users ADD COLUMN mark_read_on_view boolean default 't'`
_, err = tx.Exec(sql)
return err
},
} }

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Eintrag Sortierspalte", "form.prefs.label.entry_order": "Eintrag Sortierspalte",
"form.prefs.label.default_home_page": "Standard Startseite", "form.prefs.label.default_home_page": "Standard Startseite",
"form.prefs.label.categories_sorting_order": "Kategorien sortieren", "form.prefs.label.categories_sorting_order": "Kategorien sortieren",
"form.prefs.label.mark_read_on_view": "Einträge automatisch als gelesen markieren, wenn sie angezeigt werden",
"form.import.label.file": "OPML Datei", "form.import.label.file": "OPML Datei",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Fever API aktivieren", "form.integration.fever_activate": "Fever API aktivieren",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου", "form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου",
"form.prefs.label.default_home_page": "Προεπιλεγμένη αρχική σελίδα", "form.prefs.label.default_home_page": "Προεπιλεγμένη αρχική σελίδα",
"form.prefs.label.categories_sorting_order": "Ταξινόμηση κατηγοριών", "form.prefs.label.categories_sorting_order": "Ταξινόμηση κατηγοριών",
"form.prefs.label.mark_read_on_view": "Αυτόματη επισήμανση καταχωρήσεων ως αναγνωσμένων κατά την προβολή",
"form.import.label.file": "Αρχείο OPML", "form.import.label.file": "Αρχείο OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Ενεργοποιήστε το Fever API", "form.integration.fever_activate": "Ενεργοποιήστε το Fever API",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Entry sorting column", "form.prefs.label.entry_order": "Entry sorting column",
"form.prefs.label.default_home_page": "Default home page", "form.prefs.label.default_home_page": "Default home page",
"form.prefs.label.categories_sorting_order": "Categories sorting", "form.prefs.label.categories_sorting_order": "Categories sorting",
"form.prefs.label.mark_read_on_view": "Automatically mark entries as read when viewed",
"form.import.label.file": "OPML file", "form.import.label.file": "OPML file",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activate Fever API", "form.integration.fever_activate": "Activate Fever API",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Columna de clasificación de artículos", "form.prefs.label.entry_order": "Columna de clasificación de artículos",
"form.prefs.label.default_home_page": "Página de inicio por defecto", "form.prefs.label.default_home_page": "Página de inicio por defecto",
"form.prefs.label.categories_sorting_order": "Clasificación por categorías", "form.prefs.label.categories_sorting_order": "Clasificación por categorías",
"form.prefs.label.mark_read_on_view": "Marcar automáticamente las entradas como leídas cuando se vean",
"form.import.label.file": "Archivo OPML", "form.import.label.file": "Archivo OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activar API de Fever", "form.integration.fever_activate": "Activar API de Fever",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Lajittele sarakkeen mukaan", "form.prefs.label.entry_order": "Lajittele sarakkeen mukaan",
"form.prefs.label.default_home_page": "Oletusarvoinen etusivu", "form.prefs.label.default_home_page": "Oletusarvoinen etusivu",
"form.prefs.label.categories_sorting_order": "Kategorioiden lajittelu", "form.prefs.label.categories_sorting_order": "Kategorioiden lajittelu",
"form.prefs.label.mark_read_on_view": "Merkitse kohdat automaattisesti luetuiksi, kun niitä tarkastellaan",
"form.import.label.file": "OPML-tiedosto", "form.import.label.file": "OPML-tiedosto",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Ota Fever API käyttöön", "form.integration.fever_activate": "Ota Fever API käyttöön",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Colonne de tri des entrées", "form.prefs.label.entry_order": "Colonne de tri des entrées",
"form.prefs.label.default_home_page": "Page d'accueil par défaut", "form.prefs.label.default_home_page": "Page d'accueil par défaut",
"form.prefs.label.categories_sorting_order": "Colonne de tri des catégories", "form.prefs.label.categories_sorting_order": "Colonne de tri des catégories",
"form.prefs.label.mark_read_on_view": "Marquer automatiquement les entrées comme lues lorsqu'elles sont consultées",
"form.import.label.file": "Fichier OPML", "form.import.label.file": "Fichier OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activer l'API de Fever", "form.integration.fever_activate": "Activer l'API de Fever",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "प्रवेश छँटाई कॉलम", "form.prefs.label.entry_order": "प्रवेश छँटाई कॉलम",
"form.prefs.label.default_home_page": "डिफ़ॉल्ट होमपेज़", "form.prefs.label.default_home_page": "डिफ़ॉल्ट होमपेज़",
"form.prefs.label.categories_sorting_order": "श्रेणियाँ छँटाई", "form.prefs.label.categories_sorting_order": "श्रेणियाँ छँटाई",
"form.prefs.label.mark_read_on_view": "देखे जाने पर स्वचालित रूप से प्रविष्टियों को पढ़ने के रूप में चिह्नित करें",
"form.import.label.file": "ओपीएमएल फ़ाइल", "form.import.label.file": "ओपीएमएल फ़ाइल",
"form.import.label.url": "यूआरएल", "form.import.label.url": "यूआरएल",
"form.integration.fever_activate": "फीवर एपीआई सक्रिय करें", "form.integration.fever_activate": "फीवर एपीआई सक्रिय करें",

View file

@ -319,6 +319,7 @@
"form.prefs.label.entry_order": "Pengurutan Kolom Entri", "form.prefs.label.entry_order": "Pengurutan Kolom Entri",
"form.prefs.label.default_home_page": "Beranda Baku", "form.prefs.label.default_home_page": "Beranda Baku",
"form.prefs.label.categories_sorting_order": "Pengurutan Kategori", "form.prefs.label.categories_sorting_order": "Pengurutan Kategori",
"form.prefs.label.mark_read_on_view": "Secara otomatis menandai entri sebagai telah dibaca saat dilihat",
"form.import.label.file": "Berkas OPML", "form.import.label.file": "Berkas OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Aktifkan API Fever", "form.integration.fever_activate": "Aktifkan API Fever",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Colonna di ordinamento delle voci", "form.prefs.label.entry_order": "Colonna di ordinamento delle voci",
"form.prefs.label.default_home_page": "Pagina iniziale predefinita", "form.prefs.label.default_home_page": "Pagina iniziale predefinita",
"form.prefs.label.categories_sorting_order": "Ordinamento delle categorie", "form.prefs.label.categories_sorting_order": "Ordinamento delle categorie",
"form.prefs.label.mark_read_on_view": "Contrassegna automaticamente le voci come lette quando visualizzate",
"form.import.label.file": "File OPML", "form.import.label.file": "File OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Abilita l'API di Fever", "form.integration.fever_activate": "Abilita l'API di Fever",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "記事の表示順の基準", "form.prefs.label.entry_order": "記事の表示順の基準",
"form.prefs.label.default_home_page": "デフォルトのトップページ", "form.prefs.label.default_home_page": "デフォルトのトップページ",
"form.prefs.label.categories_sorting_order": "カテゴリの表示順", "form.prefs.label.categories_sorting_order": "カテゴリの表示順",
"form.prefs.label.mark_read_on_view": "表示時にエントリを自動的に既読としてマークします",
"form.import.label.file": "OPML ファイル", "form.import.label.file": "OPML ファイル",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Fever API を有効にする", "form.integration.fever_activate": "Fever API を有効にする",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Ingang Sorteerkolom", "form.prefs.label.entry_order": "Ingang Sorteerkolom",
"form.prefs.label.default_home_page": "Standaard startpagina", "form.prefs.label.default_home_page": "Standaard startpagina",
"form.prefs.label.categories_sorting_order": "Categorieën sorteren", "form.prefs.label.categories_sorting_order": "Categorieën sorteren",
"form.prefs.label.mark_read_on_view": "Items automatisch markeren als gelezen wanneer ze worden bekeken",
"form.import.label.file": "OPML-bestand", "form.import.label.file": "OPML-bestand",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activeer Fever API", "form.integration.fever_activate": "Activeer Fever API",

View file

@ -324,6 +324,7 @@
"form.prefs.label.entry_order": "Kolumna sortowania wpisów", "form.prefs.label.entry_order": "Kolumna sortowania wpisów",
"form.prefs.label.default_home_page": "Domyślna strona główna", "form.prefs.label.default_home_page": "Domyślna strona główna",
"form.prefs.label.categories_sorting_order": "Sortowanie kategorii", "form.prefs.label.categories_sorting_order": "Sortowanie kategorii",
"form.prefs.label.mark_read_on_view": "Automatycznie oznaczaj wpisy jako przeczytane podczas przeglądania",
"form.import.label.file": "Plik OPML", "form.import.label.file": "Plik OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Aktywuj Fever API", "form.integration.fever_activate": "Aktywuj Fever API",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Coluna de Ordenação de Entrada", "form.prefs.label.entry_order": "Coluna de Ordenação de Entrada",
"form.prefs.label.default_home_page": "Página inicial predefinida", "form.prefs.label.default_home_page": "Página inicial predefinida",
"form.prefs.label.categories_sorting_order": "Classificação das categorias", "form.prefs.label.categories_sorting_order": "Classificação das categorias",
"form.prefs.label.mark_read_on_view": "Marcar automaticamente as entradas como lidas quando visualizadas",
"form.import.label.file": "Arquivo OPML", "form.import.label.file": "Arquivo OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Ativar API do Fever", "form.integration.fever_activate": "Ativar API do Fever",

View file

@ -324,6 +324,7 @@
"form.prefs.label.entry_order": "Столбец сортировки статей", "form.prefs.label.entry_order": "Столбец сортировки статей",
"form.prefs.label.default_home_page": "Домашняя страница по умолчанию", "form.prefs.label.default_home_page": "Домашняя страница по умолчанию",
"form.prefs.label.categories_sorting_order": "Сортировка категорий", "form.prefs.label.categories_sorting_order": "Сортировка категорий",
"form.prefs.label.mark_read_on_view": "Автоматически отмечать записи как прочитанные при просмотре",
"form.import.label.file": "OPML файл", "form.import.label.file": "OPML файл",
"form.import.label.url": "Ссылка", "form.import.label.url": "Ссылка",
"form.integration.fever_activate": "Активировать Fever API", "form.integration.fever_activate": "Активировать Fever API",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "Giriş Sıralama Sütunu", "form.prefs.label.entry_order": "Giriş Sıralama Sütunu",
"form.prefs.label.default_home_page": "Varsayılan ana sayfa", "form.prefs.label.default_home_page": "Varsayılan ana sayfa",
"form.prefs.label.categories_sorting_order": "Kategoriler sıralama", "form.prefs.label.categories_sorting_order": "Kategoriler sıralama",
"form.prefs.label.mark_read_on_view": "Girişleri görüntülendiğinde otomatik olarak okundu olarak işaretle",
"form.import.label.file": "OPML dosyası", "form.import.label.file": "OPML dosyası",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Fever API'yi Etkinleştir", "form.integration.fever_activate": "Fever API'yi Etkinleştir",

View file

@ -321,6 +321,7 @@
"form.prefs.label.entry_order": "Стовпець сортування записів", "form.prefs.label.entry_order": "Стовпець сортування записів",
"form.prefs.label.default_home_page": "Домашня сторінка за умовчанням", "form.prefs.label.default_home_page": "Домашня сторінка за умовчанням",
"form.prefs.label.categories_sorting_order": "Сортування за категоріями", "form.prefs.label.categories_sorting_order": "Сортування за категоріями",
"form.prefs.label.mark_read_on_view": "Автоматично позначати записи як прочитані під час перегляду",
"form.import.label.file": "Файл OPML", "form.import.label.file": "Файл OPML",
"form.import.label.url": "URL-адреса", "form.import.label.url": "URL-адреса",
"form.integration.fever_activate": "Увімкнути API Fever", "form.integration.fever_activate": "Увімкнути API Fever",

View file

@ -320,6 +320,7 @@
"form.prefs.label.entry_order": "文章排序依据", "form.prefs.label.entry_order": "文章排序依据",
"form.prefs.label.default_home_page": "默认主页", "form.prefs.label.default_home_page": "默认主页",
"form.prefs.label.categories_sorting_order": "分类排序", "form.prefs.label.categories_sorting_order": "分类排序",
"form.prefs.label.mark_read_on_view": "查看时自动将条目标记为已读",
"form.import.label.file": "OPML 文件", "form.import.label.file": "OPML 文件",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "启用 Fever API", "form.integration.fever_activate": "启用 Fever API",

View file

@ -322,6 +322,7 @@
"form.prefs.label.entry_order": "文章排序依據", "form.prefs.label.entry_order": "文章排序依據",
"form.prefs.label.default_home_page": "默認主頁", "form.prefs.label.default_home_page": "默認主頁",
"form.prefs.label.categories_sorting_order": "分類排序", "form.prefs.label.categories_sorting_order": "分類排序",
"form.prefs.label.mark_read_on_view": "查看時自動將條目標記為已讀",
"form.import.label.file": "OPML 檔案", "form.import.label.file": "OPML 檔案",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "啟用 Fever API", "form.integration.fever_activate": "啟用 Fever API",

View file

@ -34,6 +34,7 @@ type User struct {
CJKReadingSpeed int `json:"cjk_reading_speed"` CJKReadingSpeed int `json:"cjk_reading_speed"`
DefaultHomePage string `json:"default_home_page"` DefaultHomePage string `json:"default_home_page"`
CategoriesSortingOrder string `json:"categories_sorting_order"` CategoriesSortingOrder string `json:"categories_sorting_order"`
MarkReadOnView bool `json:"mark_read_on_view"`
} }
// UserCreationRequest represents the request to create a user. // UserCreationRequest represents the request to create a user.
@ -68,6 +69,7 @@ type UserModificationRequest struct {
CJKReadingSpeed *int `json:"cjk_reading_speed"` CJKReadingSpeed *int `json:"cjk_reading_speed"`
DefaultHomePage *string `json:"default_home_page"` DefaultHomePage *string `json:"default_home_page"`
CategoriesSortingOrder *string `json:"categories_sorting_order"` CategoriesSortingOrder *string `json:"categories_sorting_order"`
MarkReadOnView *bool `json:"mark_read_on_view"`
} }
// Patch updates the User object with the modification request. // Patch updates the User object with the modification request.
@ -155,6 +157,10 @@ func (u *UserModificationRequest) Patch(user *User) {
if u.CategoriesSortingOrder != nil { if u.CategoriesSortingOrder != nil {
user.CategoriesSortingOrder = *u.CategoriesSortingOrder user.CategoriesSortingOrder = *u.CategoriesSortingOrder
} }
if u.MarkReadOnView != nil {
user.MarkReadOnView = *u.MarkReadOnView
}
} }
// UseTimezone converts last login date to the given timezone. // UseTimezone converts last login date to the given timezone.

View file

@ -86,10 +86,11 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
openid_connect_id, openid_connect_id,
display_mode, display_mode,
entry_order, entry_order,
default_reading_speed, default_reading_speed,
cjk_reading_speed, cjk_reading_speed,
default_home_page, default_home_page,
categories_sorting_order categories_sorting_order,
mark_read_on_view
` `
tx, err := s.db.Begin() tx, err := s.db.Begin()
@ -127,6 +128,7 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
&user.CJKReadingSpeed, &user.CJKReadingSpeed,
&user.DefaultHomePage, &user.DefaultHomePage,
&user.CategoriesSortingOrder, &user.CategoriesSortingOrder,
&user.MarkReadOnView,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
@ -182,9 +184,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
default_reading_speed=$18, default_reading_speed=$18,
cjk_reading_speed=$19, cjk_reading_speed=$19,
default_home_page=$20, default_home_page=$20,
categories_sorting_order=$21 categories_sorting_order=$21,
mark_read_on_view=$22
WHERE WHERE
id=$22 id=$23
` `
_, err = s.db.Exec( _, err = s.db.Exec(
@ -210,6 +213,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
user.CJKReadingSpeed, user.CJKReadingSpeed,
user.DefaultHomePage, user.DefaultHomePage,
user.CategoriesSortingOrder, user.CategoriesSortingOrder,
user.MarkReadOnView,
user.ID, user.ID,
) )
if err != nil { if err != nil {
@ -237,9 +241,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
default_reading_speed=$17, default_reading_speed=$17,
cjk_reading_speed=$18, cjk_reading_speed=$18,
default_home_page=$19, default_home_page=$19,
categories_sorting_order=$20 categories_sorting_order=$20,
mark_read_on_view=$21
WHERE WHERE
id=$21 id=$22
` `
_, err := s.db.Exec( _, err := s.db.Exec(
@ -264,6 +269,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
user.CJKReadingSpeed, user.CJKReadingSpeed,
user.DefaultHomePage, user.DefaultHomePage,
user.CategoriesSortingOrder, user.CategoriesSortingOrder,
user.MarkReadOnView,
user.ID, user.ID,
) )
@ -310,7 +316,8 @@ func (s *Storage) UserByID(userID int64) (*model.User, error) {
default_reading_speed, default_reading_speed,
cjk_reading_speed, cjk_reading_speed,
default_home_page, default_home_page,
categories_sorting_order categories_sorting_order,
mark_read_on_view
FROM FROM
users users
WHERE WHERE
@ -344,7 +351,8 @@ func (s *Storage) UserByUsername(username string) (*model.User, error) {
default_reading_speed, default_reading_speed,
cjk_reading_speed, cjk_reading_speed,
default_home_page, default_home_page,
categories_sorting_order categories_sorting_order,
mark_read_on_view
FROM FROM
users users
WHERE WHERE
@ -378,7 +386,8 @@ func (s *Storage) UserByField(field, value string) (*model.User, error) {
default_reading_speed, default_reading_speed,
cjk_reading_speed, cjk_reading_speed,
default_home_page, default_home_page,
categories_sorting_order categories_sorting_order,
mark_read_on_view
FROM FROM
users users
WHERE WHERE
@ -419,7 +428,8 @@ func (s *Storage) UserByAPIKey(token string) (*model.User, error) {
u.default_reading_speed, u.default_reading_speed,
u.cjk_reading_speed, u.cjk_reading_speed,
u.default_home_page, u.default_home_page,
u.categories_sorting_order u.categories_sorting_order,
u.mark_read_on_view
FROM FROM
users u users u
LEFT JOIN LEFT JOIN
@ -455,6 +465,7 @@ func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, err
&user.CJKReadingSpeed, &user.CJKReadingSpeed,
&user.DefaultHomePage, &user.DefaultHomePage,
&user.CategoriesSortingOrder, &user.CategoriesSortingOrder,
&user.MarkReadOnView,
) )
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
@ -551,7 +562,8 @@ func (s *Storage) Users() (model.Users, error) {
default_reading_speed, default_reading_speed,
cjk_reading_speed, cjk_reading_speed,
default_home_page, default_home_page,
categories_sorting_order categories_sorting_order,
mark_read_on_view
FROM FROM
users users
ORDER BY username ASC ORDER BY username ASC
@ -588,6 +600,7 @@ func (s *Storage) Users() (model.Users, error) {
&user.CJKReadingSpeed, &user.CJKReadingSpeed,
&user.DefaultHomePage, &user.DefaultHomePage,
&user.CategoriesSortingOrder, &user.CategoriesSortingOrder,
&user.MarkReadOnView,
) )
if err != nil { if err != nil {

View file

@ -20,7 +20,7 @@
<div class="item-meta"> <div class="item-meta">
<ul class="item-meta-info"> <ul class="item-meta-info">
<li class="item-meta-info-site-url" dir="auto"> <li class="item-meta-info-site-url" dir="auto">
<a href="{{ .SiteURL | safeURL }}" title="{{ .SiteURL }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-original-link="true">{{ domain .SiteURL }}</a> <a href="{{ .SiteURL | safeURL }}" title="{{ .SiteURL }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-original-link="{{ $.user.MarkReadOnView }}">{{ domain .SiteURL }}</a>
</li> </li>
<li class="item-meta-info-checked-at"> <li class="item-meta-info-checked-at">
{{ t "page.feeds.last_check" }} <time datetime="{{ isodate .CheckedAt }}" title="{{ isodate .CheckedAt }}">{{ elapsed $.user.Timezone .CheckedAt }}</time> {{ t "page.feeds.last_check" }} <time datetime="{{ isodate .CheckedAt }}" title="{{ isodate .CheckedAt }}">{{ elapsed $.user.Timezone .CheckedAt }}</time>

View file

@ -68,7 +68,7 @@
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
referrerpolicy="no-referrer" referrerpolicy="no-referrer"
data-original-link="true">{{ icon "external-link" }}<span class="icon-label">{{ t "entry.external_link.label" }}</span></a> data-original-link="{{ .user.MarkReadOnView }}">{{ icon "external-link" }}<span class="icon-label">{{ t "entry.external_link.label" }}</span></a>
</li> </li>
{{ if .entry.CommentsURL }} {{ if .entry.CommentsURL }}
<li class="item-meta-icons-comments"> <li class="item-meta-icons-comments">

View file

@ -72,7 +72,7 @@
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
referrerpolicy="no-referrer" referrerpolicy="no-referrer"
data-original-link="true">{{ icon "external-link" }}<span class="icon-label">{{ t "entry.external_link.label" }}</span></a> data-original-link="{{ .user.MarkReadOnView }}">{{ icon "external-link" }}<span class="icon-label">{{ t "entry.external_link.label" }}</span></a>
</li> </li>
<li> <li>
<a href="#" <a href="#"

View file

@ -3,7 +3,7 @@
{{ define "content"}} {{ define "content"}}
<section class="page-header"> <section class="page-header">
<h1 dir="auto"> <h1 dir="auto">
<a href="{{ .feed.SiteURL | safeURL }}" title="{{ .feed.SiteURL }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-original-link="true">{{ .feed.Title }}</a> <a href="{{ .feed.SiteURL | safeURL }}" title="{{ .feed.SiteURL }}" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer" data-original-link="{{ .user.MarkReadOnView }}">{{ .feed.Title }}</a>
({{ .total }}) ({{ .total }})
</h1> </h1>
<ul> <ul>

View file

@ -99,6 +99,8 @@
<label><input type="checkbox" name="show_reading_time" value="1" {{ if .form.ShowReadingTime }}checked{{ end }}> {{ t "form.prefs.label.show_reading_time" }}</label> <label><input type="checkbox" name="show_reading_time" value="1" {{ if .form.ShowReadingTime }}checked{{ end }}> {{ t "form.prefs.label.show_reading_time" }}</label>
<label><input type="checkbox" name="mark_read_on_view" value="1" {{ if .form.MarkReadOnView }}checked{{ end }}> {{ t "form.prefs.label.mark_read_on_view" }}</label>
<label for="form-cjk-reading-speed">{{ t "form.prefs.label.cjk_reading_speed" }}</label> <label for="form-cjk-reading-speed">{{ t "form.prefs.label.cjk_reading_speed" }}</label>
<input type="number" name="cjk_reading_speed" id="form-cjk-reading-speed" value="{{ .form.CJKReadingSpeed }}" min="1"> <input type="number" name="cjk_reading_speed" id="form-cjk-reading-speed" value="{{ .form.CJKReadingSpeed }}" min="1">

View file

@ -38,7 +38,7 @@ func (h *handler) showStarredEntryPage(w http.ResponseWriter, r *http.Request) {
return return
} }
if entry.Status == model.EntryStatusUnread { if user.MarkReadOnView && entry.Status == model.EntryStatusUnread {
err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead) err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)

View file

@ -41,7 +41,7 @@ func (h *handler) showCategoryEntryPage(w http.ResponseWriter, r *http.Request)
return return
} }
if entry.Status == model.EntryStatusUnread { if user.MarkReadOnView && entry.Status == model.EntryStatusUnread {
err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead) err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)

View file

@ -41,7 +41,7 @@ func (h *handler) showFeedEntryPage(w http.ResponseWriter, r *http.Request) {
return return
} }
if entry.Status == model.EntryStatusUnread { if user.MarkReadOnView && entry.Status == model.EntryStatusUnread {
err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead) err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)

View file

@ -40,7 +40,7 @@ func (h *handler) showSearchEntryPage(w http.ResponseWriter, r *http.Request) {
return return
} }
if entry.Status == model.EntryStatusUnread { if user.MarkReadOnView && entry.Status == model.EntryStatusUnread {
err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead) err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead)
if err != nil { if err != nil {
html.ServerError(w, r, err) html.ServerError(w, r, err)

View file

@ -66,13 +66,18 @@ func (h *handler) showUnreadEntryPage(w http.ResponseWriter, r *http.Request) {
prevEntryRoute = route.Path(h.router, "unreadEntry", "entryID", prevEntry.ID) prevEntryRoute = route.Path(h.router, "unreadEntry", "entryID", prevEntry.ID)
} }
// Always mark the entry as read after fetching the pagination. if user.MarkReadOnView {
err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead) entry.Status = model.EntryStatusRead
if err != nil { }
html.ServerError(w, r, err)
return // Restore entry read status if needed after fetching the pagination.
if entry.Status == model.EntryStatusRead {
err = h.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead)
if err != nil {
html.ServerError(w, r, err)
return
}
} }
entry.Status = model.EntryStatusRead
sess := session.New(h.store, request.SessionID(r)) sess := session.New(h.store, request.SessionID(r))
view := view.New(h.tpl, r, sess) view := view.New(h.tpl, r, sess)

View file

@ -32,6 +32,7 @@ type SettingsForm struct {
CJKReadingSpeed int CJKReadingSpeed int
DefaultHomePage string DefaultHomePage string
CategoriesSortingOrder string CategoriesSortingOrder string
MarkReadOnView bool
} }
// Merge updates the fields of the given user. // Merge updates the fields of the given user.
@ -53,6 +54,7 @@ func (s *SettingsForm) Merge(user *model.User) *model.User {
user.DefaultReadingSpeed = s.DefaultReadingSpeed user.DefaultReadingSpeed = s.DefaultReadingSpeed
user.DefaultHomePage = s.DefaultHomePage user.DefaultHomePage = s.DefaultHomePage
user.CategoriesSortingOrder = s.CategoriesSortingOrder user.CategoriesSortingOrder = s.CategoriesSortingOrder
user.MarkReadOnView = s.MarkReadOnView
if s.Password != "" { if s.Password != "" {
user.Password = s.Password user.Password = s.Password
@ -119,5 +121,6 @@ func NewSettingsForm(r *http.Request) *SettingsForm {
CJKReadingSpeed: int(cjkReadingSpeed), CJKReadingSpeed: int(cjkReadingSpeed),
DefaultHomePage: r.FormValue("default_home_page"), DefaultHomePage: r.FormValue("default_home_page"),
CategoriesSortingOrder: r.FormValue("categories_sorting_order"), CategoriesSortingOrder: r.FormValue("categories_sorting_order"),
MarkReadOnView: r.FormValue("mark_read_on_view") == "1",
} }
} }

View file

@ -43,6 +43,7 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
CJKReadingSpeed: user.CJKReadingSpeed, CJKReadingSpeed: user.CJKReadingSpeed,
DefaultHomePage: user.DefaultHomePage, DefaultHomePage: user.DefaultHomePage,
CategoriesSortingOrder: user.CategoriesSortingOrder, CategoriesSortingOrder: user.CategoriesSortingOrder,
MarkReadOnView: user.MarkReadOnView,
} }
timezones, err := h.store.Timezones() timezones, err := h.store.Timezones()

View file

@ -69,10 +69,10 @@ document.addEventListener("DOMContentLoaded", function () {
request.execute(); request.execute();
})); }));
onClick("a[data-original-link]", (event) => { onClick("a[data-original-link='true']", (event) => {
handleEntryStatus("next", event.target, true); handleEntryStatus("next", event.target, true);
}, true); }, true);
onAuxClick("a[data-original-link]", (event) => { onAuxClick("a[data-original-link='true']", (event) => {
if (event.button == 1) { if (event.button == 1) {
handleEntryStatus("next", event.target, true); handleEntryStatus("next", event.target, true);
} }