Notifications once per sync

This commit is contained in:
Jaidyn Ann 2021-03-01 19:13:22 -06:00
parent 2834ed4227
commit bbdc2c2865
8 changed files with 160 additions and 117 deletions

View File

@ -1,7 +1,4 @@
Important Features: Important Features:
* Show in desktray
* Make archivable
* Get menu working
* Default column layouts for ~/feeds and ~/config/settings/Pogger/Subscriptions * Default column layouts for ~/feeds and ~/config/settings/Pogger/Subscriptions
* Localization * Localization
@ -14,6 +11,7 @@ Important improvements:
and updates every 30 minutes, it got to about 200MB after a week or and updates every 30 minutes, it got to about 200MB after a week or
so. so.
* _Huge_ problem, but I haven't had luck figuring it out yet… * _Huge_ problem, but I haven't had luck figuring it out yet…
* Move from BLists to BObjectLists where possible
* No hardcoded paths * No hardcoded paths
* General input sanitization * General input sanitization
* File error-handling * File error-handling
@ -31,6 +29,7 @@ Nice Improvements:
* Main window * Main window
* Subscription-edit window * Subscription-edit window
* Proper scripting support * Proper scripting support
* Show in desktray
* Store feeds in kEnqueueFeeds/etc messages as paths? hmm * Store feeds in kEnqueueFeeds/etc messages as paths? hmm
* This way, if the user edits the feed after it is enqueued but before * This way, if the user edits the feed after it is enqueued but before
processing, the changes will be applied. processing, the changes will be applied.

View File

