Skip to content

Commit

Permalink
Merge pull request #1770 from Eitot/feature/date-added-field
Browse files Browse the repository at this point in the history
Add "Date Published" sorting option and table column 

The `createddate` SQL field is repurposed to show a "Date Published" option in the Sort By menu and to add a new column for the horizontal layout.
The existing "Date" sort option and column is renamed to "Last Update" to reflect its current purpose better. 
To keep things simple and tidy, the "Date Published" field has not been added to the vertical layout.
  • Loading branch information
barijaona committed Aug 26, 2024
2 parents bcf3087 + 2930d7e commit c2a8992
Show file tree
Hide file tree
Showing 30 changed files with 289 additions and 234 deletions.
16 changes: 8 additions & 8 deletions Vienna Tests/ArticleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,20 @@ class ArticleTests: XCTestCase {
XCTAssertEqual(self.article.link, link)
}

func testDate() {
func testLastUpdate() {
let date = Date()

self.article.date = date
self.article.lastUpdate = date

XCTAssertEqual(self.article.date, date)
XCTAssertEqual(self.article.lastUpdate, date)
}

func testDateCreated() {
func testPublicationDate() {
let date = Date()

self.article.createdDate = date
self.article.publicationDate = date

XCTAssertEqual(self.article.createdDate, date)
XCTAssertEqual(self.article.publicationDate, date)
}

func testBody() {
Expand Down Expand Up @@ -193,9 +193,9 @@ class ArticleTests: XCTestCase {

func testCompatibilityDate() {
let date = Date()
let dateKeyPath = "articleData." + MA_Field_Date
let dateKeyPath = "articleData." + MA_Field_LastUpdate

self.article.date = date
self.article.lastUpdate = date

XCTAssertEqual(self.article.value(forKeyPath: dateKeyPath) as? Date, date)
}
Expand Down
16 changes: 8 additions & 8 deletions Vienna Tests/VNAArticleTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,22 @@ - (void)testLink
XCTAssertEqualObjects(self.article.link, Link);
}

- (void)testDate
- (void)testLastUpdate
{
NSDate *date = [NSDate date];

self.article.date = date;
self.article.lastUpdate = date;

XCTAssertEqualObjects(self.article.date, date);
XCTAssertEqualObjects(self.article.lastUpdate, date);
}

- (void)testDateCreated
- (void)testPublicationDate
{
NSDate *date = [NSDate date];

self.article.createdDate = date;
self.article.publicationDate = date;

XCTAssertEqualObjects(self.article.createdDate, date);
XCTAssertEqualObjects(self.article.publicationDate, date);
}

- (void)testBody
Expand Down Expand Up @@ -201,9 +201,9 @@ - (void)testMarkEnclosureDowloaded
- (void)testCompatibilityDate
{
NSDate *date = [NSDate date];
NSString *dateKeyPath = [@"articleData." stringByAppendingString:MA_Field_Date];
NSString *dateKeyPath = [@"articleData." stringByAppendingString:MA_Field_LastUpdate];

self.article.date = date;
self.article.lastUpdate = date;

XCTAssertEqualObjects([self.article valueForKeyPath:dateKeyPath], date);
}
Expand Down
8 changes: 4 additions & 4 deletions Vienna/Resources/Base.lproj/Predicates.strings
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"%[All,Any,None]@ of the following are true" = "Article matches %1$[all,any,none]@ of the following conditions";
"%[Author,Folder,Subject,Text]@ %[is,is not]@ %@" = "%1$[Author,Folder,Subject,Content]@ %2$[is,is not]@ %3$@";
"%[Author,Subject,Text]@ %[contains,does not contain]@ %@" = "%1$[Author,Subject,Content]@ %2$[contains,does not contain]@ %3$@";
"%[Date]@ %[is,is greater than or equal to,is less than,is less than or equal to]@ %[yesterday]@" = "%1$[Date]@ %2$[is,is after or is,is before,is before or is]@ %3$[yesterday]@";
"%[Date]@ %[is,is greater than,is greater than or equal to,is less than,is less than or equal to]@ %[last week]@" = "%1$[Date]@ %2$[is,is after,is after or is,is before,is before or is]@ %3$[last week]@";
"%[Date]@ %[is,is less than,is less than or equal to]@ %[today]@" = "%1$[Date]@ %2$[is,is before,is before or is]@ %3$[today]@";
"%[Date]@ %[less than ago,more than ago]@ %[days,hours,minutes,months,weeks,years]@ %@" = "%1$[Date]@ %2$[is in the last,is not in the last]@ %4$@ %3$[days,hours,minutes,months,weeks,years]@";
"%[Date,PublicationDate]@ %[is,is greater than or equal to,is less than,is less than or equal to]@ %[yesterday]@" = "%1$[Last update, Date Published]@ %2$[is,is after or is,is before,is before or is]@ %3$[yesterday]@";
"%[Date,PublicationDate]@ %[is,is greater than,is greater than or equal to,is less than,is less than or equal to]@ %[last week]@" = "%1$[Last update,Date Published]@ %2$[is,is after,is after or is,is before,is before or is]@ %3$[last week]@";
"%[Date,PublicationDate]@ %[is,is less than,is less than or equal to]@ %[today]@" = "%1$[Last update,Date Published]@ %2$[is,is before,is before or is]@ %3$[today]@";
"%[Date,PublicationDate]@ %[less than ago,more than ago]@ %[days,hours,minutes,months,weeks,years]@ %@" = "%1$[Last update,Date Published]@ %2$[is in the last,is not in the last]@ %4$@ %3$[days,hours,minutes,months,weeks,years]@";
"%[Deleted,Flagged,HasEnclosure,Read]@ is %[No,Yes]@" = "%1$[Is deleted,Is flagged,Has enclosure,Is read]@ %2$[No,Yes]@";
7 changes: 7 additions & 0 deletions Vienna/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -6522,6 +6522,7 @@
},
"Date" : {
"comment" : "Data field name visible in menu/article list/smart folder definition",
"extractionState" : "stale",
"localizations" : {
"cs" : {
"stringUnit" : {
Expand Down Expand Up @@ -6645,6 +6646,9 @@
}
}
},
"Date Published" : {
"comment" : "Data field name visible in menu/article list/smart folder definition"
},
"Delete" : {
"comment" : "Title of a button on an alert\n Title of a menu item",
"localizations" : {
Expand Down Expand Up @@ -12888,6 +12892,9 @@
}
}
},
"Last Update" : {
"comment" : "Data field name visible in menu/article list/smart folder definition"
},
"Link" : {
"comment" : "Data field name visible in menu/article list",
"localizations" : {
Expand Down
38 changes: 22 additions & 16 deletions Vienna/Sources/Alerts/SmartFolder.m
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ - (void)prepareTemplates

// subject / author / text contains / = / != <text>
NSArray<NSExpression *> *textLeftExpressions = @[
[NSExpression expressionForConstantValue:@"Text"],
[NSExpression expressionForConstantValue:@"Author"],
[NSExpression expressionForConstantValue:@"Subject"]
[NSExpression expressionForConstantValue:MA_Field_Text],
[NSExpression expressionForConstantValue:MA_Field_Author],
[NSExpression expressionForConstantValue:MA_Field_Subject]
];
NSPredicateEditorRowTemplate *textTemplate = [[NSPredicateEditorRowTemplate alloc]
initWithLeftExpressions:textLeftExpressions
Expand All @@ -172,8 +172,14 @@ - (void)prepareTemplates

[rowTemplates addObject:[VNASeparatorPredicateEditorRowTemplate new]];


NSArray *dateLeftExpressions = @[
[NSExpression expressionForConstantValue:MA_Field_LastUpdate],
[NSExpression expressionForConstantValue:MA_Field_PublicationDate]];

// date < / > days / weeks / months / years old
NSPredicateEditorRowTemplate *dateCompareTemplate = [[VNADateWithUnitPredicateEditorRowTemplate alloc] initWithLeftExpressions:@[[NSExpression expressionForConstantValue:MA_Field_Date]]];
NSPredicateEditorRowTemplate *dateCompareTemplate = [[VNADateWithUnitPredicateEditorRowTemplate alloc]
initWithLeftExpressions:dateLeftExpressions];
[rowTemplates addObject:dateCompareTemplate];

// date = / < / <= today / yesterday / lastWeek
Expand All @@ -186,7 +192,7 @@ - (void)prepareTemplates
@(NSLessThanOrEqualToPredicateOperatorType),
];
NSPredicateEditorRowTemplate *todayTemplate = [[NSPredicateEditorRowTemplate alloc]
initWithLeftExpressions:@[[NSExpression expressionForConstantValue:@"Date"]]
initWithLeftExpressions:dateLeftExpressions
rightExpressions:todayRightExpressions
modifier:NSDirectPredicateModifier
operators:todayOperators
Expand All @@ -204,11 +210,11 @@ - (void)prepareTemplates
@(NSGreaterThanOrEqualToPredicateOperatorType)
];
NSPredicateEditorRowTemplate *yesterdayTemplate = [[NSPredicateEditorRowTemplate alloc]
initWithLeftExpressions:@[[NSExpression expressionForConstantValue:@"Date"]]
rightExpressions:yesterdayRightExpressions
modifier:NSDirectPredicateModifier
operators:yesterdayOperators
options:0];
initWithLeftExpressions:dateLeftExpressions
rightExpressions:yesterdayRightExpressions
modifier:NSDirectPredicateModifier
operators:yesterdayOperators
options:0];
[rowTemplates addObject:yesterdayTemplate];

// date = / > / >= / < / <= last week
Expand All @@ -223,7 +229,7 @@ - (void)prepareTemplates
@(NSLessThanOrEqualToPredicateOperatorType)
];
NSPredicateEditorRowTemplate *dateTemplate = [[NSPredicateEditorRowTemplate alloc]
initWithLeftExpressions:@[[NSExpression expressionForConstantValue:@"Date"]]
initWithLeftExpressions:dateLeftExpressions
rightExpressions:weekRightExpressions
modifier:NSDirectPredicateModifier
operators:weekOperators
Expand All @@ -234,10 +240,10 @@ - (void)prepareTemplates

// read / flagged / deleted / has_enclosure = YES / NO
NSArray<NSExpression *> *booleanLeftExpressions = @[
[NSExpression expressionForConstantValue:@"Read"],
[NSExpression expressionForConstantValue:@"Flagged"],
[NSExpression expressionForConstantValue:@"Deleted"],
[NSExpression expressionForConstantValue:@"HasEnclosure"]
[NSExpression expressionForConstantValue:MA_Field_Read],
[NSExpression expressionForConstantValue:MA_Field_Flagged],
[NSExpression expressionForConstantValue:MA_Field_Deleted],
[NSExpression expressionForConstantValue:MA_Field_HasEnclosure]
];
NSArray<NSExpression *> *booleanRightExpressions = @[
[NSExpression expressionForConstantValue:@"Yes"],
Expand All @@ -256,7 +262,7 @@ - (void)prepareTemplates
// folder is / is not
NSArray<NSExpression *> *folders = [self fillFolderValueField:VNAFolderTypeRoot atIndent:0];
NSPredicateEditorRowTemplate *folderTemplate = [[NSPredicateEditorRowTemplate alloc]
initWithLeftExpressions:@[[NSExpression expressionForConstantValue:@"Folder"]]
initWithLeftExpressions:@[[NSExpression expressionForConstantValue:MA_Field_Folder]]
rightExpressions:folders
modifier:NSDirectPredicateModifier
operators:@[@(NSEqualToPredicateOperatorType), @(NSNotEqualToPredicateOperatorType)]
Expand Down
34 changes: 15 additions & 19 deletions Vienna/Sources/Application/AppController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1143,15 +1143,15 @@ -(void)initSortMenu
for (Field * field in [db arrayOfFields]) {
// Filter out columns we don't sort on. Later we should have an attribute in the
// field object itself based on which columns we can sort on.
if (field.tag != ArticleFieldIDParent &&
field.tag != ArticleFieldIDGUID &&
field.tag != ArticleFieldIDDeleted &&
field.tag != ArticleFieldIDHeadlines &&
field.tag != ArticleFieldIDSummary &&
field.tag != ArticleFieldIDLink &&
field.tag != ArticleFieldIDText &&
field.tag != ArticleFieldIDEnclosureDownloaded &&
field.tag != ArticleFieldIDEnclosure)
if (field.tag != VNAArticleFieldTagParent &&
field.tag != VNAArticleFieldTagGUID &&
field.tag != VNAArticleFieldTagDeleted &&
field.tag != VNAArticleFieldTagHeadlines &&
field.tag != VNAArticleFieldTagSummary &&
field.tag != VNAArticleFieldTagLink &&
field.tag != VNAArticleFieldTagText &&
field.tag != VNAArticleFieldTagEnclosureDownloaded &&
field.tag != VNAArticleFieldTagEnclosure)
{
NSMenuItem * menuItem = [[NSMenuItem alloc] initWithTitle:field.displayName action:@selector(doSortColumn:) keyEquivalent:@""];
menuItem.representedObject = field;
Expand Down Expand Up @@ -1184,12 +1184,12 @@ -(void)initColumnsMenu
for (Field * field in [db arrayOfFields]) {
// Filter out columns we don't view in the article list. Later we should have an attribute in the
// field object based on which columns are visible in the tableview.
if (field.tag != ArticleFieldIDText &&
field.tag != ArticleFieldIDGUID &&
field.tag != ArticleFieldIDDeleted &&
field.tag != ArticleFieldIDParent &&
field.tag != ArticleFieldIDHeadlines &&
field.tag != ArticleFieldIDEnclosureDownloaded)
if (field.tag != VNAArticleFieldTagText &&
field.tag != VNAArticleFieldTagGUID &&
field.tag != VNAArticleFieldTagDeleted &&
field.tag != VNAArticleFieldTagParent &&
field.tag != VNAArticleFieldTagHeadlines &&
field.tag != VNAArticleFieldTagEnclosureDownloaded)
{
NSMenuItem * menuItem = [[NSMenuItem alloc] initWithTitle:field.displayName action:@selector(doViewColumn:) keyEquivalent:@""];
menuItem.representedObject = field;
Expand Down Expand Up @@ -1764,10 +1764,6 @@ -(void)handleFolderNameChange:(NSNotification *)nc
-(void)handleRefreshStatusChange:(NSNotification *)nc
{
if (self.connecting) {
// Save the date/time of this refresh so we do the right thing when
// we apply the filter.
[[Preferences standardPreferences] setObject:[NSDate date] forKey:MAPref_LastRefreshDate];

// Toggle the refresh button
NSToolbarItem *item = [self toolbarItemWithIdentifier:@"Refresh"];
item.action = @selector(cancelAllRefreshesToolbar:);
Expand Down
12 changes: 7 additions & 5 deletions Vienna/Sources/Criteria/Criteria+NSPredicate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ extension Criteria: PredicateConvertible {
fallback = true
criteriaOperator = .equalTo
}
case MA_Field_Date:
case MA_Field_LastUpdate, MA_Field_PublicationDate:
switch predicate.predicateOperatorType {
case .lessThan:
criteriaOperator = .before
Expand Down Expand Up @@ -231,14 +231,15 @@ extension Criteria: PredicateConvertible {
let value = self.value
let operatorType = self.operatorType

if field == MA_Field_Date, let unit = DateUnit.allCases.first(where: { value.hasSuffix($0.rawValue) }) {
if field == MA_Field_LastUpdate || field == MA_Field_PublicationDate,
let unit = DateUnit.allCases.first(where: { value.hasSuffix($0.rawValue) }) {
let countString = value
.replacingOccurrences(of: unit.rawValue, with: "")
.trimmingCharacters(in: CharacterSet.whitespaces)
guard let count = UInt(countString) else {
fatalError("malformed criteria value \(value)")
}
return DatePredicateWithUnit(field: MA_Field_Date, comparisonOperator: operatorType, count: count, unit: unit)
return DatePredicateWithUnit(field: field, comparisonOperator: operatorType, count: count, unit: unit)
} else {
return buildComparisonPredicate(field, value, operatorType)
}
Expand Down Expand Up @@ -291,9 +292,10 @@ extension Criteria: PredicateConvertible {
// TODO: constants for fixed criteria values also for Criteria+SQL,
// e.g. YES, NO, yesterday, today, last week, ...

if field == MA_Field_Date && operatorType == .after && value == "yesterday" {
if (field == MA_Field_LastUpdate || field == MA_Field_PublicationDate)
&& operatorType == .after && value == DateOffset.yesterday.rawValue {
// Use canonical "is today" instead of "is after yesterday"
comparisonPredicate = NSComparisonPredicate(leftExpression: left, rightExpression: NSExpression(forConstantValue: "today"), modifier: .direct, type: .equalTo)
comparisonPredicate = NSComparisonPredicate(leftExpression: left, rightExpression: NSExpression(forConstantValue: DateOffset.today), modifier: .direct, type: .equalTo)
} else if operatorType == .notEqualTo && (value == "No" || value == "Yes") {
// Use canonical "is yes / is no" representation instead of allowing
// ambiguous "is not yes - is no / is not no - is yes"
Expand Down
12 changes: 6 additions & 6 deletions Vienna/Sources/Criteria/Criteria+SQL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ extension Criteria: SQLConversion {
let startOfToday = Calendar.current.startOfDay(for: Date())

let startDate: Date?
if value == "today" {
if value == DateOffset.today.rawValue {
startDate = startOfToday
} else if value == "yesterday" {
} else if value == DateOffset.yesterday.rawValue {
startDate = Calendar.current.date(byAdding: .day, value: -1, to: startOfToday)
} else if value == "last week" {
} else if value == DateOffset.lastWeek.rawValue {
startDate = Calendar.current.date(byAdding: .weekOfYear, value: -1, to: startOfToday)
} else {
// Check for the pattern for date with unit criteria
Expand Down Expand Up @@ -142,10 +142,10 @@ extension Criteria: SQLConversion {
guard operatorType == .equalTo || operatorType == .notEqualTo else {
fatalError("Operator type \(operatorType) not applicable to flag field \(sqlFieldName)")
}
let val: String
if value == "Yes" { val = "1" } else { val = "0" }
let sqlValue: String
if value == "Yes" { sqlValue = "1" } else { sqlValue = "0" }
let sqlOperator = standardSqlOperator()
return "\(sqlFieldName) \(sqlOperator) \(val)"
return "\(sqlFieldName) \(sqlOperator) \(sqlValue)"
}

func folderSqlString(sqlFieldName: String, database: Database) -> String {
Expand Down
30 changes: 14 additions & 16 deletions Vienna/Sources/Criteria/Criteria.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,40 +45,38 @@ enum CriteriaOperator: Int {

// Workaround as long as this enum needs to be exposed to Objective-C and cannot have a string as raw value
init?(rawValue: String) {
let criteriaOperator: CriteriaOperator
switch rawValue {
case "\(CriteriaOperator.equalTo)":
criteriaOperator = CriteriaOperator.equalTo
self = CriteriaOperator.equalTo
case "\(CriteriaOperator.notEqualTo)":
criteriaOperator = CriteriaOperator.notEqualTo
self = CriteriaOperator.notEqualTo
case "\(CriteriaOperator.lessThan)":
criteriaOperator = CriteriaOperator.lessThan
self = CriteriaOperator.lessThan
case "\(CriteriaOperator.greaterThan)":
criteriaOperator = CriteriaOperator.greaterThan
self = CriteriaOperator.greaterThan
case "\(CriteriaOperator.lessThanOrEqualTo)":
criteriaOperator = CriteriaOperator.lessThanOrEqualTo
self = CriteriaOperator.lessThanOrEqualTo
case "\(CriteriaOperator.greaterThanOrEqualTo)":
criteriaOperator = CriteriaOperator.greaterThanOrEqualTo
self = CriteriaOperator.greaterThanOrEqualTo
case "\(CriteriaOperator.contains)":
criteriaOperator = CriteriaOperator.contains
self = CriteriaOperator.contains
case "\(CriteriaOperator.containsNot)":
criteriaOperator = CriteriaOperator.containsNot
self = CriteriaOperator.containsNot
case "\(CriteriaOperator.before)":
criteriaOperator = CriteriaOperator.before
self = CriteriaOperator.before
case "\(CriteriaOperator.after)":
criteriaOperator = CriteriaOperator.after
self = CriteriaOperator.after
case "\(CriteriaOperator.onOrBefore)":
criteriaOperator = CriteriaOperator.onOrBefore
self = CriteriaOperator.onOrBefore
case "\(CriteriaOperator.onOrAfter)":
criteriaOperator = CriteriaOperator.onOrAfter
self = CriteriaOperator.onOrAfter
case "\(CriteriaOperator.under)":
criteriaOperator = CriteriaOperator.under
self = CriteriaOperator.under
case "\(CriteriaOperator.notUnder)":
criteriaOperator = CriteriaOperator.notUnder
self = CriteriaOperator.notUnder
default:
return nil
}
self.init(rawValue: criteriaOperator.rawValue)
}

var intValue: Int {
Expand Down
4 changes: 4 additions & 0 deletions Vienna/Sources/Criteria/DatePredicateWithUnit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

import Foundation

enum DateOffset: String {
case today, yesterday, lastWeek = "last week"
}

enum DateUnit: String, CaseIterable {
case minutes
case hours
Expand Down
Loading

0 comments on commit c2a8992

Please sign in to comment.