Subscription adding/editing/removal

This commit is contained in:
Jaidyn Ann 2021-01-15 22:22:33 -06:00
parent f67a9f3d28
commit c6f5c4fed0
14 changed files with 318 additions and 52 deletions

View File

@ -36,6 +36,7 @@ SRCS = \
src/EntriesView.cpp, \ src/EntriesView.cpp, \
src/Feed.cpp, \ src/Feed.cpp, \
src/FeedController.cpp \ src/FeedController.cpp \
src/FeedEditWindow.cpp \
src/FeedListItem.cpp \ src/FeedListItem.cpp \
src/FeedsView.cpp, \ src/FeedsView.cpp, \
src/MainWindow.cpp, \ src/MainWindow.cpp, \

View File

@ -1,6 +1,9 @@
* Add subscriptions * Feeds list
* Adding/editing from GUI * Update when feeds are edited
* Do this for file refs when Feeds, too * Store feeds in kEnqueueFeeds/etc messages as paths? hmm
* This way, if the user edits the feed after it is enqueued, the changes
will be applied.
* Support for clearing queue
* Revamp configuration * Revamp configuration
* Fix saving, etc. * Fix saving, etc.
* Show progress * Show progress

View File

@ -46,7 +46,7 @@ App::App() : BApplication("application/x-vnd.Pogger")
fMainWindow->Show(); fMainWindow->Show();
BMessage* updateMessage = new BMessage(kUpdateSubscribed); BMessage* updateMessage = new BMessage(kUpdateSubscribed);
MessageReceived(updateMessage); // MessageReceived(updateMessage);
fUpdateRunner = new BMessageRunner(this, updateMessage, fUpdateRunner = new BMessageRunner(this, updateMessage,
cfg->updateInterval); cfg->updateInterval);
} }
@ -58,11 +58,8 @@ App::MessageReceived(BMessage* msg)
switch (msg->what) switch (msg->what)
{ {
case kEnqueueFeed: case kEnqueueFeed:
{
fFeedController->MessageReceived(msg);
break;
}
case kUpdateSubscribed: case kUpdateSubscribed:
case kDownloadComplete:
{ {
fFeedController->MessageReceived(msg); fFeedController->MessageReceived(msg);
break; break;
@ -71,23 +68,18 @@ App::MessageReceived(BMessage* msg)
{ {
break; break;
} }
case kParseFail: case kParseComplete:
{ {
fNotifier->MessageReceived(msg); fNotifier->MessageReceived(msg);
fFeedController->MessageReceived(msg);
break; break;
} }
case kParseFail:
case kDownloadFail: case kDownloadFail:
{ {
fNotifier->MessageReceived(msg); fNotifier->MessageReceived(msg);
fFeedController->MessageReceived(msg); fFeedController->MessageReceived(msg);
break; break;
} }
case kDownloadComplete:
{
fFeedController->MessageReceived(msg);
break;
}
default: default:
{ {
// BApplication::MessageReceived(msg); // BApplication::MessageReceived(msg);

View File

@ -42,7 +42,7 @@ AtomFeed::Parse ()
RootParse(xfeed); RootParse(xfeed);
ParseEntries(xfeed); ParseEntries(xfeed);
_PostParse(); Filetize();
} }

View File

@ -98,24 +98,6 @@ Feed::Parse()
} }
void
Feed::_PostParse()
{
BFile feedFile(cachePath, B_WRITE_ONLY);
time_t tt_date = date.Time_t();
BString url = xmlUrl.UrlString();
BString name = GetTitle();
BString type("application/x-feed-source");
feedFile.WriteAttrString("Feed:name", &name);
feedFile.WriteAttrString("META:url", &url);
feedFile.WriteAttrString("BEOS:TYPE", &type);
feedFile.WriteAttr("Feed:when", B_TIME_TYPE, 0, &tt_date, sizeof(time_t));
feedFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, type.String(),
type.CountChars() + 1);
}
// Download a remote feed's XML to the cache path. // Download a remote feed's XML to the cache path.
bool bool
Feed::Fetch() Feed::Fetch()
@ -133,6 +115,32 @@ Feed::Fetch()
} }
void
Feed::Filetize()
{
BFile feedFile(cachePath, B_WRITE_ONLY | B_CREATE_FILE);
time_t tt_date = date.Time_t();
BString url = xmlUrl.UrlString();
BString name = GetTitle();
BString type("application/x-feed-source");
feedFile.WriteAttrString("Feed:name", &name);
feedFile.WriteAttrString("META:url", &url);
feedFile.WriteAttrString("BEOS:TYPE", &type);
feedFile.WriteAttr("Feed:when", B_TIME_TYPE, 0, &tt_date, sizeof(time_t));
feedFile.WriteAttr("BEOS:TYPE", B_MIME_STRING_TYPE, 0, type.String(),
type.CountChars() + 1);
}
void
Feed::Unfiletize()
{
BEntry entry(GetCachePath().String());
entry.Remove();
}
bool bool
Feed::IsRss() Feed::IsRss()
{ {

View File

@ -34,28 +34,32 @@ public:
bool Fetch(); bool Fetch();
void Filetize();
void Unfiletize();
bool IsRss(); bool IsRss();
bool IsAtom(); bool IsAtom();
bool IsUpdated(); bool IsUpdated();
BString GetTitle(); BString GetTitle();
bool SetDate(BDateTime);
BUrl GetXmlUrl(); BUrl GetXmlUrl();
BDateTime GetDate(); BDateTime GetDate();
bool SetTitle(const char*);
bool SetXmlUrl(BUrl newUrl);
bool SetCachePath(BString path);
BString GetCachePath(); BString GetCachePath();
protected: protected:
bool SetTitle(const char*);
bool SetTitle(tinyxml2::XMLElement*); bool SetTitle(tinyxml2::XMLElement*);
bool SetDate(BDateTime);
bool SetDate(const char*); bool SetDate(const char*);
bool SetDate(tinyxml2::XMLElement*); bool SetDate(tinyxml2::XMLElement*);
bool SetXmlUrl(BUrl newUrl);
bool SetCachePath(BString path);
bool AddEntry(Entry*); bool AddEntry(Entry*);
void _PostParse();
int xmlCountSiblings(tinyxml2::XMLElement*, const char*); int xmlCountSiblings(tinyxml2::XMLElement*, const char*);
BString title; BString title;

153
src/FeedEditWindow.cpp Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright 2020, Jaidyn Levesque <jadedctrl@teknik.io>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "FeedEditWindow.h"
#include <Button.h>
#include <Message.h>
#include <LayoutBuilder.h>
#include <SeparatorView.h>
#include <StringView.h>
#include <TextControl.h>
#include "App.h"
#include "Feed.h"
#include "FeedController.h"
#include "FeedListItem.h"
FeedEditWindow::FeedEditWindow()
:
BWindow(BRect(BPoint(-1000.0, -1000.0), BSize(500, 150)), "New Feed",
B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
{
_InitInterface();
MoveOnScreen();
fDeleteButton->SetEnabled(false);
fFeed = new Feed();
}
FeedEditWindow::FeedEditWindow(BEntry feedEntry)
:
FeedEditWindow()
{
SetTitle("Edit Feed");
fFeed = new Feed(feedEntry);
fFeedNameText->SetText(fFeed->GetTitle().String());
fFeedUrlText->SetText(fFeed->GetXmlUrl().UrlString().String());
fDeleteButton->SetEnabled(true);
}
FeedEditWindow::FeedEditWindow(FeedListItem* feedItem)
:
FeedEditWindow(BEntry(feedItem->GetFeedPath()))
{
}
void
FeedEditWindow::MessageReceived(BMessage* msg)
{
switch (msg->what)
{
case kSaveButton:
{
_SaveFeed();
break;
}
case kDeleteButton:
{
_DeleteFeed();
break;
}
}
}
void
FeedEditWindow::_InitInterface()
{
// Name and URL
fFeedNameLabel = new BStringView("feedNameLabel", "Feed name:");
fFeedNameText = new BTextControl("feedName", "", "", NULL);
fFeedUrlLabel = new BStringView("feedUrlLabel", "Feed URL:");
fFeedUrlText = new BTextControl("feedUrl", "", "", NULL);
// Save/Delete
fSaveButton = new BButton("save", "Save",
new BMessage(kSaveButton));
fDeleteButton = new BButton("delete", "Delete",
new BMessage(kDeleteButton));
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(0, B_USE_DEFAULT_SPACING, 0, 0)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
.SetInsets(B_USE_ITEM_INSETS, 0, 0, B_USE_ITEM_INSETS)
.Add(fFeedNameLabel)
.Add(fFeedUrlLabel)
.End()
.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
.SetInsets(B_USE_ITEM_INSETS, 0, B_USE_ITEM_INSETS,
B_USE_ITEM_INSETS)
.Add(fFeedNameText)
.Add(fFeedUrlText)
.End()
.End()
.Add(new BSeparatorView(B_HORIZONTAL))
.AddGroup(B_HORIZONTAL)
.AddGlue()
.Add(fDeleteButton)
.Add(fSaveButton)
.SetInsets(B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING,
B_USE_DEFAULT_SPACING, B_USE_WINDOW_SPACING)
.End()
.End();
}
void
FeedEditWindow::_SaveFeed()
{
BString subLocation("/boot/home/config/settings/Pogger/Subscriptions/");
BString title(fFeedNameText->Text());
const char* urlString = fFeedUrlText->Text();
BString filename;
if (title.IsEmpty())
filename = BString(urlString);
else
filename = BString(title);
subLocation.Append(filename);
if (fFeed->GetCachePath().IsEmpty())
fFeed->SetCachePath(subLocation);
if (!title.IsEmpty())
fFeed->SetTitle(title.String());
fFeed->SetXmlUrl(BUrl(urlString));
fFeed->Filetize();
BMessage* firstUpdate = new BMessage(kEnqueueFeed);
firstUpdate->AddData("feeds", B_RAW_TYPE, (void*)fFeed, sizeof(Feed));
((App*)be_app)->MessageReceived(firstUpdate);
Quit();
}
void
FeedEditWindow::_DeleteFeed()
{
fFeed->Unfiletize();
Quit();
}

View File

@ -17,3 +17,15 @@ FeedListItem::FeedListItem(Feed* feed)
} }
BString
FeedListItem::GetFeedPath()
{
return fFeedPath;
}
BUrl
FeedListItem::GetFeedUrl()
{
return fFeedUrl;
}

View File

@ -19,6 +19,9 @@ class FeedListItem : public BStringItem
public: public:
FeedListItem(Feed* feed); FeedListItem(Feed* feed);
BUrl GetFeedUrl();
BString GetFeedPath();
private: private:
BUrl fFeedUrl; BUrl fFeedUrl;
BString fFeedPath; BString fFeedPath;

View File

@ -14,7 +14,10 @@
#include <cstdio> #include <cstdio>
#include "App.h"
#include "Feed.h"
#include "FeedController.h" #include "FeedController.h"
#include "FeedEditWindow.h"
#include "FeedListItem.h" #include "FeedListItem.h"
@ -31,6 +34,33 @@ FeedsView::MessageReceived(BMessage* msg)
{ {
switch (msg->what) switch (msg->what)
{ {
case kFeedsAddButton:
{
FeedEditWindow* edit = new FeedEditWindow();
edit->Show();
edit->Activate();
break;
}
case kFeedsRemoveButton:
{
_RemoveSelectedFeed();
break;
}
case kFeedsEditButton:
{
_EditSelectedFeed();
break;
}
case kFeedsSelected:
{
fEditButton->SetEnabled(true);
fRemoveButton->SetEnabled(true);
break;
}
case kFeedsEdited:
{
break;
}
default: default:
{ {
// BWindow::MessageReceived(msg); // BWindow::MessageReceived(msg);
@ -47,6 +77,8 @@ FeedsView::_InitInterface()
fFeedsListView = new BListView("feedsList"); fFeedsListView = new BListView("feedsList");
fFeedsScrollView = new BScrollView("feedsScroll", fFeedsListView, fFeedsScrollView = new BScrollView("feedsScroll", fFeedsListView,
B_WILL_DRAW, false, true); B_WILL_DRAW, false, true);
fFeedsListView->SetSelectionMessage(new BMessage(kFeedsSelected));
fFeedsListView->SetInvocationMessage(new BMessage(kFeedsEditButton));
BList feeds = FeedController::SubscribedFeeds(); BList feeds = FeedController::SubscribedFeeds();
for (int i = 0; i < feeds.CountItems(); i++) { for (int i = 0; i < feeds.CountItems(); i++) {
@ -55,28 +87,32 @@ FeedsView::_InitInterface()
} }
// Add, Remove, Edit // Add, Remove, Edit
fAddButton = new BButton("addFeed", "+", fAddButton = new BButton("addFeed", "+", new BMessage(kFeedsAddButton));
new BMessage('fadd')); fRemoveButton = new BButton("removeFeed", "-", new BMessage(kFeedsRemoveButton));
fRemoveButton = new BButton("removeFeed", "-", fEditButton = new BButton("editFeed", "Edit…", new BMessage(kFeedsEditButton));
new BMessage('frem'));
font_height fontHeight; font_height fontHeight;
GetFontHeight(&fontHeight); GetFontHeight(&fontHeight);
int16 buttonHeight = int16(fontHeight.ascent + fontHeight.descent + 12); int16 buttonHeight = int16(fontHeight.ascent + fontHeight.descent + 12);
BSize charButtonSize(buttonHeight, buttonHeight); BSize charButtonSize(buttonHeight, buttonHeight);
fAddButton->SetTarget(this);
fAddButton->SetExplicitSize(charButtonSize); fAddButton->SetExplicitSize(charButtonSize);
fRemoveButton->SetTarget(this); fAddButton->SetEnabled(true);
fRemoveButton->SetExplicitSize(charButtonSize); fRemoveButton->SetExplicitSize(charButtonSize);
fRemoveButton->SetEnabled(false);
fEditButton->SetExplicitSize(
BSize(fEditButton->ExplicitPreferredSize().Width(),
charButtonSize.Height()));
fEditButton->SetEnabled(false);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0) BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(B_USE_DEFAULT_SPACING) .SetInsets(B_USE_DEFAULT_SPACING)
.Add(fFeedsScrollView) .Add(fFeedsScrollView)
// Add, Remove, and Edit buttons
.AddGroup(B_HORIZONTAL, 0, 0.0) .AddGroup(B_HORIZONTAL, 0, 0.0)
// Add and Remove buttons
.Add(new BSeparatorView(B_VERTICAL)) .Add(new BSeparatorView(B_VERTICAL))
.AddGroup(B_VERTICAL, 0, 0.0) .AddGroup(B_VERTICAL, 0, 0.0)
.AddGroup(B_HORIZONTAL, 1, 0.0) .AddGroup(B_HORIZONTAL, 1, 0.0)
@ -88,7 +124,41 @@ FeedsView::_InitInterface()
.End() .End()
.Add(new BSeparatorView(B_VERTICAL)) .Add(new BSeparatorView(B_VERTICAL))
.AddGlue() .AddGlue()
// Edit button
.Add(new BSeparatorView(B_VERTICAL))
.AddGroup(B_VERTICAL, 0, 0.0)
.AddGroup(B_HORIZONTAL, 1, 0.0)
.SetInsets(1)
.Add(fEditButton)
.End()
.Add(new BSeparatorView(B_HORIZONTAL))
.End()
.Add(new BSeparatorView(B_VERTICAL))
.End(); .End();
} }
void
FeedsView::_EditSelectedFeed()
{
int32 selIndex = fFeedsListView->CurrentSelection();
FeedListItem* selected = (FeedListItem*)fFeedsListView->ItemAt(selIndex);
FeedEditWindow* edit = new FeedEditWindow(selected);
edit->Show();
edit->Activate();
}
void
FeedsView::_RemoveSelectedFeed()
{
int32 selIndex = fFeedsListView->CurrentSelection();
FeedListItem* selected = (FeedListItem*)fFeedsListView->ItemAt(selIndex);
Feed delFeed = Feed(BEntry(selected->GetFeedPath()));
delFeed.Unfiletize();
}

View File

@ -14,6 +14,16 @@ class BListView;
class BScrollView; class BScrollView;
enum
{
kFeedsAddButton = 'sadd',
kFeedsRemoveButton = 'srem',
kFeedsEditButton = 'sedt',
kFeedsSelected = 'flsl',
kFeedsEdited = 'fedd'
};
class FeedsView : public BGroupView { class FeedsView : public BGroupView {
public: public:
FeedsView(const char* name); FeedsView(const char* name);
@ -23,8 +33,12 @@ public:
private: private:
void _InitInterface(); void _InitInterface();
void _EditSelectedFeed();
void _RemoveSelectedFeed();
BButton* fAddButton; BButton* fAddButton;
BButton* fRemoveButton; BButton* fRemoveButton;
BButton* fEditButton;
BListView* fFeedsListView; BListView* fFeedsListView;
BScrollView* fFeedsScrollView; BScrollView* fFeedsScrollView;
}; };

View File

@ -21,10 +21,7 @@
#include "UpdatesView.h" #include "UpdatesView.h"
enum { M_BUTTON_CLICKED = 'btcl' }; MainWindow::MainWindow()
MainWindow::MainWindow (void)
: :
BWindow(BRect(BPoint(-1000.0, -1000.0), BSize(520, 380)), "Pogger", BWindow(BRect(BPoint(-1000.0, -1000.0), BSize(520, 380)), "Pogger",
B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
@ -39,6 +36,14 @@ MainWindow::MessageReceived(BMessage *msg)
{ {
switch (msg->what) switch (msg->what)
{ {
case kFeedsAddButton:
case kFeedsRemoveButton:
case kFeedsEditButton:
case kFeedsSelected:
{
fFeedsView->MessageReceived(msg);
break;
}
default: default:
{ {
BWindow::MessageReceived(msg); BWindow::MessageReceived(msg);

View File

@ -24,7 +24,8 @@ Notifier::MessageReceived(BMessage* msg)
if (msg->FindString("feed_name", &feedName) == B_OK if (msg->FindString("feed_name", &feedName) == B_OK
&& msg->FindInt32("entry_count", &entryCount) == B_OK) && msg->FindInt32("entry_count", &entryCount) == B_OK)
{ {
_NewEntryNotification(feedName, entryCount); if (entryCount > 0)
_NewEntryNotification(feedName, entryCount);
} }
break; break;
} }

View File

@ -40,7 +40,7 @@ RssFeed::Parse()
RootParse(xchan); RootParse(xchan);
ParseEntries(xchan); ParseEntries(xchan);
_PostParse(); Filetize();
} }