@ -54,22 +54,16 @@ App::MessageReceived(BMessage* msg)
{ {
switch (msg->what) switch (msg->what)
{ {
case kDownloadComplete:
fMainWindow->PostMessage(msg);
case kEnqueueFeed:
case kUpdateSubscribed: case kUpdateSubscribed:
case kControllerCheck: case kControllerCheck:
{ {
fFeedController->MessageReceived(msg); fFeedController->MessageReceived(msg);
break; break;
} }
case kDownloadComplete:
fMainWindow->PostMessage(msg);
case kEnqueueFeed:
{
fNotifier->MessageReceived(msg);
fFeedController->MessageReceived(msg);
break;
}
case kFeedsEdited: case kFeedsEdited:
case kProgress:
case kDownloadStart: case kDownloadStart:
{ {
fMainWindow->PostMessage(msg); fMainWindow->PostMessage(msg);
@ -77,8 +71,10 @@ App::MessageReceived(BMessage* msg)
} }
case kClearQueue: case kClearQueue:
{ {
fFeedController->MessageReceived(msg);
break; break;
} }
case kProgress:
case kParseComplete: case kParseComplete:
case kParseFail: case kParseFail:
case kDownloadFail: case kDownloadFail:

View File

@ -20,11 +20,13 @@
FeedController::FeedController() FeedController::FeedController()
: :
fEnqueuedTotal(0),
fMainThread(find_thread(NULL)), fMainThread(find_thread(NULL)),
fDownloadThread(0), fDownloadThread(0),
fParseThread(0), fParseThread(0),
fDownloadQueue(new BList()), fDownloadQueue(new BList()),
fMessageRunner(new BMessageRunner(be_app, BMessage(kControllerCheck), 50000, -1)) fMessageRunner(new BMessageRunner(be_app, BMessage(kControllerCheck), 50000, -1))
{ {
fDownloadThread = spawn_thread(_DownloadLoop, "here, eat this", fDownloadThread = spawn_thread(_DownloadLoop, "here, eat this",
B_NORMAL_PRIORITY, &fMainThread); B_NORMAL_PRIORITY, &fMainThread);
@ -58,6 +60,7 @@ FeedController::MessageReceived(BMessage* msg)
_EnqueueFeed((Feed*)data); _EnqueueFeed((Feed*)data);
i++; i++;
} }
_SendProgress();
break; break;
} }
case kUpdateSubscribed: case kUpdateSubscribed:
@ -66,21 +69,18 @@ FeedController::MessageReceived(BMessage* msg)
for (int i = 0; i < subFeeds.CountItems(); i++) { for (int i = 0; i < subFeeds.CountItems(); i++) {
_EnqueueFeed((Feed*)subFeeds.ItemAt(i)); _EnqueueFeed((Feed*)subFeeds.ItemAt(i));
} }
_SendProgress();
break; break;
} }
case kClearQueue: case kClearQueue:
{ {
fDownloadQueue->MakeEmpty();
break; break;
} }
case kControllerCheck: case kControllerCheck:
{ {
_ProcessQueueItem(); _ProcessQueueItem();
_CheckStatus(); _ReceiveStatus();
break;
}
default:
{
// BWindow::MessageReceived(msg);
break; break;
} }
} }
@ -100,6 +100,24 @@ FeedController::SubscribedFeeds()
} }
void
FeedController::_SendProgress()
{
int32 dqCount = fDownloadQueue->CountItems();
if (fEnqueuedTotal < dqCount)
fEnqueuedTotal = dqCount;
BMessage progress(kProgress);
progress.AddInt32("total", fEnqueuedTotal);
progress.AddInt32("current", fEnqueuedTotal - dqCount);
be_app->MessageReceived(&progress);
if (dqCount == 0)
fEnqueuedTotal = 0;
}
void void
FeedController::_EnqueueFeed(Feed* feed) FeedController::_EnqueueFeed(Feed* feed)
{ {
@ -116,15 +134,15 @@ FeedController::_ProcessQueueItem()
send_data(fDownloadThread, 0, (void*)buffer, sizeof(Feed)); send_data(fDownloadThread, 0, (void*)buffer, sizeof(Feed));
BMessage downloadInit = BMessage(kDownloadStart); BMessage downloadInit = BMessage(kDownloadStart);
downloadInit.AddString("feed_url", buffer->GetXmlUrl().UrlString());
downloadInit.AddString("feed_name", buffer->GetTitle()); downloadInit.AddString("feed_name", buffer->GetTitle());
downloadInit.AddString("feed_url", buffer->GetXmlUrl().UrlString());
((App*)be_app)->MessageReceived(&downloadInit); ((App*)be_app)->MessageReceived(&downloadInit);
} }
} }
void void
FeedController::_CheckStatus() FeedController::_ReceiveStatus()
{ {
thread_id sender; thread_id sender;
@ -137,6 +155,7 @@ FeedController::_CheckStatus()
case kDownloadComplete: case kDownloadComplete:
{ {
BMessage complete = BMessage(kDownloadComplete); BMessage complete = BMessage(kDownloadComplete);
complete.AddString("feed_name", feedBuffer->GetTitle());
complete.AddString("feed_url", complete.AddString("feed_url",
feedBuffer->GetXmlUrl().UrlString()); feedBuffer->GetXmlUrl().UrlString());
((App*)be_app)->MessageReceived(&complete); ((App*)be_app)->MessageReceived(&complete);
@ -147,26 +166,31 @@ FeedController::_CheckStatus()
case kDownloadFail: case kDownloadFail:
{ {
BMessage failure = BMessage(kDownloadFail); BMessage failure = BMessage(kDownloadFail);
failure.AddString("feed_name", feedBuffer->GetTitle());
failure.AddString("feed_url", failure.AddString("feed_url",
feedBuffer->GetXmlUrl().UrlString()); feedBuffer->GetXmlUrl().UrlString());
((App*)be_app)->MessageReceived(&failure); ((App*)be_app)->MessageReceived(&failure);
break; _SendProgress();
}
case kParseComplete:
{
BMessage complete = BMessage(kParseComplete);
complete.AddString("feed_url", feedBuffer->GetXmlUrl().UrlString());
complete.AddInt32("entry_count", feedBuffer->GetNewEntries().CountItems());
((App*)be_app)->MessageReceived(&complete);
break; break;
} }
case kParseFail: case kParseFail:
{ {
BMessage failure = BMessage(kParseFail); BMessage failure = BMessage(kParseFail);
failure.AddString("feed_name", feedBuffer->GetTitle());
failure.AddString("feed_url", feedBuffer->GetXmlUrl().UrlString()); failure.AddString("feed_url", feedBuffer->GetXmlUrl().UrlString());
((App*)be_app)->MessageReceived(&failure); ((App*)be_app)->MessageReceived(&failure);
_SendProgress();
break; break;
} }
// If parse was successful, the code is the amount of new entries
default:
BMessage complete = BMessage(kParseComplete);
complete.AddString("feed_name", feedBuffer->GetTitle());
complete.AddString("feed_url", feedBuffer->GetXmlUrl().UrlString());
complete.AddInt32("entry_count", code);
((App*)be_app)->MessageReceived(&complete);
_SendProgress();
break;
} }
} }
} }
@ -209,6 +233,7 @@ FeedController::_ParseLoop(void* data)
int32 code = receive_data(&sender, (void*)feedBuffer, sizeof(Feed)); int32 code = receive_data(&sender, (void*)feedBuffer, sizeof(Feed));
BList entries; BList entries;
int32 entriesCount;
BString feedTitle; BString feedTitle;
BUrl feedUrl = feedBuffer->GetXmlUrl(); BUrl feedUrl = feedBuffer->GetXmlUrl();
BDirectory outDir = BDirectory(((App*)be_app)->fPreferences->EntryDir()); BDirectory outDir = BDirectory(((App*)be_app)->fPreferences->EntryDir());
@ -218,9 +243,10 @@ FeedController::_ParseLoop(void* data)
feed = new AtomFeed(feedBuffer); feed = new AtomFeed(feedBuffer);
feed->Parse(); feed->Parse();
entries = feed->GetNewEntries(); entries = feed->GetNewEntries();
entriesCount = entries.CountItems();
feedTitle = feed->GetTitle(); feedTitle = feed->GetTitle();
for (int i = 0; i < entries.CountItems(); i++) for (int i = 0; i < entriesCount; i++)
((Entry*)entries.ItemAt(i))->Filetize(outDir); ((Entry*)entries.ItemAt(i))->Filetize(outDir);
delete feed; delete feed;
} }
@ -229,19 +255,20 @@ FeedController::_ParseLoop(void* data)
feed = new RssFeed(feedBuffer); feed = new RssFeed(feedBuffer);
feed->Parse(); feed->Parse();
entries = feed->GetNewEntries(); entries = feed->GetNewEntries();
entriesCount = entries.CountItems();
feedTitle = feed->GetTitle(); feedTitle = feed->GetTitle();
for (int i = 0; i < entries.CountItems(); i++) for (int i = 0; i < entriesCount; i++)
((Entry*)entries.ItemAt(i))->Filetize(outDir); ((Entry*)entries.ItemAt(i))->Filetize(outDir);
delete feed; delete feed;
} }
if (feedBuffer->IsAtom() || feedBuffer->IsRss()) { if (feedBuffer->IsAtom() || feedBuffer->IsRss()) {
send_data(main, kParseComplete, (void*)feedBuffer, sizeof(Feed)); send_data(main, entriesCount, (void*)feedBuffer, sizeof(Feed));
} }
else { else {
send_data(main, kParseFail, (void*)feedBuffer, sizeof(Feed)); send_data(main, entriesCount, (void*)feedBuffer, sizeof(Feed));
} }
} }

