Просмотр исходного кода

Add option to keep or reset article sort order when navigating (#8969)

* Add option to keep or reset article sort order when navigating

Adds a new per-user reading option, "Keep the current sort order when
navigating between categories and feeds" (config key: sticky_sort), under
Settings > Reading > "Left navigation: Categories". It defaults to enabled,
which reproduces the current behaviour exactly.

Background (addresses #8953)
----------------------------
Once a sort/order was active in one view, it was propagated to every sidebar
link and to the "mark all as read" redirect. Opening another category then
ignored that category's own defaultSort/defaultOrder, because FreshRSS_Context
only applies those defaults when sort/order are absent from the request. As a
result the current view's sort (whether chosen manually or resolved from that
view's default) "bled" into the next category/feed.

Behaviour of the new option
---------------------------
- ON (default): unchanged. The current sort/order stays sticky while
  navigating, exactly as before.
- OFF: sidebar links and the "mark all as read" redirect no longer carry
  sort/order, so each target resolves its own order in FreshRSS_Context:
  feed/category defaultSort/defaultOrder, falling back to the global Reading
  sort criterion when none is configured.

order/sort propagation across the UI (for reference)
----------------------------------------------------
- Categories & feeds (sidebar): now gated by sticky_sort (app/layout/aside_feed.phtml).
- "Mark all as read" -> next category, both the top navigation button and the
  stream-footer button: now gated by sticky_sort
  (app/Controllers/entryController.php::readAction, non-AJAX redirect).
- Custom user queries: unaffected. A query's link is a self-contained URL built
  from that query's own saved parameters, so switching query A -> B never
  carried A's sort; no option is needed there.
- Stream transition links when sorting by category/feed name: intentionally
  left unchanged (out of scope; the sort is intrinsic to that grouping).

Compatibility
-------------
- Not a breaking change: the default (true) reproduces the previous behaviour.
- No database migration. The setting is a standard user configuration value
  with its default declared in config-user.default.php, so existing users keep
  the previous behaviour transparently.
- The read/unread state filter still persists across navigation regardless of
  this option.

i18n
----
English strings authored; en-US marked as IGNORE. Translations for the other
25 languages were produced with an automated (AI) translation service and
should be reviewed by native speakers.

* Update app/i18n/en/conf.php

Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>

* Comments preference

* Update app/i18n/en/conf.php

Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>

* i18n updates and comment

* Update translations to match reworded sticky_sort strings

Re-applies the 24 non-English/French translations of the "sticky_sort"
reading option after the English and French wording was updated to
"Keep manual sort order during navigation".

* improve Dutch

* i18n DIRTY

* i18n en: custom sort order

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Co-authored-by: Frans de Jonge <fransdejonge@gmail.com>
i @man 12 часов назад
Родитель
Сommit
2188070aa6

+ 1 - 0
CHANGELOG.md

@@ -17,6 +17,7 @@ See also [the FreshRSS releases](https://github.com/FreshRSS/FreshRSS/releases).
 	* Fix null warning in IRI for PHP 8.5+ [#8918](https://github.com/FreshRSS/FreshRSS/pull/8918), [simplepie#979](https://github.com/simplepie/simplepie/pull/979)
 * Features
 	* New option to hide badges showing number of unread articles (*Phantom Obligation*) [#8844](https://github.com/FreshRSS/FreshRSS/pull/8844)
+	* New option to keep or not the custom sort order when navigating between categories and feeds [#8969](https://github.com/FreshRSS/FreshRSS/pull/8969)
 * Bug fixing
 	* Fix lost elements while parsing search query [#8884](https://github.com/FreshRSS/FreshRSS/pull/8884)
 * CLI

+ 1 - 1
README.fr.md

@@ -236,7 +236,7 @@ Voir le [dépôt dédié à ces extensions](https://github.com/FreshRSS/Extensio
 | فارسی (fa) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Suomi (fi) | ■■■■■■■■■・ 92% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Français (fr) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
-| עברית (he) | ■■■■・・・・・・ 41% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
+| עברית (he) | ■■■■・・・・・・ 42% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Magyar (hu) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Bahasa Indonesia (id) | ■■■■■■■■・・ 89% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Italiano (it) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%24%2F) |

+ 1 - 1
README.md

@@ -132,7 +132,7 @@ See the [repository dedicated to those extensions](https://github.com/FreshRSS/E
 | فارسی (fa) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Suomi (fi) | ■■■■■■■■■・ 92% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Français (fr) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
-| עברית (he) | ■■■■・・・・・・ 41% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
+| עברית (he) | ■■■■・・・・・・ 42% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Magyar (hu) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Bahasa Indonesia (id) | ■■■■■■■■・・ 89% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fid+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Italiano (it) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fit+%2F%28TODO%7CDIRTY%29%24%2F) |

+ 1 - 0
app/Controllers/configureController.php

@@ -150,6 +150,7 @@ class FreshRSS_configure_Controller extends FreshRSS_ActionController {
 			FreshRSS_Context::userConf()->lazyload = Minz_Request::paramBoolean('lazyload');
 			FreshRSS_Context::userConf()->sides_close_article = Minz_Request::paramBoolean('sides_close_article');
 			FreshRSS_Context::userConf()->sticky_post = Minz_Request::paramBoolean('sticky_post');
+			FreshRSS_Context::userConf()->sticky_sort = Minz_Request::paramBoolean('sticky_sort');
 			$markReadButton = Minz_Request::paramStringNull('mark_read_button', plaintext: true);
 			FreshRSS_Context::userConf()->mark_read_button = in_array($markReadButton, ['big', 'small', 'none'], true) ? $markReadButton : 'big';
 			FreshRSS_Context::userConf()->reading_confirm = Minz_Request::paramBoolean('reading_confirm');

+ 7 - 5
app/Controllers/entryController.php

@@ -202,11 +202,13 @@ class FreshRSS_entry_Controller extends FreshRSS_ActionController {
 		}
 
 		if (!$this->ajax) {
-			if (Minz_Request::hasParam('order')) {
-				$params['order'] = Minz_Request::paramString('order', plaintext: true);
-			}
-			if (Minz_Request::hasParam('sort')) {
-				$params['sort'] = Minz_Request::paramString('sort', plaintext: true);
+			if (FreshRSS_Context::userConf()->sticky_sort) {
+				if (Minz_Request::hasParam('order')) {
+					$params['order'] = Minz_Request::paramString('order', plaintext: true);
+				}
+				if (Minz_Request::hasParam('sort')) {
+					$params['sort'] = Minz_Request::paramString('sort', plaintext: true);
+				}
 			}
 			Minz_Request::good(
 				$is_read ? _t('feedback.sub.articles.marked_read') : _t('feedback.sub.articles.marked_unread'),

+ 1 - 0
app/Models/UserConfiguration.php

@@ -66,6 +66,7 @@ declare(strict_types=1);
  * @property array<string,string> $shortcuts
  * @property bool $sides_close_article
  * @property bool $sticky_post
+ * @property bool $sticky_sort To carry the manual sort/order over to the next navigation
  * @property string $theme
  * @property string $darkMode
  * @property string $token

+ 2 - 0
app/i18n/cs/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Při otevření připnout článek na začátek',
+		'sticky_sort' => 'Zachovat ruční řazení při navigaci',	// DIRTY
+		'sticky_sort_help' => 'Určuje, zda se zachová poslední ruční řazení, nebo zda každá kategorie či kanál vždy použije vlastní výchozí nebo globální nastavení.',	// DIRTY
 		'title' => 'Čtení',
 		'view' => array(
 			'default' => 'Výchozí zobrazení',

+ 2 - 0
app/i18n/de/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Artikel als Favorit markieren…',
 		),
 		'sticky_post' => 'Wenn geöffnet, den Artikel ganz oben anheften',
+		'sticky_sort' => 'Manuelle Sortierung bei der Navigation beibehalten',	// DIRTY
+		'sticky_sort_help' => 'Legt fest, ob die letzte manuelle Sortierung aktiv bleibt oder ob jede Kategorie bzw. jeder Feed immer die eigene Standard- oder globale Einstellung verwendet.',	// DIRTY
 		'title' => 'Lesen',
 		'view' => array(
 			'default' => 'Standard-Ansicht',

+ 2 - 0
app/i18n/el/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Σήμανση άρθρου ως αγαπημένου…',
 		),
 		'sticky_post' => 'Καρφίτσωμα του άρθρου στην κορυφή όταν ανοίγεται',
+		'sticky_sort' => 'Διατήρηση της χειροκίνητης ταξινόμησης κατά την πλοήγηση',	// DIRTY
+		'sticky_sort_help' => 'Καθορίζει αν διατηρείται η τελευταία χειροκίνητη ταξινόμηση ή αν κάθε κατηγορία ή ροή χρησιμοποιεί πάντα τη δική της προεπιλεγμένη ή καθολική ρύθμιση.',	// DIRTY
 		'title' => 'Ανάγνωση',
 		'view' => array(
 			'default' => 'Προεπιλεγμένη προβολή',

+ 2 - 0
app/i18n/en-US/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favorite…',
 		),
 		'sticky_post' => 'Stick the article to the top when opened',	// IGNORE
+		'sticky_sort' => 'Keep custom sort order during navigation',	// IGNORE
+		'sticky_sort_help' => 'Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.',	// IGNORE
 		'title' => 'Reading',	// IGNORE
 		'view' => array(
 			'default' => 'Default view',	// IGNORE

+ 2 - 0
app/i18n/en/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',
 		),
 		'sticky_post' => 'Stick the article to the top when opened',
+		'sticky_sort' => 'Keep custom sort order during navigation',
+		'sticky_sort_help' => 'Determines whether the last custom sort order is kept active or whether each category or feed always uses its own default or global setting.',
 		'title' => 'Reading',
 		'view' => array(
 			'default' => 'Default view',

+ 2 - 0
app/i18n/es/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Marca un artículo como favorito…',
 		),
 		'sticky_post' => 'Fijar el artículo a la parte superior al abrirlo',
+		'sticky_sort' => 'Mantener el orden de clasificación manual durante la navegación',	// DIRTY
+		'sticky_sort_help' => 'Determina si se mantiene activo el último orden de clasificación manual o si cada categoría o fuente usa siempre su propia configuración predeterminada o global.',	// DIRTY
 		'title' => 'Lectura',
 		'view' => array(
 			'default' => 'Vista por defecto',

+ 2 - 0
app/i18n/fa/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'یک مطلب را به عنوان مورد علاقه علامت‌گذاری کن...',
 		),
 		'sticky_post' => ' وقتی باز شد مقاله را به بالا بچسبانید',
+		'sticky_sort' => 'حفظ ترتیب مرتب‌سازی دستی هنگام پیمایش',	// DIRTY
+		'sticky_sort_help' => 'تعیین می‌کند که آیا آخرین ترتیب مرتب‌سازی دستی فعال بماند یا هر دسته یا خوراک همیشه از تنظیم پیش‌فرض یا سراسری خود استفاده کند.',	// DIRTY
 		'title' => ' خواندن',
 		'view' => array(
 			'default' => ' نمای پیش فرض',

+ 2 - 0
app/i18n/fi/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Merkitse artikkeli suosikiksi…',
 		),
 		'sticky_post' => 'Kiinnitä artikkeli ylimmäksi avattaessa',
+		'sticky_sort' => 'Säilytä manuaalinen lajittelujärjestys navigoinnin aikana',	// DIRTY
+		'sticky_sort_help' => 'Määrittää, pysyykö viimeisin manuaalinen lajittelu käytössä vai käyttääkö jokainen luokka tai syöte aina omaa oletus- tai yleisasetustaan.',	// DIRTY
 		'title' => 'Lukeminen',
 		'view' => array(
 			'default' => 'Oletusnäkymä',

+ 2 - 0
app/i18n/fr/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Marquer un article comme favori…',
 		),
 		'sticky_post' => 'Aligner l’article en haut quand il est ouvert',
+		'sticky_sort' => 'Conserver l’ordre de tri manuel lors de la navigation',
+		'sticky_sort_help' => 'Détermine si le dernier ordre de tri manuel est conservé ou si chaque catégorie ou flux utilise toujours son propre paramètre par défaut ou global.',
 		'title' => 'Lecture',
 		'view' => array(
 			'default' => 'Vue par défaut',

+ 2 - 0
app/i18n/he/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'הצמדת המאמר לחלק העליון כאשר הוא פתוח',
+		'sticky_sort' => 'שמירת סדר המיון הידני בעת ניווט',	// DIRTY
+		'sticky_sort_help' => 'קובע אם סדר המיון הידני האחרון נשאר פעיל או שכל קטגוריה או הזנה משתמשת תמיד בהגדרת ברירת המחדל או הכללית שלה.',	// DIRTY
 		'title' => 'קריאה',
 		'view' => array(
 			'default' => 'תצוגת ברירת המחדל',

+ 2 - 0
app/i18n/hu/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Cikk megjelölése kedvencnek…',
 		),
 		'sticky_post' => 'A cikk gördüljön felülre, amikor megnyitásra kerül',
+		'sticky_sort' => 'Kézi rendezés megtartása navigáció közben',	// DIRTY
+		'sticky_sort_help' => 'Meghatározza, hogy az utolsó kézi rendezés aktív marad-e, vagy minden kategória, illetve hírcsatorna mindig a saját alapértelmezett vagy globális beállítását használja.',	// DIRTY
 		'title' => 'Olvasás',
 		'view' => array(
 			'default' => 'Alapértelmezett nézet',

+ 2 - 0
app/i18n/id/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Tandai artikel sebagai favorit…',
 		),
 		'sticky_post' => 'Sematkan artikel ke bagian atas saat dibuka',
+		'sticky_sort' => 'Pertahankan urutan pengurutan manual saat menavigasi',	// DIRTY
+		'sticky_sort_help' => 'Menentukan apakah urutan pengurutan manual terakhir tetap aktif atau setiap kategori atau umpan selalu menggunakan pengaturan bawaan atau globalnya sendiri.',	// DIRTY
 		'title' => 'Membaca',
 		'view' => array(
 			'default' => 'Tampilan baku',

+ 2 - 0
app/i18n/it/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Segna un articolo come preferito…',
 		),
 		'sticky_post' => 'Blocca il contenuto a inizio pagina quando aperto',
+		'sticky_sort' => 'Mantieni l’ordinamento manuale durante la navigazione',	// DIRTY
+		'sticky_sort_help' => 'Determina se l’ultimo ordinamento manuale rimane attivo oppure se ogni categoria o feed usa sempre la propria impostazione predefinita o globale.',	// DIRTY
 		'title' => 'Lettura',
 		'view' => array(
 			'default' => 'Visualizzazione predefinita',

+ 2 - 0
app/i18n/ja/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => '記事をお気に入りに登録する。',
 		),
 		'sticky_post' => '開いたときにトップを記事にする',
+		'sticky_sort' => 'ナビゲーション中も手動の並び順を保持する',	// DIRTY
+		'sticky_sort_help' => '最後に指定した手動の並び順を保持するか、各カテゴリーやフィードが常に独自の既定または全体設定を使用するかを決めます。',	// DIRTY
 		'title' => 'リーディング',
 		'view' => array(
 			'default' => 'デフォルトビュー',

+ 2 - 0
app/i18n/ko/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => '글이 펼쳐진 경우 최상단에 고정하기',
+		'sticky_sort' => '탐색 중에도 수동 정렬 순서 유지',	// DIRTY
+		'sticky_sort_help' => '마지막 수동 정렬 순서를 계속 사용할지, 아니면 각 카테고리나 피드가 항상 자체 기본값 또는 전역 설정을 사용할지 결정합니다.',	// DIRTY
 		'title' => '읽기',
 		'view' => array(
 			'default' => '기본 보기 모드',

+ 2 - 0
app/i18n/lv/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Uzlīmēt rakstu augšā, kad atvērts',
+		'sticky_sort' => 'Saglabāt manuālo kārtošanas secību navigācijas laikā',	// DIRTY
+		'sticky_sort_help' => 'Nosaka, vai tiek saglabāta pēdējā manuālā kārtošanas secība, vai arī katra kategorija vai plūsma vienmēr izmanto savu noklusējuma vai globālo iestatījumu.',	// DIRTY
 		'title' => 'Lasīšana',
 		'view' => array(
 			'default' => 'Noklusējuma skats',

+ 2 - 0
app/i18n/nl/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Markeer een artikel als favoriet…',
 		),
 		'sticky_post' => 'Koppel artikel aan de bovenkant als het geopend wordt',
+		'sticky_sort' => 'Aangepaste sorteervolgorde behouden bij het bladeren',
+		'sticky_sort_help' => 'Bepaalt of de laatste aangepaste sorteervolgorde actief blijft of dat elke categorie of feed altijd zijn eigen standaard- of algemene instelling gebruikt.',
 		'title' => 'Lees modus',
 		'view' => array(
 			'default' => 'Standaard weergave',

+ 2 - 0
app/i18n/oc/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Gardar l’article amont quand es dobèrt',
+		'sticky_sort' => 'Servar l’òrdre de triada manual pendent la navigacion',	// DIRTY
+		'sticky_sort_help' => 'Determina se lo darrièr òrdre de triada manual es conservat o se cada categoria o flux utiliza totjorn son pròpri paramètre per defaut o global.',	// DIRTY
 		'title' => 'Lectura',
 		'view' => array(
 			'default' => 'Vista per defaut',

+ 2 - 0
app/i18n/pl/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Oznacz wiadomość jako ulubioną…',
 		),
 		'sticky_post' => 'Przesuń wiadomość na górę strony po otworzeniu',
+		'sticky_sort' => 'Zachowaj ręczną kolejność sortowania podczas nawigacji',	// DIRTY
+		'sticky_sort_help' => 'Określa, czy ostatnia ręczna kolejność sortowania pozostaje aktywna, czy każda kategoria lub kanał zawsze używa własnego ustawienia domyślnego lub globalnego.',	// DIRTY
 		'title' => 'Czytanie',
 		'view' => array(
 			'default' => 'Domyślny widok',

+ 2 - 0
app/i18n/pt-BR/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Marque um artigo como favorito…',
 		),
 		'sticky_post' => 'Coloque o artigo no topo quando aberto',
+		'sticky_sort' => 'Manter a ordem de classificação manual durante a navegação',
+		'sticky_sort_help' => 'Determina se a última ordem de classificação manual é mantida ativa ou se cada categoria ou feed sempre usa sua própria configuração padrão ou global.',
 		'title' => 'Lendo',
 		'view' => array(
 			'default' => 'Visualização padrão',

+ 2 - 0
app/i18n/pt-PT/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Coloque o artigo no topo quando aberto',
+		'sticky_sort' => 'Manter a ordenação manual durante a navegação',
+		'sticky_sort_help' => 'Determina se a última ordenação manual é mantida ativa ou se cada categoria ou fonte usa sempre a sua própria configuração predefinida ou global.',
 		'title' => 'Lendo',
 		'view' => array(
 			'default' => 'Visualização padrão',

+ 2 - 0
app/i18n/ru/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Отмечать статью избранной…',
 		),
 		'sticky_post' => 'Прикрепить статью к верху при открытии',
+		'sticky_sort' => 'Сохранять ручной порядок сортировки при навигации',	// DIRTY
+		'sticky_sort_help' => 'Определяет, сохраняется ли последний ручной порядок сортировки или каждая категория либо лента всегда использует собственную настройку по умолчанию или глобальную.',	// DIRTY
 		'title' => 'Чтение',
 		'view' => array(
 			'default' => 'Вид по умолчанию',

+ 2 - 0
app/i18n/sk/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Mark an article as favourite…',	// TODO
 		),
 		'sticky_post' => 'Po otvorení posunúť článok hore',
+		'sticky_sort' => 'Zachovať ručné zoradenie počas navigácie',	// DIRTY
+		'sticky_sort_help' => 'Určuje, či zostane zachované posledné ručné zoradenie, alebo či každá kategória či kanál vždy použije vlastné predvolené alebo globálne nastavenie.',	// DIRTY
 		'title' => 'Čítanie',
 		'view' => array(
 			'default' => 'Prednastavené zobrazenie',

+ 2 - 0
app/i18n/tr/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Bir makaleyi favori olarak işaretle…',
 		),
 		'sticky_post' => 'Makale açıldığında üstte sabitle',
+		'sticky_sort' => 'Gezinme sırasında el ile belirlenen sıralama düzenini koru',	// DIRTY
+		'sticky_sort_help' => 'Son el ile belirlenen sıralama düzeninin etkin kalıp kalmayacağını ya da her kategori veya beslemenin her zaman kendi varsayılan veya genel ayarını kullanacağını belirler.',	// DIRTY
 		'title' => 'Okuma',
 		'view' => array(
 			'default' => 'Varsayılan görünüm',

+ 2 - 0
app/i18n/uk/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => 'Вподобати статтю…',
 		),
 		'sticky_post' => 'Закріплювати статтю вгорі при відкритті',
+		'sticky_sort' => 'Зберігати ручний порядок сортування під час навігації',	// DIRTY
+		'sticky_sort_help' => 'Визначає, чи зберігається останній ручний порядок сортування, чи кожна категорія або стрічка завжди використовує власне типове або глобальне налаштування.',	// DIRTY
 		'title' => 'Читання',
 		'view' => array(
 			'default' => 'Типовий показ',

+ 2 - 0
app/i18n/zh-CN/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => '将文章标记为收藏时…',
 		),
 		'sticky_post' => '打开文章时将其置顶',
+		'sticky_sort' => '导航时保持手动排序',
+		'sticky_sort_help' => '决定保持最近一次手动排序,还是让每个分类或订阅源始终使用各自的默认或全局设置。',
 		'title' => '阅读',
 		'view' => array(
 			'default' => '默认视图',

+ 2 - 0
app/i18n/zh-TW/conf.php

@@ -311,6 +311,8 @@ return array(
 			'when' => '標記文章為最愛…',
 		),
 		'sticky_post' => '開啟文章時將其固定於頁首',
+		'sticky_sort' => '導覽時保持手動排序',
+		'sticky_sort_help' => '決定保持最近一次手動排序,還是讓每個分類或訂閱源始終使用各自的預設或全域設定。',
 		'title' => '閱讀',
 		'view' => array(
 			'default' => '預設檢視',

+ 7 - 5
app/layout/aside_feed.phtml

@@ -13,11 +13,13 @@
 	if (($s = Minz_Request::paramString('state', plaintext: true)) !== '' && ctype_digit($s)) {
 		$state_filter_manual .= '&state=' . $s;
 	}
-	if (($s = Minz_Request::paramString('sort', plaintext: true)) !== '' && preg_match('/^[a-z.]+$/', $s)) {
-		$state_filter_manual .= '&sort=' . $s;
-	}
-	if (($s = Minz_Request::paramString('order', plaintext: true)) !== '' && ctype_alpha($s)) {
-		$state_filter_manual .= '&order=' . $s;
+	if (FreshRSS_Context::userConf()->sticky_sort) {
+		if (($s = Minz_Request::paramString('sort', plaintext: true)) !== '' && preg_match('/^[a-z.]+$/', $s)) {
+			$state_filter_manual .= '&sort=' . $s;
+		}
+		if (($s = Minz_Request::paramString('order', plaintext: true)) !== '' && ctype_alpha($s)) {
+			$state_filter_manual .= '&order=' . $s;
+		}
 	}
 
 	$hideSucGlobal = FreshRSS_Context::userConf()->show_unread_count !== 'all' ? ' data-unread-hide="1"' : '';

+ 11 - 0
app/views/configure/reading.phtml

@@ -167,6 +167,17 @@
 					</label>
 				</div>
 			</div>
+
+			<div class="form-group">
+				<div class="group-controls">
+					<label class="checkbox" for="sticky_sort">
+						<input type="checkbox" name="sticky_sort" id="sticky_sort" value="1"<?=
+							FreshRSS_Context::userConf()->sticky_sort ? ' checked="checked"' : '' ?> />
+						<?= _t('conf.reading.sticky_sort') ?>
+					</label>
+					<p class="help"><?= _i('help') ?> <?= _t('conf.reading.sticky_sort_help') ?></p>
+				</div>
+			</div>
 		</fieldset>
 
 		<fieldset>

+ 2 - 0
config-user.default.php

@@ -62,6 +62,8 @@ return array (
 	# 'id'|'date'|'link'|'title'
 	'secondary_sort' => 'id',
 	'secondary_sort_order' => 'DESC',
+	# To carry the manual sort/order over to the next navigation
+	'sticky_sort' => true,
 
 	'anon_access' => false,
 	'mark_when' => array (