mirror of
https://github.com/FreshRSS/FreshRSS.git
synced 2026-07-16 10:02:59 -04:00
* 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>
147 lines
5.5 KiB
PHP
147 lines
5.5 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* @property string $apiPasswordHash
|
|
* @property array{keep_period:string|false,keep_max:int|false,keep_min:int|false,keep_favourites:bool,keep_labels:bool,keep_unreads:bool} $archiving
|
|
* @property bool $auto_load_more
|
|
* @property bool $auto_remove_article
|
|
* @property bool $bottomline_date
|
|
* @property bool $bottomline_favorite
|
|
* @property bool $bottomline_link
|
|
* @property bool $bottomline_read
|
|
* @property bool $bottomline_sharing
|
|
* @property bool $bottomline_tags
|
|
* @property bool $bottomline_myLabels
|
|
* @property string $content_width
|
|
* @property-read int $default_state
|
|
* @property string $default_view
|
|
* @property string|bool $display_categories
|
|
* @property string $show_tags
|
|
* @property int $show_tags_max
|
|
* @property string $show_author_date
|
|
* @property string $show_feed_name
|
|
* @property string $show_article_icons
|
|
* @property bool $display_posts
|
|
* @property string $email_validation_token
|
|
* @property-read bool $enabled
|
|
* @property string $feverKey
|
|
* @property bool $hide_read_feeds
|
|
* @property int $html5_notif_timeout
|
|
* @property bool $html5_enable_notif
|
|
* @property int $good_notification_timeout
|
|
* @property int $bad_notification_timeout
|
|
* @property-read bool $is_admin
|
|
* @property int|null $keep_history_default
|
|
* @property string $language
|
|
* @property string $timezone
|
|
* @property bool $lazyload
|
|
* @property string $mail_login
|
|
* @property bool $mark_updated_article_unread
|
|
* @property array<string,bool|int> $mark_when
|
|
* @property int $max_posts_per_rss
|
|
* @property-read array<string,int> $limits
|
|
* @property int|null $old_entries
|
|
* @property bool $onread_jump_next
|
|
* @property string $passwordHash
|
|
* @property int $posts_per_page
|
|
* @property array<int,array{get?:string,name?:string,order?:string,search?:string,state?:int,url?:string,token?:string,
|
|
* shareRss?:bool,shareOpml?:bool,description?:string,imageUrl?:string}> $queries
|
|
* @property bool $reading_confirm
|
|
* @property int $since_hours_posts_per_rss
|
|
* @property bool $show_fav_unread
|
|
* @property bool $show_favicons
|
|
* @property bool $icons_as_emojis
|
|
* @property int $simplify_over_n_feeds
|
|
* @property bool $show_nav_buttons
|
|
* @property bool $show_title_unread
|
|
* @property 'all'|'important'|'none' $show_unread_count
|
|
* @property bool $sidebar_hidden_by_default
|
|
* @property 'big'|'small'|'none' $mark_read_button
|
|
* @property 'ASC'|'DESC' $sort_order
|
|
* @property 'id'|'c.name'|'date'|'f.name'|'length'|'link'|'rand'|'title' $sort
|
|
* @property 'ASC'|'DESC' $secondary_sort_order
|
|
* @property 'id'|'date'|'link'|'title' $secondary_sort
|
|
* @property array<int,array<string,string>> $sharing
|
|
* @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
|
|
* @property bool $topline_date
|
|
* @property bool $topline_display_authors
|
|
* @property bool $topline_favorite
|
|
* @property bool $topline_myLabels
|
|
* @property bool $topline_sharing
|
|
* @property bool $topline_link
|
|
* @property bool $topline_read
|
|
* @property bool $topline_summary
|
|
* @property string $topline_website
|
|
* @property string $topline_thumbnail
|
|
* @property int $ttl_default
|
|
* @property int $dynamic_opml_ttl_default
|
|
* @property string $view_mode
|
|
* @property array<string,bool|int|string> $volatile
|
|
* @property array<string,array<string,mixed>> $extensions
|
|
* @property bool $retrieve_extension_list
|
|
* @property array<string> $send_referrer_allowlist
|
|
*/
|
|
final class FreshRSS_UserConfiguration extends Minz_Configuration {
|
|
use FreshRSS_FilterActionsTrait;
|
|
|
|
/** @throws Minz_FileNotExistException */
|
|
public static function init(string $config_filename, ?string $default_filename = null): FreshRSS_UserConfiguration {
|
|
parent::register('user', $config_filename, $default_filename);
|
|
try {
|
|
return parent::get('user');
|
|
} catch (Minz_ConfigurationNamespaceException $ex) {
|
|
FreshRSS::killApp($ex->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Access the default configuration for users.
|
|
* @throws Minz_FileNotExistException
|
|
*/
|
|
public static function default(): FreshRSS_UserConfiguration {
|
|
/** @var FreshRSS_UserConfiguration|null $default_user_conf */
|
|
static $default_user_conf = null;
|
|
if ($default_user_conf === null) {
|
|
$namespace = 'user_default';
|
|
FreshRSS_UserConfiguration::register($namespace, '_', FRESHRSS_PATH . '/config-user.default.php');
|
|
$default_user_conf = FreshRSS_UserConfiguration::get($namespace);
|
|
}
|
|
return $default_user_conf;
|
|
}
|
|
|
|
/**
|
|
* Register and return the configuration for a given user.
|
|
*
|
|
* Note this function has been created to generate temporary configuration
|
|
* objects. If you need a long-time configuration, please don't use this function.
|
|
*
|
|
* @param string $username the name of the user of which we want the configuration.
|
|
* @return FreshRSS_UserConfiguration|null object, or null if the configuration cannot be loaded.
|
|
* @throws Minz_ConfigurationNamespaceException
|
|
*/
|
|
public static function getForUser(string $username): ?FreshRSS_UserConfiguration {
|
|
if (!FreshRSS_user_Controller::checkUsername($username)) {
|
|
return null;
|
|
}
|
|
$namespace = 'user_' . $username;
|
|
try {
|
|
FreshRSS_UserConfiguration::register($namespace,
|
|
USERS_PATH . '/' . $username . '/config.php',
|
|
FRESHRSS_PATH . '/config-user.default.php');
|
|
} catch (Minz_FileNotExistException $e) {
|
|
Minz_Log::warning($e->getMessage(), ADMIN_LOG);
|
|
return null;
|
|
}
|
|
|
|
$user_conf = FreshRSS_UserConfiguration::get($namespace);
|
|
return $user_conf;
|
|
}
|
|
}
|