diff options
-rw-r--r-- | res/about/version.gmi | 1 | ||||
-rw-r--r-- | src/feeds.c | 15 | ||||
-rw-r--r-- | src/feeds.h | 1 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 45 |
4 files changed, 49 insertions, 13 deletions
diff --git a/res/about/version.gmi b/res/about/version.gmi index cb3f482a..a2a773e9 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi | |||
@@ -23,6 +23,7 @@ | |||
23 | * Fixed percent-decoding of URLs on the command line and coming in via system URL handlers. | 23 | * Fixed percent-decoding of URLs on the command line and coming in via system URL handlers. |
24 | 24 | ||
25 | User interface: | 25 | User interface: |
26 | * Added unread feed entry count to the sidebar. | ||
26 | * Default page scroll keybindings changed: PageUp/Down scroll a whole page, and Space/Shift+Space scrolls half a page. If you're changed these bindings, you'll need to rebind them. | 27 | * Default page scroll keybindings changed: PageUp/Down scroll a whole page, and Space/Shift+Space scrolls half a page. If you're changed these bindings, you'll need to rebind them. |
27 | * UI scaling factor is applied immediately when closing Preferences. Restarting is no longer necessary. | 28 | * UI scaling factor is applied immediately when closing Preferences. Restarting is no longer necessary. |
28 | * Window scaling changes automatically when moving window to a different display. | 29 | * Window scaling changes automatically when moving window to a different display. |
diff --git a/src/feeds.c b/src/feeds.c index 73c68987..db426994 100644 --- a/src/feeds.c +++ b/src/feeds.c | |||
@@ -381,7 +381,8 @@ static iThreadResult fetch_Feeds_(iThread *thread) { | |||
381 | } | 381 | } |
382 | initCurrent_Time(&d->lastRefreshedAt); | 382 | initCurrent_Time(&d->lastRefreshedAt); |
383 | save_Feeds_(d); | 383 | save_Feeds_(d); |
384 | postCommandf_App("feeds.update.finished arg:%d", gotNew ? 1 : 0); | 384 | postCommandf_App("feeds.update.finished arg:%d unread:%zu", gotNew ? 1 : 0, |
385 | numUnread_Feeds()); | ||
385 | return 0; | 386 | return 0; |
386 | } | 387 | } |
387 | 388 | ||
@@ -624,6 +625,18 @@ size_t numSubscribed_Feeds(void) { | |||
624 | return size_PtrArray(listSubscriptions_()); | 625 | return size_PtrArray(listSubscriptions_()); |
625 | } | 626 | } |
626 | 627 | ||
628 | size_t numUnread_Feeds(void) { | ||
629 | size_t count = 0; | ||
630 | size_t max = 100; /* match the number of items shown in the sidebar */ | ||
631 | iConstForEach(PtrArray, i, listEntries_Feeds()) { | ||
632 | if (!max--) break; | ||
633 | if (isUnread_FeedEntry(i.ptr)) { | ||
634 | count++; | ||
635 | } | ||
636 | } | ||
637 | return count; | ||
638 | } | ||
639 | |||
627 | #define iPluralS(c) ((c) != 1 ? "s" : "") | 640 | #define iPluralS(c) ((c) != 1 ? "s" : "") |
628 | 641 | ||
629 | const iString *entryListPage_Feeds(void) { | 642 | const iString *entryListPage_Feeds(void) { |
diff --git a/src/feeds.h b/src/feeds.h index 7528d111..3ebef8ac 100644 --- a/src/feeds.h +++ b/src/feeds.h | |||
@@ -54,3 +54,4 @@ void refreshFinished_Feeds (void); /* called on "feeds.update.finished" */ | |||
54 | const iPtrArray * listEntries_Feeds (void); | 54 | const iPtrArray * listEntries_Feeds (void); |
55 | const iString * entryListPage_Feeds (void); | 55 | const iString * entryListPage_Feeds (void); |
56 | size_t numSubscribed_Feeds (void); | 56 | size_t numSubscribed_Feeds (void); |
57 | size_t numUnread_Feeds (void); | ||
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 8c1bb60d..2cc1d899 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -99,6 +99,7 @@ struct Impl_SidebarWidget { | |||
99 | int maxButtonLabelWidth; | 99 | int maxButtonLabelWidth; |
100 | int width; | 100 | int width; |
101 | int itemFonts[2]; | 101 | int itemFonts[2]; |
102 | size_t numUnreadEntries; | ||
102 | iWidget * resizer; | 103 | iWidget * resizer; |
103 | iWidget * menu; | 104 | iWidget * menu; |
104 | iSidebarItem * contextItem; /* list item accessed in the context menu */ | 105 | iSidebarItem * contextItem; /* list item accessed in the context menu */ |
@@ -507,6 +508,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
507 | iZap(d->modeScroll); | 508 | iZap(d->modeScroll); |
508 | d->side = side; | 509 | d->side = side; |
509 | d->mode = -1; | 510 | d->mode = -1; |
511 | d->numUnreadEntries = 0; | ||
510 | d->itemFonts[0] = uiContent_FontId; | 512 | d->itemFonts[0] = uiContent_FontId; |
511 | d->itemFonts[1] = uiContentBold_FontId; | 513 | d->itemFonts[1] = uiContentBold_FontId; |
512 | #if defined (iPlatformAppleMobile) | 514 | #if defined (iPlatformAppleMobile) |
@@ -587,6 +589,9 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
587 | d->menu = NULL; | 589 | d->menu = NULL; |
588 | addAction_Widget(w, SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh"); | 590 | addAction_Widget(w, SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh"); |
589 | updateMetrics_SidebarWidget_(d); | 591 | updateMetrics_SidebarWidget_(d); |
592 | if (side == left_SideBarSide) { | ||
593 | postCommand_App("~sidebar.update"); /* unread count */ | ||
594 | } | ||
590 | } | 595 | } |
591 | 596 | ||
592 | void deinit_SidebarWidget(iSidebarWidget *d) { | 597 | void deinit_SidebarWidget(iSidebarWidget *d) { |
@@ -686,14 +691,19 @@ static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { | |||
686 | const iBool isTight = | 691 | const iBool isTight = |
687 | (width_Rect(bounds_Widget(as_Widget(d->modeButtons[0]))) < d->maxButtonLabelWidth); | 692 | (width_Rect(bounds_Widget(as_Widget(d->modeButtons[0]))) < d->maxButtonLabelWidth); |
688 | for (int i = 0; i < max_SidebarMode; i++) { | 693 | for (int i = 0; i < max_SidebarMode; i++) { |
689 | if (!d->modeButtons[i]) continue; | 694 | iLabelWidget *button = d->modeButtons[i]; |
690 | if (isTight && ~flags_Widget(as_Widget(d->modeButtons[i])) & tight_WidgetFlag) { | 695 | if (!button) continue; |
691 | setFlags_Widget(as_Widget(d->modeButtons[i]), tight_WidgetFlag, iTrue); | 696 | setFlags_Widget(as_Widget(button), tight_WidgetFlag, isTight); |
692 | updateTextCStr_LabelWidget(d->modeButtons[i], tightModeLabels_[i]); | 697 | if (i == feeds_SidebarMode && d->numUnreadEntries) { |
698 | updateText_LabelWidget(button, | ||
699 | collectNewFormat_String("%s " uiTextAction_ColorEscape "%zu%s", | ||
700 | tightModeLabels_[i], | ||
701 | d->numUnreadEntries, | ||
702 | !isTight ? " Unread" : "")); | ||
693 | } | 703 | } |
694 | else if (!isTight && flags_Widget(as_Widget(d->modeButtons[i])) & tight_WidgetFlag) { | 704 | else { |
695 | setFlags_Widget(as_Widget(d->modeButtons[i]), tight_WidgetFlag, iFalse); | 705 | updateTextCStr_LabelWidget(button, |
696 | updateTextCStr_LabelWidget(d->modeButtons[i], normalModeLabels_[i]); | 706 | isTight ? tightModeLabels_[i] : normalModeLabels_[i]); |
697 | } | 707 | } |
698 | } | 708 | } |
699 | } | 709 | } |
@@ -814,11 +824,18 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
814 | updateItems_SidebarWidget_(d); | 824 | updateItems_SidebarWidget_(d); |
815 | scrollOffset_ListWidget(d->list, 0); | 825 | scrollOffset_ListWidget(d->list, 0); |
816 | } | 826 | } |
817 | else if (equal_Command(cmd, "sidebar.update") || | 827 | else if (equal_Command(cmd, "sidebar.update")) { |
818 | (equal_Command(cmd, "visited.changed") && | 828 | d->numUnreadEntries = numUnread_Feeds(); |
819 | (d->mode == history_SidebarMode || d->mode == feeds_SidebarMode))) { | 829 | checkModeButtonLayout_SidebarWidget_(d); |
820 | updateItems_SidebarWidget_(d); | 830 | updateItems_SidebarWidget_(d); |
821 | } | 831 | } |
832 | else if (equal_Command(cmd, "visited.changed")) { | ||
833 | d->numUnreadEntries = numUnread_Feeds(); | ||
834 | checkModeButtonLayout_SidebarWidget_(d); | ||
835 | if (d->mode == history_SidebarMode || d->mode == feeds_SidebarMode) { | ||
836 | updateItems_SidebarWidget_(d); | ||
837 | } | ||
838 | } | ||
822 | else if (equal_Command(cmd, "bookmarks.changed") && (d->mode == bookmarks_SidebarMode || | 839 | else if (equal_Command(cmd, "bookmarks.changed") && (d->mode == bookmarks_SidebarMode || |
823 | d->mode == feeds_SidebarMode)) { | 840 | d->mode == feeds_SidebarMode)) { |
824 | updateItems_SidebarWidget_(d); | 841 | updateItems_SidebarWidget_(d); |
@@ -954,8 +971,12 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
954 | } | 971 | } |
955 | return iTrue; | 972 | return iTrue; |
956 | } | 973 | } |
957 | else if (equal_Command(cmd, "feeds.update.finished") && d->mode == feeds_SidebarMode) { | 974 | else if (equal_Command(cmd, "feeds.update.finished")) { |
958 | updateItems_SidebarWidget_(d); | 975 | d->numUnreadEntries = argLabel_Command(cmd, "unread"); |
976 | checkModeButtonLayout_SidebarWidget_(d); | ||
977 | if (d->mode == feeds_SidebarMode) { | ||
978 | updateItems_SidebarWidget_(d); | ||
979 | } | ||
959 | } | 980 | } |
960 | else if (equal_Command(cmd, "feeds.markallread") && d->mode == feeds_SidebarMode) { | 981 | else if (equal_Command(cmd, "feeds.markallread") && d->mode == feeds_SidebarMode) { |
961 | iConstForEach(PtrArray, i, listEntries_Feeds()) { | 982 | iConstForEach(PtrArray, i, listEntries_Feeds()) { |