mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-05 16:58:59 +00:00
Rewriting short and long date formatting, both for server and ios. Also loading offline stories when server fails half-way through.
This commit is contained in:
parent
fe237cb80c
commit
a56f44cdef
12 changed files with 169 additions and 45 deletions
|
@ -611,7 +611,7 @@ def load_single_feed(request, feed_id):
|
|||
if not include_story_content:
|
||||
del story['story_content']
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
if usersub:
|
||||
story['read_status'] = 1
|
||||
|
@ -683,6 +683,9 @@ def load_single_feed(request, feed_id):
|
|||
# if page <= 1:
|
||||
# import random
|
||||
# time.sleep(random.randint(0, 3))
|
||||
|
||||
# if page == 2:
|
||||
# assert False
|
||||
|
||||
return data
|
||||
|
||||
|
@ -797,7 +800,7 @@ def load_starred_stories(request):
|
|||
|
||||
for story in stories:
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
starred_date = localtime_for_timezone(story['starred_date'], user.profile.timezone)
|
||||
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
||||
|
@ -960,7 +963,7 @@ def load_river_stories__redis(request):
|
|||
story['story_hash'] not in unread_feed_story_hashes):
|
||||
story['read_status'] = 1
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
if story['story_hash'] in starred_stories:
|
||||
story['starred'] = True
|
||||
|
|
|
@ -125,8 +125,8 @@ def load_social_stories(request, user_id, username=None):
|
|||
story['social_user_id'] = social_user_id
|
||||
# story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
shared_date = localtime_for_timezone(story['shared_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(shared_date, now)
|
||||
story['long_parsed_date'] = format_story_link_date__long(shared_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(shared_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(shared_date)
|
||||
|
||||
story['read_status'] = 1
|
||||
if (read_filter == 'all' or query) and socialsub:
|
||||
|
@ -279,7 +279,7 @@ def load_river_blurblog(request):
|
|||
if story['story_hash'] not in unread_feed_story_hashes:
|
||||
story['read_status'] = 1
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
if story['story_hash'] in starred_stories:
|
||||
story['starred'] = True
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
NSString *storyTitle;
|
||||
NSString *storyAuthor;
|
||||
NSString *storyDate;
|
||||
NSInteger storyTimestamp;
|
||||
int storyScore;
|
||||
BOOL isStarred;
|
||||
BOOL isShared;
|
||||
|
@ -44,6 +45,7 @@
|
|||
@property (nonatomic) NSString *storyTitle;
|
||||
@property (nonatomic) NSString *storyAuthor;
|
||||
@property (nonatomic) NSString *storyDate;
|
||||
@property (nonatomic) NSInteger storyTimestamp;
|
||||
|
||||
@property (nonatomic) UIColor *feedColorBar;
|
||||
@property (nonatomic) UIColor *feedColorBarTopBorder;
|
||||
|
|
|
@ -23,6 +23,7 @@ static UIFont *indicatorFont = nil;
|
|||
@synthesize storyTitle;
|
||||
@synthesize storyAuthor;
|
||||
@synthesize storyDate;
|
||||
@synthesize storyTimestamp;
|
||||
@synthesize storyScore;
|
||||
@synthesize siteTitle;
|
||||
@synthesize siteFavicon;
|
||||
|
@ -223,7 +224,8 @@ static UIFont *indicatorFont = nil;
|
|||
}
|
||||
|
||||
paragraphStyle.alignment = NSTextAlignmentRight;
|
||||
[cell.storyDate
|
||||
NSString *date = [Utilities formatShortDateFromTimestamp:cell.storyTimestamp];
|
||||
[date
|
||||
drawInRect:CGRectMake(leftMargin + (rect.size.width) / 2 - 10, storyAuthorDateY, (rect.size.width) / 2 + 10, 15.0)
|
||||
withAttributes:@{NSFontAttributeName: font,
|
||||
NSForegroundColorAttributeName: textColor,
|
||||
|
|
|
@ -301,7 +301,8 @@
|
|||
|
||||
- (void)beginOfflineTimer {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
if (!appDelegate.storyLocationsCount && self.feedPage == 1 && !self.isOffline) {
|
||||
if (!appDelegate.storyLocationsCount && !self.pageFinished &&
|
||||
self.feedPage == 1 && !self.isOffline) {
|
||||
self.isShowingOffline = YES;
|
||||
self.isOffline = YES;
|
||||
[self showLoadingNotifier];
|
||||
|
@ -381,13 +382,11 @@
|
|||
if (request.isCancelled) {
|
||||
NSLog(@"Cancelled");
|
||||
return;
|
||||
} else if (self.feedPage == 1) {
|
||||
} else {
|
||||
self.isOffline = YES;
|
||||
self.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
} else {
|
||||
[self informError:[request error]];
|
||||
self.pageFinished = YES;
|
||||
}
|
||||
[self.storyTitlesTable reloadData];
|
||||
}];
|
||||
|
@ -574,15 +573,12 @@
|
|||
if (request.isCancelled) {
|
||||
NSLog(@"Cancelled");
|
||||
return;
|
||||
} else if (self.feedPage == 1) {
|
||||
} else {
|
||||
self.isOffline = YES;
|
||||
self.isShowingOffline = NO;
|
||||
self.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
} else {
|
||||
[self informError:[request error]];
|
||||
self.pageFinished = YES;
|
||||
[self.storyTitlesTable reloadData];
|
||||
}
|
||||
}];
|
||||
[request setCompletionBlock:^(void) {
|
||||
|
@ -604,12 +600,11 @@
|
|||
NSLog(@"Cancelled");
|
||||
return;
|
||||
} else if ([request responseStatusCode] >= 500) {
|
||||
if (self.feedPage == 1) {
|
||||
self.isOffline = YES;
|
||||
self.isShowingOffline = NO;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
}
|
||||
self.isOffline = YES;
|
||||
self.isShowingOffline = NO;
|
||||
self.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
if ([request responseStatusCode] == 503) {
|
||||
[self informError:@"In maintenance mode"];
|
||||
self.pageFinished = YES;
|
||||
|
@ -902,8 +897,9 @@
|
|||
|
||||
NSString *title = [story objectForKey:@"story_title"];
|
||||
cell.storyTitle = [title stringByDecodingHTMLEntities];
|
||||
|
||||
|
||||
cell.storyDate = [story objectForKey:@"short_parsed_date"];
|
||||
cell.storyTimestamp = [[story objectForKey:@"story_timestamp"] integerValue];
|
||||
cell.isStarred = [[story objectForKey:@"starred"] boolValue];
|
||||
cell.isShared = [[story objectForKey:@"shared"] boolValue];
|
||||
|
||||
|
|
|
@ -1922,7 +1922,7 @@
|
|||
NSMutableDictionary *newStory = [story mutableCopy];
|
||||
[newStory setValue:[NSNumber numberWithBool:saved] forKey:@"starred"];
|
||||
if (saved) {
|
||||
[newStory setValue:[Utilities formatDateFromTimestamp:nil] forKey:@"starred_date"];
|
||||
[newStory setValue:[Utilities formatLongDateFromTimestamp:nil] forKey:@"starred_date"];
|
||||
} else {
|
||||
[newStory removeObjectForKey:@"starred_date"];
|
||||
}
|
||||
|
|
|
@ -360,6 +360,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
NSString *storyDate = [Utilities formatLongDateFromTimestamp:[[self.activeStory
|
||||
objectForKey:@"story_timestamp"]
|
||||
integerValue]];
|
||||
NSString *storyHeader = [NSString stringWithFormat:@
|
||||
"<div class=\"NB-header\"><div class=\"NB-header-inner\">"
|
||||
"<div class=\"NB-story-title\">"
|
||||
|
@ -373,7 +376,7 @@
|
|||
"</div></div>",
|
||||
storyUnread,
|
||||
storyTitle,
|
||||
[self.activeStory objectForKey:@"long_parsed_date"],
|
||||
storyDate,
|
||||
storyAuthor,
|
||||
storyTags,
|
||||
storyStarred];
|
||||
|
|
|
@ -22,6 +22,7 @@ void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor
|
|||
+ (void)saveimagesToDisk;
|
||||
+ (UIImage *)roundCorneredImage:(UIImage *)orig radius:(CGFloat)r;
|
||||
+ (NSString *)md5:(NSString *)string;
|
||||
+ (NSString *)formatDateFromTimestamp:(NSInteger)timestamp;
|
||||
+ (NSString *)formatLongDateFromTimestamp:(NSInteger)timestamp;
|
||||
+ (NSString *)formatShortDateFromTimestamp:(NSInteger)timestamp;
|
||||
|
||||
@end
|
||||
|
|
|
@ -154,14 +154,117 @@ static NSMutableDictionary *imageCache;
|
|||
];
|
||||
}
|
||||
|
||||
+ (NSString *)formatDateFromTimestamp:(NSInteger)timestamp {
|
||||
+ (NSString *)formatLongDateFromTimestamp:(NSInteger)timestamp {
|
||||
if (!timestamp) timestamp = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(double)timestamp];
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:@"LLLL, d Y h:mma"];
|
||||
static NSDateFormatter *dateFormatter = nil;
|
||||
static NSDateFormatter *todayFormatter = nil;
|
||||
static NSDateFormatter *yesterdayFormatter = nil;
|
||||
static NSDateFormatter *formatterPeriod = nil;
|
||||
|
||||
NSDate *today = [NSDate date];
|
||||
NSDateComponents *components = [[NSCalendar currentCalendar]
|
||||
components:NSIntegerMax
|
||||
fromDate:today];
|
||||
[components setHour:0];
|
||||
[components setMinute:0];
|
||||
[components setSecond:0];
|
||||
NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
|
||||
NSDate *yesterday = [NSDate dateWithTimeInterval:-60*60*24 sinceDate:midnight];
|
||||
|
||||
if (!dateFormatter || !todayFormatter || !yesterdayFormatter || !formatterPeriod) {
|
||||
dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setDateFormat:@"EEEE, MMMM d'Sth', y h:mm"];
|
||||
todayFormatter = [[NSDateFormatter alloc] init];
|
||||
[todayFormatter setDateFormat:@"'Today', MMMM d'Sth' h:mm"];
|
||||
yesterdayFormatter = [[NSDateFormatter alloc] init];
|
||||
[yesterdayFormatter setDateFormat:@"'Yesterday', MMMM d'Sth' h:mm"];
|
||||
formatterPeriod = [[NSDateFormatter alloc] init];
|
||||
[formatterPeriod setDateFormat:@"a"];
|
||||
}
|
||||
|
||||
NSString *dateString;
|
||||
if ([date compare:midnight] == NSOrderedDescending) {
|
||||
dateString = [NSString stringWithFormat:@"%@%@",
|
||||
[todayFormatter stringFromDate:date],
|
||||
[[formatterPeriod stringFromDate:date] lowercaseString]];
|
||||
} else if ([date compare:yesterday] == NSOrderedDescending) {
|
||||
dateString = [NSString stringWithFormat:@"%@%@",
|
||||
[yesterdayFormatter stringFromDate:date],
|
||||
[[formatterPeriod stringFromDate:date] lowercaseString]];
|
||||
} else {
|
||||
dateString = [NSString stringWithFormat:@"%@%@",
|
||||
[dateFormatter stringFromDate:date],
|
||||
[[formatterPeriod stringFromDate:date] lowercaseString]];
|
||||
}
|
||||
dateString = [dateString stringByReplacingOccurrencesOfString:@"Sth"
|
||||
withString:[Utilities suffixForDayInDate:date]];
|
||||
|
||||
return [formatter stringFromDate:date];
|
||||
return dateString;
|
||||
}
|
||||
|
||||
+ (NSString *)formatShortDateFromTimestamp:(NSInteger)timestamp {
|
||||
if (!timestamp) timestamp = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(double)timestamp];
|
||||
static NSDateFormatter *dateFormatter = nil;
|
||||
static NSDateFormatter *todayFormatter = nil;
|
||||
static NSDateFormatter *yesterdayFormatter = nil;
|
||||
static NSDateFormatter *formatterPeriod = nil;
|
||||
|
||||
NSDate *today = [NSDate date];
|
||||
NSDateComponents *components = [[NSCalendar currentCalendar]
|
||||
components:NSIntegerMax
|
||||
fromDate:today];
|
||||
[components setHour:0];
|
||||
[components setMinute:0];
|
||||
[components setSecond:0];
|
||||
NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
|
||||
NSDate *yesterday = [NSDate dateWithTimeInterval:-60*60*24 sinceDate:midnight];
|
||||
|
||||
if (!dateFormatter || !todayFormatter || !yesterdayFormatter || !formatterPeriod) {
|
||||
dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setDateFormat:@"dd LLL y, h:mm"];
|
||||
todayFormatter = [[NSDateFormatter alloc] init];
|
||||
[todayFormatter setDateFormat:@"h:mm"];
|
||||
yesterdayFormatter = [[NSDateFormatter alloc] init];
|
||||
[yesterdayFormatter setDateFormat:@"'Yesterday', h:mm"];
|
||||
formatterPeriod = [[NSDateFormatter alloc] init];
|
||||
[formatterPeriod setDateFormat:@"a"];
|
||||
}
|
||||
|
||||
NSString *dateString;
|
||||
if ([date compare:midnight] == NSOrderedDescending) {
|
||||
dateString = [NSString stringWithFormat:@"%@%@",
|
||||
[todayFormatter stringFromDate:date],
|
||||
[[formatterPeriod stringFromDate:date] lowercaseString]];
|
||||
} else if ([date compare:yesterday] == NSOrderedDescending) {
|
||||
dateString = [NSString stringWithFormat:@"%@%@",
|
||||
[yesterdayFormatter stringFromDate:date],
|
||||
[[formatterPeriod stringFromDate:date] lowercaseString]];
|
||||
} else {
|
||||
dateString = [NSString stringWithFormat:@"%@%@",
|
||||
[dateFormatter stringFromDate:date],
|
||||
[[formatterPeriod stringFromDate:date] lowercaseString]];
|
||||
}
|
||||
|
||||
return dateString;
|
||||
}
|
||||
|
||||
+ (NSString *)suffixForDayInDate:(NSDate *)date {
|
||||
NSInteger day = [[[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] components:NSDayCalendarUnit fromDate:date] day];
|
||||
if (day == 11) {
|
||||
return @"th";
|
||||
} else if (day % 10 == 1) {
|
||||
return @"st";
|
||||
} else if (day % 10 == 2) {
|
||||
return @"nd";
|
||||
} else if (day % 10 == 3) {
|
||||
return @"rd";
|
||||
} else {
|
||||
return @"th";
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -2606,7 +2606,7 @@
|
|||
"-all_load",
|
||||
);
|
||||
PRODUCT_NAME = NewsBlur;
|
||||
PROVISIONING_PROFILE = "A0156932-124B-4F8E-8B93-EE6598D778F0";
|
||||
PROVISIONING_PROFILE = "EB97D956-BB90-4F2F-9919-F71949B04B3F";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
"WARNING_CFLAGS[arch=*]" = "-Wall";
|
||||
};
|
||||
|
@ -2638,7 +2638,7 @@
|
|||
"-all_load",
|
||||
);
|
||||
PRODUCT_NAME = NewsBlur;
|
||||
PROVISIONING_PROFILE = "A0156932-124B-4F8E-8B93-EE6598D778F0";
|
||||
PROVISIONING_PROFILE = "EB97D956-BB90-4F2F-9919-F71949B04B3F";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
|
||||
//#define DEBUG 1
|
||||
#define DEBUG 1
|
||||
|
||||
#ifdef DEBUG
|
||||
#define BACKGROUND_REFRESH_SECONDS -5
|
||||
|
|
|
@ -17,25 +17,39 @@ from vendor import reseekfile
|
|||
# COMMENTS_RE = re.compile('\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>')
|
||||
COMMENTS_RE = re.compile('\<!--.*?--\>')
|
||||
|
||||
def format_story_link_date__short(date, now=None):
|
||||
if not now: now = datetime.datetime.now()
|
||||
diff = date.date() - now.date()
|
||||
if diff.days == 0:
|
||||
def midnight_today():
|
||||
return datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
def midnight_yesterday(midnight=None):
|
||||
if not midnight:
|
||||
midnight = midnight_today()
|
||||
return midnight - datetime.timedelta(days=1)
|
||||
|
||||
def beginning_of_this_month():
|
||||
return datetime.datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
def format_story_link_date__short(date):
|
||||
date = date.replace(tzinfo=None)
|
||||
midnight = midnight_today()
|
||||
if date > midnight:
|
||||
return date.strftime('%I:%M%p').lstrip('0').lower()
|
||||
elif diff.days == 1:
|
||||
elif date > midnight_yesterday(midnight):
|
||||
return 'Yesterday, ' + date.strftime('%I:%M%p').lstrip('0').lower()
|
||||
else:
|
||||
return date.strftime('%d %b %Y, ') + date.strftime('%I:%M%p').lstrip('0').lower()
|
||||
|
||||
def format_story_link_date__long(date, now=None):
|
||||
if not now: now = datetime.datetime.utcnow()
|
||||
diff = now.date() - date.date()
|
||||
if not now:
|
||||
now = datetime.datetime.now()
|
||||
date = date.replace(tzinfo=None)
|
||||
midnight = midnight_today()
|
||||
parsed_date = DateFormat(date)
|
||||
if diff.days == 0:
|
||||
|
||||
if date > midnight:
|
||||
return 'Today, ' + parsed_date.format('F jS ') + date.strftime('%I:%M%p').lstrip('0').lower()
|
||||
elif diff.days == 1:
|
||||
elif date > midnight_yesterday(midnight):
|
||||
return 'Yesterday, ' + parsed_date.format('F jS g:ia').replace('.','')
|
||||
elif date.date().timetuple()[7] == now.date().timetuple()[7]:
|
||||
elif date > beginning_of_this_month():
|
||||
return parsed_date.format('l, F jS g:ia').replace('.','')
|
||||
else:
|
||||
return parsed_date.format('l, F jS, Y g:ia').replace('.','')
|
||||
|
|
Loading…
Add table
Reference in a new issue