View File

@ -16,6 +16,7 @@ class Feed;
enum enum
{ {
kProgress = 'npro',
kEnqueueFeed = 'fenq', kEnqueueFeed = 'fenq',
kClearQueue = 'frmq', kClearQueue = 'frmq',
kDownloadStart = 'fdst', kDownloadStart = 'fdst',
@ -38,12 +39,17 @@ public:
static BList SubscribedFeeds(); static BList SubscribedFeeds();
private: private:
void _SendProgress();
void _EnqueueFeed(Feed* feed);
void _ProcessQueueItem();
void _ReceiveStatus();
static int32 _DownloadLoop(void* data); static int32 _DownloadLoop(void* data);
static int32 _ParseLoop(void* data); static int32 _ParseLoop(void* data);
void _EnqueueFeed(Feed* feed); int32 fEnqueuedTotal;
void _ProcessQueueItem();
void _CheckStatus();
thread_id fMainThread; thread_id fMainThread;
thread_id fDownloadThread; thread_id fDownloadThread;

View File

@ -60,13 +60,12 @@ MainWindow::MessageReceived(BMessage *msg)
case kProgress: case kProgress:
{ {
fFeedsView->MessageReceived(msg); fFeedsView->MessageReceived(msg);
int32 max = 0; int32 total,current = 0;
int32 current = 0;
if (msg->FindInt32("max", &max) == B_OK if (msg->FindInt32("total", &total) == B_OK
&& msg->FindInt32("current", &current) == B_OK) && msg->FindInt32("current", &current) == B_OK)
{ {
_UpdateProgress(max, current); _UpdateProgress(total, current);
} }
break; break;
} }
@ -120,12 +119,12 @@ MainWindow::_InitInterface()
void void
MainWindow::_UpdateProgress(int32 max, int32 current) MainWindow::_UpdateProgress(int32 total, int32 current)
{ {
int32 prog = max - current; if (current < fStatusBar->CurrentValue())
fStatusBar->Reset();
fStatusBar->SetMaxValue(max); fStatusBar->SetMaxValue(total);
fStatusBar->SetTo(prog); fStatusBar->SetTo(current);
} }

View File

@ -22,7 +22,7 @@ public:
private: private:
void _InitInterface(); void _InitInterface();
void _UpdateProgress(int32 max, int32 current); void _UpdateProgress(int32 total, int32 current);
BGroupView* fBaseView; BGroupView* fBaseView;
BTabView* fTabView; BTabView* fTabView;

View File

@ -5,6 +5,7 @@
#include "Notifier.h" #include "Notifier.h"
#include <List.h>
#include <Message.h> #include <Message.h>
#include <Notification.h> #include <Notification.h>
@ -14,8 +15,9 @@
Notifier::Notifier() Notifier::Notifier()
: :
fEnqueuedFeeds(0), fFailedFeeds(new BList()),
fFeedsInProgress(0) fUpdatedFeeds(new BList()),
fTotalEntries(0)
{ {
} }
@ -25,45 +27,44 @@ Notifier::MessageReceived(BMessage* msg)
{ {
switch (msg->what) switch (msg->what)
{ {
case kEnqueueFeed: case kProgress:
{ {
fEnqueuedFeeds++; int32 total, current = 0;
fFeedsInProgress++;
_UpdateProgress(); if (msg->FindInt32("total", &total) == B_OK
&& msg->FindInt32("current", &current) == B_OK
&& total == current)
{
_SendNotifications();
}
break; break;
} }
case kParseComplete: case kParseComplete:
{ {
BString feedName; BString feedName;
BString feedUrl;
int32 entryCount; int32 entryCount;
if (msg->FindString("feed_name", &feedName) == B_OK if ((msg->FindString("feed_name", &feedName) == B_OK
|| msg->FindString("feed_url", &feedUrl) == B_OK)
&& msg->FindInt32("entry_count", &entryCount) == B_OK) && msg->FindInt32("entry_count", &entryCount) == B_OK)
{ {
if (entryCount > 0) if (entryCount > 0)
_NewEntryNotification(feedName, entryCount); _SaveUpdated(feedName, feedUrl, entryCount);
} }
fFeedsInProgress--;
_UpdateProgress();
break;
}
case kParseFail:
{
BString feedUrl = msg->GetString("feed_url", "");
_ParseFailNotification(feedUrl);
fFeedsInProgress--;
_UpdateProgress();
break; break;
} }
case kDownloadFail: case kDownloadFail:
case kParseFail:
{ {
BString feedUrl = msg->GetString("feed_url", ""); BString feedName;
_DownloadFailNotification(feedUrl); BString feedUrl;
fFeedsInProgress--; if (msg->FindString("feed_name", &feedName) == B_OK
_UpdateProgress(); || msg->FindString("feed_url", &feedUrl) == B_OK)
{
_SaveFailed(feedName, feedUrl);
}
break; break;
} }
} }
@ -71,19 +72,40 @@ Notifier::MessageReceived(BMessage* msg)
void void
Notifier::_NewEntryNotification(BString feedName, int32 entryCount) Notifier::_SendNotifications()
{ {
if (((App*)be_app)->fPreferences->fNewNotify == false) _SendUpdatedNotification();
_SendFailedNotification();
fFailedFeeds->MakeEmpty();
fUpdatedFeeds->MakeEmpty();
fTotalEntries = 0;
}
void
Notifier::_SendUpdatedNotification()
{
if (((App*)be_app)->fPreferences->fNewNotify == false
|| fTotalEntries == 0) {
return; return;
}
BNotification notifyNew(B_INFORMATION_NOTIFICATION); BNotification notifyNew(B_INFORMATION_NOTIFICATION);
BString notifyLabel("New Feed Entries"); BString notifyLabel("Feed Updates");
BString notifyText("%n% new entries from %source%"); BString notifyText("%n% new entries from %source%");
BString numStr(""); if (fUpdatedFeeds->CountItems() > 1)
numStr << entryCount; notifyText = "%n% new entries from %source% and %m% others";
notifyText.ReplaceAll("%source%", feedName);
notifyText.ReplaceAll("%n%", numStr); BString entryNum,feedNum = "";
entryNum << fTotalEntries;
feedNum << fUpdatedFeeds->CountItems();
notifyText.ReplaceAll("%n%", entryNum);
notifyText.ReplaceAll("%m%", feedNum);
notifyText.ReplaceAll("%source%",
((BString*)fUpdatedFeeds->ItemAt(0))->String());
notifyNew.SetTitle(notifyLabel); notifyNew.SetTitle(notifyLabel);
notifyNew.SetContent(notifyText); notifyNew.SetContent(notifyText);
@ -92,56 +114,53 @@ Notifier::_NewEntryNotification(BString feedName, int32 entryCount)
void void
Notifier::_ParseFailNotification(BString feedUrl) Notifier::_SendFailedNotification()
{ {
if (((App*)be_app)->fPreferences->fFailureNotify == false) if (((App*)be_app)->fPreferences->fFailureNotify == false
|| fFailedFeeds->CountItems() == 0) {
return; return;
}
BNotification notifyError(B_ERROR_NOTIFICATION); BNotification notifyError(B_ERROR_NOTIFICATION);
BString notifyText("Failed to parse feed from %url%"); BString notifyLabel("Update Failure");
BString notifyText("Failed to update %source%");
if (feedUrl.IsEmpty()) if (fFailedFeeds->CountItems() > 1)
notifyText = "Failed to parse a feed"; notifyText = "Failed to update %source% and %m% others";
notifyText.ReplaceAll("%url%", feedUrl); BString feedNum = "";
feedNum << fFailedFeeds->CountItems();
notifyError.SetTitle("Parse Failure"); notifyText.ReplaceAll("%m%", feedNum);
notifyText.ReplaceAll("%source%",
((BString*)fFailedFeeds->ItemAt(0))->String());
notifyError.SetTitle(notifyLabel);
notifyError.SetContent(notifyText); notifyError.SetContent(notifyText);
notifyError.Send(); notifyError.Send();
} }
void void
Notifier::_DownloadFailNotification(BString feedUrl) Notifier::_SaveUpdated(BString feedName, BString feedUrl, int32 entryCount)
{ {
if (((App*)be_app)->fPreferences->fFailureNotify == false) BString name = feedName;
return; if (feedName.IsEmpty())
name = feedUrl;
BNotification notifyError(B_ERROR_NOTIFICATION); fTotalEntries += entryCount;
BString notifyText("Failed to download feed from %url%"); fUpdatedFeeds->AddItem(new BString(feedName));
if (feedUrl.IsEmpty())
notifyText = "Failed to download a feed";
notifyText.ReplaceAll("%url%", feedUrl);
notifyError.SetTitle("Download Failure");
notifyError.SetContent(notifyText);
notifyError.Send();
} }
void void
Notifier::_UpdateProgress() Notifier::_SaveFailed(BString feedName, BString feedUrl)
{ {
BMessage progress = BMessage(kProgress); BString name = feedName;
progress.AddInt32("max", fEnqueuedFeeds); if (feedName.IsEmpty())
progress.AddInt32("current", fFeedsInProgress); name = feedUrl;
((App*)be_app)->MessageReceived(&progress); fFailedFeeds->AddItem(new BString(feedName));
if (fFeedsInProgress == 0)
fEnqueuedFeeds = 0;
} }

View File

@ -7,16 +7,11 @@
#include <SupportDefs.h> #include <SupportDefs.h>
class BList;
class BString; class BString;
class BMessage; class BMessage;
enum
{
kProgress = 'npro'
};
class Notifier { class Notifier {
public: public:
Notifier(); Notifier();
@ -24,14 +19,16 @@ public:
void MessageReceived(BMessage* msg); void MessageReceived(BMessage* msg);
private: private:
void _NewEntryNotification(BString feedName, int32 feedCount); void _SendNotifications();
void _ParseFailNotification(BString feedUrl); void _SendUpdatedNotification();
void _DownloadFailNotification(BString feedUrl); void _SendFailedNotification();
void _UpdateProgress(); void _SaveUpdated(BString feedName, BString feedUrl, int32 feedCount);
void _SaveFailed(BString feedName, BString feedUrl);
int32 fEnqueuedFeeds; BList* fFailedFeeds;
int32 fFeedsInProgress; BList* fUpdatedFeeds;
int32 fTotalEntries;
}; };